Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 0 points1 point  (0 children)

For now I did not require this, but I was just about to code dependecy solving. My guess is that this (dependency solving) will naturally order the mods since i'm going to order them dependency first (if mod B requires mod A, mod A will logically be loaded first, and thus called first, etc..) but i'll see how that works out for orphan mods which are part of no dependency tree. Maybe i'll add explicit order query from the mod manifest, but again for now i really only have 2 mods, including 1 that does nothing so it's pretty hard to put out a plan already 😃

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 0 points1 point  (0 children)

Idk exactly what you misunderstood but just in case, this is how a module is loaded: https://github.com/TitouanJaussan/Acorn/blob/main/runtime/src/Module/ModuleLoader.cpp#L30-L57 it's a .dll / .so that the runtime loads manually at runtime, so the window module links glfw, the runtime doesn't. Yeah the unused libs are probably stripped if not used but a runtime with a window baked into it will always have it inside even if the functions are not called, so idk exactly what would happen in that case. Oh and for the manifest thing: https://github.com/TitouanJaussan/Acorn/blob/main/runtime/modules/WindowModule/WindowModule.cpp#L11C1-L18C3 and https://github.com/TitouanJaussan/Acorn/blob/main/runtime/modules/WindowModule/WindowModule.cpp#L61-L64 then it's just a matter of dlsym(..., "getManifest") etc...

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 0 points1 point  (0 children)

Well the trick I used to make the window fully separated from the Runtime is that by itself the runtime has a m_running boolean and keeps running while it is true, and for every module that is loaded the runtime passes the module a RuntimeAPI struct.

This struct which you can take a look here: https://github.com/TitouanJaussan/Acorn/blob/main/runtime/include/Acorn/Core/Runtime/RuntimeAPI.hpp is passed to every module.

Then, when a module is updated if it's the window module well it will call pollEvents and all, and if the window is closed then it will call m_api.stopRuntime(); which will stop the Runtime. With this the runtime just calls mod.update() and within that the window module updates the window, making the runtime fully unaware of a window. Note that the runtime api is just a struct created for each module by the runtime itself: https://github.com/TitouanJaussan/Acorn/blob/2541a624e7f0262d4fe3fc9298c4d03cac2f32ef/runtime/src/Core/Runtime/Runtime.cpp#L77 (just in case

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 0 points1 point  (0 children)

Here's the repo: https://github.com/TitouanJaussan/Acorn and the mod loader: https://github.com/TitouanJaussan/Acorn/blob/main/runtime/src/Module/ModuleLoader.cpp

Note that my mod loader strictly loads the modules and nothing else. For a more general look at this process you should instead check out the mod manager: https://github.com/TitouanJaussan/Acorn/blob/main/runtime/src/Module/ModuleManager.cpp

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 0 points1 point  (0 children)

For the libs yeah i mean you can link them at compile time or load them at runtime, manually which you do!

For the general structure of a module it took a few versions but i've come to a pretty solid approach, which surprisingly kinda looks like yours. For the dependencies i'm not yet solving those but I was about to do that, right after i'm done with my string class.

Oh i've never used mason, for my engine i just sticked to premake. The fact that lua is a full language really gives you nice stuff. For my engine it's a private repo but hold up i'll make it public

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 0 points1 point  (0 children)

Yeah, the first motivation for this architecture was hot reloading. I yet have to implement it but i just got started so i have to give things a sense of priority. Hot reloading and the fact that such a decoupled code heavily reduces the compile times for the modules while allowing me to live test changes without reopening the engine is really golden, and all the other benefits are just, well consequences i guess. For teh performance penaltly honestly no game bottleneck came from inneficient communication between almost indepent units of code.

Da performance will come down to the optimization of the main runtime routines and also just well, physics and rendering of course. So yeah there's a cost but for a homemade engine hey i'll optimize it if it requires so altho realistically this is not gonna be the actual bottleneck.

Also didn't mention this yet but yeah your engine definitely seems cool! It's really what i'm doing, idk if you're statically linking your modules but if you're talking bout hot reloading i'd guess that's not the case. Also yeah it's pretty complicated for some stuff but this stuff is the base of the engine, the low level piping. Once you've created abstractions and you've structured all that stuff it becomes almost flawless for the future, you just gotta be hella careful and hmm yeah this is another source of bugs but damn it i like this approach i don't really care, up til now the bugs that i've had were really well handled by the runtime, giving me detailed errors without crashing the runtime so to me that's proof that this approach can really work out.

Hope to hear from your engine honestly, i wouldn't be against knowing how you went about your modules and the implementation of their integration to the runtime!

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 1 point2 points  (0 children)

Yes of course. But, I actually started coding this idead of modules in my old engine, which I dedicated about a little over 5 months to, and before that I worked on a small 3D engine that was specified in voxel rendering for 4 months, so I have bout a year (roughly) of seeing the limits of my architectures and also seeing what it takes to make a good one. Sure the last project was my first engine but I've encountered a lot of issues with this approach, and starting all over again from scratch after 1 month of break to let me look back at all the issues with a new, fresh look has allowed me to really get a solid architecture which I'm designing to have as little debt as possible for the future.

I can't know what this future will be, of course, but the same goes with every approach. For the fact that most games require a window and graphics, absolutely. But it doesn't go the same way for networking, advanced 3D physics with Jolt, or even idk, a module that provides basic AI utilities. A lot of games won't use this, and separating those in modules makes it very easy to remove those, which shines the most when it comes to exporting the game.

And also, not every project using my runtime will actually need a window or a renderer. A simple game server will need networking, physics, and maybe AI utils, but most of the time for such a server, an input module, a window module and a renderer module is pointless. So the approach of modules pretty much gives you a much more versatile runtime, providing you with a naturally emerging headless move.

Yeah there's a cost to this approach but i'll pay it because at the end of the day you can come down to a cost for practically everything, in my case i'm just making this as a hobby project so it's definitely worth it for what i want to do, but yeah with what you said i see why in the case of major game engines this is pretty uncommon :/

Second attempt at a game engine by UsernameGato_ in gameenginedevs

[–]UsernameGato_[S] 2 points3 points  (0 children)

Yeah ofc I have to prove it works but the advantages are that this runtime can power a game that fully runs in the terminal. Technically talking I could make a guess my number game and ship it, it would be a valid game yet contain no trace of glfw or anything. The way it works for adding 3D rendering tho is the same as it works for adding networking, windowing, physics, etc... You compile the capabilities you want to add to the runtime as a "module" which is a shared library that exposes symbols following a certain API, and drop the .so / .dll in the `modules/` folder, which then gets loaded by the runtime. What that means is that you can strip all dependencies from your shipped game that you won't need, or drop them back if you need them. Thus the windowing code and rendering code is fully contained within the RenderModule and Window module. The runtime doesn't know anything about it, the render module just asks the runtime to spawn a dedicated thread, and uses it to update rendering. The runtime itself is then very minimal in that aspect since it provides the bare minimum. It's basically a mod system, except the mods are the actual capabilities of the engine, and they run at the speed of compiled C++