guerro323 / GameHost

MIT License
0 stars 0 forks source link

revghost v2 #118

Open guerro323 opened 1 year ago

guerro323 commented 1 year ago

A very big rework of revghost is coming (previously GameHost), which will focus even more on the ECS Host aspect. The Host ECS has been swapped from DefaultEcs to flecs, which provide more features (and even an explorer!) and performance improvement that will be useful in the long run.

What is kept:

What has been removed:

Roadmap:

guerro323 commented 1 year ago

The C# wrapper is almost finished, the most important features that needs to be completed for it to be considered done are:

guerro323 commented 1 year ago

Processors aren't an obligation for now, since I replicated the needs for them with using foreach for nested queries (and it works well!) image

guerro323 commented 1 year ago

Observers are now coded in. image

Before releasing the wrapper, I'll remake the Low Level part use my own bindings and include binaries of flecs (so that it can be used on windows and macos without compiling it)

guerro323 commented 1 year ago

Will be released very soon (approx some hours from now), there are still some bugs that needs to be resolved but they're not gamebreaker

guerro323 commented 1 year ago

wrapper release: https://github.com/guerro323/revghost.flecs work on revghost2 is starting now

guerro323 commented 1 year ago

File and storage entities :eyes: image

guerro323 commented 1 year ago

The concept for Storage is a bit problematic since I couldn't do it the way I originally wanted (using multiple EcsIsA relations from different storage into one storage). Instead I'll make it more basic with a hierarchy and priority system:

Example of a world hierarchy:

flecs
    | ...
mods
    | ... 
**storages**
    | FileSystemExecutableFolder
    | Mod0
    | Mod1
    | FileSystemUserData
    | ...
    | ServerMod0
    | ...
    | CurrentMap
**contexts**
    | **root**
            | XXXX.YYYY # config/inputs.json
            | XXXX.YYYY # maps/topkek.zip
            | ...
    | player_guerro_skin
           | XXXX.YYYY # config/inputs.json (since the goal of this file may differ from the root context, having it isolated prevent that (for example this file can be material inputs))
           | XXXX.YYYY # tex/skin.tga
    | player_guerro_data
           | XXXX.YYYY # config/inputs.json (a multiplayer game could show the current input configuration of a player! having it isolated here prevent it from conflicting with root/config/inputs.json)
           | XXXX.YYYY # player_skin -> context: player_guerro_skin
    | ...

Usage example:

struct Configuration : IComponent {
    public int Value;   
}

var rootCtx = world["contexts.root"];
// Lookup for config.json, and put a placeholder if it either doesn't exist or didn't load yet
var configFile = rootCtx.LookupFile("config.json", placeholder: true);

// Create the reload state of our config entity.
// When the file will get loaded or reloaded we will refresh with these components
var reloadState = world.New()
                  .Add<Disabled>()
                  .Add<IoLoadFileContent>() // ParseJson need to get the content from somewhere!
                  .Add<ParseJsonToStruct, Configuration>();
// Then, create our config entity, set the target to our config file and attach the reload state to it.
// Note: the framework will complain if the target doesn't have a Disabled state.
var config = world.New("config")
                  .Add((IoFile.EntityId, configFile))
                  .Add((IoReloadTarget.EntityId, reloadState));

// pseudo code
while (!config.Has<Configuration>);

var cfgData = config.Get<Configuration>().Value;
// If the user update the file, changes will be automatically be reflected!
//
// Of course if you don't need to have the reload feature
// you can just move the components of 'reloadState' to the 'config' entity:
//
//  var config = world.New("config")
//                   .Add((IoFile.EntityId, configFile))
//                   .Add<IoLoadFileContent>()
//                   .Add<ParseJsonToStruct, Configuration>();
//
guerro323 commented 1 year ago

The storage concept has now been finalised and is currently being implemented.

Once done, I'll go work on the module load/unload system, which will be relatively much easier to do. The biggest difference is that there will be a root module per assembly again (need to register the loadable modules of this assembly) :

// -- as of now we can only load 'flecs modules'
world.Register<MyModule>(); //< only work if you referenced the module in your code

// -- revghost modules
// In your root module:
void Load(World world) {
     // only register the description of the module (so that it doesn't load it)
     world.Register<ModuleDescription<MyModule>>();
}

// -- In any other places (even outside of the assembly)
// Note that this will only load the module on next frame and if it was registered beforehand.
// There will be a warning logged to the console if the module was not registered and a skippable error if the module couldn't be loaded after 3 seconds.
world.New("mods.MyModule");

This goes hand in hand with how flecs and the wrapper work; if the module wasn't loaded/created, a system will pick up on the empty entity and try to see if it match in the register from the name.

Of course this is also gonna go hand in hand with the storage concept since it will utilize it (under the hood the mods entity is a context)

guerro323 commented 1 year ago

Small change to the module concept:

And progression of module loading: image (The only thing left for it to be finished is to add assembly loading, and see if it can unload well)

guerro323 commented 1 year ago

Storage progress: image

What's left for it to be finished is to make sure that the order is respected (order should be: dependencies->creation)

guerro323 commented 1 year ago

Ordering is half here, for now there is only creation ordering image image

A cool unexpected feature is that you can nest contexts, and also override with a storage that was overriden (for example in my_custom_sub_ctx we can see that my_storage_a overrided the B storage (even though it's not the case on the other context, because we explicitly re-added it)

guerro323 commented 1 year ago

I need to investigate why there is an 'infinite' loop on Windows, it seems it come when the storage module get loaded (maybe because of the file system watchers?)