mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
437 lines
9.2 KiB
Lua
437 lines
9.2 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
|
|
local Msg = Msg
|
|
local type = type
|
|
local pairs = pairs
|
|
local gmod = gmod
|
|
local table = table
|
|
|
|
--[[
|
|
|
|
This module is to help bind the engine's saverestore stuff to Lua.
|
|
|
|
This is so we can save Lua stuff in the save game file. The entities
|
|
should automatically save most of their table contents to the save file.
|
|
|
|
!!Warning!!: Editing this file may render old saves useless.
|
|
|
|
You can hook into this system like so
|
|
|
|
local function MySaveFunction( save )
|
|
saverestore.WriteTable( my_table, save )
|
|
end
|
|
|
|
local function MyRestoreFunction( restore )
|
|
my_table = saverestore.ReadTable( restore )
|
|
end
|
|
|
|
saverestore.AddSaveHook( "HookNameHere", MySaveFunction )
|
|
saverestore.AddRestoreHook( "HookNameHere", MyRestoreFunction )
|
|
|
|
--]]
|
|
|
|
module( "saverestore" )
|
|
|
|
local TYPE_NONE = 0
|
|
local TYPE_FLOAT = 1 -- Treat all numbers as floats (they're all the same to Lua)
|
|
local TYPE_STRING = 2
|
|
local TYPE_ENTITY = 3
|
|
local TYPE_VECTOR = 4
|
|
local TYPE_TABLE = 5
|
|
local TYPE_BOOL = 6
|
|
local TYPE_ANGLE = 7
|
|
|
|
local SaveHooks = {}
|
|
local RestoreHooks = {}
|
|
local TableRefs = {}
|
|
local TableRef = 1
|
|
|
|
function PreSave()
|
|
|
|
TableRefs = {}
|
|
TableRef = 1
|
|
|
|
end
|
|
|
|
function PreRestore()
|
|
|
|
TableRefs = {}
|
|
TableRef = 1
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: GetTypeStr
|
|
Desc: Given a string returns a TYPE_
|
|
-----------------------------------------------------------]]
|
|
local function GetTypeStr( name )
|
|
|
|
if ( name == "function" ) then return TYPE_NONE end
|
|
|
|
if ( name == "number" ) then return TYPE_FLOAT end
|
|
if ( name == "string" ) then return TYPE_STRING end
|
|
if ( name == "Entity" ) then return TYPE_ENTITY end
|
|
if ( name == "Vehicle" ) then return TYPE_ENTITY end
|
|
if ( name == "NPC" ) then return TYPE_ENTITY end
|
|
if ( name == "Player" ) then return TYPE_ENTITY end
|
|
if ( name == "Weapon" ) then return TYPE_ENTITY end
|
|
if ( name == "Vector" ) then return TYPE_VECTOR end
|
|
if ( name == "Angle" ) then return TYPE_ANGLE end
|
|
if ( name == "table" ) then return TYPE_TABLE end
|
|
if ( name == "boolean" ) then return TYPE_BOOL end
|
|
|
|
-- These aren't saved
|
|
if ( name == "ConVar" ) then return TYPE_NONE end
|
|
if ( name == "PhysObj" ) then return TYPE_NONE end
|
|
|
|
-- Bitch about it incase I've forgot to hook a savable type up
|
|
Msg( "Can't save unknown type " .. name .. "\n" )
|
|
return TYPE_NONE
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: GetType
|
|
Desc: Given a variable returns a TYPE_
|
|
-----------------------------------------------------------]]
|
|
local function GetType( var )
|
|
|
|
return GetTypeStr( type(var) )
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: IsWritable
|
|
Desc: Returns true if we can save the K/V pair
|
|
-----------------------------------------------------------]]
|
|
local function IsWritable( k, v )
|
|
|
|
local itype = GetType( k )
|
|
if ( itype == TYPE_NONE ) then return false end
|
|
if ( itype == TYPE_STRING && k == "SR_Recursion" ) then return false end
|
|
|
|
local itype = GetType( v )
|
|
if ( itype == TYPE_NONE ) then return false end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: WriteVar
|
|
Desc: Writes a single variable to the save
|
|
-----------------------------------------------------------]]
|
|
function WritableKeysInTable( t )
|
|
|
|
local i = 0
|
|
|
|
for k, v in pairs( t ) do
|
|
if ( IsWritable( k, v ) ) then
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
return i
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: WriteVar
|
|
Desc: Writes a single variable to the save
|
|
-----------------------------------------------------------]]
|
|
function WriteVar( var, save )
|
|
|
|
local itype = GetType( var )
|
|
if ( itype == TYPE_NONE ) then return end
|
|
|
|
save:StartBlock( type( var ) )
|
|
|
|
if ( itype == TYPE_FLOAT ) then
|
|
save:WriteFloat( var )
|
|
elseif ( itype == TYPE_BOOL ) then
|
|
save:WriteBool( var )
|
|
elseif ( itype == TYPE_STRING ) then
|
|
save:WriteString( var )
|
|
elseif ( itype == TYPE_ENTITY ) then
|
|
save:WriteEntity( var )
|
|
elseif ( itype == TYPE_ANGLE ) then
|
|
save:WriteAngle( var )
|
|
elseif ( itype == TYPE_VECTOR ) then
|
|
save:WriteVector( var )
|
|
elseif ( itype == TYPE_TABLE ) then
|
|
WriteTable( var, save )
|
|
else
|
|
Msg( "Error! Saving unsupported Type: " .. type( var ) .. "\n" )
|
|
end
|
|
|
|
save:EndBlock()
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: ReadVar
|
|
Desc: Reads a single variable
|
|
-----------------------------------------------------------]]
|
|
function ReadVar( restore )
|
|
|
|
local retval = 0
|
|
local typename = restore:StartBlock()
|
|
|
|
local itype = GetTypeStr( typename )
|
|
|
|
if ( itype == TYPE_FLOAT ) then
|
|
retval = restore:ReadFloat()
|
|
elseif ( itype == TYPE_BOOL ) then
|
|
retval = restore:ReadBool()
|
|
elseif ( itype == TYPE_STRING ) then
|
|
retval = restore:ReadString()
|
|
elseif ( itype == TYPE_ENTITY ) then
|
|
retval = restore:ReadEntity()
|
|
elseif ( itype == TYPE_ANGLE ) then
|
|
retval = restore:ReadAngle()
|
|
elseif ( itype == TYPE_VECTOR ) then
|
|
retval = restore:ReadVector()
|
|
elseif ( itype == TYPE_TABLE ) then
|
|
retval = ReadTable( restore )
|
|
else
|
|
Msg( "Error! Loading unsupported Type: " .. typename .. "\n" )
|
|
end
|
|
|
|
restore:EndBlock()
|
|
|
|
return retval
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: WriteTable
|
|
Desc: Writes a table to the save
|
|
-----------------------------------------------------------]]
|
|
function WriteTable( tab, save )
|
|
|
|
-- Write a blank table (because read will be expecting one)
|
|
if ( tab == nil ) then
|
|
|
|
save:StartBlock( "Table" )
|
|
save:EndBlock()
|
|
|
|
end
|
|
|
|
-- We have already saved this table
|
|
if ( TableRefs[ tab ] ) then
|
|
|
|
save:StartBlock( "TableRef" )
|
|
save:WriteInt( TableRefs[ tab ] )
|
|
save:EndBlock()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
TableRefs[ tab ] = TableRef
|
|
|
|
save:StartBlock( "Table" )
|
|
|
|
local iCount = WritableKeysInTable( tab )
|
|
|
|
save:WriteInt( TableRef )
|
|
TableRef = TableRef + 1
|
|
|
|
save:WriteInt( iCount )
|
|
|
|
for k, v in pairs( tab ) do
|
|
|
|
if ( IsWritable( k, v ) ) then
|
|
|
|
WriteVar( k, save )
|
|
WriteVar( v, save )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
save:EndBlock()
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: ReadTable
|
|
Desc: Assumes a table is waiting to be read, returns a table
|
|
-----------------------------------------------------------]]
|
|
function ReadTable( restore )
|
|
|
|
local name = restore:StartBlock()
|
|
local tab = {}
|
|
|
|
if ( name == "TableRef" ) then
|
|
|
|
local ref = restore:ReadInt()
|
|
if ( !TableRefs[ ref ] ) then
|
|
TableRefs[ ref ] = {}
|
|
return
|
|
end
|
|
|
|
tab = TableRefs[ ref ]
|
|
|
|
else
|
|
|
|
local iRef = restore:ReadInt()
|
|
local iCount = restore:ReadInt()
|
|
|
|
if ( TableRefs[ iRef ] ) then
|
|
tab = TableRefs[ iRef ]
|
|
end
|
|
|
|
for i = 0, iCount - 1 do
|
|
|
|
local k = ReadVar( restore )
|
|
local v = ReadVar( restore )
|
|
tab[ k ] = v
|
|
|
|
end
|
|
|
|
TableRefs[ iRef ] = tab
|
|
|
|
end
|
|
|
|
restore:EndBlock()
|
|
|
|
return tab
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: SaveEntity
|
|
Desc: Called by the engine for each entity
|
|
-----------------------------------------------------------]]
|
|
function SaveEntity( ent, save )
|
|
|
|
save:StartBlock( "EntityTable" )
|
|
|
|
WriteTable( ent:GetTable(), save )
|
|
|
|
save:EndBlock()
|
|
|
|
end
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: LoadEntity
|
|
Desc: Called by the engine for each entity
|
|
-----------------------------------------------------------]]
|
|
function LoadEntity( ent, restore )
|
|
|
|
local EntTable = ent:GetTable()
|
|
|
|
local name = restore:StartBlock()
|
|
|
|
if ( name == "EntityTable" ) then
|
|
|
|
table.Merge( EntTable, ReadTable( restore ) )
|
|
|
|
end
|
|
|
|
restore:EndBlock()
|
|
|
|
ent:SetTable( EntTable )
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: AddSaveHook
|
|
Desc: Adds a hook enabling something to save something..
|
|
-----------------------------------------------------------]]
|
|
function AddSaveHook( name, func )
|
|
|
|
local h = {}
|
|
h.Name = name
|
|
h.Func = func
|
|
SaveHooks[ name ] = h
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: AddRestoreHook
|
|
Desc: Adds a hook enabling something to restore something..
|
|
-----------------------------------------------------------]]
|
|
function AddRestoreHook( name, func )
|
|
|
|
local h = {}
|
|
h.Name = name
|
|
h.Func = func
|
|
RestoreHooks[ name ] = h
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: SaveGlobal
|
|
Desc: Should save any Lua stuff that isn't entity based.
|
|
-----------------------------------------------------------]]
|
|
function SaveGlobal( save )
|
|
|
|
save:StartBlock( "GameMode" )
|
|
WriteTable( gmod.GetGamemode(), save )
|
|
save:EndBlock()
|
|
|
|
for k, v in pairs( SaveHooks ) do
|
|
|
|
save:StartBlock( v.Name )
|
|
|
|
v.Func( save )
|
|
|
|
save:EndBlock()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[---------------------------------------------------------
|
|
Name: LoadGlobal
|
|
Desc: ...
|
|
-----------------------------------------------------------]]
|
|
function LoadGlobal( restore )
|
|
|
|
local name = restore:StartBlock()
|
|
|
|
if ( name == "GameMode" ) then
|
|
table.Merge( gmod.GetGamemode(), ReadTable( restore ) )
|
|
end
|
|
|
|
restore:EndBlock()
|
|
|
|
|
|
while ( name != "EndGlobal" ) do
|
|
|
|
name = restore:StartBlock()
|
|
|
|
local tab = RestoreHooks[ name ]
|
|
if ( tab ) then
|
|
|
|
tab.Func( restore )
|
|
|
|
end
|
|
|
|
restore:EndBlock()
|
|
|
|
end
|
|
|
|
end
|
|
|