-
Torque3D
The pinnacle raw Torque power, Torque3D has been used for everything from driving simulators to MMOs!
Check Out Torque3DTorque2D
All the power of Torque with less of those pesky dimensions to tie you down!
Check Out Torque2DForums
Looking for answers, wanna see some cool projects or talk about new / upcoming features?
Read the Forums -
Work Blog Updates
-
By JeffR in Torque 3DGreetings and salutations!
It’s been a hot minute and a half since the last workblerg, admittedly in part because it’s a lot easier to just keep working on stuff rather than stopping to type a bunch about working on stuff, but ultimately a lot of people get a high-level sense of progress on the engine from these so really, I should keep up on them more.
Not everyone is constantly hoovering up all the information in the various discord channels, after all.
So, given that, there’s a lot to go over to get everyone caught up, so we may as well get cracking!
What’s Been Done So Far?
So, all told, there’s been 289 pull requests merged in since the last work blog. Which is a lot, to say the least. So why not go over some of the highlights!
General Fixes and Improvements
We fixed up a LOT of miscellaneous errors, warnings and other related issues that would cause message spam. Similarly we added various sanity checks in a whole bunch of places to catch overruns or out of bound problems which are obviously just generally a good thing.
Less critical, but similarly important to the general application stability we did a pass in a bunch of files to ensure classes initialize their variables and clean up unused values, which keeps things behaving reliably, especially when you’re hopping between Debug or Release builds.
Various mechanical bugs that got fixed pertained to:
castRay behavior various bits of playing audio Vehicle physics tweaks and corrections Sound effect spam from impacts Tweaks and fixes for player animations and callbacks relating to them playing Datachunker and FrameAllocator refactor for better memory management Sanity checks on prefabs getting child objects that have somehow ended up as null Vehicle steering thread fixes so mounted objects work as expected on network File write improvements Resolved various crashes, in particular ones that happen on exit Fixed up GBitmap getColor behavior and cleanups to the color pickers Added setSkinName to TSStatic for consistency of utility methods Additionally, a few passes were done to comply up the code to some modern conventions, such as rather than simply marking everything as virtual, and letting the compiler figure things out - which didn’t always work consistently between compilers and platforms - we now use virtual on the topmost declaration and the ‘override’ keyword on all derivatives, ensuring compilers understand the design intent better.
Another more general shift which is a ‘partway’ step for follow up work is templatization of Matrix math classes. While it doesn’t replace the existing Matrix math classes, the idea is that in the future we have templates defined for the various Matrix math classes so that we can utilize common code rather than duplicating and redefining everything for every permutation, such as 3x3, 3x4, 4x3 and 4x4.
Having more common code via templates means less duplication, which means fewer places code could misalign in one spot but not the other.
The idea would eventually follow a similar setup for most of our ‘multiple’ math types such as Point*F and the like.
All told, we had 72 different PRs merged for various fixes, improvements and additions. Which is a pretty sizable chunk of the whole.
GUI
On the gui side of things, it wasn’t as monstrous as the general fixes, but we certainly had a good number of fixes and improvements there as well.
Some key highlights:
Fixed a buffer overflow in GuiTreeViewCrtl Updated editor theming to utilize the stuff Nils provided for a more sleek dark theme Updated BaseUI in a myriad of ways to facilitate gamemodes selection and filtering(more on that further down) as well as improved handling of menu navigation with both mouse and keyboard as well as gamepad Added the ability to enable search filtering in dropdown controls Fixed various callback behaviors from some gui controls Added a method to forcefully constrain the mouse to a canvas(Thanks Steve!) Added the ability for MLTextCtrl to write out characters over type for a typewriter effect Fixed guiObjectView control issues Fixed up the state management for GuiBitmapButton This is less huge than the general fixes, but still some good changes in here. Probably the biggest specific changes were the updates to the Editor theme:
Old:
New:
As well as updates to the BaseUI
Old:
New:
In addition to the main menu stuff in BaseUI, the pause menu was updated to be the ‘Game Menu’ to allow easier slot-in of game-specific menus easily, even with just dropping in a module.
For example, Catographer utilizes inventory and map menus for gameplay stuff, and you can see how dropping in those modules just registers the menus to the GameMenu below:
The default Game Menu setup at the pause screen:
And as you can see with Catographer like mentioned above, we’ve dropped in new pages to the menu, like the map, inventory or objectives menus. Which show in the top bar and can easily be swapped between:
Much easier to expand the menu in a consistent, easy-to-use way for both the dev and the player, leading to a better experience overall. All you need is the hook against the callback which is invoked when the GameMenu is opened, and it looks like this:
Editor
The editor updates were the main focus for 4.1 and while we haven’t hit everything we were hoping to, the big focus was some important foundational updates to make working with and expanding the editor a LOT easier than it currently is.
Some of the highlight changes are:
Added typehints in the SceneTree, as well as what primary asset is used on certain classes, such as showing the ShapeAsset used by a TSStatic below. All of which is data that the search filter on the tree can find Added multi dimensional entries for certain math types in the inspector Fixed up the forest element inspector Expanded the editor number range to 7 digits Formatting fixes for the several GUIs and editor windows Added an ‘Add’ menubar entry that parses object class categories to automatically register spawnable classes to both world and gui editors Added a class prototyping UI to easily block out derivatives and callbacks Various fixes for IBL and probes Adds a callback to objects so if the editor is saving, objects can do special logic in response. Such as resetting PathShapes back to start so they’re always in the right spot in the saved level Updates Material and ParticleData fields to organize them sanely to facilitate shifting off of custom adhoc editor GUIs for those to using normal inspectors(more on that below) Fixed presentation of bitmask/enum fields in the inspector Ensures material animation flags are cleared when editing so they don’t ‘stick’ Fixes for arrays of imageAsset types so things correctly update in classes like guiBitmapCtrl when editing Fixed guiShapeEdPreview not displaying IBL Fixed animation scrubber in ShapeEd Fixed some value irregularities with positions when editing Fixed saving of Asset Browser position so it stays where you left it Added search bar to Datablock Editor inspector Properly preserves gridsnap settings between runs Makes snap buttons visually synced to their value Integrated SubScenes and SceneGroups into the world editor interface. For some of the more ‘meaty’ changes, specifically to facilitate that whole ‘easier to expand and work with the editor’ we’ve got stuff like:
Programmatic action pallets
You may not have ever thought about these:
But in the original editor stuff they were explicit gui controls that were just added onto the gui stack of the editor suite. That meant that while it worked perfectly, expanding them was kind of a pain. It wasn’t easy to just be like “Hey, in this specific context, I want to be able to show/hide more buttons/actions on the pallet!”
So I added a programmatic version of it. You shouldn’t even normally notice a difference, but it means that we can now inject in additional buttons in certain contexsts when needed.
What might those contexts be, you might ask?
A fine question!
Here’s one example with SubScenes or SceneGroups(we’ll get to what the deal with those is further down, but think of them as ‘like prefabs, but rather than a dedicated file, they’re just child objects in a SimGroup you can control the position of’.
So, because we may want to move the group itself and not the child objects in some specific cases, we wanted mode buttons to let you pop between normal behavior(moving the SceneGroup naturally moves all the child objects) and moving JUST the SceneGroup(leaving the child objects where they are, causing an offset)
You can see it in action here:
Those buttons for the ‘Move/Rotate SubScene + children’ only show up when selecting a valid object type, otherwise they disappear! And before, that would’ve been kind of a pain to do.
Improvements To ‘In Place’ Workflow
This is a somewhat perceptibly minor change, but can improve workflows a fair bit. Namely, it Adds some additional elements to the Datablock fields on Gamebase derived objects:
The three dots button jumps to the datablock in the DB editor directly, which isn’t a big change. What’s more important is the little plus button, which if clicked, jumps you straight to creating a new datablock with the inheritance already filled in.
So if we take our DefaultPlayerData there, hit the button(and select what Module it goes to) we see the Create New Datablock window pop up like so:
As you can see, inheritance is already filled in to come from the DefaultPlayerData, so you can just make it and create it easily, That allows you to jam out derivatives right when you’re working instead of needing to pop over to the DB editor, track to the class, create new, select the parent DB, etc to create a derivative.
You still CAN do all that, of course, but the idea is to automate those steps in the context of the + button on the DB field.
Similarly, to facilitate the easy workflows when working with datablocks, especially because that list can get LONG, you can now search/filter the DB field dropdown too!
When typing ‘dem’ it filters to the DB entry(ies) that have those letters in it:
Library
We updated various libraries and library-associated things here. This isn’t anything overly special, but it is important to keep track of!
Here’s what was updated:
Updated SDL to 2.28.4 Added STB for image loading Updated Assimp Fixed up logic so when converting from assimp data structures to Torque, the matrices are correct. Fixed various issues relating to using Theora Changed to using libSndFile Updated openAL Fixed dynamic library builds on windows Cleared out a bunch of temp files for Bullet that weren’t needed Added support for modules to define the inclusion of libraries, so one can simply drop in a module into the data/ directory and regen CMake and it will detect and process not only source files, but cmake configs needed to build libraries such as libCurl Platform/System
Likewise to library updates, this is mostly maintenance and upkeep stuff, though there were some important tweaks to various parts of how the CMake configs are organized/ran
Cleaned up fileModifiedTime stuff Fixes up the libCurl module cmake config Fixed issue with sdlCPUInfo with FreeBSD Making startTime static to avoid collisions in the core/console stuff Clean up display of optional core modules in the cmake config Fixed the cmake config to properly add in the wind deformation hlsl and glsl shader feature files Brought engine requirement down to C++17 standards from 20 Multiple various apple fixes to make it build more properly and pack files in a more ‘apple friendly way’ Fix so you can disable TORQUE_TOOLS flag and still build Fixed zip archive reading Adds a TORQUE_TOOLS_EXT flag for specialty stuff that you only wanna turn on very deliberately beyond just tools support, such as enabling the ability for the engine to run commandline calls. Various cmake format/config changes in the interest of trying to cut down how much duplication and redundant defines/settings there are throughout various places Rendering
Altogether there weren’t any sort of ‘gigantic’ changes for rendering on this one, since it wasn’t really the target goal. But that doesn’t mean there weren’t quite a number of fixes or improvements of render-related matters!
Highlights:
Reverse depth & 32F buffer format OpenGL fixes for HDR Fix vert color swizzle Optimizing Bins Various lighting corrections Adds ability for IBL to scale with ambient lighting so it works with Time of Day D3DCompiler_47 dll to ensure deployed projects have it packed and ready when publishing Make cubic reflectors respect detailAdjust Fixed probe capturing behavior Fizzle fix for GL Fix Sun corona Updates to GFX Shader handling Implemented IES light profiles Fix dynamic cubemaps on objects Removes glowbin as a render pass Added normal map handling to imposters with assets Fixed cubemap baking DX11 Add skylight IBL display to Material Preview display Tweaked attenuation for probes Roughness corrections with mip ramp-up Overall there weren't big shakeups, but various fixes and optimizations and the like. Probably the biggest specific visual change was the IES profiles which allow lights to load up mathmatic representations of certain lights in real life to make them have more real penumbra patterning like so:
Scripting
For scripting stuff, we had some various fixes and improvements, but a couple of big changes as well.
Highlights:
Console Refactor Add localization utility methods Fixed type bugs for TS Fixed an error in the DB substitution logic Fixed evaluateF argument handling Fix foreach breaking if it iterates over non-existent objects Removed CInterface script hooks because Console Refactor superseded it Console interop improvements Various script stability fixes Various updates and improvements to the TS compiler, parser and lexer Fixed error printing Fix callOnChildren varargs All in all the biggest thing is the Console Refactor where the idea was doing a lot of standardization and making it generally easier to interop and maintain. Not really anything that’d impact the end user, but it has some convenient bits for up-keep.
Assets
For assets it’s broadly just a bunch of fixes for functionality, so we can just pick out a few of the highlights:
SFX Playlist asset working Fixes saving of asset definitions that have sub-objects properly Adjusts the logic for spawned simObjects from tamil files so array’d fields works properly Updates to asset load workflow generateCachedPreviewImage fixed Ensures that when an asset is edited, it’ll properly refresh imageAssets can be blank Improvements to triggering of shape loading with TSStatics Simplify sound slots Fix glb asset importer file detection Correct malformed import config passthrough Updates to Asset Importer Fixed utilization of material fields so they can work with NamedTexTargets Added a reloadModuleFiles(%moduleGroup) command to allow forcing of reloads when needed Testing/Debugging
Not much specific here, just a bunch of various fixes to improve the CICD/Testing suite along with a few debug reporting cleanups.
Gamemodes, Subscenes And Spawning
This is one of the bigger updates to things, so we’ll go more in-depth with it here, as was mentioned in a couple of spots above.
So!
Gamemodes
Gamemodes were always sort of a loose concept as far as T3D was concerned. Obviously there needed to be a grand arbiter of gameplay logic such as rules for ‘if players kill X number of enemies they win’, but beyond the necessary callbacks to have them kick off when a player connects to a server, everything else was pretty loosey-goosey in terms of integration.
Want to know what gamemodes you have available? Want to be able to filter selectable maps by gamemodes? Want to use a ‘Racing’ game mode, but rather than the default assumption of racing cars, you want it to be a footrace so you spawn players?
All that sort of thing would require a good bit of extra developer integration and it wasn’t easy for modules to just interop with it.
This is especially a problem when the goal with modules is being able to drop them in and largely be integrated automatically so you can focus on the glue bits that brings them together into a coherent gameplay design.
And, above all of that, frankly people weren’t positive how you were supposed to set/associate a Gamemode to a level either. As well as the fact that it was just a text field on the Scene object meant that if you typo’d the gamemode name nothing worked and that could be annoying to chase down.
So what do you do?
Well you set some standards!
In specific, Gamemode is now an actual, concrete class rather than just a ScriptObject with a namespace slapped onto it. On it likewise we have utility methods to query what gamemodes exist and some other neat doodads.
Another important bit is Gamemodes can be marked as being activated or not, as well as if they automatically activate.
This is prudent because if you have a game with only one gamemode, then it’s silly to need to faff around with toggling it on in the menus or whatnot.
So, where that gets you is you can have 1 or many gamemodes, and then the system knows what gamemodes it has, and can run queries on them.
The old callGamemodeFunction, which originally just iterated on whatever was defined in the Scene object now works against the standardized ‘get a list of our gamemodes’ method, and calls the method if it’s available, and the gamemode is activated.
This means that any level of mix-and-match for gamemodes Just Works with interoping to the level loading sequence, or if you do call signalling for gameplay glue code logic.
Want a Racing Capture The Flag Deathmatch game? Just activate Racing, CTF and Deathmatch Gamemodes and spawn in and bask in the glorious chaos you’ve created.
But you may be wondering ‘Surely maps have to be compatible with certain gamemodes right? How do you set that?’ and that is a fantastic observation.
The reality is that you can’t assume your insane RCTFD gameplay smorgasbord you just invented above would work on every map. If a map doesn’t support capture the flag in any capacity, you wouldn’t want that map to be chooseable on the level select screen after all!
The good news is, it’s pretty danged easy to select gamemodes for Scenes now. If you have a Gamemode made and the script executes, then when you edit the Scene object in your mis file, you can look in the inspector and see this nifty shindig:
And selecting what Gamemodes the level is compatible with is as easy as picking them there!
With updates to the BaseUI menus, we scan the levels’ listed Gamemodes picked via that field, and if you pick a Gamemode in it like so:
Then when you advance to the Levels list it filters down appropriately:
The logic of the menu is fairly smart too, in that if the Scene never defined a gamemode, we figure it’s a sort of ‘assumed default’ state and let you at least *try* to run any gamemode with it. Likewise, if you only have one Gamemode, we assume that’s THE gamemode, and activate it automatically.
What that means is if you’re making a pretty simple game, like maybe it’s an exploration game with one map and just the one Gamemode, then you don’t have to do any special sauce to set it up, it just figures “Only one of these, and one of these? That’s probably the winning combo there”.
Keeps things easy to snap in and iterate on.
Once you have the gamemode picked and running, it largely behaves the same. The client/server and level loading logic has various callGamemodeFunction invokes that, as mentioned above, call the function for any active Gamemodes, and just… does what the gamemode logic defines, largely same as before.
Just more standardized and structured.
Pretty neat huh?
But what if you want like, one main map, but then do something crazy like having a Nighttime variant, that not only changes a bunch of small bits in the map(Streetlights? On! Sun? Gone!). Or if you wanted to have a single base map, but be able to slap in necessary bits for certain game modes, like changing the ‘bits’ in the map depending on if you’re doing CTF or Racing?
Or heck, what if you just look at the map and go “Good lord there’s so much junk here, do I really need to load it ALL right off the bat?”
Well, I have fantastic news because that brings us to…
SubScenes
So what’s a Subscene, you may ask?
Well it’s like a regular Scene we’ve had for levels for a while, but… sub-ier.
Thank you, thank you, don’t forget to turn out the lights when you leave.
Alright, jokes aside, it really is a ‘Sub-ier Scene’. Where a Scene is basically the grand arbiter of the content of a level and has some neat utility in tracking/managing the objects under it, being able to pick gamemodes it works for, etc, etc.
Subscenes are similar, but they are intended to exist WITHIN a scene. So if you have a big ol’ chonker map with roads and trees and terrain and all that jazz as your main scene.
You could have a SubScene that only has certain objects to load from its own subMis file when you need it. Think of it like how Prefabs are placed in the map, and it loads the contents from a file, and you can move it to where you need the bits to be.
The main difference is SubScenes are intended to act more as a container of objects, rather than AN object made of bits.
So how’s that work?
Well, first thing is we need some junk to make into a SubScene!
So you have some objects in your map and for whatever your vision you have, you need it to be ripped callously out of existence and shoved into a pocket reality, er, subMis file. Like lets just take these little ConvexShapes minding their own business.
I’ve decided I need them to be in a SubScene.
So, per the video below, you can see how I can make a new SubScene, then add the objects to it.
Once we have it and have a SubScene in the map, we just add objects to it like a SimGroup, and then save the Subscene. This’ll save the child objects out to that subMis file, rather than the main level mis file.
From there, you’ve got options. You can either programmatically force a subscene to load in script by just invoking the load() method(or unload, for the opposite) or have it load when a client enters into the bounds of the subscene - which allows for a simplified form of level streaming.
Per the video above, you can even see how when I don’t have it selected, and the camera isn’t within the bounds it’ll unload after a few seconds(a configurable variable), and when the client re-enters the bounds we load again!
You can even establish conditions on if the SubScene can load, making it so players need to complete an objective before the next part of the map is loaded in or similar.
You can even set Gamemodes on subscenes like you can for regular Scenes, which lets you build out logic to filter subscenes easily for your game’s logic.
Ultimately, in its current form it’s a pretty baseline implementation, but with a lot of options for how to utilize it to control stuff being layered on or loaded in.
As it gets more beatups and used more, we’ll expand and refine the functionality of it to make it even more useable and more powerful.
Spawning
The last big chunk of work that was done was for the spawning logic. Originally the gamemode was the ultimate controller of when and what spawned and why.
It worked, of course, but it was pretty restrictive, and absolutely got in the way of the idea of mix-and-matching gamemodes, or making it easy to drop in modules and just have it work easily.
If you wanted to do the previously mentioned ‘Racing game but you spawn as a player instead’ idea? You were dropping in the racing kit module and then getting down and dirty in the script to change it yourself to spawn a player.
That was ‘fine’, but also quite restricting. And beyond that, poor for rapid prototyping and iteration times. So where we ended up shifting things is pulling the invokes for spawning back into the client/server loading stack.
We know that when a client connects to a server and loads into a map, they need to spawn as *something*. Even if that something is just a camera.
So? We just do module and gamemode calls to let them have a chance to interject what they think the client should spawn as, where, and with what parameters.
It works via an override system, so last thing to override has final say.
In the end there’s 3 main new methods that get called:
SetSpawnObjectType Sets what the connecting client should spawn as in terms of object type/class. Such as camera, player, vehicle, etc SetSpawnPoint Indicates WHERE they should spawn. OnPostSpawn Final after-spawn effects. Setting up inventory, attachments, changing the team colors, etc These are called as part of the client connect/load stack, as mentioned, with it walking through any modules that have those functions defined, as well as any active gamemodes that also have the functions defined.
The logic of the calls utilizes a signal and counting system, so it ensures all modules and gamemodes that *can* work with those functions have a chance to do their work before continuing.
Normally, it’s a simple ‘run script and be done’, but depending on the gameplay in question, you may need to wait for a maze to generate, or other asynchronous logic to execute you can’t assume a certain amount of time for.
From you, the developer’s perspective, it just slots in and works, but in the back end it gives everything enough time to ‘breath’ to try and keep things running even when stuff may take inconsistent amounts of time to run.
Why do all of this? It’s simple.
It allows things to drop in and Just Work.
If you’re doing a racing game, but want the footrace style, then dropping in a player module instead of a vehicle module, with said player module definition the SetSpawnObjectType to be a player means that the incoming client will ultimately spawn as a player, not a vehicle.
It lets the logic and rules break out much more piecemeal to let stuff interop more cleanly.
To further facilitate this, we added a Priority field to Modules, that allow you to nudge them around for these callbacks’ order without messing with the ACTUAL load order and dependencies structure.
Ultimately, nothing stops you from just defining all the logic and rules in your gamemode and have it be super strict and rigid, but the main point is you no longer *have* to, and we can set up modules to behave in a much, much more ‘Drop In and Go’ manner.
Better flexibility, better prototyping speed.
So, What’s Left?
Good news is, honestly not much.
4.1 certainly has taken longer than desired, but that’s what happens when you’re doing practical beatups and realizing there’s a lot of spots that have rust or dust all over them and need a good pass with a pressure washer and an aggressive polishing pass after.
But even with the unexpected drag-out time, the majority of the desired work for this pass in helping lay foundational stuff and make moving forward easier is locked in, meaning that our remainders would be:
BaseUI fixes
While a lot of good work has been done on the BaseUI to make it clean but flexible, there’s still a number of rough spots. Namely? Bugs.
The options menu is a particular culprit in this because options menus are bloody complex things to work seamlessly.
Volume levels not respecting the settings, keybind mapping and display being flakey with multiple action maps, changing between borderless and windowed mode not automatically shifting to display resolution options and more.
All relatively minor things, but definitely gets in the way of the user experience being seamless. And some of those get in the way of developer time too. If you don’t want your game’s music or sound effects blasting while on a discord call, sure would be useful if the volume sliders worked, right?
Additionally, there’s little oddities of behavior like highlighting and selecting being muddied logic-wise when using mouse and keyboard, some UI elements not updating/refreshing like one would expect, or some scaling/formatting oddness.
Again, relatively minor, but it builds up to be a rough experience, and the Baseline UI needs to be good enough to hit the ground running with, not making you have to stop and slap it around to play nice.
Editor improvements
A lot of the desired work for this has been knocked out, but some stuff remains.
Some things, like customizable layouts were put on hold while more design-time consideration is put into it. I did a fair bit of R&D work into getting it to play nice, as you can see from this video here, and it *almost* works. But in looking at current UX conventions, both Torque’s and other engines’, as well as talking to you guys, “Just Doing What The Other Guys Are Doing” isn’t a good approach here, I don’t think.
Certainly, making sure the editor suite UI works WITH or FOR you while you’re making your game is paramount, but that doesn’t innately translate into being able to dock 11 billion sub-windows either.
I’ve got a few ideas on how to *really* maximize workflow speed with the editors I’ll keep cranking at on the R&D side and come back to how we’ll do customizable layouts and stuff in the next version or two, but for today the editor suite will largely stay ‘Classic Torque’.
That said, it doesn’t mean NO changes are incoming before 4.1 closes out.
The big one is complying most all of the editors’ interfaces to utilizing GuiInspectors where possible. I’m sure you all have seen the Material Editor a lot:
Or the Particle Editor:
And while they work, if you never looked at their guts in the script you may not realize that they’re completely specialty-case GUI controls that do a lot of custom script voodoo to function.
That works fine enough, obviously, but it also means it’s a paaaaaaaaaain to expand, tweak, or update stuff.
And also doesn’t follow the standard conventions of display in other parts of the editor.
So we’re moving them to utilize the normal GuiInspectorCtrls like we use in the vast majority of places. Same functionality, just a more standardized way of displaying, and it’s more automatic(being driven by the class’ fields) rather than a bunch of specialty adhoc stuff.
Easier to maintain, easier to expand, follows the conventions of every other spot in the editor, but it still does the exact same job in the end from a ‘working on my game’ perspective.
Win-win all around.
The work on this is mostly done, with the ParticleEditor conversion needing most of the work yet. MatEd is mostly done but has some residual fixes and tweaks to finish it out, and I’d like to get the Terrain MaterialEd to behave similarly before we lock 4.1 in.
Not too much work, thankfully, but it should help a good bit going forward once it’s in place.
Asset Management Improvements
The work for this is actually mostly done, just been sidetracked on helping polish out other WIPwork to get it locked in.
Pragmatically you shouldn’t *notice* a difference in general behavior when this all goes in, but under the hood it’s a big step up.
Functions are more standardized across asset types, use clearer, less confusing names. Asset Browser has a lot of special-casing trimmed out so things are easier to understand when reading through the code, etc, etc.
Main idea is it moves Asset Editing/Management logic out of the Asset Browser scripts, and into the Asset Type’s scripts, running through the assetType’s namespace, like so:
Each asset type of interest works like that and behaves consistently across the board now with basically no special-casing in the AB itself.
It also has some utility methods for registering asset types, so you can create ‘Asset Types’ that exist entirely in script and have the AB work with them as normal.
Meaning you could create a special type of Asset just for, say, NPCs, and integrate that into the Asset Browser seamlessly for creating new NPC assets, have it display them in the browser, be editable, and all that, but all the logic for it exists in your NPC module, without having to edit the editor/Asset Browser scripts to get it to show up.
Following the theme, this’ll make it easier to maintain the whole asset pipeline, as well as make it easier for modules to Drop In and Go with custom logic and content without you needing to do a lot of screwing around to make it hook in.
Better flexibility, better prototyping speed.
Project Manager
The last thing for this is the Project Manager. Going off feedback people’ve given when using it, it’s in a pretty decent spot as far as usability/clarity goes for being able to easily make and manage projects and modules.
The biggest thing being a problem right now is the reliance on using commandLine calls to git in order to pull stuff from the internet.
Good news is, we think we’ve cracked the big hurdles on libGit integration - which if you don’t know, is what all the visual git clients use - which would mean we can just interface with git directly rather than routing via commandLine to call git commands and hope it executes well.
That lets us report back REAL errors and not telephone game’d commandline error codes, progress bars, checking if there are pending changes to pull down, and more.
With that stuff in place, the overall experience of using the Project Manager should become quite smooth, though naturally we’ll continue to taken and listen to feedback to make it a fantastic one-stop-shop for kicking off or wrangling your Torque game project needs.
Beyond that, there’s only really just hanging small fixes and bugs as far as priority issues go, which we’ll continue to patch as we move.
Once these things here are locked in we’ll do some final test passes to make sure no hideous new bugs slipped the radar, but once they go in there’s no other new features/functionality going in for 4.1.
It’ll just be polishing up, working on documentation and example modules.
Whew
Quite the doozy, huh?
Again, an apology is in order. It’s too easy to slip into keeping your head down and just getting work done(which yields solid dividends, when you look at the above!) and just talking to people in the discord, but the reality is that you sometimes need to write down an obscene number of words and pin it to the bulletin board for everyone else, too.
So I’ll try and get back on top of doing monthly workblergs to facilitate that.
We’re also mulling on the idea of potentially doing a monthly-or-so community voice chat in the discord for some more direct live-fire Q&A stuff that’s a little more consolidated/pointed on the topic than random conversations spread across a dozen channels, but a bit easier to just ‘do’ than a full-bore workblerg like this, too.
If that sounds appealing, be sure to let us know!
And if you wanna help facilitate the ongoing Coolification(no trademark, unfortunately) of things, feel free to hop over to the Patreon and toss some money our way. It goes to paying for hosting costs and other such operational things of the sort.
But, for now, I’m going to let my hands fall off for a little while before I staple ‘em back on and get cracking back on those last TODOs so we can get 4.1 out the door.
And when it is?
4.2 and Components be on ye horizon.
*Dramatic Music Sting*
Later everyone!
-JeffR
-
By JeffR in Torque 3DSo, on today's installment of "random rambles about development things"
But for real, it's a good time to do a new workblog and keep people in the loop for those not in the discord, or those that aren't spending every day in it
So, what's on the ol' discussion stuffs today?
Well, for the big one, the main Feature target for 4.1: Components.
Or, more specifically DOCs. What does DOCs mean? Well...
Directors, Objects, Components
You may have heard us discuss 'Entity-Components or Entity-Component-Systems(EC and ECS, respectively). For a brief refresher in concept, here's a simple breakdown:
Entity-Components as a paradigm can be described simply as having an Entity object, and then Component objects that contain and implement data. As in, if you have a component to render a shape, the component not only holds the info for what shape to render, but also the logic to render the shape. This is how, most other engines do components.
The reason for that is pretty simple. It's robust, and it's easy to work with. It's not the most efficient system, but it's pretty hard to screw up. You slap a component onto an object, set the properties on the component, and then the component does the thing.
When I did the main previous implementation of components, this was also the system I went with. The MAIN problem with this approach is that any given component is kinda...chonky. And you also have a lot of bloat on the Entity object in most cases. And with all the bits that have to cross-communicate to ensure dependencies work(you gotta have collisions for physics to work properly for example) as well as order of events(collisions are calculated then physics) as well as any deeper engine system dependencies. It can spiral quite a lot.
Beyond that, it's also very difficult to thread any of the component's workloads because everything cross-communicates in order to work. You can't easily punt a physics component into a thread if other threads need to talk to the same collision component or entity it uses, etc.
So, advancements to the theory of components implementations lead to ECS: Entity-Component-Systems.
Now, the confusing use of "Systems" aside, the main differentiator to EC is that Components now ONLY contain data. They don't implement any logic whatsoever. Likewise, ALL the burden of functionality is moved off of Entities. In a 'pure' ECS implementation, an Entity is nothing more than an ID for Components and Systems to reference. Instead, Systems implement all functionality logic. If you have a physics component, there's PhysicsSystem that implements the actual logic for it.
This is certainly more complex to implement. In fact, very few engines or games use ECS. Unity's new DOTS approach is based on ECS, and a few games like Overwatch have utilized it. But the innate complexity of the approach and how abstracted the data and implementation means that it's far less common.
So why use it?
Because it is MUCH easier to be cache-coherent and thread things. For the non-coders out there, cache-coherency is the idea of wanting to keep all the memory a given chunk of code in the engine uses all bunched together. Think of it like how if you're studying. Rather than getting a book, reading a paragraph, then walking back to the shelf, putting that book away, and getting a new book and reading the next paragraph, and so on - which would be very, very inefficient - instead you just get all the books you need, and can quickly reference between them.
In practice, memory in the computer works similarly. So if you can cram all the data you need to work into the same blob of memory. Performance is improved SIGNIFICANTLY. But it's not very 'human friendly'. Which is why you get stuff like ECS. All components of a type can be crammed into a dense set of data. So when a System goes to implement logic, you've got all the relevent components in a tight blob of memory, and the whole thing can be processed without having to go "get another book" as it were.
In addition to this, the data being more detached from implementing logic(and better managed in memory) makes it much easier to implement the logic in multiple threads. This allows the machine to crunch a lot of objects in parallel - which is especially good on modern CPUs that have sometimes dozens of threads.
But there's a good number of downsides to this approach as well. It is, as said, not very human friendly. Implementing new components and their associated systems is not how most code is implemented, so it can be difficult to work with. It also requires much more tracking of when things are added, removed, when things should run. Dependencies are still burdened on the components and systems to keep track of for when to implement things, and scripting it is very, very difficult.
All those and a bunch of other smaller inconveniences make it generally a pretty poor paradigm to work with in something as complex as a game engine. There's a LOT of ECS implementations out on the internet. But they're more academic than practical because of the inherent limitations of the approach. Cramming it into a game engine while still making it easy to work with from a scripter, designer or artist's perspective is pretty hard.
And both of these have various limitations in how to deal with it from a networking perspective. It's very difficult to have the server and client safely agree on the data the client has without trafficking a ton of data, which is bad for net performance.
So, between what I learned from implementing an EC style deal in the first pass of components, and a lot of tests and research into ECS. I settled on the fact that, both approaches just kinda aren't ideal.
So I did some work and fashioned up a - as far as I can tell - novel components implementation for Torque3D.
Directors, Objects, Components, natch.
So, what’s the deal then? Well, per the name, there’s 3 main components(heh) to the model, which we’ll cover here:
Directors
So what’s a director? Well, in practice a Director is a simple class that ‘directs’ when and where updates to components happen, hence the name. The idea is that we want to move the burden of when and why updates happen off the objects and components.
At it’s core, a Director is in charge of doing a particular thing, generally updating a specific component or set of components. Like, say, when we want our RenderMesh component to draw. The Director has a specific timing to it(aka, Rendering) that the rest of the engine can invoke to the DirectorManager, which is pretty much just a simple container class.
When we want anything with the Rendering timing to kick off, we tell that DirectorManager to run an update on said timing. And in turn, any Director with that timing is told to do it’s work. Simple enough.
So in our example of the RenderMesh components, the RenderMeshDirector has the Rendering timing, the engine, when it goes to draw objects, can tell the DirectorManager to run the Rendering timing, and our RenderMeshDirector gets told to update. When this happens, the Director loops over valid RenderMesh components and directs them to do their work.
And thus, our RenderMesh components have drawn their meshes.
Now this sounds like a lot of work compared to just looping over the objects or components directly, but there’s a bunch of benefits to this.
For example, as noted with EC and ECS implementations, one of the biggest tangle-up points is dependency management. Normally components have to track what dependencies they have, if they’re fulfilled, and if not then they are not enabled. Any time a new component is added to it’s owner, the component is in charge of validating its dependencies.
This is important, certainly, but it also can lead to a lot of complexity, spiraling dependency chains, and code bulk on the components themselves. So instead, we move that to the director.
Because ultimately, the director is in charge of a set of components, like our RenderMesh components, we can track which ones are valid in the Director. If an Object adds a new RenderMesh component, it naturally associates to our RenderMeshDirector, and it now knows if it’s valid or not. The component itself doesn’t have to care in the slightest.
This keeps the component code leaner and cleaner, so it’s easier to maintain.
It also means we can very much more explicitly control the timing of when things run and sequence in the engine. I used the example of the “Rendering” timing before, but it’s powered by a simple enum. So you have as many entries as you can cram into an enum for when to kick off updates. You can update just physics things, or just rendering things, or specifically objects that have client inputs because they’re controlled.
This gives a much more comprehensible order of operations about when and where stuff is executed in the engine, making it easier to track and debug when stuff kicks off.
Additionally, because the director has an explicit list of components it’s in charge of, and we are specifically working on that list of components at a specific time in the execution of the engine’s loop, it means that we have MUCH more control over the memory in play for the engine.
This ties back to the aforementioned cache coherency. We can keep a list of components, like RenderMesh components, and that list can be much more easily just shoved into memory as a straight shot, minimizing how much the CPU needs to jump around. The Director works on THESE objects, so the CPU can have all the data on hand.
It also means that, between the more tightly bound memory and the express execution timing, we can much more safely handle when things are threadable. Which is a big thing for game engines.
Even major engines are still predominantly single threaded. So when you’re busting out your brand new CPU with 36 cores. Most of them are sitting around doing nothing. With Directors controlling the memory and execution, we can spool up a bunch of tasks in the threadpool and split the workload across those cores/threads that aren’t doing anything, allowing the regular workloads to be processed way faster. And this should, in theory, scale well with object counts.
So yeah, Directors are kinda the MVP of the system, what with keeping a tight wrangle on memory, streamlining execution of parts of the engine, standardizing a lot of bits, and also making the engine significantly more threadable than before.
So, you know. A little bit of a thing there. Which takes us to the next bit of our paradigm:
Objects
Compared to everything that directors do and are, Objects are pretty simple in the end. These are your entities that you slap components onto. Unlike a full-fat ECS implementation, Entities are ultimately still full objects.
There’s a good reason for that, of course. The big one is that T3D has a scripting language, and that’s super useful. So an Entity can’t just be a ID that exists in the void, because we gotta have an object for the scripts to work through.
Additionally, T3D also has a very good networking system, and not maximizing that is just dumb. And rather than having each component be manually replicated, or ghosted to clients, we exploit the way T3D does networking streams and packing to go through our Entities.
Specifically, Entities keep a list of components they own. And if a component is marked to be networked, it has a separate list for that. When a networking event happens, such as a component is added, removed, or updated, the Entity is itself flagged for networking action.
Since the Entity is ghosted to clients as normal, we can then piggyback the Entity’s network updates. Each component that’s networked has it’s own mask bits for granularity - we only need to update what actually changes - and this is packed into the Entity’s network update.
This means we can fully network whatever number of components, but only 1 ghost per Entity. And what updates we DO traffic to the client is able to be as lean as possible. This keeps the traffic as thin as physically possible without giving up the very solid networking that T3D offers.
And lastly, we have the mainstay of any component system(duh):
Components
In DOCs, Components behave very similarly to in the previously mentioned EC paradigm. They hold data and implement the functionality for that data. So a RenderMesh component holds what mesh we want to render, and also does the logic to render the mesh.
The main difference, as covered in the section on directors, is that the components are stripped down to JUST the data and implementing logic and all the surrounding boilerplate is largely standardized up into the Directors, as well as when the components are told when to kick off their logic.
This means that implementing new components can be relatively easy, as you have the basic data/implement setup, along with any networking pass-through logic as noted in the Objects section, and then a companion Director to manage when the whole shindig activates.
All in all, while a bit more complex than standard game object classes, you get a lot of flexibility and ability to quickly slap stuff together without completely shifting to a new conceptual paradigm like a pure ECS implementation.
It also keeps networking lean, keeps scripting on the table, but also opens up the door to massively thread workloads in the engine.
So more flexibility, cleaner structure, more performance, and without compromising the good bits the engine already offers.
Not too shabby a deal, eh? 😉
Now, this update’s already quite a long one, pretty technical and tragically limited on pictures, so I’ll do a follow up post next weekend going into the front-end usage(which is realistically where most people will work with DOCs) as well as other development stuff going on or planned.
So I’ll see you all then!
-JeffR
-
By JeffR in Torque 3DHey Everyone!
Given that the rapid-fire releases have waned and we’re back to working on the primary feature release of 4.1, it’s good to get back onto regular work blogs.
And so, to that end of things, here. We. goooooo.
4.1 Progress
So how is 4.1 going? Getting there. As you know, we shifted the target for development of the engine for 4.1 from the ECS, to Editor/UI work.
So how’s it going? Not bad, overall. Lots of foundational work’s been chipped at previously with work done going into 4.0, but since it wasn’t “ready” it wasn’t frontline for the featurestuffs.
But, now that that IS the point, the actual work of “updating the editor suite to not be all old spaghetti” is chugging along.
So, lets get into talking about the work done so far, and what’s on the TODO!
Objectives module
Az and I had recently put up the 1.0 of the Objectives Module onto the Torque3DResources repository(you can get it here.)
Specifically, it’s a module for managing and utilizing Objectives in your game. Objectives being a more general-purpose name, but it can be used for any task a player must complete. Quests, Mission Objectives, yada yada.
We worked on it because we needed it for quests tracking in Catographer anyways, but obviously opening that up for beatups and further refinement by everyone else was an easy win.
Well that doesn’t sound like it has much to do with Editor or UI updates
Right, right. Back on track. One element that was very useful as a tester of the paradigm, but also just useful for our needs, was a custom drop-in editor tool.
Specifically, the ObjectivesModule within it contains a tools folder for the ObjectivesEditor, as seen below:
This works out quite nicely as a demonstrator for module-tools generally, of course. Being able to drop a module into the data directory and immediately get whatever tooling for the modules’ needs right then and there without needing additional copies is an obvious quality of life gain.
But beyond that, there’s the actual tooling utility itself.
One thing we’ve had in the engine and used lightly in various places previously was the “VariableInspector”.
What is it? It’s basically the existing GuiInspector used anytime you went to inspect an object, with all the display of the various fields and properties of the object.
Except for the VariableInspector, it was originally fashioned as a simple inspector for variables, per it’s namesake.
For 4.0, I’d expanded the functionality to inspecting objects, arbitrary fields, global variables, callback actions, and support for completely arbitrary field types.
It was certainly useful, and is used in stuff like the Editor Settings editor and a few other places.
But ultimately it was a duplicate Inspector class, so the next step - both in the interests of simplifying how many GUI controls we have, as well as simplifying usage of inspecting things generally - was to fold the ability to do arbitrary fields and field types into the GuiInspector directly.
And so now, you have what we’re doing in the ObjectiveEditor. Below is a code snippet showing off the onInspect callback function:
As you can see, we have the onInspect callback. This is called when any object is inspected(natch).
This is an important notion, though, because normally the GuiInspector doesn’t do that at all. It all handles the field logic internally with the statically-defined fields in the engine side for the class.
Now, though, we inspect the object, we get the onInspect callback, and then can go on the manage or create groups as well as add fields to said groups entirely in script.
There is no source class defining the logic or behavior of the ObjectiveInfo. In the module, that’s just a scriptObject with the namespace ObjectiveInfo defined. Once it’s inspected, we call through, and do the prompted logic.
Further, we can see pretty common types on the fields. Strings, bools, etc. But there’s an interesting one. “ObjectiveList”
Now, you may have surmised that that’s not a normal type in T3D, and you’d be correct. That type doesn’t exist. On the engine side.
Instead, what happens is when the GuiInspector is processing the fields, if it hits a type it is unfamiliar with, it will attempt to call down into the script for a build function for that type, allowing 100% custom field types to be implemented.
So, we do this function here:
And when that builds the field for us as part of the field population logic, we end out with a nice custom field type that is a dropdown that populates a list of Objectives the engine currently has loaded:
Pretty slick, right?
So that’s why this is important to the Editor and UI update work. A litmus test and showcase of more free-form handling and boosting the script-only viability of editor tools.
This will become increasingly important as we overhaul field-heavy editor tools like the Material or Particle Editors.
They currently use custom GUIs with lots of backend logic for all the binding behavior, but we’ll be updating them to utilize GuiInspectors with the script hooks as needbe for special field types for 4.1.
This will give us less special snowflake code, more standardized layouts, easier to expand or update tooling, and just generally be cleaner and more consistent an experience overall.
Editor Core work
Next on the discuss-a-roo for what’s currently baking in the oven at the moment, is the EditorCore module.
What is that?
Well, calm down a second and I’ll tell ya!
The EditorCore module is designed to rectify the whole old-spaghetti issue that currently plagues the whole of the tools folder.
If you’ve ever gone digging into the tools stuffs, you’ll realize it’s a big blob of auto-executing scripts, seemingly completely arbitrary execution orders of scripts and guis, multiple redundant re-executions of stuff like GuiControlProfiles, and then everything is duct taped together by just adding every single GUI and EditorTool to the EditorGUi control, smooshing everything together and making it almost impossible to edit or detangle without a ton of manual work.
Not great.
So the EditorCore is a “clean slate” after a fashion, while also skipping the need to actually start the entire editor suite over, because that would be really, really dumb.
Instead, we’ll do a progressive update structure with a common core.
An *EditorCore* 😉
Specifically, the EditorCore will do the following:
It acts as the central loading point for the entire tools suite. It always executes first, and all the common-use stuff like icons, common images, GuiControlProfiles, etc are handled in it. Since it is always executed first, you can rely on the fact that anything within it will be ready and loaded before any subsequent tolls are loaded. This will simplify the loading behavior considerably It will provide several standardized utility functions for common behaviors. Stuff like layout management, Menubar/Context Menu building, etc. This will cut out a lot of the mess we currently do with the menubars and RMB popup menus being defined inconsistently, and also all over the place. Help standardize theming, by letting us massively reduce how many random, floating GuiControlProfiles we have everywhere. The EditorCore profiles can be relied on to be there if the tools are loaded, and will be rebuilt from the ground up to be consistent. We’ll also look at theming support with them so tweaking colors and the like for better user experience is less of a nightmare. Once the EditorCore is in place, we can then begin porting the existing tools to actual modules, simplify and standardize the hook-ins and execution code, and then doing any other thematic/format updates to the tools(like the aforementioned updating of the Material/Particle editors to use the Inspectors)
In this way, we can keep the vast majority of the existing functionality, but we can ensure all the tools get some TLC and brought up to a modern standard.
Nil’s Theme and style work
Topical to theming and style, Nils had done some work on a side-branch of the engine in his repo that does some very lovely touch-ups. It standardizes some of the colors and stylistic notions, and updates quite a number of the icons or images utilized throughout the editor.
Additionally, it has some nice expansions like the ability to snap certain windows to a layout. While the final implementation in devhead won’t be identical to this, you can expect a similar ability to lock certain windows and panes to a layout(and have it keep that layout next time the editor loads)
Work on updated AB
Tying into editor form and style updates, we’ve gotten a bunch of feedback with the Asset Browser, which is very good!
It seems like by and large, the layout and operation of the AB is pretty widely liked, but there’s room for improvement on clarity and functionality.
So I’ve been working on updates to the layout and behavior. Here’s an image of the WIP:
One thing that gets ‘lost’ in terms of immediate user experience affordances is how spawning/creating objects for the scene works.
While the drag-and-drop action is intuitive to a lot of people, it isn’t intuitive to everyone - or it could be intuitive if it was more apparent what was a spawnable item listing versus non-spawnable.
For example, one can drag a datablock listed in the AB into the scene and it will spawn the class associated to that DB. Drag a ItemDatablock, spawns an item with that datablock.
But an image is not spawnable and dragging and dropping does nothing.
So, while the functionality generally won’t change for drag-and-drop, We’ll be having a separate window/tab for “Creator” that is JUST spawnable assets and classes. If you want to spawn an item, waterblock, or light. You can go into the Creator tab and only spawnable items will be listed there.
Beyond that, once customizable layouts are working, it’ll be easy for you guys to put the Creator tab up by the Scene Tree like the old layout if that’s your fancy, or you can keep the Browser and Creator docked in a panel at the bottom of the screen, or whatever else makes the mose sense for you.
Additionally, per the image, you can see we’re going with icon buttons that also have text for the main action buttons. So for newer users not used to the iconography can still very easily find what actions they need to get their work done(this will be a common design thread throughout the editor going forward, incidentally).
And you can see some tweaks to the display of the ‘cards’ for the items listed in the browser, with a whole sub-line indicating the type for it. In conjunction with the border colorization we already had, there should be multiple ways a user can quickly identify an image from a material, or a material from a shape.
Work on updated importer
Another one that’s gotten a lot of excellent feedback is the Asset Import system. In it’s current form, it’s all processed in the engine, and since very few people have really fiddled with it, it’s a sort of ‘black box’ in terms of how it behaves.
While there’s a lot of customization settings in the Editor Settings:
It can be a pretty daunting wall of things you “have” to tweak. Plus some settings impact other settings and it’s hard to convey that well in this format.
So, in the interest of boosting maintainability, making it so other people can more readily fiddle with the importer behavior, and making it easier to customize AND understand, the Asset Import toolstuffs will be getting an overhaul as well.
Specifically, I’ve been experimenting with something like this:
What’s all this, then?
Well, it’s a WIP of the updated UI for the importer editor/designer.
Rather than a monolithic blob-class of executable logic, it’ll be shifted over to a “tasks” system. By which I mean, when you go to import a given file, it figures out the type of file, and then that type will have a list of “tasks” assigned to it.
Each task has a discrete set of settings that tell the task how to do it’s work.
For example, a RenameAssetTask simply establishes rules to rename the asset from the originating file name, since file names can use characters that asset names don’t support.
Once it knows the type and has the tasks for that type, it then just walks through them in-order, performing the informed task based on the settings.
This gives complete control over the person setting up the import pipeline without having to manually edit any code for sequencing.
Once the tasks for that item are done, the item is marked as processed, and - presuming all items are processed - final asset creation is performed.
At which point, the asset is loaded, registered and ready for use immediately.
Now, ideally, we have a good config out of the box so most people won’t need to fiddle with this at all, but the idea is that if you do - whether it’s because your artists have… interesting naming conventions, or there’s an entirely new type of file and asset you want to import - it’s easy to modify and expand.
Tasks will be script-defined objects with standard callback functions for them all, so adding new tasks or processing new asset types will be quite easy.
ScriptAssets
Now, topical to “new types of assets”, one thing that was confirmed to work(but ultimately not a good fit for the ObjectivesModule) was expanded behavior for ScriptAssets.
Originally a ScriptAsset was an asset for a script file(natch).
However, this is kinda ‘meh’ for utility, since most of the time scripts are either associated to other stuff(GUIs, shape constructor files, etc) or they’re standalone and need to be told specifically when to execute as part of the module/gameplay setup logic.
So, not especially useful most of the time
But then it occurred: why not just…let ScriptAssets be SCRIPTED assets?
In the same way we have “ScriptObject”, aka an object who’s properties and behaviors are defined entirely in script, you have the ability for ScriptAssets to do similar.
If you need management and tracking of a special asset type for something, but it doesn’t need special handling code drafted on the engine side, then you can define it as a new ScriptAsset type.
This can hook against the prior mentioned onInspect behavior to be able to easily draft in custom editor logic.
Additionally, it has standard callbacks for when the asset is initialized, reloaded or unloaded.
AND you can keep the pre-existing scriptFile association if needbe.
So you can have a full micro-ecosystem of a special type of “thing” via ScriptAsset, with full editor, resource management and execution tracking.
While still being able to lean on the Asset Dependencies system, easily finding stuff regardless of location with AssetId’s and being able to find by type with the AssetType.
They’ll even show up in the Asset Browser, and have callbacks for working with that.
Want a special data type asset for a maze generator ruleset, then be able to drag the asset in and spawn an object that uses that ruleset to spawn a maze on map load?
All pretty easy to set up by using the callbacks and interop provided.
There’s definitely a lot of room for cool stuff with that, and it also makes the drop-in-and-go-ness of modules with custom types and editors even more expandable, since it means you can often avoid needing to add a new asset type on the engine side.
Just drop in the module and bam. It’s ready to go now.
Marauder’s work with graphical updates
While not a focal point for 4.1(since the feature target for it is the UI/Editor updates) it’s worth observing that ongoing work is being done to keep updating the rendering side of thing.
Marauder had been doing work into updating some stuff, like expanding the global illumination behavior from just the IBL with probes, to an Screen-Space GI implementation. While there’s always more work to do, the work done thus far with it is certainly very promising:
It's subtle, but there's color bleeding happening with the bounced light from the curtains and the like. The next step is ensuring rays properly contribute to the AO for occluded areas like back behind said curtains and the technique'll be pretty well top-notch AND fully dynamic.
He’d also done some work to do more physically correct camera behavior, specifically a higher quality Depth of Field effect. While not used during gameplay too often, it can be very useful for framing certain shots or cutscenes:
And also technique update for shadows, to make them higher quality, for less resources and fewer irregularities:
You can see it even does penumbra and loss of sharpness the further the shadow is from the caster. This helps better ground objects and makes the shadows more realistic.
Additionally, there's updates to the physical bloom, so even when over-exposed and bright, it doesn't completely blow out detailing:
Now, as said, it’s not the focus, but if any of these techniques get finished out by release, then they’ll probably go in. But even if they miss the release target for 4.1, you can expect further fidelity refinements and new techniques to go in render-wise.
Dialogue System
Now, to change gears, another module that’s juuuuust about ready to go in, with a few bits of refinement is another one that we’d made for Catographer.
Specifically, it’s a dialogue system that utilizes the ‘yarnspinner’ format.
If you’re unfamiliar, yarn, or yarnspinner, is a dialogue library/format standard that has been used in a buuuuunch of indie games.
It’s pretty well beat up and proven, and we needed a dialogue system for cats. So, the implementation to work with the *.yarn files was done.
Internally, it converts all logic to torquescript, so you can easily invoke functions, access global variables and do other evaluatable logic as part of the normal flow of it.
Conversations can have any number of speakers, and the dialogue bubbles will ‘find’ the speaker as long as the AI or Player has an NPCName field to match the speaker from the dialogue file.
It also supports ‘barks’, or non-conversational dialogue pop-ups, like if a shopkeep tries to call the player over as they walk past.
As said, a few bits to polish up, but you can expect that in the Torque3DResources in the neat future as well.
For future expansions, I’d like to have it more easily support different styles of UI(as is, it’s designed around ‘word bubble over head’) like being able to have the dialogue show across the bottom of the screen, have character portraits, etc, etc.
With a fairly consistent file format like yarn, it’s mostly just a question of ensuring flexibility of the UI/UX stuff(and possibly a fully integrated dialogue editor in the future).
Quick overview of TTR gameplan
Speaking of future prospects, if you’ve been in the discord, especially in the past months, you’ll probably have heard me mention ‘TTR’. Originally a UT99 mod, The Third Reich was a WW2 total conversion mod that emphasized “fun realism”. It had a pretty good sized community back in the day, and a good swath of content.
It was actually what got me into the gamedev scene when I was onboarded and as the original work from the project waned and faded off, I was put in charge of.
Unfortunately, being poopy baby-faced new developer that I was, I didn’t have the skills or know-how to meaningfully port a full-fat complete project to Torque back in the day.
So it’s just sorta been simmering in the backburner waiting for an opportunity to be ported and done justice.
Ok, why is this relevant? Aren’t you working on Catographer?
Excellent inquiry, reader-stand-in!
Indeed, far as commercial prospects go, Catographer is the main game project I’m working on. Very much the primary-focus of my time if it isn’t for T3D itself.
Plus, in the interests of maintaining the legacy of the original mod that was fun and free, I don’t wanna sell TTR for a price tag anyways.
So why would I bring this up at all?
Because what TTR can do for the T3D community is quite a lot, actually!
One thing I’d noted some months back in the discord as the discussion at the time covered modding, was that some of the best introduction to game development was the modding scene.
And while modding may not be quite as gigantic as it’s heyday because people can just grab a game engine and jump straight into their dream project, I think there’s a misjudgement on if that’s the best route for a complete newbie developer.
You see, what modding did, was it gave a new developer a fully functional, fully playable game.
No duh, right?
But this matters, because it means that what the developer themselves has to do is very, very small.
If you wanna learn how to map? You have gigabytes of assets already and maps to look at and reference from.
You don’t have to make or buy trees, and cars, and rock assets to put into your map just so you can learn the ropes.
Same with modelling, or texturing, or materials, or sounds.
You can focus on that tiny sliver of game development, drop it in, and immediately play with it in the context of a full project.
This minimizes how overwhelming starting out brand new to game development can be.
If you’ve ever watched tutorials for getting started - with any engine, really - the problem is it’s basically a DEEPEST LORE DUMP of the engine you’re trying to use.
You wanna make maps? Well you gotta have assets first. And code a game mode. And make sure you have a player to spawn. And that player has to have physics and movement. And input/keybinds. And, and and.
So even simple introduction tutorials tend to have quite a spread of obligatory knowledge, and for someone that has NO experience, it can be paralyzing.
So, What if you can remove a lot of that initial burden? Then tutorials can be purely focused on a specific thing, because there’s already a full game’s content there.
It’s also a good morale booster, because getting a gun model in, or new texture, can be part of a full, playable experience immediately.
It’s a small victory, but for someone just starting out, it can be a big validator that they’re going the right direction.
So, having a fully functional game that’s 100% designed for actual play, not just a random demo scene is a good foundation for newbies to build off of, rather than jumping and drowning in the ocean of gamedev.
So it’s just a moddable project?
Well, not JUST that.
As noted, it being a fully featured game, with a lot of existing content that’s just fun to play is the first step.
Once it’s there, then it can be made moddable.
This lets us have “first contact” tutorials emphasize modding TTR first as a ‘dip your toes’ deal. And once some foundational knowledge is learned, they can go on and start doing their own projects.
But beyond that, having a project that’s a sort of “The Engine’s Game” is good for marketing, drawing attention and a bunch of other stuff.
Like?
Well, in no specific order of priority, I see TTR as being able to provide the following for the engine and the community:
Newbie Developers ‘first contact’ tutorials Super small, focused tutorials for learning all the baby-step foundational knowledge of gamedev without needing other foundational knowledge to even get to the point of displaying the results helps keep new people “in” A game people can play that is upfront about what engine it uses, bringing attention Similar to Unreal’s Unreal Torunament, or most any game from Valve for Source, having a game that’s up front in it’s association to the engine, and linkbacks and directed flow back to the engine and community is a good funnel. If people like playing the game, they may want to mod it. And if they mod it, they may just use the engine full-time for their personal projects A Benchmark testbed. We can put camera markers and flight paths, and run canned benchmarks in the various levels which lets us find performance hotspots, or see how new tech fares in different environments Demonstrates/Tests basically every feature of the engine The game had a bunch of different maps, and fairly in-depth gameplay. Indoor, outdoor. Forests, water. Vehicles, infantry combat. AI, teams. Times of day and weather and more. So if there’s a thing the engine can do, the game can show it off. And that means it can also do…. Feature Regression tests One thing that’s tricky to deal with is regression testing. While we have a few test maps like Outpost, it’s hard to be truely comprehensive for any given feature for the engine. Especially as we look into doing stuff like Components in the future. Having all the different features the engine can do in the various maps and gameplay allow much more comprehensive spread of cases and easier to see when something goes wrong. Performance regressions can also be detected with the aforementioned benchmarking Network demonstration As a multiplayer game, it’s a good tester for one of the most fundamentally core features of the engine, the networking. New Feature Testing/Demonstrations As new features go in, like SSGI or Components or whatever, they can be tossed into a build for TTR as a good all-rounder way to test them in different scenarios, to ensure they work well with them all before being rolled in. This should help ensure stability of new roll-ins and minimize how much hotfixing happens. Not bad. So it’ll be ready soon then?
Oh. Ha. Haha, aahhh. No. Not exactly.
To be specific, most of the OG art and content is basically ready and waiting for being rolled in and turned back into TTR, but on T3D.
But that takes time, and I have to ensure all the bits are formatted right, conversion from the old archive files or extracted content isn’t hideously mangled, and so on.
I also gotta finish up the Design Document and probably a roadmap for work on it so if people want to pitch in, they can and know what needs doing.
Plus, as noted, outside of engine work itself, my main priority is Catographer, at the moment.
Having said that, the utility TTR can provide to the engine and community is, in my opinion, quite apparent, so I’m not going to just let it sit in a dusty box for several more years.
My plan is to over the next months, slowly get all the pieces pre-arranged and positioned, with documentation for design and intent on it. Sorta like laying out all the bits before assembling your IKEA furniture.
Once that’s ready, and Catographer is punted out(fingers crossed, this summer!) I can spend some intermediate time after that goes out ripping through the work and getting TTR assembled in T3D and put out there.
Once it’s live, it’ll be easier for people to poke and prod everything to fill in any missing bits or make their own mods for it to expand upon it.
So while it’s not right around the corner, I wouldn’t say it’s far off, either. Just a matter of managing the timing and priorities.
In Closing
So, uh, yeah. Wow, that was quite a bit of yapping, huh?
Buuuut, it’s been a hot minute since I did a workblog, and the release updates for 4.0 and the hotfixes aren’t exactly real replacements for these then either.
But now you’ve got the jist of the big bits that are cooking. Hopefully that’s got the ol’ game development appetite going 🙂
And if you want to help facilitate all this cool stuff and the engine as a whole, I DO have(even though I never remember/bother to mention it) a Patreon.
I’ll be working on updating it this week and providing more details, linking back against roadmaps, and do more to detail out what exactly the whole shindig with it and how it helps the engine.
But it does help. First and foremost helps cover all the hosting and service costs we accrue. But also so I can help feed Az so he doesn’t return to his true shoggoth form and bring about the end of at least 1 small country.
Quite important indeed 😛
So, yeah. Every bit helps. But I also acknowledge that just throwing money with absolutely no return isn’t always appealing either. Budgets are tight for everyone these days, and even a token return is better than nothing.
I’ll be looking into Discord integration for patrons to get a nifty special role indicating that you’re donating, and when TTR comes out, me and Az have talked about some bits for that too. Like if you are a patron, you can get your name in for one of the AI Bot names.
Small, but fun little things like that.
Anywho. Lots of work to do, as you can probably guess from the above, so I’d better get back to it!
Thanks everyone, and happy dev’ing!
-JeffR
-
-
Topics
-
- 9 replies
- 124 views
-
- 45 replies
- 14610 views
-
- 128 replies
- 21598 views
-
- 0 votes
- 4 answers
-
- 382 replies
- 216678 views
-
-
Show-Off
-
- 45 replies
- 14610 views
-
- 128 replies
- 21598 views
-
- 260 replies
- 64675 views
-
- 1 reply
- 890 views
-
- 1 reply
- 2899 views
-
-
Built with Torque
-
Catographer
Open Community · 10 fans
-
Visitors: First Contact
Public Community
-
MegaMotion
Open Community · 1 fan
-
Übergame
Open Community · 1 fan
-
Another Tremulous Clone Sortof
Public Community
-
Rad Alert
Open Community · 2 fans
-
The ManFisher
Open Community · 4 fans
-
Airship Dragoon
Open Community · 2 fans
-
Pirate Code
Public Community
-
Nessie Sim 2014
Open Community · 1 fan
-