Search Unity

Modding in DOTS-based game

Discussion in 'Entity Component System' started by SupinePandora43, Apr 21, 2020.

  1. SupinePandora43

    SupinePandora43

    Joined:
    May 13, 2019
    Posts:
    18
    How can i do safe modding system with DOTS.
    with C#, Job Systems and Entities!!!
    *with NetCode
     
  2. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    One problem with ECS is that there are no private components, so everyone can change everything.

    One way would be an IL2CPP build and use LUA for mods over which you have full control. Probably.

    Another problem could be that C # Mods are just "normal" libraries, there was no burst or IL postprocessing, which can have a big impact on game performance.
    I don't even know if SystemBase works without postprocessing at all.
     
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    SystemBase works without postprocessing. it is quite easy to just have a setup where modders simply make additional systems and your runtime code loads those .NET dll's manually and injects them into the simulation world.
     
  4. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    Which would be especially useful for mods if you could export DLL via Unity, including IL postprocessing and burst AOT. Maybe useful for pre-compiled packages.
     
  5. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    1,124
    @Joachim_Ante I remember first we wanted to do this in Unity 2.6 and back then Lucas Meijer wasn't working with you guys and I guess he had a blog or maybe it was angry ant showing how to save a DLL as a byte array and then load it at runtime as an assembly via reflection and it worked everywhere other than in WebPlayer. We were making a PC game which never saw the light of day being the first game of very young indies :))
    We also had to serialize components of the dll and their values for each prefab in a data format of our own and ship it either with the dll or as a separate asset/a text asset in the asset bundle containing the prefabs.

    Is the live link data format done in a way now that it can be used for mods as well so a mod and its prefabs and external new DLLs can be packaged using the live link data format? How does it identifies assemblies and the objects in them?
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    No. I would strongly recommend making your own modding data formats that are highly specific to your game.
    Unity.Properties can be useful in serializing the data. But i think it's fundamentally a different problem from how to efficiently load entity binary files from disk which are in "memory ready" format & insanely fast to load.
     
    pal_trefall likes this.
  7. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    1,124
    Well at least should there be a way to bake our mod data into a format which can be loaded very fast. Our game in pre-production allows the users to create very big world with 100s of 1000s of objects and the only realistic way to be able to load them is a way to store them in a format which can be memcpyed to the game like the live link stuff so I would like to at least be able to bake the data after the first load in a way which can be loaded that fast, will look into unity.properties but hopefully we can somehow serialize a world and deserialize them in this manner or at least are capable of writing a solution which can do that? What I want to make sure is available is just primitives which I can use to serialize all of the user generated entities and their serialized fields and the DLLs in a way (after the exact dll was known) that it can be streamed very fast
     
  8. SupinePandora43

    SupinePandora43

    Joined:
    May 13, 2019
    Posts:
    18
    @runner78
    thanks for info
    game ierarchy should be:
    • MainMenu Scene (locked access from mods)
      • GameMode Picker
    • MainMenu Background (can be edited by active gamemode mod)
    • GameMenu Scene (locked access)
    • GameLevel (full access from mods)
    mod script should be:

    Code (CSharp):
    1. using MyGame.API;
    2. namespace MyMod {
    3.     public class MyMod: MyGame.API.MOD {
    4.         public MyMod(MyGame.API.MODinit initializer){
    5.             initializer.AddComponent(MyComponentData.class)
    6.             initializer.AddSystem(MySystem.class);
    7.         }
    8.     }
    9.     public MyComponentData : IComponentData {
    10.         public int myData=0;
    11.     }
    12.     public class MySystem : SystemBase {
    13.         protected void OnUpdate(){
    14.                MyGame.API.Entities.ForEach((ref MyComponentData myComponent) => {
    15.                       myComponent.myData++;
    16.                })
    17.         }
    18.     }
    19. }
    for loading mod:
    1. load dll's from /Mods folder
    2. find all MyGame.API.MOD implementations
    3. initialize them
    questions:
    • can i compile main game with il2cpp, but MyGame.API without il2cpp?
    • how preprocess mod with Burst, il2cpp?
    • i can reference MyGame.API in csproj if it "IL", but what if dll compiled with "il2cpp"?
    • how add systems, Icomponents at runtime?
     
  9. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    When you do modding. I think you really want to define the data format specific to your game. Eg. you work in
    * instantiate this prefab at this location, with the specific overrides of the instance that heavily depends on your game.
    * As opposed to having all the data flattened out like in a normal entity scene because in Unity prefabs allow for arbitrary overrides. Thats useful for a development tool catering to all kinds of use cases. But not to a constrainted dedicated in-game level editing tool.

    Entities provides very efficient instantiation and you can even do that on a job. I just really don't think that serializing a whole world is something a modded game should do. What is the specific use case when that is actually a useful approach?
     
  10. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    With il2cpp, the game don't have mono running, so you can't load .NET dll

    You can use World.AddSystem:
    Code (CSharp):
    1. WorldInstance.AddSystem(new MySystem(myParams));
     
  11. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    1,124
    You might be right, the usecase in my mind was allowing users to heavily mod the game like what can be done in games like say far cry and arma. something like allow the users to open a tool in unity editor which is for our game with all of what we want to provide available and then they can make their mod in unity and export as an assetbundle/addressable and also compile their DLL and provide them to the game. but I did not think all the details so you are right that in fact that might not be desirable to give them that much control.
     
  12. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    1,124
    @Joachim_Ante on second thought you are right about that even in the case of Arma 3 they are using their own specific tools to allow specific things to happen only and that has to be our own format. However using unity.properties as a utility will greatly help which is awesome!
     
  13. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091
    Are there any known workarounds? Some kind of C# interpreter that works with il2cpp (for ex. Roslyn C# Scripting API).

    This would be really useful not only for modding but some kind of live coding that would allow to test and tweak many functions even runtime by just changing text file.
     
  14. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    I think it's not entirely impossible to implement an custom .NET runtime for scripting, but that wouldn't make much sense, you don't have the Unity API and need to build your own native<->C# API.
    It would be easier to implement LUA.
     
  15. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    1,124
    Guys you don't have to use IL2CPP specially with burst and the fact that the code which need perf will be compiled to a native code DLL and you'll still can load user dlls as well.
     
  16. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
  17. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,091

    Something simple like Math.Sin can run 10x times slower on Mono not to mention code obfuscation. Changing all code to burst is impossible for me.
     
    Last edited: Apr 24, 2020
  18. RamType0

    RamType0

    Joined:
    Sep 11, 2018
    Posts:
    67
    Could we define custom component data in mod?
    I think there is a serious issue around TypeIndex of ComponentType.
     
    IliqNikushev likes this.
  19. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Assuming you load the mod after startup, it is possible. It takes some reflection hackery though. I do this to generate concrete instances of generic tag components at runtime.
     
    RamType0 likes this.
  20. IliqNikushev

    IliqNikushev

    Joined:
    Feb 1, 2017
    Posts:
    22
    I am currently experiencing this as well

    The issue can be resolved with
    Code (CSharp):
    1. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
    2.     static void Initialize()
    3.     {  ... loading mods logic }
    4. }
    The TypeManager gets initialized on BeforeSceneLoad, so any moment before it is great
    As long as the Types are available before that - everything is good.

    Sadly this means that they cannot be unloaded, as the whole cache would get weird :D
     
  21. IliqNikushev

    IliqNikushev

    Joined:
    Feb 1, 2017
    Posts:
    22

    Imagine you have

    Player.dll

    which has

    Code (CSharp):
    1. public class PlayerComponent : IComponent
    2. {
    3.     public int score;
    4. }
    5.  
    Then in your Main project, you need to have in your 'Initialize Method'
    System.AppDomain.CurrentDomain.Load(System.IO.File.ReadAllBytes("Player.dll"));

    And that type is now registered to work with any system that you have
     
  22. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,779
    Just wonder, wat are current available approaches for modding, for latest 1.x DOTS and ECS.
    Does anything from previous posters is still valid?
     
  23. IliqNikushev

    IliqNikushev

    Joined:
    Feb 1, 2017
    Posts:
    22
    I am porting now to V1, there isn't really much changed in the flow
    Still works as i wrote above (windows/linux) haven't tested on mac, but i think they have some mumbo-jumbo when it comes to runtime loading of code

    Systems work, but you need to inject them yourself in bootstrap (make sure they are created)
    Classes / structs get loaded, so all prefabs are created as they are

    For Burst Code there is a function 'Unity.Burst.BurstRuntime.LoadAdditionalLibrary'

    In order to make NetCode work, you may need to make your own custom RPC to manage with the state of the entity (as i mentioned here : https://forum.unity.com/threads/add...ghost-entity-at-runtime.1307499/#post-9550198)

    The main thing that needs to be considered is Bakers (a prefab that has the baked component)
    I am currently trying to see if there would be a nicer way to do that, than exporting the prefab as a json and re-creating the entity on 'mod loaded'

    other than that, things work
     
    Last edited: Jan 17, 2024
    Antypodish likes this.