OSGi - a dynamic plugin reloader type mod useful for development

Ahoi, good people of Sponge,

is a mod which is a kind of “dynamic plugin reloader” of other mods. This can be a very useful tool for other mod developers as a time saver during development. This goes way beyond what e.g. hot-swapping by the debugger from the IDE can do, as it really re-loads the entire mod, on change. The README explains how to set it up and use it.

It is based on a technology called OSGi, which is the de-facto standard for modular dynamic development in Java. Mods have to be valid OSGi bundles for this to work, but an OSGi bundle is just a JAR file, and your same mod JAR file can well be also a “normal” (traditional) Sponge mod JAR.

Hope this is useful - enjoy, and have fun modding.

Best,
M. http://www.vorburger.ch

2 Likes

I’m not particularly sure what the purpose of this is. I’ve never had an issue with HotSwapping, I guess, that would warrant an advanced “replacement” of the sort.

This just seems like it would be hacky at best for some things, and I’m mostly concerned about just this complicating the process that people suggest for making plugins in the future.

Also, I really hope that this doesn’t move very far past a development tool.

If I am understanding this correctly, this is something that allows the server to unload a plugin, allow for a change, and then reload it in with those changes… Which would be very beneficial for large modpacks that take 5 minutes or so to restart.

You don’t quite understand the potential downsides of that. That could literally break everything that the plugin was doing on the server due to the way Sponge works. It’s relatively dangerous, especially since Sponge isn’t built with this system in mind.

1 Like

Plugins are built directly on the Sponge API, assuming Sponge functionality, and truth of Sponge documentation. The understanding is that certain lifecycle events may happen in an actual cycle, such as server stopping and starting, and certain lifecycle events will run only once, such as game stopping and starting, and class internal state can be very heavily tied to the single-run lifecycle events.
And that’s just Sponge.
Forge mods are even worse in terms of assumption of lifecycle. So many different things are precariously balanced, especially with mod class internal state codependent with Minecraft classes’ internal state. I 100% agree with @codeHusky here:

1 Like

I’m going to start by comparing this to something we all know and love, Pore.

When I started looking into transitioning my server from Cauldron to Sponge, I was extremely hesitant to do so because Sponge was majorly a WIP, there weren’t many plugins available, and both my players and I were familiar with the Bukkit plugins. Trying to make such a transition like that at the time was near impossible for me, so something like Pore felt like a lifesaver. I kept tabs on it (and it’s surrounding controversy) for a couple months, and I supported the project until I could code and actually understood what it was. From there, I realized why such a system was impossible - it attempted to make two incompatible systems compatible.

The point of this isn’t to debate about Pore, but to strike a comparison between that project and this one - what you are attempting to do is beyond the capabilities of Sponge (and Minecraft!), and is far from reliable.

Before anything else, I’ve taken a look at the resources given and cannot for the life of me figure out how the heck to install the thing. It’s complex, appears to require an IDE to even build (don’t get me s, and is vastly outdated - seems like most of the work was done months ago, not to mention for an outdated Sponge version. If this actually is only meant as a development tool, then I fail to see it’s usefulness. In all honestly, this does not belong in Plugin Releases, let alone Sponge.

Now, let’s talk dependencies. Plugins that depend on another plugin should not be allowed to be disabled is if the other one is still enabled. That’s a simple enough concept, but it gets even more complex when you’re dealing with optional dependencies - then what? You won’t be able to tell when a plugin tries to access something that’s disabled before it’s far too late, and now you’re making a mess out of things - spamming the config with errors at best, crashing and corrupting data at worst - I hope. The only way this thing works is if each and every plugin natively support it, and I’m pretty sure that Sponge’s reload is meant for just that.

The next issue is with stages of the plugin lifecycle, and by extent the lifecycle of the game itself. It’s critical for many plugins (especially the more complex you get) that certain gamestates only occur once - attempting to modify or change that is just going to result in more issues. Of course, his isn’t accounting for all the different registry stuff in Forge or the client-server handshake through mods.

Here’s the thing - we’re leaving out the elephant in the room! Sponge isn’t it’s own program - it works with things like Forge, yes, but also Minecraft! Things like mixins would be near impossible to disable, and I doubt you could change the internals of Minecraft to be able to load these game changing things on the fly - don’t even get me started on Forge mods! Forget everything else; Minecraft does not allow for such a system to exist.

I’ve never really explored OSGi until now, but I see it as a development tool that sections off and modularizes groups of code so they can function (mostly) independently. You cannot take such a system and apply it to existing projects expecting it to work. Projects would need to be designed to work with such a system - that means Plugins, Sponge, Forge, Minecraft… everything… and that isn’t possible.

The simplest way I can put it is “You’re pounding a square peg into a round hole”. These systems do not function together, and for good reasons.

1 Like

Weird… Hot-swapping always failes for me with some error complaining about the MinecraftServer class being incompatible with the file. So while this sounds interesting I don’t think I’ll end up testing it.

@mark332 this is actually not using “hot-swapping” (as in how a Java debugger hot swaps) at all - it reloads your entire mod. @codeHusky and @pie_flavor know what you mean, but it does actually work really well for my own development (YMMV). @Simon_Flash dunno what in the README made you assume IDE dependency, and where you’re going with dependencies and the rest - for me, this works just fine, for real dev.

1 Like

Just out of curiosity though, what happens when a plugin or mod uses a Game Initialization event to do certain setup tasks and stuff? Or what about when it depends on another plugin/mods events to finish setup or something.

As an example:

@EventHandler
public void load(FMLInitializationEvent event) {
    logger.info("Registering event handlers");
    MinecraftForge.EVENT_BUS.register(renderHandler = new RenderHandler(Minecraft.getMinecraft()));
    MinecraftForge.EVENT_BUS.register(this);
    logger.info("Registering MinecraftForge networking channels");
    FCClientNetworkManager.instance().registerNetworkingChannels();
}

From what I understand, while my mod would be totally reloaded, the game initialization event wouldn’t occur again cause it has already passed. this means that network channels and stuff cannot be registered here.

This sounds like it could be a really useful tool for development, but I feel like it would still hit a lot of the same roadblocks that the regular debugger does, because this is a complex event based system.

I don’t know tons about OSGi though, so maybe it can handle this… I would be interested to know first though.

Edit: The little bit of OSGi I have used was with a group of people for a project where plugins didn’t really have a setup/tear down phase, and the system would constantly detect new plugins and instantiate them on a set clock cycle.

1 Like

I’ll just say that really, this would complicate development of bigger, more featureful or lower level programs rather than improve development. It doesn’t really matter how skilled the dev is or whatever, its more so that OSGi isn’t something sponge natively supports, and Sponge has a relatively strict life cycle. If you do things at the wrong time, it gets pretty mad.

Can totally stand behind this project. Thanks for the contributions. I’ll play around with it when I get a chance. This is the sort of modularization, and encapsulation that the mc community is missing in general.

1 Like

So I want to clear something up here. The fact that this plugin’s name is OSGi is very misleading.

OSGi IS NOT A DEVELOPMENT TOOL AT ALL.

OSGi stands for Open Service Gateway Initiative, which is an SOA, or Service Oriented Architecture.

OSGi is a framework and method of development that allows modules to be loosely coupled with each other, in such a way that you can remove and swap entire modules without having to halt the rest of the application. As such, OSGi is used heavily in the enterprise java world.

OSGi uses bundles and services, which is an architecture that has a STATE AGNOSTIC LIFECYCLE, which Minecraft, Forge, and Sponge DO NOT HAVE.

OSGi is not something you can slap onto an existing project. It is a base framework that you need to start with.

I’m sure everyone else has beaten this into the ground, but my verdict is this:

If hot-swapping and debug mode doesn’t do what you want it to do, there are other more aggressive hot-swap debuggers that you can use besides the default java one. If that’s not enough, your only other choice is to restart minecraft. If you don’t like that, you need to rethink your plugin architecture a little bit to make better use of hot-swapping.

5 Likes

@curscascis thank you (and the other Likes) for the love - appreciate it. More likes, anyone?

@d4rkfly3r tx for the (first, real) Q here. So yeah you’re spot on there, absolutely right - there’s no magic fairy dust, in this world… It’s all real work! So your mod/plugin’s code still has to correctly unregister and (re) register any “hooks” (commands, event handlers and the like) into its surrounding environment (in this case, Sponge), at the right time in the lifecycle. The way I have it for the moment (this COULD evolve later), as outlined in #7 on the projects README, an OSGi-based Minecraft Mod uses an OSGi Bundle Activator, instead of the Sponge @Plugin annotated class, to register its Minecraft Commands and Event Listeners. This keeps things clear and nicely separated, to start with. Now you can, of course, make a project have both a Sponge Plugin as well as an OSGi Activator (links to an example where I’m successfully doing this), and register the same commands and listeners in it; thus creating a JAR which is usable in both environments - both as OSGi bundle (during development, for fast iterative development) as well as a “normal” Sponge mod JAR (for distribution).

This could evolve in the future - e.g. there could be what’s called an OSGi Extender which would automatically detect the @Plugin annotated class and invoke it’s lifecycle methods correctly itself - that’s totally doable (and then there would be no need for an Activator; this is similar to what e.g. OSGi’s Blueprint implemented by Apache Aries, or the OSGi Declarative Services DS do).

Of course, if your respective code does not unregister stuff (e.g. removeMapping for commands, and the like), then you can create havoc in Sponge and “it gets pretty made” (@codeHusky) , and it will not correctly reload, yeah. IMHO that’s just too bad - life is tough, and short - so just code well?

This also could theoretically evolve in the future, and it’s not impossible to imagine transparent auto-unregistration of stuff; FYI e.g. OSGi own service registry (which is something similar to Sponge’s ServiceManager), is actually smart enough to unregister all services registered by a bundle when it unloads, without it having to do that explicitly. It would imaginable to build something like that into this. A minor problem one may run into with Sponge’s current API is the static Sponge Game stuff, which probably makes it a bit harder to intercept registrations to be able to automatically undo them; but there are ways to work around it.

Now for your specific example of MinecraftForge.EVENT_BUS.register(), I wouldn’t actually know myself what the unregister() equivalent of that API is - sorry. There should be one, and if there isn’t, one should be added (eventually). At least Sponge’s CommandManager and EventManager do this right, and offer both register and unregister type of API methods.

As for your Q re. “when it depends on another plugin/mods events to finish setup or something”, that entire area has been well threaded in OSGi. What you usually do it make something dependant on a service published by something else. Solutions such as DS then are smart enough to restart things in the correct order when others come and go.

@gravityfox may I in turn clarify? The OSGi in the plugin name is totally accurate, because that is what this project is - it’s a Sponge “plugin which embeds an OSGi Framework” (first line of the README). On your SOA rant, yeah… A few years ago, EVERYTHING had SOMETHING to do with “SOA”, and so OSGi too was labeled, as was even my aunt’s SOA enabled labrador puppy! :wink: And nowadays everything is a “Microservice” (even OSGi services)… Be that as it may, none of it changes the fact that an OSGi framework at the end of the day basically is just another little ClassLoader framework (and a reasonably well thought through one, IMHO). Not exactly sure where you’re going re. the “state agnostic lifecycle” - but I gathered you know more about Minecraft’s current internal implemenations than at least I do. All I can say to you is that I wanted to have a way to build Minecraft plugins “in such a way that you can remove and swap without having to halt the rest of the application”, and after earlier experimenting with some custom ClassLoader tricks of my own, found OSGi to be a good fit for this. I’m using this myself to write some plugins, and it works great for me. YMMV - I respect that.

We’ll agree to disagree on this. I still think that you’re trying to do something that isn’t possible and has way too many compatibility issues for it to be feasible. There are a lot of things it could do, but it’s both a question of how and should at this point. I think it’d be way more work to implement support for this system (presuming that all of your dependencies do, in fact, have the necessary support), than it would be to just restart a server in the first place - not to mention any bugs caused by duplicate registration or invalid states.

I’d also like to request this thread to be moved to the Resources Category. By being in Plugin Releases, it implies that this is a functional plugin safe to use in a production environment - which, in my mind and others, it is not.

1 Like

oh, nvm.

You seem to not understand that sponge wants to to register stuff at the RIGHT TIME. It doesn’t matter if you can unregister it or whatever, because Sponge will tend to freak out if you register a command during the running state.

Asking people to “code well” for something that isn’t native is just stupid.

I think that treating this project as some sort of foreign idea that would implicate and destroy Sponge as we know it is a really bad way to look at things. This is being presented as an inclusion of a framework, no one’s saying to use it anywhere and no one has to use it. Either people use it or don’t use it, and it (as it is being presented in the form of a tool for further development with these concepts) is perfectly acceptable to have something that breaks things along the way in a development environment.

Personally I’m glad someone put all the effort to put together a pretty powerful tool that could lead to some more inter-operative systems running off of sponge, that would in the end lead to the enhanced experience of players in general. Weather or not this is the best way to do it, doesn’t really matter… I don’t think? It’s a way… and it works for it’s intended purpose, mostly…

I’m always hearing this tone when people bring up new ideas, or try new things of “oh that’s not how sponge works” “Sponge won’t be happy”, “sponge doesn’t like this/that”. Sponge is software that is everyday being changed and modified. And although I must say is very elegant and beautiful in how it is put together, it’s architecture has been assembled to make Development ontop of it a lot easier, but it is far from perfect, and is not the one ideal solution.Of course there’s problems in just changing things at runtime, of course the framework we’re building on top doesn’t natively support these tools. It doesn’t natively support half the things we end up adding on top of it, API’s and other people added these things. Do you think sponge was designed with the exact same architecture that minecraft, forge, or bukkit use… No it evolved, the team took their own steps and took to plan how they wanted the API to be.

I think it’s great that in this community we try to make it easier to have people make plugins, and learn to develop, and get excited to do things with the API. But we can’t just reject ideas that aren’t normative or don’t work well with the system. A self containing encapsulated system that is properly modularized can work with one that wasn’t built to natively support it. Obviously the ideal case would be that everything that isn’t sponge itself would be coding against these new standards in mind. But hey it depends who is making them, and what their target is.

Saying it’s stupid to ask people to “code well” isn’t really useful in any way, neither is asking people to “code well”, besides I think english might be his second language, and maybe it was expressed incorrectly. Regardless, I think if someone asks someone that will be using their product to use it with their guidelines isn’t stupid at all. No one is forced to use this, I’m glad that it’s been made, and I hope people have fun with it and make cool things.

As for things being “dangerous”. So what. We’re dev’s working on minecraft, our purpose is to build, break, and fix. If someone wants to go through the effort to use it and test out all the bugs, let them. We’re building software not jumping off cliffs. Most software has multiple ways to be used, things go beyond the original intended usage, and that’s great. Obviously if someone completely derailed off the guidelines, they probably shouldn’t expect to get much help… implementing with a design structure like this, hopefully you know what you’re doing.

@vorburger I think a productive addition to this conversation might be, if we can see some examples of how it facilitates development, or just run time operations. Maybe make some dependants for this framework and add them to this thread with explanations, or videos, of it being in action. Why is it better than what we have, where can we use it, how will it trickle down to improve player experience. I think without examples and useful implementations, the project will probably just be ignored and crapped on.

1 Like

Ok guys…

This has gotten WAY out of hand…

I admit that I have a few concerns about how this plugins will be overly useful at the moment (I don’t really want to have to rewrite my plugins main class to work with the OSGi bundle system), however this is an open community, and this has kind of turned into a lets shit on the project session…

@vorburger I would be interested in seeing what the future of this holds, right now I have to say that I don’t really understand or feel like this could be helpful (to me at least), however that does not mean that I am telling you that it is a stupid idea. Any advancements to anything ever all came from people who had been willing to push the boundaries and repeatedly try different things. My largest concern right now, is that a lot of people on the forums don’t necessarily know Java… and I’m a little concerned that they are going to see this, and then start spamming people for help if they have issues or crashes or exceptions in the log.

To the rest of you, guys chill out a little bit. I understand it might not be something you’ll ever use, and I can see where some of the frustration might come into play, but really some of the stuff that I have done has broken the game way more than this… (yeah… lets try in game bytecode manipulation and dynamically loading of said modified classes)
Not to mention the fact that if your main plugin class is abstracted enough, and in a testing environment, this could still be very useful.

Sorry if this kinda turned into a rant… I just woke up to see a bit of wtf comments on here, and it feels to me like people aren’t in a huge spirit of being a friendly developer right now (maybe everyone is tired and cranky, or hasn’t had their coffee, who knows and I don’t really care, I just feel like these comments have gotten a bit out of the friendly suggest zone).

4 Likes

Moved to Resources as this is primarily for developers.

You are trying to remove a wheel of a running car, you can do that if you know how, but something will get wrong at some point. I never liked plugin reloading because sometimes (or most of the times) something just break and you spend yours trying to figure out what the … happened, and finally find that you missed to unregister a thing. Most of my plugins made for bukkit, for example, can’t be reloaded because them hook in nms and replace instances, trying to reload them cause entirely bukkit to be unloaded, and I reflectively added dependencies of all plugins on my to force the catastrophe, in Sponge is a bit different because you use reflection less often (or never uses), but this does not means that you can reload plugins, reloading plugins causes states to be lost, things be incomplete, blocks unprotected or changed to another state, which theoretically, may change to another state by a task scheduled, and so on…

This is my opinion, we can spend hours talking about advantages and disadvantages. In other platforms it may work, but for Sponge, no, it won’t work even if plugins are designed to.

1 Like

Thanks for experimenting, whilst I understand there would be clear problems with registering and unregistering blocks, recipes, and a few other things, simple plugins with event listeners, that don’t offer a service or dependencies to other plugins could probably use this pretty well.

I’d be very interested in how learning how dependencies would work with such a system for other plugins that arn’t necessarily following the same structure.

1 Like