The core motivation of OpenRA is to be a set of games on a shared engine that improve on the classic C&C titles both as games and as a modding platform. Having a shared engine that runs packaged mods (first or third party) actively sabotages these goals, and IMO is no longer sustainable.
There are two main reasons for this:
Mods are slaves to whatever engine version the player has installed, and we break the whole platform on every new OpenRA release. This sucks for players who lose access to their thirdparty mods (e.g. crossfire or TDX which are based on outdated releases), it sucks for modders who are forced to update their mods on our schedule instead of theirs, and it sucks for us because modders give up and abandon their mods because this requirement is not fair or sustainable.
On the technical side, for all our flexibility there are still far too many cases where customizing something basic means either begging for upstream changes (e.g. #11813, #11830) or duplicating and renaming huge chunks of the Mods.Common logic.
We put a lot of effort into building out a framework for oramod support, but this doesn't solve the main problems faced by non-trivial mods. They either distribute a copy of the OpenRA repository with their own changes (Shattered Paradise, Crystallized Doom, Attacque Supérior, Rewire, etc) or fall apart (cough).
On the player side, we have people writing scripts to circumvent the oramod packaging, and complaints about how annoying it is to switch between even our own playtest vs release mod versions.
Out of all the feedback on our new logo design, the main underlying complaint seems to be that players don't want some generic icon on their launcher, they want something that they can identify with the mod(s) that they play. I can't fault this argument, but this is incompatible with our goal/requirement for our project-neutral launcher to have a project-neutral icon.
The only way I can see to solve these problems is to change from a shared engine + dependent mods to fully self-contained mods. This is mainly a packaging exercise – I am not proposing to split OpenRA/OpenRA into multiple repositories (that would make it impossible to test engine PRs) or to offer individual installers for our official mods.
The repository layout (and running the development versions) would stay the same, but the packaging scripts would separate out the different mods into something like:
<prefix>/
ra-release-xxxx/
OpenRA.Game.exe
(other shared files)
mods/
common/
(common files)
ra/
(ra files)
ra-content/
(ra content manager files)
cnc-release-xxxx/
OpenRA.Game.exe
(other shared files)
mods/
common/
(common files)
cnc/
(TD files)
cnc-content/
(TD content manager files)
(and so on)
On OSX each mod would have its own .app bundle, and on Windows/Linux they would get their own launcher shortcut (yes, this is returning to our pre-2012 packaging standards). The launchers would use the mods's own name and own logo.
The ingame modchooser mod would be dropped, so would oramods, support dir mod loading, and runtime mod dependencies. The horrible filesystem behaviour on Windows means that we can't merge the content installer into the main mod, so we'd need each to ship its own content manager (replacing the Mods button in the menu with Manage Content). It sucks to move away from the shared UI that I developed for this, but at least we will be reusing the same backend code this time. It also means that mods that ship all their own assets can completely opt out of the content manager.
Third party mods would then be free to target whatever engine version they want, including their own custom versions if they want to include changes that aren't/won't be merged upstream. The downside here is that they will need to provide their own OS-specific packaging, but this is something that the big mods are already doing.
Having a shared multiplayer server list with the ability to switch mods on the fly is one of OpenRA's best features, so we need a way for mods to register themselves and launch other mods. We can solve this by having the platform launchers pass a Launch.Launcher argument to the game exe that defines the platform specific command to run that mod and join a server. The game writes this to a metadata file in the support directory, and mods read these files to populate the Game.Mods data. The awesome thing here is that players will be able to switch between playtest and release versions of the same mod in exactly the same way that they switch between different mods.
The explicit mod registration means that players need to manually launch a mod at least once before it can be switched to from the MP lobby.
We would have to remove support for the orarep file type handler, and the either remove or change the openra:// uri handler to something like openra-<mod>-<version>://.
The directory layout of development versions would be fundamentally different to packaged versions, which will cause bugs. Hopefully largely solved, see my update below.
Some people (who don't care about the reason for this change) will be very unhappy about the file duplication. Hopefully largely solved, see my update below.
This is a big change, so it needs thought and input before we decide whether to move forward with it.
This also sounds like a solution regarding the .NET-cannot-unload-assemblies issue since mod-switch would involve restarting the game now.
My main concern currently is dll mixing between various mods, asin we still haven't finished moving every shared-between-more-mods logics into Common (case coming into my mind is TS using RA's infiltration logic but certain there's more) and I'm not sure where those dlls would sit in your proposed folder hierarchy. This would also make simplemodders' life harder due to the omitted dlls, something they can fix easily today (open mod.yaml, include), but not that easily after this takes effect (get the same game's other-mod-counterpart, copy-dll, include), which might increase complaints such as http://ppmforums.com/viewtopic.php?p=541013#541013. I dare suggesting that we should axe mod-specific dlls altogether/ship all dlls with all mods against complaints like such.
As a modder primarily, I have to say I am leaning towards fully supporting this idea though.
Branding confusion
Out of all the feedback on our new logo design, the main underlying complaint seems to be that players don't want some generic icon on their launcher, they want something that they can identify with the mod(s) that they play. I can't fault this argument, but this is incompatible with our goal/requirement for our project-neutral launcher to have a project-neutral icon.
https://github.com/cerebrum/dr/blob/master/games-strategy/openra/openra-20161019.ebuild#L72 already solved this for Gentoo Linux. It is easy to add launchers to the official installers, but also easy to make these shortcuts manually yourself so not really a huge deal either.
My main concern currently is dll mixing between various mods, asin we still haven't finished moving every shared-between-more-mods logics into Common (case coming into my mind is TS using RA's infiltration logic but certain there's more)
Identifying and moving those should be relatively simple. I probably would have filed PRs already if I had been aware of this.
I dare suggesting that we should axe mod-specific dlls altogether/ship all dlls with all mods against complaints like such.
Considering how few mod-exclusive features would remain if we moved all remaining shared functionality to Common, you're probably right.
The directory layout of development versions would be fundamentally different to packaged versions, which will cause bugs.
@pchote This is the drawback I'm most concerned about, however I can't picture in what way exactly the directory structure would differ, could you give an example?
Edit: Nevermind, I just realized that's what the example further above was about. I am interested in what kind of bugs you think we have to expect, though.
@Mailaender I'd say the branding issue makes up <20% of the argument, despite the recent icon uproar.
All the issues @pchote listed regarding mod support are correct.
For anything more complex than TDX, I would take the same route the mentioned larger mods already take. Support dir mod loading and oramod files may be nice on paper, but for larger-scale projects they simply aren't really that practical, and the percentage of (worthwhile) small mods is relatively low.
The future success of OpenRA as an engine depends more on the support for the "bigger-and-better" projects, I dare say.
Long story short, I'm leaning towards this change, as I'm afraid that sticking to the current structure may lead to OpenRA hitting a dead-end for good sooner rather than later.
I support pchotes idea too. It seems as a better solution for bigger/complex projects.
Crystallized Doom's betas are already shipped with custom OpenRA builds with it's own adaptions. Yesterday I added for example Graions AS.dll which has some useful features I can use for CD.
The beta testers are already used to this method where we provide them the required/compatible OpenRA build and mod files in one package.
Later down the road I would also expect to have a single installer for fitting engine version + mod as one package (at best with as less content from other games/mods as possible to keep it clean/in order).
Once the first public build (for CD) would arrive, it would be easier installed and distributed for the enduser/players.
The only thing which might become a problem is where bugreports would blend in depending if players report with an official build or a custom build to you. Well it should be common sense that you first contact/report to the mod authors instead of bugging the ORA contributors. So the modauthors can look for the reported bugs/problem themself first and then take the necessary actions (fix themself or contact contributors).
So far I can only tell that I always worked with custom shipped OpenRA builds since I started the port from TS to OpenRA. I don't know how much workload this change/suggestion would mean for you guys, so I can't comment on that.
I can understand that thirdparty mods fork the engine and ship their own CrystallizedDoom.exe at some point in development. However doing so with the current default mods whose release engineering is scheduled with engine releases, is totally backwards. While I agree that the monolithic design of the OpenRA engine is a huge design flaw we can't get rid of that easily, reinforcing this by duplicating binaries per mod, is exactly the opposite of what needs to happen.
This project needs to become way more modular with stable API/ABIs and long-term planned specifications to end this compatibility and upgrade nightmare for modders and mappers. Not sure if we are already at a stage where this is feasible.
TBH, API-like modularity went out in the window when explicit interfaces became the norm with their impossibility to be expanded through inheritance got labelled as feature and not a bug.
It is easy to add launchers to the official installers, but also easy to make these shortcuts manually yourself so not really a huge deal either.
This isn't possible on OSX, where applications are self-contained and portable bundles. Appimages on Linux may end up having a similar issue.
This isn't possible on OSX.
I think Mac OS X knows the concept of folders in application launchers, so we could make an OpenRA button which then expands and adds icons for each mod to directly launch them. According to https://support.apple.com/kb/PH21859?viewlocale=en_US&locale=en_US you can even create such folders yourself by dragging application icons on top of each other.
The directory layout of development versions would be fundamentally different to packaged versions, which will cause bugs.
@pchote This is the drawback I'm most concerned about, however I can't picture in what way exactly the directory structure would differ, could you give an example?
Edit: Nevermind, I just realized that's what the example further above was about. I am interested in what kind of bugs you think we have to expect, though.
The same kind of bugs that we already have to deal with when people change the directory/file structure and forget to update the packaging scripts, but worse because they now need to track the individual mod includes instead of just a global layout.
I think Mac OS X knows the concept of folders in application launchers, so we could make an OpenRA button which then expands and adds icons for each mod to directly launch them
On OSX an "icon" is not a shortcut like on Linux or Windows, it is a full portable installation containing all of the application's files. You can't have separate "icons" for each mod without also having separate executable and data files (or resorting to hacks that violate platform standards).
On OSX an "Application Launcher" is not a shortcut like on Linux or Windows, it is a full portable installation containing all of the application's files. You can't have separate "icons" for each mod without also having separate executable and data files.
In that case I suggest to have the workaround of duplicated OpenRA.Game.exe files per mod only for our Mac packages as this technical limitation doesn't exist on the other platforms.
You're focusing on what is really a minor / secondary benefit the proposal, while ignoring the main points. This really feels like
Some people (who don't care about the reason for this change) will be very unhappy about the file duplication.
The primary goal of duplicating OpenRA.Game.exe is explained above and has nothing to do with OSX. Implementing all the packaging and game registration logic to do this separation for OSX, but then purposely not doing it for the other platforms is more work and error prone for little practical benefit.
Okay, to give you further
Other issues / drawbacks:
The duplication will also raise Linux packaging quality flags. For example rpmlint will notice the duplicates and suggest to link them with fdupes to avoid the warning and save disc space. This will then cause extremely weird constructs when packagers try to resolve these warnings.
It violates the proven design philosophy in hobbyist game development of having a shared and flexible engine that runs in different configurations (mods) many modders are used to. The message sent is not "contributions are welcome, let's find common ground" but then "go away, make your private fork, it's the only way" which I find very disturbing. Especially since the number of contributors is already in a decline.
The package size will increase needlessly. While this doesn't matter nowadays as we and most of our players don't have to pay for the extra bandwidth, I could imagine community repacks of just <prefix>/ra-release-xxxx/ without the other "junk" nobody plays anyway.
Anti-Virus vendors have to be asked to whitelist 3 OpenRA.Game.exe files per release of the same name that can only be distinguished by the folder they are sitting in. While I personally wouldn't put much attention to this, lot's of our players use Microsoft Windows and rely on virus scanners. The past showed that OpenRA get's flagged easily due to the dynamic code generation features and large security software publishers don't care for small non-commercial indie projects like this one.
It makes FHS compliant Linux packaging even harder as it requires binaries and data files to follow a directory structure where everything has to be bundled instead of allowing to separate them cleanly.
My fear is that this construct of multiple independent engines animates coders back into copy pasting source code together with minor mod specific variations. After all the hard consolidation of historically diverged mess in this project, I feel like this could all come back pretty quickly undoing what we achieved for the last few years of mostly tidying up and putting new features on the backburner.
Ok, thanks for the comments. These are all good points, so i'll give my thoughts on each.
The duplication will also raise Linux packaging quality flags
Valid point, but we can solve this without much trouble on distros that have OpenRA in a repository. They can package individual openra-<mod> packages and have the openra metapackage require the default mods (or not, I guess...). I expect some distros would prefer this over us shipping our own proprietary package manager (the mod chooser) that installs content to the user's home directory. The deb packaging is a problem, but migrating that to a custom repository is a long-standing open issue.
It violates the proven design philosophy in hobbyist game development of having a shared and flexible engine that runs in different configurations (mods) many modders are used to.
Three of our four biggest modders have replied just above saying that this philosophy has actively failed them and that they are (or would) actively circumventing it in practice. With the exception of @Holloweye's WW1 mod, all the mods that i'm aware of that did follow this principle have stopped development and are no longer playable.
The package size will increase needlessly.
I just checked this, and all the common files on OSX add up to 26 MB uncompressed / 4.7 MB compressed. This is a lot more than I was expecting, so I have no valid (serious) counter point. Loading facebook page a couple of times still probably outweighs it :smile:.
Anti-Virus vendors have to be asked to whitelist 3 .exe files per release
Valid point which I have no counter point to.
It makes FHS compliant Linux packaging even harder
I don't understand what you're saying here. Does my comment above about the mod chooser effectively being a DIY package manager counter this?
My fear is that this construct of multiple independent engines animates coders back into copy pasting source code together with minor mod specific variations.
I think this is a very important point because in theory I completely agree. In practice, however, mods are already doing this, and IMO we need to be pragmatic and include these projects in our ecosystem (shared server list / mod switching / resource center) instead of leaving them as separate and second-class citizens. The main mods are essentially complete and in maintenance mode, so without these outside projects OpenRA development is not going to survive in the long and possibly even medium term. You know as well as anyone how difficult it is to get new and unproven or incomplete features merged upstream, so giving mods the flexibility to ship their own features without battling through our quality control means that they can try new and unique things that may later be uplifted.
Anti-Virus vendors have to be asked to whitelist 3 .exe files per release
Valid point which I have no counter point to.
Not really counter-points, but at least points to consider:
It makes FHS compliant Linux packaging even harder
I don't understand what you're saying here. Does my comment above about the mod chooser effectively being a DIY package manager counter this?
I have to admit that I may not fully understand where this is going and what this is really trying to solve. Implementing something like Steam just for OpenRA mods that effectively become individual games is weird and pretty much unexpected from my side.
One could argue that we will never be accepted into Debian/Fedora/SUSE anyway as our default mods rely so much on foreign intellectual property and bundle lot's of sprites with (at best) unclear redistribution rights.
My idea was to solve this with a http://flatpak.org/ package once and for all. This seems to be best practice for .NET on Linux nowadays http://apebox.org/wordpress/linux/1184 but I haven't made any progress there and as you are proposing a complete shift of directions here, I might as well abandon that plan before even starting with it. Plus, I guess nobody seems to care for clean Linux distribution packaging and traditional Unix philosophies like modular design where every component can be replaced. :disappointed:
I suggest to have the workaround of duplicated OpenRA.Game.exe files per mod only for our Mac packages
I thought about this a bit, and came up with a compromise that could work very well if we are prepared to adjust the repo layout (I wanted to avoid that because it breaks github history): Move all the common files (engine code + binaries, mods.common + misc docs) into a sdk subdirectory of the base repo, then have the platform launchers and launch-game scripts execute OpenRA.Game.exe using explicit mod paths.
What does this give us?
sdk directories inside the individual app bundles.sdk directory at the root of their repository that points at OpenRA/OpenRA/sdk/@their-favourite-commit, and then compiling/developing/running them is almost identical to our firstparty mods (this is a refined version of what i've been suggesting for ages that the ra2 mod do). Git doesn't natively support submodules rooted at a subdirectory, but there are plenty of other options:I'm not very happy with the idea of breaking our git history by moving all the core engine files to a subdirectory, so the less clean but less breaking approach would be to do the packaging bits without the sdk repo dir. This also means that thirdparty mods could use vanilla submodules, but has downsides of the dev/repo layout not matching the installed layout and thirdparty mods would end up pulling in the firstparty mods as part of their engine submodule.
As a modder, my worst fear is releasing a mod and being forced to update it whenever the engine changes, which means that the mod will become unplayable if I am busy or missing in action, that's a critical change that should be adressed, even tho it's easy to fix by uploading a custom build as everyone says, giving each mod its own exe helps ensuring it doesn't become unplayable, so it's a good point.
Then you have the fact that it increases flexibility for us modders, so we are able to make changes to the engine without the need to modify the main repo, if this allows to make more changes that .dlls alone can do, then it's great, tho since I don't make new code myself, I can't give a deeper apreciation of this.
TBH I don't like loosing the mod chooser or duplicating the games many times, it would be cool if there was a way to get around this, say, make a launcher that syncs each mod with its own version, everything in one exe, but if that's not possible, it isn't a terrible change, just a bit annoying, but it shouldn't cause rage or hate (I hope).
Well, the issue with the installers isn't new, as most new mods are dependant on the Isometric grid, which isn't included on the current release, we have been using the bleed for a long time already, so we have been always in trouble whenever an non-windows user comes in wishing to play, we are already used / aware that we need to compile a custom version of the game for people that don't use the same OS as us, this is supported by the fact that it's impossible to keep up with the release / playtest updates forever, so eventually the only thing that will remain is the latest bleed build of the modder, tl dr, no issue with the custom installers.
The biggest problem I see is the amount of work you guys would have to put to enable this, (making the changes, maintenance and bug fixing), I would stress to make the decision around that. But if what you want is to give more room for developing mods, then I would say it's necessary, because while it's true that you can create new codes to increase the amount of things you can do, you can't edit what already comes in the vanilla engine, and that may limit some people. whenever a tried to convine new users to come in, they lose interest after knowing that the specific thing they want to do is not possible, this might change that, or atleast give them hope that they can do what they want once they have the knowledge needed to do it.
We put a lot of effort into building out a framework for oramod support, but this doesn't solve the main problems faced by non-trivial mods. They either distribute a copy of the OpenRA repository with their own changes (Shattered Paradise, Crystallized Doom, Attacque Supérior, Rewire, etc) or fall apart (cough).
Well, all the mods you mention rely on Tiberian Sun which by policy (not due to technical reasons) is still unreleased, even for nightly CI builds and Red Alert 2 is also excluded solely due to political reasons. This is essentially a home made problem.
As a modder, my worst fear is releasing a mod and being forced to update it whenever the engine changes, which means that the mod will become unplayable if I am busy or missing in action, that's a critical change that should be adressed, even tho it's easy to fix by uploading a custom build as everyone says, giving each mod its own exe helps ensuring it doesn't become unplayable, so it's a good point.
A clean solution would be to modularize the game and version individual parts of it to then define dependencies. This is how enterprise software with long support term solves things. They have legacy releases where only small bug fixes are allowed into for backward compatibility and new release series where larger refactors and API breakages are allowed with documented migration guides for developers.
I could imagine that something like the file formats or the platform DLL will probably not update much. Also end users probably don't care for the lint rules, but at the moment we still ship them for everyone and packagers don't have a choice to exclude them from the distribution as it is so clutched together.
So a more modular structure could in a best case scenario lessen all these problems such as duplication and make migrations easier as you can update individual parts of the platform such as the file format library, if you want to just include some bug fixes or a new format into your mod and want to avoid a large weapon rule refactor for now until you get time to adapt things.
It comes with additional complexity though that has to be handled. At the moment you will see that we only use the .NET package manager NuGet for our external libraries and also in a very basic and essentially hacky way. All OpenRA DLLs have a hardcoded version 1.0.0.0 or whatever the backfall is when you don't define anything. This needs to change and a lot of infrastructure has to adapt to that.
I am not really telling you anything new by the way. We essentially had this idea a long time ago already https://github.com/OpenRA/OpenRA/issues/8850. It was suggested by the founder of this project @chrisforbes back in 2015.
Splitting OpenRA/OpenRA into different repositories by itself doesn't solve any of the issues that are discussed here, and would be completely compatible with this overall proposal. This ticket focuses on the way we package the games and allow separate engine installations to communicate. Whether the packaging scripts pull from one repository or several doesn't change this in any meaningful way.
I am not really telling you anything new by the way. We essentially had this idea a long time ago already
Yes, and it has been discussed completely to death many times since then why splitting the repository might be attractive in theory but is completely unworkable in practice. That discussion does not belong here.
So a more modular structure could in a best case scenario lessen all these problems such as duplication and make migrations easier as you can update individual parts of the platform such as the file format library, if you want to just include some bug fixes or a new format into your mod and want to avoid a large weapon rule refactor for now until you get time to adapt things.
Making the project modular doesn't let modders swap out pieces if our packaging then forces users to have a single engine that all mods depend on. The proposal here does let modders do this (that's the main point of it), with or without a modular repo layout.
I don't have time to flesh this out right now, but I just want to throw in an idea (this is more meant as something complementary, regardless of if and what changes we make to the repository and/or packaging layout):
It might be worth considering to split SDK releases (just engine + logic, not containing 1st-party mods) from "full" releases (containing everything). All we'd need would be an additional packaging script that skips the mod folders (like we already do for TS). Merging the mod-specific dlls into Common would be the only prerequisite, and it would allow us to release SDK builds for modders much more frequently without worrying about the 1st-party mods.
While we're at it, we could split the potentially IP-sensitive file format loaders to separate DLLs, like "FileFormats.WW.dll" for things like AUD, VQA, TMP and some compressions and not package those with the SDK.
While we're at it, we could split the potentially IP-sensitive file format loaders to separate DLLs, like "FileFormats.WW.dll" for things like AUD, VQA, TMP and some compressions and not package those with the SDK.
I think the best option for this would be a single and separate (to Mods.Common.dll) Mods.Classic.dll with these loaders and the other classic mod specific logic (ion cannon, tesla zaps, worms, etc).
It might be worth considering to split SDK releases (just engine + logic, not containing 1st-party mods) from "full" releases (containing everything).
I don't see any benefit to releasing specific "sdk installers" because they aren't going to be useful to players. A better option would be to have solid documentation or possibly a template / example mod (which becomes simpler to maintain once mod development/packaging is decoupled from upstream releases) that explains how to pick an "sdk" version by setting up a submodule pointing at an arbitrary OpenRA/OpenRA commit/tag, and sample scripts for how to run their development version and how to generate installers.
Sorry for my answer being sporadic, but I will only reply what I feel important for now.
SDK installers wouldn't benefit to modders - we don't have a nonWW useable image format we can use for assets, also a lot of the modders ignore the documentation and learn from the shipped-default-mod examples.
@Mailaender The main issue is that you can't replace everything. Yes, interfaces might imply you can substitute one thing for the other, but I can flatout prove the opposite with your own work of RA2's WithSwimSuit (which was made because WithDeathAnimation isn't conditional and even then it sacrificed prone animations). I've also listed a similar example in https://github.com/OpenRA/OpenRA/issues/11813#issuecomment-239447749 when I tried to override the Refinery trait for Ore Purifier. Modularity might imply that you can resolve these issues with such, but no matter how much you split, you will run into an issue like the above from it. Unless you want to hash everything into their own plugin but then you reach the other end of the issue.
I am disagreeing with @ABrandau even, because the big mods still ship the source code along with the "compiled" build, so people from other OSes can get the mod build working via make clean && make dependencies && make all (Okay, I had to go back to precompiling AS for Windows, but that's because of our issues regarding the LARGEADDRESSAWARE flag and apparently AS needs it already). It's one of the things my Linux preference fought out so to say. It's also part of the GPLv3 license.
I am also not fond of the splitting dlls idea and then setting them up as dependencies of each other, because due to the intention of linking mod dlls always against Common only and not against each other I have already seen mods duplicating other mod's code in their own - the aforementioned WWI mod only uses Common and WWI with the latter having the spy traits duplicated from RA1 - and I can imagine it could lead to a dependency conflict if a thirdparty mod starts building from another mod - again, nothing stops a modder from including the WWI mod's dll into his own, along with RA1's.
By following that principle I also was forced to duplicate things at a point - to deal with https://github.com/OpenRA/OpenRA/pull/12129 I did introduced a WithVoxelHelicopterBody trait in AS namespace at https://github.com/GraionDilach/OpenRA.Mods.AS/commit/64e0ed514c2410295862a00d83529d115a9acb0a as was suggested there and had to duplicate BodyAnimationFrameInit to avoid linking to the TS mod dll.
What would decide what goes to that Mods.Classic, who would decide that? Right, we just got the InstantHit projectile, but for more than a year now, I was using teslazaps without any bolts for that, because I felt the single-frame difference of a superfast Bullet's wrong.
Hey guys. Just posting my $0.02 here, since this something that interest me not only because of PPM, but also as a potential future modder for this engine (I need to finish some personal business first).
Anyway, I think you are moving into a wrong direction, although I fully agree with the diagnostic background posted in the issue. You don't need to replace or disable the mod chooser. You need to add additional options for modder or whoever builds a project with OpenRA and you need a separate package of OpenRA that doesn't feature the default mods.
What I'd suggest to add to your packaging script are options that lets users to set (not necessarily in this order):
1) Name of the Project
2) Version (optional)
3) Authors (optional)
4) Location of the image set (which may include icons, logo and other graphics from the main project)
5) Update channel (URL where the game will verify if there is an upgrade for it)
6) News channel (URL of the RSS feeds or whatever the game uses to fetch news) (optional)
7) Multiplayer server URL (optional, although it is required if you want multiplayer in your project)
8) Ability to enable and disable options and their location in the interface (I think you guys may already have that working somewhere, but I'm not sure, so I'm including it here).
9) Description of each Project included in the game, including the same items from 1 to 8 for each of the included projects, and, for the included projects, the update channel should be optional as well.
@BansheePPM Most of it is already configurable. You may want per mod settings then. https://github.com/OpenRA/OpenRA/issues/8276
I was asked to comment as well, so here we go. (Read the second last paragraph for a tl;dr.)
Following the principle of "return early", I'd like to get some thoughts of minor importance written down first.
I would be a bit sad when it gets removed, as I always liked the idea to be able to browse mods on the resource site from it one day. But although that is not a real blocker, I wonder if we could keep it, as the plan is to allow mod switching from the multiplayer lobby anyway. Couldn't the same system be used for the mod chooser? (As alternative if my final suggestion isn't feasible/appreciated.)
To be honest, I don't really consider branding a real issue here (yet). I don't recall anyone coming up with that except @pchote who wanted a new logo for the engine in order to be able to better differentiate between the actual engine and ra mod. Mods like @ABrandau's Shattered Paradise already have "custom" icons. (I guess @Mailaender's comments should be looked at here, he and @pchote know more than me about icons, especially on non-windows OSes.)
Now to the main part.
At first I want to describe the actual problem with mod support. At least how I see it because of my involvement in the RA2 mod development.
The expert here is probably @GraionDilach though, as he did way more code work in his AS dll.
This is mostly an issue for mods which rely on the TS dll. The TS dll is not packaged inside the release/playtest builds, so we needed to use bleed.
Simply telling people to "just use latest bleed" often lead to confusion, as updating the mod almost always lagged behind updates in OpenRA/OpenRA.
To circumvent that problem, the RequiresMods: trait was introduced. However I found it not very feasible, because of the exact reasons which caused the problem in the first place.
The engine development moved fast, as did the mod development "these days". It would have meant to constantly update the version definition, even if the mod yaml/code itself didn't need a change.
But I don't think this can be blamed on upstream OpenRA. It's just me being lazy and stubborn there. As I lack the time to look after the RA2 mod actively in the last months, I'm at the moment tending towards giving RequiresMods: a try when I find time.
The real PITA here is updating a mod to a newer OpenRA version. The utility is only of limited help. It is erasing comments, not being able to process all changes and doing other weird things. So you always have to keep track of all the changes (using git) and manually correct them. Which is kind of expected, but still annoying. The yaml changes aside, updating dll code is also very annoying.
It would of course make life at least a bit easier if you could load the dll from the OpenRA solution. Otherwise you always need to have two solutions (mod and engine) open at the same time, making both updating your code and designing/creating changes for upstream code more complicated.
The first attempt to "solve" this was forking OpenRA/OpenRA and just integrating the mod into the fork. But that had the side effect, that PRs broke when you updated to latest bleed (see here and/or here).
Of course you can try to avoid this by using submodules/subtrees/... for keeping track of your mod folders. However, this still fails to help: a) You would need to keep track of three different git instances. The engine, the folder of your dll's source code and the mod's main folder (see OpenRA2/Engine).
b) If you want to modify OpenRA engine code directly, you still need commits living on top of the latest upstream commits, which brings us back to the rebasing issue.
The second attempt was to have a version of OpenRA/OpenRA as submodule (see Phrohdoh/oramod-ra2) which worked (and still works) nice, except that it doesn't really solve any of our issues. You can still not edit engine code easily.
In the end, I fail to see how a self-containing mod package containing only that one mod and the engine solves this issue. You would still need to somehow get your engine changes rebased onto upstream updates.
Consequently it comes really down to "This is mainly a packaging exercise [...]". Being able to bundle individual mods as self-containing package is indeed a good idea. It is also already being done, as was pointed out several times, and properly supporting it from upstream would be great indeed.
I don't see then why we need to split the default mods up and kill the modchooser, though.
Finally: I think we're partly missing the goal here. I read discussions about mods "copy pasting source code together with minor mod specific variations". But as I tried to tell above, I fail to see how this proposal will improve the situation there. This actually doesn't really seem to have much to do with it.
It might even be a good compromise all are happy with to just provide the option (for mods) to bundle a mod + engine only package, but at the same time not force mods to use it. The benefits (I can see) are:
Mods are slaves to whatever engine version the player has installed
This sounds like the main root cause of the issue. If you're breaking everything with each OpenRA release then why doesn't the team settle on API compatibility, maintaining backwards compatible changes, and for major architecture overhauls version the API?
Maintaining a stable API and versioning it sounds like the best option. Then, as development continues, older API versions can be deprecated over long periods of time allowing mods the opportunity to update at their pace. New releases will be providing an older version of stable APIs with new features in the new version. Eventually, this versioning could be used as a compatiblilty detection mechanism for loading mods and alert the user with a friendly message that the mod is incompatible rather than strange and inconsistent behavior. It could even warn the user that the mod is getting out of date and the parts of the API it is using will soon be removed in favor of the newer APIs.
This is a problem that has been solved before... I don't like the idea in this proposal and much prefer the mod architecture. Just adopt better mod support with versioned APIs.
Regarding the "icons" complaint, this can be offloaded to an installer which can offer check boxes to create shortcuts specific to launching the mod and giving that specific shortcut an icon. It seems like an aesthetic problem with an easy fix.
why doesn't the team settle on API compatibility, maintaining backwards compatible changes, and for major architecture overhauls version the API?
A clean solution would be to modularize the game and version individual parts of it to then define dependencies.
Remarks like these are frustrating because they are obvious points at a theoretical level, but when run through the constraints imposed by the .NET runtime, platform packaging conventions, and mod support desires, the approach I outline above is the most (and in many respects the only) practical way of achieving this. The implication that I hadn't considered this is a bit insulting.
The engine API is narrow, relatively stable, and already provides API versioning using per-feature flags: isometric/classic cell grids, flat vs heightmapped terrain, and order-based vs z-buffer rendering are all examples of our versioned engine API.
The problem is the shared mod code. The .NET runtime lets us load dynamic libraries into the application domain at runtime, but it doesn't let us unload that code. When a player switches to another mod the original mod's code stays in the application domain. We have a check to make sure that identical dlls are skipped, but the runtime will happily load custom assemblies that have duplicated class implementations and then break in unusual and difficult to reproduce ways.
The architecture of our trait code (being an entity component system) is to have many small classes that interact with many other small classes in a complicated dependency web. There are large groups of traits that can't be broken apart, and must be considered as a group with regards to API versioning. We can break these out into multiple assemblies, but that doesn't change the core runtime unloading problem. There are only two options for that:
This second option is acceptable (however see my point below) but we still need to consider how to compile, and package each "api version" into a separate Mods.Common.dll (or multiple dlls) that downstream mods can include:
Even if one of these options were acceptable, the .NET runtime still gets in the way of guaranteeing full bacwards compatibility:
It simply isn't possible to build a single engine installation that provides proper backwards compatibility support for mods. A half-arsed solution that gives only partial compatibility is not worth the effort it would take to maintain.
I'll follow up on the multiple engines + mod chooser points in a future comment.
I know I said this on IRC, but it is possible to load your DLLs into another app domain, and then unload the app domain it self when you go to switch between mods. There are some flaws to this method but most of them can be worked around. It is theoretically possible to get around unloading dlls from your "app domain" in this manor. Getting this architected and developed would be quite an effort, but if it helped here it may be a path someone should explore.
You'd end up with a system that would basically be the bare minimum to run the mod chooser in the primary appdomain, and any loaded mod would exist in a secondary app domain.
I'm a bit tired of having to write paragraphs and paragraphs for each minor point, so please just trust me when I say "no". I have looked into that option in the past, and it's not feasible for our purposes.
The explicit mod registration means that players need to manually launch a mod at least once before it can be switched to from the MP lobby.
With however a mod is installed could a config not be updated at install time to not require this step?
@abcdefg30 Regarding your thoughts in Versioning -> your a) solution is what I'm doing since day 1, the engine is stored in a repo which only has two additional commits I can rebase all the time, with those two commits just hiding AS/RA2 mod/dll folders through .gitignore and still including them in the solutions/makefiles. I have the AS git repo in it's place as a subdir and I have the RA2 engine code symlinked from the mods/ra2 subfolder as well and I never had issues about that so far.
Regarding this API POV - we already have standardized APIs in a way. Those are the trait-interfaces within releases. And as long as someone doesn't intend to add custom code but work only with the traits they have, they won't feel the main problem here - asin while theoretically you can override any trait, in practice dependencies/linking might prevent doing them the coder-modder would like to. Bleed modders have accepted they are working with unstable APIs from the get-go.
However, if we sit down and say that nor traits nor interfaces get any change between build 20160101 and build 20170230 (random dates ftw) that is basically freezing progression for good.
Random thought now that I reread the whole discussion - what if we decouple the modchooser to it's own executable and simply tell it to launch the game executable with the selected mod? Then we allow the thirdparty mods which want to have their own game-executable as well, while using the modchooser executable for the network API and whatnot. That would also mean firstparty mods can stay as-is entirelly and thirdparty mods only need any release version for the modchooser.
Random thought now that I reread the whole discussion - what if we decouple the modchooser to it's own executable and simply tell it to launch the game executable with the selected mod? Then we allow the thirdparty mods which want to have their own game-executable as well, while using the modchooser executable for the network API and whatnot. That would also mean firstparty mods can stay as-is entirelly and thirdparty mods only need any release version for the modchooser.
And the game/mod main menu 'Mods' button would basically close the currently running game and launch the modchooser exe, which would work around the .NET "no-dll-unloading" issue.
The implication that I hadn't considered this is a bit insulting.
Certainly not my intent. I took the time to read this entire thread with thesis abstract length comments and noticed options were not being discussed. To feel my suggestion was insulting because I "should have known you would think of it," despite having no idea who you are, is a bit much.
In any case, I guess I don't have much to add since .Net is not my forte.
_This is part two of my comment from yesterday, where I explained why it is not technically possible to have a single engine installation that exposes multiple stable APIs._
Why does moving forward with multiple engines imply dropping the mod browser and oramods? This comes down to a mess of technical and user experience reasons that are completely solved by doing so. There are going to be ways to work around individual points, but unless someone can suggest alternatatives to all of them then I don't think we'll find a better overall solution.
The main job of the mod chooser now is to manage/install mod content. I explained above why we can't maintain multiple API versions in a single engine, and the same thing applies here. We would have to freeze the capabilities of the shared content manager, which just isn't going to work. Content management needs to move back to the individual mods (which can then use the shared logic from their own Mods.Common), and the mod chooser would go back to being a simple launcher. For this, it could indeed use the backend I outlined above for cross-engine mod switching... but i'll come back to this point at the end.
Mod installation and launching will work differently for different mods on the same OS, and differently for the same mod on different OSes. This makes for a horrible user experience:
We have direct statements just above that our biggest and most exciting thirdparty mods are going to continue to ignore our shared mod infrastructure and ship their own installers. I can only assume that these installers will ignore or remove the mod chooser provide their own direct-to-mod application launchers on all the platforms they support.
Oramod packages need to be copied manually by the player to an OS-specific and engine-specific location. This location is hidden from the file browser on Linux or OSX, and is only visible on Windows because we violate platform standards by putting our data in the Documents folder (see #10374).
Repeat points 1 and 2, replacing "install" with "update". I don't see #9028 or #9029 ever being implemented, but if they were then we would be stuck with inconsistent systems for updating mods and engines.
The main conclusion from the branding kerfuffle is that playes want their OpenRA launchers to focus on the things that they play, not some abstract project branding. We can do this for our default mods on Linux and Windows, and third party mods can do it on all OSes, but we can't do it for our default mods on OSX or oramods on any OS.
We can't do mod specific branding with a shared engine at all on OSX where the engine is the launcher. Players are forced to pick between launching "OpenRA - Engine A" or "OpenRA - Engine B" or (repeat for all installed engines) from their launchpad/dock/applications folder, which all go to the same shared mod chooser UI. They then get to choose their mod from a custom UI that isn't exposed to Spotlight or Siri, slide out of full screen when the mod chooser is closed, then back into full screen with their selected mod and finally play what they want. This is just horrible.
Most players wouldn't expect oramods to be able to delete/encrypt/steal your personal data, but they can do this or other malicious things using any of the APIs exposed by .NET/mono. Reasonable people will use common sense before running an installer or exe file.
I don't think anyone would seriously argue that the points above are good things that we would accept if we were talking about adding the mod chooser for the first time. Things have changed a lot since then, when we only cared about improving the visibility of our default mods.
My proposal at the top, with the modifications from my later comment, avoids all those problems and instead:
The final question is then "why can't we do all this but still keep the mod browser screen", to which really all I can say is "...why?". Shipping the mod chooser, on OSX in particular, actively hurts the user experience by introducing context shifts and failing to integrate with OS features. The only things we lose are the mod description paragraphs and the prominently displayed project logo that a vocal subset of players actively hate.
I have started on the changes to implement this with #12600, but will soon hit a point of no return – once I start with the asset management and packaging changes (which are too big to do over one pr) we will need to run this through to completion.
Personally, I'm still in favor of this because I think the benefits outweigh the disadvantages.
However, I do wonder whether the follow-ups to #12600 should be left for Next+1, in other words, whether we should split off a prep branch shortly after #12600 and some unrelated PRs (D2k, performance, activities) are merged.
One last release in the "old" way might leave us with more breathing room and time to test - and where necessary, fix - the new setup.
I wouldn't object to that at all. It could also be worth PRing changes towards this into a separate branch, and then only merging it all into bleed once we're confident the different parts work well enough together.
I think we should aim for this release to do the mod dll merge (ra/td/ts – i'd like to keep d2k separate as an example and because most of its contents are useless for other mods) and move the common chrome yaml to mods/common. I will also adapt #12600 to use the new UI for the internal mod switching, since that will be living for more than just a few more weeks.
Can we get a more flexible layout?
binary/
openra-sdk-release-xxxx/
OpenRA.Game.exe
OpenRA.FileFormats.dll
OpenRA.Platform.Default.dll
OpenRA.Mods.Common.dll
data/
openra-sdk-release-xxxx/
mods/
common/
(common yaml files)
(common ui graphics)
user-data/
ra-release-xxxx/
(ra gamerules)
(ra ui)
(ra assets)
(ra maps)
config/
ra-release-xxxx/
(ra settings)
temp-cache/
ra-release-xxxx/
(ra replays)
(ra logs)
With binary and data configurable at build time and user data, config and temp-cache folders coming from system configuration. https://github.com/OpenRA/OpenRA/issues/10374
the thing is that when you guys update OpenRA, ra2 mod needs to update too,and other mod should update too(if their mod wants to run on dev version)
You guys needs to make this engine stable, and change the mod things, don't change core things too frequently
As for the structure of the new OpenRA, i prefer this:
(OpenRA-root-directory)
Core
(Core things of the OpenRA)
Mods
ra-release-xxx
maps
rules
ra-config.yaml
ts-release-xxx
maps
rules
ts-config.yaml
Content
ra-release-xxx
movies
music
something.mix
ts-release-xxx
movies
music
something.mix
OpenRA.exe
README.md
@cookgreen this ticket is all about how to solve that issue without killing the development of the upstream engine. "not changing things" means not supporting TS or RA2 at all, because many many things need to change to be able to support them properly.
An update on where we are at:
mods/common/OpenRA.Mods.Cnc.dll. [#12678, #12757, #12763]mods/ra/chrome to mods/common/chrome. [#12762]modchooser mod with contentinstaller mod for per-mod asset management. [#13049]--register-mod utility command to pre-register mod switching during install on windows/linux [#10374].The remaining engine and packaging changes are complete, and #13049, #13133, #13129, #13138 are waiting on review/merge.
The mod template work remains blocked on #13049.
The core engine and packaging changes are now finished, and the mod template has feature parity with mods that previously worked from a fork of bleed. I'm calling this issue DONE.
Most helpful comment
The remaining engine and packaging changes are complete, and #13049, #13133, #13129, #13138 are waiting on review/merge.
The mod template work remains blocked on #13049.