Hot code reload and interaction with the core of the engine

I noticed that in Handmade Hero the entities code (just to pick one as an example) resides in the gameplay DLL.

I've been thinking about the architecture of my own engine and I'd rather have all the entity management system in the core or the engine so that in the end I can reuse that for a new game and just write the game specific parts in the DLL.

If I opt to do something like that I guess I'll have to expose the core entity management functions to the game code DLL in a way similar to how the platform API is exposed and that would force to create as many typedefs as the functions that I want to let the game code DLL call. Is this the only way to achieve something like that?

Cheers!
tanis
I noticed that in Handmade Hero the entities code (just to pick one as an example) resides in the gameplay DLL.

I've been thinking about the architecture of my own engine and I'd rather have all the entity management system in the core or the engine so that in the end I can reuse that for a new game and just write the game specific parts in the DLL.

If I opt to do something like that I guess I'll have to expose the core entity management functions to the game code DLL in a way similar to how the platform API is exposed and that would force to create as many typedefs as the functions that I want to let the game code DLL call. Is this the only way to achieve something like that?

Cheers!


Problem with that is that most of the code concerning entities will depend on the size of the entity struct. So any time you change the entity struct you will need to recompile the platform layer as well.

The platform layer is meant to be a thin shim between the kernel and the game. The reason for them to be separate binaries is to assist in live code editing. There is no real reason to pull the entity code out of the game dll.

If you want to reuse the code in future projects then you only need to make sure the code to be reused is grouped in a logical set of files.
ratchetfreak

Problem with that is that most of the code concerning entities will depend on the size of the entity struct. So any time you change the entity struct you will need to recompile the platform layer as well.


True, but my entity is just going to be an id (integer). The system is going to hold an array (or hashmap) that holds a connection between the id and the pointer to the actual structure of the entity. But the structure is going to be defined in the game code DLL but allocated through the platform Memory object still.
The rest of the system is just functions to iterate over the entities or manipulate them (like get the components or stuff like that).
Of course if the struct of the entity changes, hot reloading won't help as all the pre-existing entities would be invalid. But that would happen even if all the entity stuff lived in the game code DLL.

ratchetfreak

The platform layer is meant to be a thin shim between the kernel and the game. The reason for them to be separate binaries is to assist in live code editing. There is no real reason to pull the entity code out of the game dll.

If you want to reuse the code in future projects then you only need to make sure the code to be reused is grouped in a logical set of files.


While I can agree to some extent about the reuse (even though I'd rather have common code in a library instead of copy & pasting it around), I am more concerned about the time it takes to recompile a project that isn't just a couple of files. Once the game code base grows, recompiling on the fly is going to take more and more time until it's like recompiling everything from scratch and it sort of defeats one part of the purpose of hot reloading which si making the iteration times quick, wouldn't it?
tanis
ratchetfreak

Problem with that is that most of the code concerning entities will depend on the size of the entity struct. So any time you change the entity struct you will need to recompile the platform layer as well.


True, but my entity is just going to be an id (integer). The system is going to hold an array (or hashmap) that holds a connection between the id and the pointer to the actual structure of the entity. But the structure is going to be defined in the game code DLL but allocated through the platform Memory object still.
The rest of the system is just functions to iterate over the entities or manipulate them (like get the components or stuff like that).
Of course if the struct of the entity changes, hot reloading won't help as all the pre-existing entities would be invalid. But that would happen even if all the entity stuff lived in the game code DLL.


But without knowing things about the entity you can't do much to the entity anyway.

And crossing the platform layer - game dll boundary is a hard optimization boundary for the compiler. It cannot know what you will be doing on the other side of the dynamically loaded dll so it has to assume the worst.
tanis


ratchetfreak

The platform layer is meant to be a thin shim between the kernel and the game. The reason for them to be separate binaries is to assist in live code editing. There is no real reason to pull the entity code out of the game dll.

If you want to reuse the code in future projects then you only need to make sure the code to be reused is grouped in a logical set of files.


While I can agree to some extent about the reuse (even though I'd rather have common code in a library instead of copy & pasting it around), I am more concerned about the time it takes to recompile a project that isn't just a couple of files. Once the game code base grows, recompiling on the fly is going to take more and more time until it's like recompiling everything from scratch and it sort of defeats one part of the purpose of hot reloading which si making the iteration times quick, wouldn't it?


HMH only took a second to compile (if that) even at the very end. That was a full from scratch compile. And the entity system really isn't that large to begin with.
So, let's say that I keep all the entity related code, along with all the other systems together in the game code DLL. If you're right then compile time isn't going to be an issue, so let's rule that out.

Let's go back to structs instead. What happens if the struct of an entity changes? Those that have been created before the change would need to be invalidated and/or the whole executable should reload and start from scratch, or at the very least call some initialization function to recreate the current level or whatever the main environment of the game is.
Would there be any better way to manage this kind of changes?
ratchetfreak
HMH only took a second to compile (if that) even at the very end. That was a full from scratch compile. And the entity system really isn't that large to begin with.

But HMH has barely any game-code to be honest.
I'd posit that compile times will become a problem soon enough (meaning more than 1-2 secs per iteration).

And there really isn't any pretty solution for this. Splitting hotswap-able code into multiple re-compilable modules becomes really hairy and complicated pretty fast (dependency management).

This is why I gravitate towards TCC, as with it I can recompile/hotswap everything at >30FPS.
And the compile times are increasing very, very slowly.

The same codebase hotswapping with MSVC (the C compiler) takes 600ms. And the compile times rise
on the order of magnitude faster. This is the build to fire up for debugging though.

tanis
So, let's say that I keep all the entity related code, along with all the other systems together in the game code DLL. If you're right then compile time isn't going to be an issue, so let's rule that out.

Let's go back to structs instead. What happens if the struct of an entity changes? Those that have been created before the change would need to be invalidated and/or the whole executable should reload and start from scratch, or at the very least call some initialization function to recreate the current level or whatever the main environment of the game is.
Would there be any better way to manage this kind of changes?

To hotswap changes to entity struct you need:
1. Metadata/reflection - that is to parse C/C++ (or use some macro/template markup thing)
2. Entity structs have to be in hot-swapable portion

And then you can either serialize(old) into deserialize(new) entities from disk or memory. The serialization has to include metadata headers. Or generate code which maps the differences between entity metadata in new DLL vs old DLL.

Honestly this is a huge pain in the ass to do in C/C++. Totally worth it though.

This is fairly easy to do in Dlang and modern pascal dialects (both have fairly fast compilers)
This is easy to do in C# (and alike), but it's hard to make the serialization/deserialization/state-mapping fast (because it's almost impossible to memcpy most things in C#, and working with value types has been cumbersome up to C#7).

It would be really easy to do in JAI as it has fast compiler + metadata + compile time execution. I wouldn't be surprised if John had some sort of system in the works for his games which hotswaps everything (including datastructs) in way less than a second.

Hell, if he gets rid of the slow MS linker and puts on fast codegen I'm sure JAI could also do *interactive framerates* hotswapping. It would be really cool.

pragmatic_hero

This is why I gravitate towards TCC, as with it I can recompile/hotswap everything at >30FPS.
And the compile times are increasing very, very slowly.


TCC as in Tiny C Compiler?

pragmatic_hero

This is fairly easy to do in Dlang and modern pascal dialects (both have fairly fast compilers)


I know pretty much nothing about Dlang as I've never used it, but it's interesting.

I've been using Rust but serialization/deserialization would still be cumbersome. And there's no metadata attached anywhere by default AFAIK so you'd have to manage that as well just like with C/C++.


pragmatic_hero

It would be really easy to do in JAI as it has fast compiler + metadata + compile time execution. I wouldn't be surprised if John had some sort of system in the works for his games which hotswaps everything (including datastructs) in way less than a second.

Hell, if he gets rid of the slow MS linker and puts on fast codegen I'm sure JAI could also do *interactive framerates* hotswapping. It would be really cool.


I'm looking forward to JAI as well, even though I guess it will take quite a long time till it's ready to be distributed out in the wild with a decent cross-platform toolchain.