I am working on a game framework that would allow users to use multiple mods/plugins to add additional features to the game.
For the remainder of the post, I'll use the following definitions:
mod
: code that requires changes to both the client and the server. For example, adding a new packet to the protocol.
plugin
: code that changes existing functionality without requiring a change on the other side. For example, adding a remote management interface to the server, or allows the client more fine-grained controls over sound and audio quality.
This question relates to both of these aspects, however I'll be focusing on mods
as they seem to be giving me the biggest trouble.
Let's say I provide a default player class called Player
that models a Player's character. Let's say, for this particular server, the server operator wants to include 2 mods
, Foo
and Bar
, both of which are written by different people.
Both Foo
and Bar
need to add additional functionality to the Player
class. Foo
needs a method doFoo
, and Bar
needs a method doBar
. Both actual implementations are included somehow by the mod developers (probably in a different class).
One solution I've considered is using Reflection, and modifying the class at runtime, extending specific mod interfaces. Something like
public interface FooPlayer {
void doFoo();
}
public interface BarPlayer {
void doBar();
}
public class FooPlayerImplementation implements FooPlayer {
public void doFoo() {
// ...
}
}
public class BarPlayerImplementation implements BarPlayer {
public void doBar() {
// ...
}
}
public class FooLoader {
public void onLoad() {
SomeManager.findPlayerClass()
.implementInterface(FooPlayer.class, FooPlayerImplementation.class);
}
}
public class BarLoader {
public void onLoad() {
SomeManager.findPlayerClass()
.implementInterface(BarPlayer.class, BarPlayerImplementation.class);
}
}
Where at runtime, it would inject the Player
class with the implementations from Foo
and Bar
, and make it implement FooPlayer
and BarPlayer
. But then we have issues where two different mods add the same method signature in their own interface (which could be resolved by prepending the class name to the method, but then we're going down a very dark rabbit hole).
Another thing that I had thought about briefly was just going event-driven to an insane degree, so that developers didn't need to do something like this, but that opens an equally hair can of worms, as well as not providing the amount of control a developer might need.
But I'd REALLY like to avoid reflection if at all possible.
I've seen AspectJ and aspect-oriented programming, and it looks like it may work, but I don't have any experience to tell.
The questions I have are:
- Is there a way to get this sort of functionality in an OOP way?
- Is there a way to do this with the standard Java SE library?
- Could AOP accomplish this?
Considerations: If any of these are wrong or misguided, please let me know.
- I don't think that inheritance will work because there could be multiple mods that want to extend the functionality of
Player
, and allPlayer
s would be subject to all of themods
. There couldn't be aFooPlayer
and aFooBarPlayer
at the same time. Ifn
mods extend the Player functionality, than the Player must haven
components. - The decorator pattern won't really work I think because manual intervention would be required by the operator (who may or may not know anything about programming) to weave the implementations together.
Something like
public class FooBarStaminaMagickaPlayer implements Player, Foo, Bar, Stamina, Magicka
- If possible, I would like to avoid having each mod developer have a mapping within their code to keep track of things.
For example, something like
public class StaminaMapper {
private final Map<Player, Stamina> playerStaminaMap;
}