Files
wnsrc/gamemodes/sandbox/gamemode/save_load.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

148 lines
3.6 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/
--]]
if ( SERVER ) then
--
-- Pool the shared network string
--
util.AddNetworkString( "GModSave" )
--
-- Console command to trigger the save serverside (and send the save to the client)
--
concommand.Add( "gm_save", function( ply, cmd, args )
if ( !IsValid( ply ) ) then return end
-- gmsave.SaveMap is very expensive for big maps/lots of entities. Do not allow random ppl to save the map in multiplayer!
-- TODO: Actually do proper hooks for this
if ( !game.SinglePlayer() && !ply:IsAdmin() ) then return end
if ( ply.m_NextSave && ply.m_NextSave > CurTime() && !game.SinglePlayer() ) then
ServerLog( tostring( ply ) .. " tried to save too quickly!\n" )
return
end
ply.m_NextSave = CurTime() + 10
ServerLog( tostring( ply ) .. " requested a save.\n" )
local save = gmsave.SaveMap( ply )
if ( !save ) then return end
local compressed_save = util.Compress( save )
if ( !compressed_save ) then compressed_save = save end
local len = string.len( compressed_save )
local send_size = 60000
local parts = math.ceil( len / send_size )
local ShowSave = false
if ( args[ 1 ] == "spawnmenu" ) then ShowSave = true end
local start = 0
for i = 1, parts do
local endbyte = math.min( start + send_size, len )
local size = endbyte - start
net.Start( "GModSave" )
net.WriteBool( i == parts )
net.WriteBool( ShowSave )
net.WriteUInt( size, 16 )
net.WriteData( compressed_save:sub( start + 1, endbyte + 1 ), size )
net.Send( ply )
start = endbyte
end
end, nil, "", { FCVAR_DONTRECORD } )
local function LoadGModSave( savedata )
-- If we loaded the save from main menu and the player entity is not ready yet
if ( game.SinglePlayer() && !IsValid( Entity( 1 ) ) ) then
timer.Create( "LoadGModSave_WaitForPlayer", 0.1, 0, function()
if ( !IsValid( Entity( 1 ) ) ) then return end
timer.Remove( "LoadGModSave_WaitForPlayer" )
LoadGModSave( savedata )
end )
return
end
local ply = nil
if ( IsValid( Entity( 1 ) ) && ( game.SinglePlayer() || Entity( 1 ):IsListenServerHost() ) ) then ply = Entity( 1 ) end
if ( !IsValid( ply ) && #player.GetHumans() == 1 ) then ply = player.GetHumans()[ 1 ] end
gmsave.LoadMap( savedata, ply )
end
hook.Add( "LoadGModSave", "LoadGModSave", function( savedata, mapname, maptime )
savedata = util.Decompress( savedata )
if ( !isstring( savedata ) ) then
MsgN( "gm_load: Couldn't load save!" )
return
end
LoadGModSave( savedata )
end )
else
local buffer = ""
net.Receive( "GModSave", function( len, client )
local done = net.ReadBool()
local showsave = net.ReadBool()
local length = net.ReadUInt( 16 )
local data = net.ReadData( length )
buffer = buffer .. data
if ( !done ) then return end
MsgN( "Received save. Size: " .. buffer:len() )
local uncompressed = util.Decompress( buffer )
if ( !uncompressed ) then
MsgN( "Received save - but couldn't decompress!?" )
buffer = ""
return
end
local MapAddon = nil
for id, addon in pairs( engine.GetAddons() ) do
if ( file.Exists( "maps/" .. game.GetMap() .. ".bsp", addon.title ) ) then
MapAddon = addon.wsid
end
end
engine.WriteSave( buffer, game.GetMap() .. " " .. util.DateStamp(), CurTime(), game.GetMap(), MapAddon )
buffer = ""
if ( showsave ) then
hook.Run( "PostGameSaved" )
end
end )
end