Friday, August 10, 2012
Man I suck at blogging. I'm gonna post more details on some older stuff I've done. I've been meaning to post about it for ages but keep forgetting.
So, autorefresh. We all know what it is right now? Right? If not see that video.
I don't know why I never added this before. I guess because I thought it would be too much work, too hard. It didn't help that the Lua file loading code was everywhere. Files could be loaded from about 5 different sources. I cleaned that up. It hurt, and took a week, but I cleaned it all up.
So this is how the Lua refresh works in code. I wrote a nice little file change class years ago and put it in Bootil. So I hooked that up.
So now any time a file changes in the garrysmod folder we get notified about it. So every frame in a Cycle function we check for changes..
If there's no changes then fuck it, return and do nothing. But if there's a change then grab it.
This gets the file that's changed and removes it from the changed queue.. Then we separate this filename into file extension, folder and filename, and pass to some handler functions. (A nicer way to have done this would to add some kind of factory - but fuck that for 3 functions).
The easiest of these to hook up was the material reloading function.. because all of the work is already done for us. Obviously this is a total waste of time on dedicated servers - and only useful to the listen server host (because the texture isn't changing on clients).
And there we go, materials are auto reloading. Lua is a little more tricky - and involves specializing reload routines for every type of file load (entity, effect, gamemode, weapon).
First we get the file that has changed. In our Lua system we store a cache'd of every file that has been loaded (so we don't have to load from disk again if we don't have to).
No we've got the file but we've got a problem. This file could be part of an entity and we need to extract the filename from it. For example, the entity could be in entity/ball/shared.lua - but this file could be entity/ball/extrastuff.lua - which was included from shared.lua.
So what we do is, whenever a file is included() we store its parents file. So this function goes up the chain and finds the first file that was included (one without a parent).
At this point we have our file, we have our root file, we're ready to see if we can do business. So we load the changed Lua file and replace the contents in pFile with those. Then we call the shared function..
The first parameter here is the source - which describes what engine function loaded this file (Entity, Gamemode, Weapon etc). This enables us to perform special operations based on the type.
This is kind of a messy system - and it's something I've long regretted in GMod. Entities and Weapons shouldn't be separate systems, with separate management functions. They're all Entities.
But anyway - the HandleLuaFileChanges function looks like this..
EntityFilename seeks the entity's actual name out. This convert "blahblah/garrysmod/lua/entities/sent_ball/init.lua" into "sent_ball". Which isn't that hard.
The reload functions are pretty simple. It;s pretty much all Lua from there on. It switches the table in the entity manager library and then goes through all the active entities replacing their functions with the new functions on the table. The entities don't get re-initialized - that's more trouble than it's worth with very little value.
So that's the serverside reloading. But what about client entities? Where you at dawg? Well basically it's a piece of piss.
First of all we have to make sure the client has this file. What I mean by that is we need to check that this is a clientside file. We'd be wasting our time sending changes to server only files.
Then we update the datapack with the new file changes. This is so that clients joining the server after this point will get the updated files.
Then we simply send a usermessage to all clients with the changes. Which is then received on the client and we get to call HandleLuaFileChange..
So now the clientside is updating live too!