As a player, I found the following problems about creating and using "extensions" (aka mods) for games:
1) Whenever the game is updated, all the mods break.
2) Most mods don't work with each other, so the player "has to choose"
3) If you ever de-install a mod, your "saved games" almost always become unusable.
I want to design a game in Scala/Java that does NOT exhibit those issues. I need help with point 2. I want to write it such that it is maximally extensible. My problem is I cannot nail down properly how I should do this, and since the whole design reside on top of the component/service/plugin architecture, than I can't move forward until I solved this problem.
The design qualities I want to achieve are:
1) For any "service", there should be a single object (at any given time) that implements it. Since it is a cycle-based simulation, I can safely "swap implementation" between the cycles.
2) It should be possible for a "third party" to create a "bundle" which either modifies or more likely extends the functionality of a "service", and "bind" it into the existing application at runtime, without recompilation.
3) It should be possible to load and unload those bundles at runtime, because they will be used in a long-running server.
4) Developing extensions should be easily possible, even for a "junior" programmer, without requiring extensive knowledge of some complex framework.
5) It should be possible for several bundles to extend/modify the same service at the same time, as long as they follow a certain set of rules preventing most conflicts.
I was first planning to use OSGi, but I can't really see how to get this to work. OSGi solution is to let many bundles register the same service and use a "filter" to choose one in the client code. Making the code aware that at any given time, there can be several objects that implements different variations of the same service, and that those instances can come and go, would make everything much too complicated and brittle.
My plan was to register every service as a generic "handle", which the user of the service can use to get the real instance and cast to what they want. The handle content could change over time, but the handle object itself would be valid for the duration of the program, therefore bypassing the constant querying of the registry, with associated filtering.
I think OSGi can solve 2 to 5, but only by using multiple instances of the same service, which is in contradiction to 1. I think that 1 an be achieved either by using composition, or by fusing all the different implementation of a service into a single object through byte-code manipulation. A look at Javaassist showed me that "rebasing" a class does not seem too difficult, if they all extend the same base-class and take the same constructor parameters. Composition, on the other hand, seem to put much more work on the hands of the third-party extensions developers, which is in contradiction to 4, and generally is a clunky solution at best.
If I implement the byte-code manipulation strategy, than I have to basically do almost everything myself, and loose most of the benefits of OSGi. Also, I cannot really create the fused service until all bundles have been activated, so they cannot register a "real" service instance at activation time, which is what OSGi is about (?). Do I even know from OSGi when it's "done"?
Is the only way of achieving those designs goal to create my own component framework, or can I still do it using OSGi, or some other system? Reinventing the wheel at that level sound like a stupid (and time consuming) idea, but I can't see how to solve those problems with OSGi. Maybe another service/plugin framework can do it? Or by using a specific well-defined design strategy?
UPDATE: It will a be an Internet Client-Server (Cluster) model running on OpenGL. I am mostly "framework unencumbered", that is, I can choose whatever fits my needs, but I want to stick to the JVM. OSGi is an attempt at standardizing "components" (called bundles) for the JVM.