BattletechModders / ModTek

Mod system for HBS's PC game BattleTech.
GNU Lesser General Public License v2.1
121 stars 34 forks source link

Criticisms and Ideas #2

Closed CptMoore closed 6 years ago

CptMoore commented 6 years ago

Hey there,

I went through your code, and have some comments on your ModTek idea.

First and foremost, only concentrate on the manifest stuff asap, and only the most simple of things (not even partial loading). That seems to be the most important thing modders need. Once that is done and stable, move to dlls loading, partial loading, dependency management etc.

Topics

Manifest Additions

Partial JSON Loading

I would suggest postponing the partial json loading topic until a proper json manipulation language can be integrated (e.g. JSONata)

mod.json File

DLL loading

Dependency Management

I would suggest postponing the hole dependency topic and use a simple mod load order list, that also reflects the manifest load order mechanism used by battletech.

Suggested Directory Structure for Mods

Code Style

My Contributions

If you want I can try to address any of the points I rased above.

As a first small step I would like to provide the following things in a PR:

Further ideas for ModTek

mpstark commented 6 years ago

Thanks for taking a look -- I've read through your suggestions and they're extremely helpful. Let me take a bit to digest, look through the code, and get a proper reply written up.

mpstark commented 6 years ago

mod.json specification

DLL Mods

Partial JSON Loading

Dependancies

Logging

As to your coding style suggestions, I'll be sure to start using them! I think sometimes no curly brace statements can be a net-benefit for code clarity, but I know that I wasn't consistent about it.

mpstark commented 6 years ago

I would be very happy to see any Harmony-specific tips and tricks if you have them. Traversing to find private members sounds very, very useful, although I think the next Harmony version will include some additional tools to do that.

CptMoore commented 6 years ago

mod.json specification

MyModName.modtek.json

I would want to avoid having to write the mod name everywhere.. ideally I only need to change it at one place for everything (code, files, ..). Every file name, every variable that includes a name, that I have to set myself, is just another source of error when creating new mods.

I rather have mod.json than mymodname.modtek.json . What about settings.modtek.json ?

adding a DontLoadImplicit bool to the ModDef would allow mods to do own handling if need be.

Why not create an autoimport directory? call it autoimport.. ? then there would be no need for the flag and its clear whats happening to the files inside there

Newtonsoft.Json [...] as far as I know, there is no advantage to not using it

Yea no difference here, I usually prefer using the utilities the ecosystem is using, in this case Battletech seems to be using JSONSerializationUtility for their data files. Newtonsoft is better documented though and should work fine.

DLL Mods + Logging

Mod .dlls should never have to include a reference to ModTek.ModDef

I'm now thinking about just passing the JSON

It's easy enough to roll your own log file in your own directory

I believe you don't want ModTek internals be exposed to a mod right? There should be a modtek-modding library that both ModTek and the Mod can share, so ModTek can fill up a context (similar to ModDef) and let the mod have that.

I really would want an easy to use utility (easy logging, easy file access, easy configuration loading, additional dynamic manifest loads) to jumpstart mods, so such a shared lib would allows that easily. What do you say?

Or are you afraid of compatibility issues over time? Thats why that helper lib should be bare bones only right?

having mods ship modTek.dll is a recipe for disaster

call it different then, like mod.dll or mod.modtek.dll

look at how factorio does it https://wiki.factorio.com/Modding

info.json control.lua data.luia

they also have a nice info.json

{
  "name": "EvoGUI",
  "version": "0.4.302",
  "factorio_version": "0.16",
  "title": "EvoGUI - Evolution Factor Indicator and more",
  "author": "Octav \"narc\" Sandulescu",
  "contact": "factorio-mods@narc.ro",
  "homepage": "https://github.com/narc0tiq/evoGUI/",
  "description": "Places some indicators on your UI for various little statistics that are nice to have.",
  "dependencies": ["base >= 0.16.1", "? moweather"]
}

? = optional ! = required I believe

In order to avoid wrong handling of everything, mods are zipped.

See Assembly.Load(byte[]) to load an assembly from memory, so read it from the zip into memory then load the bytes. Of course this would now definatly require a helper class to handle loading files from a zip.

Partial JSON Loading

The large constants files like SimGameConstants.json that make

Yea ok, especially like changing the starting mech becomes very easy, or adding in the tutorial skip (well the devs will fix that but I get your point).

Newtonsoft.Json includes a handy simple json merge function that happily does a lot of the work for us

The problem is the setting, sometimes I want to replace an array, sometimes I want to add an element to the end, sometimes I want to remove something but not everything. That requires more precise modification abilities. Question would be if that's necessary for the first ModTek release or not or even ever. And what should be the standard, Union, Merge or Replace? I would suggest replace, in worse case one has to replicate data, but at least one can always remove unwanted data without creating a DLL mod.

There are a fair amount of JSON errors

Really? Would explain why they use their own JSON utility?!

CptMoore commented 6 years ago

I would be very happy to see any Harmony-specific tips and tricks if you have them.

Well its very simple to use, mostly just annoying to find and expose the private members every time you find them.

I usually create a class I name something-Adapter to signify that its just an access point to an existing class.

    internal class MechLabLocationWidgetAdapter
    {
        private readonly MechLabLocationWidget _instance;
        private readonly Traverse _traverse;

        internal MechLabLocationWidgetAdapter(MechLabLocationWidget instance)
        {
            _instance = instance;
            _traverse = Traverse.Create(instance);
        }

        internal MechLabPanel MechLab => _traverse.Field("mechLab").GetValue() as MechLabPanel;
        internal TextMeshProUGUI LocationName => _traverse.Field("locationName").GetValue() as TextMeshProUGUI;
        internal List<MechLabItemSlotElement> LocalInventory => _traverse.Field("localInventory").GetValue() as List<MechLabItemSlotElement>;
        internal LocationLoadoutDef Loadout => _instance.loadout;
    }

Just remember to use Property instead of Field is its an actual Property you are accessing. Thats it already..

CptMoore commented 6 years ago

btw my new suggestion for a mod structure

Suggested Structure for Mods

mpstark commented 6 years ago

Implicit Loading of Manifest Entries

The way I see this feature working is that we'll define two different implicitly-loaded directory structures that don't need to be included in the mod.json file.

The first (and most presently pressing) would be the data directory that mirrors the streaming assets one -- the purpose behind this directory is to modify/replace existing game files. In this regard, supporting JSON merge operations on JSON with specific types, with whatever MergeArrayHandling value we choose as the default.

The second would be directories with pluralized type names like ModFolder\MechDefs\. This would generally be for new additions with no partial JSON files that expect to be merged.

Any behavior beyond this is specified in mod.json's manifest. These implicitly-loaded directories need to be able to be configured by the mod in-case the modder wants the behavior to change. First of all, specifying "LoadImplicitManifest": false, will disable it completely. Providing a ManifestEntry in the manifest that matches an implicit one will also take precedence. Full control should always be possible.

Regarding Utilities/Logging

I want ModTek to stay dependent on only the game and BTML. I don't believe that other mods should ever rely on ModTek's assembly itself. I do not want centralized logging into ModTek's log.

These are design decisions and ultimately rely on personal value judgements.

CptMoore commented 6 years ago

The second would be directories with pluralized type

any reason for that? why not mimic streamingAssets\data again?

Any behavior beyond this is specified in mod.json's manifest

do we still need manual manifest loading if the automatic one already works? whats the point of having two ways of doing things? in the automatic case the mod author still has full control, one can still decide what files to put in a directory.

is the automatic way not working with everything and therefore manual manifest entries are still required?

I want ModTek to stay dependent on only the game and BTML

I am a bit confused, why not just integrate BTML as part of ModTek? ModTek should become the new BTML, maybe even provide a own startup exe for in-memory injection for battletech, so no need to modify any files anymore, just start modtek.exe .

I'm thinking for the user to have the simplest experience possible.

I don't believe that other mods should ever rely on ModTek's assembly itself

Sure maybe not the main ModTek assembly, but what about a helper library?

CptMoore commented 6 years ago

@Mpstark what do you think about the dynamic compilation feature? like adding a .cs file to a modtek based mod and that will be compiled dynamically? I'm right now looking at making it feasible.

mpstark commented 6 years ago

Could be a feature later on, but right now, looking at nuts and bolts of the first release.

umbravi commented 6 years ago

Great thread thus far, with a lot of great points. On:

instead of == null and != "" use string.IsNullOrEmpty .

This is rather small, but:

CptMoore commented 6 years ago

I'm currently splitten up all my points I made into separate tickets and add more information to it. @Mpstark please feel free to re-add your comments on the topics to those tickets.

mpstark commented 6 years ago

I'm leaving issue open so that others can chime in. Thanks for breaking it up though, makes it a bit easier to handle.