Yep! Sorry guys, ended up getting engaged at the beginning of the first part of last week, so my afternoons for the week got sucked up trying to get the implications of that sorted out.
All good now, so back down to business(and by business, we mean gamedev!)
So here we go. I'm going to go over the bits from T2D(and tangentally, T3D) that would make sense to peel out and integrate into or replicate into T3D's current structure.
Lets start with T2D, as that's where the bulk of the good ideas stem out of:
Separation of console functions into *_ScriptBinding.h files
This one is rather straightforward. Rather than having the various console methods for, say, the Player(or going forward, components/entities) tossed into the main cpp file at the bottom. ...usually at the bottom. They can be placed into a separated file so they're easy to find(for example, you can find ALL the mesh component's console methods by just opening the meshComponent_ScriptBinding.h file as an example) but also cleaner. It keeps the files easier to organize consistently as well, without needing to worry about console methods being in the middle of the code because they were added to the bottom and then a function was added after and began a terrible cycle, etc.
Tweaks to the file structure
T3D's file structure arrangement is largely actually pretty good, but there's a few spots that definitely got kinda weird. For example, SimObject currently is in the console directory, which generally makes sense as it's a core class that all console-integrated objects will derive from. But then we have a sim folder, which has a bunch of various sorta-sim-related stuff such as the action map for keybinds, netObject, netEvents, etc.
Shuffling around some of these files and directories to be better groupd and arranged should further help the code structure clarity and make it easier to find any given file or class you're looking for.
Scene Object(not to be confused with SceneObject) and a better scene structure
This would be the first big one, I think.
In T3D, the way a scene is arranged is that you have your MissionGroup, and MissionCleanup simgroups.
MissionGroup is basically our 'permanent' objects - objects loaded out of the level file
MissionCleanup is any 'dynamic' objects - objects spawned over the course of normal gameplay that we want cleaned up when the level ends
These are managed in an indirect way due to how object loading in scripts is done. When editing a level, new objects are always spawned into MissionGroup via the editor, and during gameplay MissionCleanup is made the default simgroup to spawns stuff into. When a SceneObject is made, it's automagically added into our SceneGraphs - either Client or Server depending on which end the object is spawning.
This lets you easily poll through the SceneGraph and find any object that exists as part of the 'scene'. There's a few issues that have developed over time with this approach, however.
- Management OF said scene is messy and spaghetti-tastic in some spots
- Using a octree system to manage EVERYTHING in the scene isn't necessarily the most efficient, especially if you may or may not be planning to cull certain objects. It can be extra overhead not required to be spent spacially managing objects like that
- How stuff like culling, zones and other scene-aware/managing objects integrate and behave with the SceneGraph is also messy, and trying to track through it gets disorienting quickly.
- MissionGroup and MissionCleanup aren't *technically* required to be named as such, but there are parts that do expect it(while most of it doesn't) so it's a rule, but also not and that can lead to losing track of things when trying to spawn objects.
- The SceneGraph, by virtue of helping manage culling/zones is tangled up in the rendering code as well in a clunky way.
T2D, takes an alternate approach by having the scene be handled in a more specific, literal way. A level has a Scene object created, and parent to any permanent object by virtue of being the first object in the level file, as opposed to the T3D way of a regular Simgroup.
This lets us immediately assume that any object initially childed to our Scene is a permanent object and we can track them internally as such. From there any new objects added(while not editing a level) can be understood to be dynamic. We no longer need multiple separate groups that kinda-sorta follow a naming convention, we can know pretty definitively what's in our scene and how to access that information.
Further, because the Scene is a specific object, we can do a lot of very useful, flexible things operating under this presumption.
- We can better consolidate all our scene management code into a main Scene object class, rather than seeded around in a bunch of different places and files in the engine structure.
- We can do specialized Scene objects. For example, the regular Scene could behave very similarly to how it currently does, but we could then derive a new class from it and have a LevelStreamingScene class, which has logic to deal with streaming levels built right into it for open-world style games. Instead of needing to d a bunch of hoop jumping, supporting systemic code and other things to enable this, you just have that specialized Scene class and let it do the work by virtue of just using it.
- It enables sub-scenes. If a Scene can be expected to understand it's permanent and dynamic objects innately, we can do cool stuff like sub-scenes loaded in overtop the current scene. So for example, you could do your main level file with all the terrain, objects, etc. And then 2 sub-scene level files: one for daytime and one for night.
When we load the main level, we can also then pick the day or night subscene level and load it as well afterwards which would establish lighting, skies, etc appropriately as opposed to needing to duplicate an entire level file just for setting tweaks like that.
- The related scene-rendering code can be a lot simpler by just letting the rendering code just poll the Scene object(s) and get back the things that can render given the frustum and camera positions. The main render path code doesn't need to fret on visibility or culling because the Scene should already understand that so it lets us keep things more structured and streamlined.
Now, from some of the work Andrewmac did on T6, we can glean some useful bits from there as well, such as:
Full DLL support
T6 has a pretty good frame of reference for how to expose the classes and functions for DLLs. This would let us move plugins and addons and stuff like Tools-related code into DLLs that can be better self contained, meaning they're easier to drop in and go, and also lets us keep the main codebase cleaner.
Plugins via the Asset system
Another bit that was really smart was plugins managed via the asset system. Part of the problem with using DLLs is the OS needs to know where they are to load them. It's usually not an issue if you just drop them into the exe's directory, but if you wanted to have them cleanly contained in modules for easier dropin/out functionality, then it needs to know where they are. Fortunately, by virtue of the module/asset system, we can have a plugin asset which has that DLL path and supporting code for the loading/unloading of the DLLs. This would let you drop in a module, and then when the engine loads it, it loads the DLL alongside, enabling any expanded engine functionality with it. An example of this would be all the tools related stuff being in a tools.dll file in the tools directory. If you don't want the tools released with the game, you can just remove the tools folder, and you don't even need to waste the additional disk space on the code for tools that you don't use.
Not directly related to the above, but there's a good number of utility classes and functions sprinkled allll around the engine that are super useful, but far too easily lost. We rediscover useful bits like that all the time. I think we need to take all those and better consolidate them so we know where they are and can actually make proper use of them. Otherwise they're just wasted bytes on the disk and extra seconds of compile time for no reason.
So there we have it, the big bullet points from my research on this so far. The best part of course, is none of this requires a massive burndown and rebuild, but can instead be done in small, localized burndowns. You know, instead of a forest fire, more like insurance frau-er. So yeah! Lets open this up and get a discussion going on it.
For my part, I feel the Scene object is the best place to start. It'll let us simplify a good bit of the loading code in the scripts, as well as streamline a good chunk of code in the engine, including bits with the main render pipeline code - which makes it easier for the changes to come with that as well.