Mildly delayed workblog is a go!
So, as you all know, we kicked off a pre-alpha tester build of 4.0, and a ton of you guys have been testing and giving excellent feedback. Not only has this lead to the pointing out of bugs, as was expected, but also general design/implementation weaknesses/faults that hadn't really come up until you guys started actually laying into it.
So July was a bit of a funky month so I didn't get as much done as normal, but there was some progress made and August should go much, much faster progress wise. So below lets get into what all was worked on, and then what all is left to do!
Preview Build July work
So, the short version is, that since the last workblog post, we've had 28 commits fixing quite a bunch of stuff. Various PBR issues like probe indicies not updating when probes are deleted, re-org'ing the cubemap loading code on probes for consistency, and fixing up and making the forward pass version of it all have almost complete parity. Mainly for translucent materials, but we'll be able to support full PBR in forward rendering going forward too, which is always handy.
Outside of that, I've been keeping a list of all the stuff everyone's been noting problem-wise and been checking it off as it's been cropping up. I'll get the list posted over into the dedicated preview build thread for reference later, but it's definitely been helpful in pegging down the problem spots.
I've been trying to finish out the themeing work in the editor, and while by and large most of it is converted over now:
There's still some bits to fix up, a few improvements to be made from feedback, and get the verve editor updated to hook into the theme settings as well.
Still, big progress on that end.
I also fixed up a lot of asset path initialization, so they use 'loose files' now, so assets only need the name of the file in the same dir as the asset def, and it figures out all the pathing automagically. This makes moving assets around much, much easier.
From there, we started hammering on the module/asset stuffs more in earnest. I started with shifting the importer config settings stuff to use the already existing Settings class. This is nearly done, and will make it much more consistent and much less code duplication, so that'll be much nicer to work with.
I also shifted new code asset creation to utilize template files, instead of generating the text for new script files via code in the asset browser scripts. So it's much more standardized and streamlined.
We also realized with Lukas' c# stuff that we could have an editor setting that would pick between TS and C# template script files, so that'd make using either mode much more consistent and straightforward.
Client-Server Module Madness
Most recently, me and Az realized that while the existing module loading code worked, it was fairly cludgy, especially with the networking considerations. Having clear, comprehensible separation between client loading code and server loading code wasn't really a thing, so it was easy to mush it all together and have it break.
So, I implemented a system for separation of how modules load in each case:
We now have split calls that happen when:
The server is initialized
The client is initialized
The server is created or destroyed as part of the game-server starting up/shutting down
The client is created or destroyed as part of a client connecting or disconnecting from a server
This allows us to exec scripts just during setup, but stuff that may need to be ensured up to date, such as datablocks, can be loaded only when the game actually starts.
It worked like a treat, and I had no problems getting a local multiplayer game working:
So, just have to do cleanup and make the other modules properly utilize this approach.
Tying off of this is the new code for handling Game Modes.
In the full template, it handled gamemodes via some awful, cthulhu-esque mess of overriding packages, namespace overrides and inheritance voodoo and the like to create an indirection/rerouting nightmare so you could end up in the right namespace for running of gamemode functions.
Since that's objectively awful at almost every level, I wanted to do a much more clear approach, which is what I hammered out this weekend.
The new way is much more clean, less bloat, more direct, but also much, much, much more flexible, because it allows you to utilize Scenes and subscenes to invoke gamemodes in a seamless way, and gamemodes can exist via modules in a simple, drop-in sort of way.
Game Modes and You
So how does this new setup work?
Lets start with how gamemodes are actually run. We have, effectively, 5 functions of interest
- onMissionStart - This is called when the server finishes loading the level, and activates the Gamemode(s)
- onMissionEnd - This is called when the server concludes the game, either due to gamemode logic, or it's shut down
- onMissionReset - This is called when the level is told to reload, it effectively cleans up then kicks off onMissionStart again
- onClientEnterGame - This is called when a client enters the server's game
- onClientLeaveGame - This is called when a client leaves the server's game
Pretty self explanatory, really. In the gamemode code, these are used to set up gameplay rules like kill counts, game timers, player spawns and loadouts, and basically everything you'd actually use to implement gameplay beyond 'clients have connected to the server, which has loaded a level'
As said, before now it was a gigantic mush of hard to track code, so the new approach is much simpler.
When the server finishes loading a level, the level naturally contains a Scene and potentially SubScenes. I added a new field to Scene: GameModeName.
If this is filled in, it'll do a eval check and try and invoke the onMissionStart call for the gamemodes for any of the scenes that have it defined.
This is useful, because it lets you, say, have a common base level Scene, but then have subScene level assets that you can load for each given gamemode.
the CTF subscene can have the flag locations and modified spawns, versus the deathmatch subscene won't have those flags, and may have more weapons and randomized spawn locations.
So if we load our Scenes in, we roll through and find any scenes with a gamemodename defined and call the above functions to kick off said gamemode behavior.
If no scenes have any gamemodenames defined, then we defer to the Project Settings, which has a DefaultGameMode field. If that is also empty, then and only then will it just spawn the clients in as spectator cameras, with no gamemode logic in effect.
This is much cleaner and simpler, but also much more flexible and powerful. It would even let you combine gamemodes if you wanted, which could get pretty wild!
I already successfully tested this in the FPSGameplay module, where one level(as in the above screenshot) spawn in players with full kits for basic deathmatch gameplay, and other levels have nothing defined, so you just spawn as spectators.
The plan is to have FPSGameplay offer a few different gamemodes so you have a solid example of how to lean on this, but it's all looking incredibly more streamlined and easier to get than the old way, so I'd call that a win already!
So what's next?
Outside the aforementioned bugfixes and corrections people have spotted. I still have to finish the overhaul of the BaseGameUI, finish breaking down the FPSGameplay into it's properly separated parts, finish the Das Boot test level so we have a proper stress test environment again, and flesh out the component/game objects stuff.
I'd hoped to get most of this done in July, but as said, circumstances arose to make that untennable. But progress, as you can see, hasn't exactly been bad, either so I've very high hopes for getting most everything wrangled in August.
I'll have a build up soon with the FPSGameplay module effective in it so multiplayer testing can be leaned on while I try and wrap on the UI overhaul so it's overall an easier build to work with, but I believe that's the bulk of the update for the moment(as usual, I feel like I've forgotten some bits, so if I remember anything else, I'll definitely update
Until next time!