Sandbox Logo
30 May 2021

May 2021

Community requests, lots of refactoring and a bit of experimentation this month.
Tone Change
There's going to be a bit of a tone change in these blogs now since they're probably being targeted at people with access to the dev preview more. If you're not a developer you're probably going to get a bunch of information you're not interested in.

Maybe that was always kind of the case, but I thought I'd mention it.
Viewmodel Framerate
Clientside animation entities were updating at the server tickrate. This was only really noticeable when host_timescale or the tickrate was reduced.


Drawing
I added the ability to draw at runtime. We kind of had this in GMod, but it works a bit differently in S&box, but with a few benefits.

These cubes are drawn using the new methods. These aren't models, they're drawn manually in c# each frame. 
The cool thing about Source 2 is that we don't have to leave it there. Procedural content can look just like regular models. It can get the same lighting and cast the shadows like everything else can.
The render pipeline lets you do some nice tricks, like rendering only to the bloom pass.

This stuff was only really made for things like in game widgets, but it's a lot of fun to mess around with, so I think we'll find a lot of uses for it.
World Art
We've got a strong direction with the citizen characters. We know what we want it to be, we know what we don't want it to be.

Less so with the world art. We've been dithering a lot, trying to decide the direction we want to go. Do we want it kind of cartoony to match the citizen or do we want it more realistic?

Here are a few of the more stylized concepts we tried which follow the citizen's proportions:
Early this month we decided to commit and say we want realistic. Part of this was seeing how great the citizen looked in Alyx levels. The contrast between the real world gritty look and the sausage headed cartoony citizen is exactly what I want. It's interesting.
So we've started to work out a pipeline to get world art going. This is all new to me so I've been struggling with organising it and getting everyone to work together transparently, but I think we're making baby steps now.

The aim with this is to fix the problem of baseline content. With GMod we had it easy, we had all the Half-Life 2 materials and props. We have the Rust art now, but its scale isn't always consistent with Source.

So we're trying to get it all together. All we need is for our 3 artists to make the world look as good as Alyx and we'll be set.
Player Refactor
I did a big mutl-week refactor of the Player system this month. 

Previously when your player spawned, that's who you were. While you could technically control any entity by coding a system yourself, it wasn't built in to work like that.

So this month I made a Pawn system. Now when you join a server it can create an entity that you will control. The server can change your Pawn at any time.

This is a much cleaner system when making gamemodes that aren't First Person Shooters. Like games where different players have to take turns controlling the same entity, or gamemodes where you need to jump between controlling different entities.. or gamemodes where you don't control any entities and are just a floating camera.
Network Refactor
The previous network system was really there as a placeholder, just rushed through to get something working. When networking an Entity you'd have to wrap it in an EntityHandle, or when networking a List you'd have to use a special NetList class instead. You'd also sometimes have to manually call NetworkDirty functions to get it to actually network.

Worse than all that, the entire thing was networked as 4 big byte arrays and any time the network was dirty we'd rebuild them, manually writing the entire class again.

Why 4? Regular, Predicted, Local, Local Predicted. On re-doing this I realised that we don't need the predicted ones at all, because we're handling the prediction ourselves. So now we're down to just regular and local.

So I set out to fix all these problems and make it better defined and tighter. And now it feels good. There's a wiki page on how it works now.
Stack Traces
I got stack traces showing up in the in-game console. You can click on one and it'll open/switch to visual studio at the right file and line.
Move Helper
Writing your own movement code is a bit daunting. Something I felt we could abstract and simplify is the actual slide movement code. 

The Source Engine's movement code isn't as simple as "move here if you can, stop if you can't". If it hits a surface, it slides across it. If it hits another one when it's sliding, it slides across that one too, as long as it isn't going to push it into the original one. 

So I extracted all this behaviour into a helper struct called MoveHelper.
I've kept it as a struct because it's actually pretty lightweight and doesn't reference an Entity at all, so you can use it for non entity things.
Dependencies
Something that comes up now and then in our chats in the preview discord is the subject of dependencies. A lot of people want to make an addon that relies on another addon. They want to make a base addon and then make addons based on that. Some people only want to make bases.

Runtime dependencies suck. It's something I want to stomp out in s&box. Your game should include everything it needs to run. It shouldn't be pulling in 8 different addons. It shouldn't need people to install CS:S.

Using inheritance and re-using code is smart. The issue is when you're doing that at runtime. The addon you're using updates, or is deleted, or an addon which that addon relies on is updated or deleted. Now we have a ton of addons that don't work.

So the official recommendation right now is to copy and paste code into your addon to re-use it between projects. 

If you want to make an addon based on sandbox, download the repo and copy over what you want to take from it. It won't stay up to date with changes from the official sandbox repository - but that's a good thing - you're in control.
Pool Game
I've been working on a pool game this month, and in doing so I've found a bunch of useful stuff we could have in s&box. 

To start with, balls were clinging to the side of the table a lot, instead of bouncing away as you might expect them to.  What I found was, in the engine, the bounce threshold was being hardcoded to a velocity of 40, meaning if balls were travelling any slower than that, they would not bounce at all. So we've now bound that value so it can be changed per surface, so now the balls all have this value set to 0.1.

Another problem was detecting whether balls have stopped, so the next player can take their turn, but now Garry has added a way to speed up the physics simulation so after a certain amount of time the game can fast-forward.

Here's a video demonstrating Pool, and how to play it really poorly:
Construct
In Garry's Mod gm_construct started life as a lightweight map that you could load into quickly to test things. An alternative to waiting for d1_trainstation_02 to open for 50 seconds each time.

It's tempting when re-making it for s&box to make it bigger, make more areas, slides, race tracks, football fields. But this all goes against its original purpose.
  • Fast loading
  • Light Room (for taking screenshots of props)
  • Dark Room (testing entities in dark, taking dynamic light lit screenshots)
  • Water (for testing entities in water)
  • Flat areas (for testing vehicles etc)
  • Nav mesh (for testing AI)
  • Stairs (for testing movement)
  • Ramps (for testing movement)
With the current version we're trying to focus down on these requirements. It's a map for testing your game or your entity or your model. It doesn't need to be more than that.

It's also an opportunity for us to work on the world art and build workflows internally to texture and decorate the map as a team by breaking it into prefabs and passing it around.
Map Entities
Something else causing a bit of confusion is our attitude to map entities. Mappers that get the developer preview are finding that when creating things with inputs and outputs, they're not working as they expect.

We have a unique opportunity right now to liberate the engine from its 20 years of iteration. To remove old entities, to give things logical names, to make things easier for everyone.

The Entity Input/Output system is now totally in c#. Entities trying to do input stuff in c++ do nothing. This just means we need to delete the c++ entity and rewrite it in c#.

This is what we've been doing this week. It's less of a recreation and more of a curation. When we're converting these things, can we make it better, can we add features that mean mappers don't have to create a IO web to do something.

So if you're in the dev preview, making a map, and entities aren't behaving as you'd like.. please share it with us here. If you create an example map and attach it, as this young developer did, it helps immensely.
Health Is A Float
When I asked in discord whether I should change Health from an int to a float there was a huge uproar against it. I didn't really understand why.

Turns out they thought that this would mean that health would be on the HUD like 98.34534f.

So health is a float now. This makes more sense in my opinion, since adding or subtracting fractionally per tick is pretty common and is made a ton harder by it being an int. 

The only downside is that you have to not show fractions on the HUD, and that's not too hard right?
Compile Errors
Our code generator can now show errors and warnings if you're fucking it up.

I imagine in the future we can expand this to be even more useful.. like if you're accessing client only stuff in a server only function.
Runtime Dynamic Meshes
I added support for creating and updating GPU vertex buffers and index buffers.
These can be used to create meshes at runtime.

Buffer data can be set and updated at any time, this locks the data on the gpu and allows you to write to it.

This allows us to create meshes with many triangles at runtime.
I'm using this API to create a voxel sandbox. You can try it right now, we're going to work on making it multiplayer.
Performance Improvements

Prediction Store


After prediction happens (clientside) we make a backup of all the predicted variables on all the predicted entities. This is so that when the server runs that tick and sends all the networked variables back we can compare our result with the server result and take action if they're different.

Someone on discord mentioned that with a ton of predicted entities this was running like shit, so I did an optimization pass and got it about 40x faster, so now it doesn't even register on vprof.

Compiling


When editing a gamemode and hotcompiling those changes, we were also compiling the base addon. I fixed this so it only needs to compile what you change.

This was best case 2x slower, but fixing it actually gave us about a 8x speed up here. This was worst case a second or two, but now it's down to a fraction of a second and feels a ton better.

Filesystem


I found a problem with the way Zio was doing file searches on aggregate filesystems. On one of my tests, searching our core folder for "*_c" took over 10 seconds. 

On the live version, calling Assets.LoadAll on the client routinely took between 3-4 seconds. This is now down to 0.07 seconds. All in all this fix took over 6 seconds off every map load or us.
Package Stats
I started tracking playtime in games early this month. This lets us have a kind of leaderboard - for both games and maps.

Eventually this won't look like shit, but you can drill down into your game or map to see the usage stats per day.
Part of the reason we want to track these stats is to monetise them.. so people aren't just making stuff for nothing. The idea is that we can take the top games every month and pay out based on their position, or player hours, or player hours capped at one hour. 

This is all TBD but it's important to me that this time around we let developers profit from their work in some way. If not then why not put the extra effort into making a game in Unity instead?
Citizen Clothing
With Max merging CitizenV2 this month we've been doing some look-dev on the citizen clothing. The old stylised ones weren't really working for us, the hand-painted look really jarred next to anything realistic or gritty.

The updated style is all about realistic materials on the cartoony Citizen proportions. A tailored suit should look like it's made of fabric, their smart shoes should look like they're made of leather. Here's a peek at the updated suit:


We're aiming to made everything as modular as possible, items can be reused across lots of different outfits and should be tintable where possible.
Physics Timestep
I added a couple of physics parameters to help Conna out with the pool game. He was having trouble with the balls going through the other balls at high velocity so I added Global.PhysicsSubsteps, which you're probably only going to want to change in specific circumstances.
I also added Global.PhysicsTimescale.
If you hook it to MathF.Sin you get a nice laggy gmod server enumator.

Summary
Nice standard month this month. Nothing amazing, nothing too sparkly - just getting shit sorted - making things a little bit less shit every day.

Over the next month I'd like to see us have more direction with the world art. I'd love to have construct pretty much done and ideally not using any Rust assets. I'd like to start deleting some of the more problematic Rust assets. I'd like to get the party system working and have party follow the host into games. I'd like to be automatically hiding gamemodes that are generating compile errors. I'd also love to have VR working, even if it makes you throw up.

I'd also really love to create a couple of gamemodes of my own and add more to DM98. We have to balance what we want to get done with what we need to do for the community, because that list ain't shrinking on its own, but dogfooding is a pretty good way to get at the nub of fundamental problems.

See you next month 💝