• How I made it impossible to undo prop spawns
    3 replies, posted
For a gamemode I'm working on, deriving from sandbox, I need to have it work exactly like sandbox, and players should be able to use tools and spawn props, they should be able to undo tools like weld, but they should [i]not[/i] be able to undo props. This turned out to be surprisingly difficult for me to accomplish, as the undo library was not made very dev-friendly to manipulate. I'm a bit of a noob, but this feels like some pretty advanced stuff! So anyway, here is my code. I felt like sharing, because maybe someone somewhere will find this useful. Please tell me what you think of the code - I don't think you can conceptually get any cleaner than this, but maybe there's some convention I'm not using or something like that. Please enjoy and criticize! [lua]AddCSLuaFile( "cl_init.lua" ) AddCSLuaFile( "shared.lua" ) include( "shared.lua" ) oldundofinish = undo.Finish function undo.Finish() local OUT = {} for uid, undos in pairs(undo.GetTable() ) do OUT[uid] = table.GetKeys(undos) end oldundofinish() local CUT = undo.GetTable() for uid, undos in pairs(CUT) do for undokey, undodata in pairs(undos) do if !OUT[uid] or !table.HasValue(OUT[uid], undokey) then hook.Run( "UndoCaught", uid, undokey, undodata ) end end end end hook.Add( "UndoCaught", "PreventPropUndo", function(uid, id, data) if data.Name == "Prop" then undo.GetTable()[uid][id] = nil local ent = data.Entities[1] local enttable = ent:GetTable() if enttable.OnDieFunctions then for _, func in pairs(enttable.OnDieFunctions) do if string.StartWith(func.Name, "undo") then func.Function(ent, id, data.Owner) ent:RemoveCallOnRemove(func.Name) end end end end end )[/lua] [editline]29th January 2015[/editline] I just made it slightly shorter and IMHO cleaner (edit: and added comments): [lua]AddCSLuaFile( "cl_init.lua" ) AddCSLuaFile( "shared.lua" ) include( "shared.lua" ) local oldundofinish = undo.Finish function undo.Finish() local OUT = {} -- OUT = Old Undo Table for uid, undos in pairs(undo.GetTable() ) do OUT[uid] = table.GetKeys(undos) end oldundofinish() -- Do the ACTUAL undo.Finish() local CUT = undo.GetTable() -- CUT = Current Undo Table for uid, undos in pairs(CUT) do for undokey, undodata in pairs(undos) do if !OUT[uid] or !table.HasValue(OUT[uid], undokey) then hook.Run( "UndoCaught", uid, undokey, undodata ) end end end end hook.Add( "UndoCaught", "PreventPropUndo", function(uid, id, data) if data.Name == "Prop" then undo.GetTable()[uid][id] = nil -- This prevents it from actually getting undone local ent = data.Entities[1] ent:GetTable().OnDieFunctions["undo"..id].Function(ent, id, data.Owner) -- This stops the client from thinking it could be undone ent:RemoveCallOnRemove("undo"..id) end end )[/lua]
Why not detour undo.Create instead and then check for the string prop and do nothing if you find it, that way it never gets added to the undo table to begin with.
[QUOTE=King Penisless;47029416]Why not detour undo.Create instead and then check for the string prop and do nothing if you find it, that way it never gets added to the undo table to begin with.[/QUOTE] Hmm... Good idea, I didn't think of that. However, I do need the entity itself for a different purpose in the gamemode (a sort of gamemode-specific prop protection) which --- Just stopped myself right there because there's the PlayerSpawnedProp hook. Hmph. Thanks! I'll consider changing it to that.
Okay, had a good think. Basically there's a bunch of other places in my code that also use the hook UndoCaught, and I feel like it'd be better to keep it like this rather than have each one work both on UndoCaught and PlayerSpawnedProp. It's just better this way, in my opinion. [editline]29th January 2015[/editline] Also, this code is more generic. It provides basis for removing any undo from the table without having it get undone - which might be useful later, not just for me, but also other people possibly coming across this. :)
Sorry, you need to Log In to post a reply to this thread.