423 lines
11 KiB
Lua
423 lines
11 KiB
Lua
--[[
|
|
This file is part of Ice Lua Components.
|
|
|
|
Ice Lua Components is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Ice Lua Components is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with Ice Lua Components. If not, see <http://www.gnu.org/licenses/>.
|
|
]]
|
|
|
|
local function copytab(t)
|
|
local nt = {}
|
|
local k,v
|
|
for k,v in pairs(t) do
|
|
if type(v) == type({}) then
|
|
nt[k] = copytab(v)
|
|
else
|
|
nt[k] = v
|
|
end
|
|
end
|
|
return nt
|
|
end
|
|
|
|
local function wrapenv(f, state)
|
|
print("wrap", f, state)
|
|
return function(...)
|
|
local oldenv = getfenv(f)
|
|
setfenv(f, state.e)
|
|
return (function (...)
|
|
setfenv(f, oldenv)
|
|
return ...
|
|
end)(f(...))
|
|
end
|
|
end
|
|
|
|
function fastload_getfile(fname, state)
|
|
-- Get our file if we don't have it already
|
|
if state.f[fname] == nil then
|
|
if fname == "*GAMEMODE" then
|
|
state.f[fname] = wrapenv(loadfile(GAME_MODE), state)
|
|
else
|
|
state.cache["lua:" .. fname] = common.bin_load(fname)
|
|
state.f[fname] = wrapenv(loadfile(fname), state)
|
|
end
|
|
end
|
|
|
|
return state.f[fname]
|
|
end
|
|
|
|
function fastload_analyse_client()
|
|
local k,v
|
|
|
|
-- Create our state
|
|
state = {
|
|
cache = {},
|
|
e = {
|
|
client = {},
|
|
--server = {},
|
|
common = {
|
|
version = copytab(common.version)
|
|
},
|
|
coroutine = {},
|
|
math = {},
|
|
string = {},
|
|
table = {},
|
|
},
|
|
f = {},
|
|
}
|
|
|
|
-- _G refers to the environment
|
|
state.e._G = state.e
|
|
|
|
-- Stash the current map
|
|
local svmap = common.map_get()
|
|
local svmap_copy = common.map_new(common.map_get_dims())
|
|
print("Copying server map")
|
|
do
|
|
local x,y
|
|
local w,h,_
|
|
w, _, h = common.map_get_dims()
|
|
for y=0,h-1 do
|
|
for x=0,w-1 do
|
|
common.map_set(svmap)
|
|
local l = common.map_pillar_get(x, y)
|
|
common.map_set(svmap_copy)
|
|
common.map_pillar_set(x, y, l)
|
|
end
|
|
end
|
|
end
|
|
common.map_set(nil)
|
|
print("Server map copied!")
|
|
|
|
-- Functions we need to dummy out
|
|
for k,v in pairs({
|
|
"print",
|
|
}) do state.e[v] = function(...) end end
|
|
|
|
-- Function tables we need to copy
|
|
for k,v in pairs(coroutine) do state.e.coroutine[k] = v end
|
|
for k,v in pairs(math) do state.e.math[k] = v end
|
|
for k,v in pairs(string) do state.e.string[k] = v end
|
|
for k,v in pairs(table) do state.e.table[k] = v end
|
|
|
|
-- Special wrappers
|
|
|
|
-- loadfile: we need to feed through fastload_analyse
|
|
local function loadfile_wrap(fn)
|
|
return fastload_getfile(fn, state)
|
|
end
|
|
state.e.loadfile = loadfile_wrap
|
|
|
|
-- loadstring: we need to wrap what we've got
|
|
function state.e.loadstring(...)
|
|
return wrapenv(loadstring, state)(...)
|
|
end
|
|
|
|
-- dofile: depends on loadfile
|
|
function state.e.dofile(fn)
|
|
local f = state.e.loadfile(fn)
|
|
return f()
|
|
end
|
|
|
|
-- Some things we need to just pass through
|
|
state.e.getfenv = getfenv
|
|
state.e.setfenv = setfenv
|
|
state.e.getmetatable = getmetatable
|
|
state.e.setmetatable = setmetatable
|
|
state.e.rawget = rawget
|
|
state.e.rawset = rawset
|
|
state.e.pcall = pcall
|
|
state.e.pairs = pairs
|
|
state.e.ipairs = ipairs
|
|
state.e.unpack = unpack
|
|
|
|
-- Tell it there's a sandbox
|
|
state.e.sandbox = {}
|
|
|
|
-- client.wav_play_local/global
|
|
function state.e.client.wav_play_local(...) return 1 end
|
|
function state.e.client.wav_play_global(...) return 1 end
|
|
|
|
-- common.map_set/get: Pass straight through
|
|
state.e.common.map_set = common.map_set
|
|
state.e.common.map_get = common.map_get
|
|
|
|
-- client.map_fog_set/get: Stash some defaults
|
|
do
|
|
local fog = {192, 238, 255, 60}
|
|
|
|
function state.e.client.map_fog_set(r, g, b, dist)
|
|
fog[1] = r
|
|
fog[2] = g
|
|
fog[3] = b
|
|
fog[4] = dist
|
|
end
|
|
|
|
function state.e.client.map_fog_get()
|
|
return fog[1], fog[2], fog[3], fog[4]
|
|
end
|
|
end
|
|
|
|
-- common.json_load: refers to stuff in clsave as well as other stuff
|
|
function state.e.common.json_load(fname)
|
|
print("json_load", fname)
|
|
if fname == "clsave/pub/user.json" then
|
|
return {
|
|
name = "FastLoadTest",
|
|
kick_on_join = false,
|
|
sensitivity = 1.0,
|
|
hold_to_zoom = false,
|
|
fog = 127.5,
|
|
|
|
skins = {},
|
|
}
|
|
elseif fname == "clsave/pub/controls.json" then
|
|
return {
|
|
}
|
|
elseif fname == "*MODCFG" then
|
|
return common.json_load(mod_conf_file)
|
|
else
|
|
state.cache["json:" .. fname] = common.bin_load(fname)
|
|
return common.json_load(fname)
|
|
end
|
|
end
|
|
|
|
-- common.map_load: *MAP anyone?
|
|
function state.e.common.map_load(fname, fmt)
|
|
print("map_load", fname, fmt)
|
|
if fname == "*MAP" then
|
|
return svmap_copy
|
|
else
|
|
state.cache[fmt .. ":" .. fname] = common.bin_load(fname)
|
|
return common.map_load(fname, fmt)
|
|
end
|
|
end
|
|
|
|
-- common.img_load
|
|
function state.e.common.img_load(fname, fmt)
|
|
if fname:find("clsave/pub/skin/", 1, true) == 1 then
|
|
return nil
|
|
end
|
|
|
|
print("fetch_img", fmt, fname)
|
|
if fname == "*MAPIMG" then
|
|
return common.img_new(800, 600)
|
|
else
|
|
fmt = fmt or "tga"
|
|
state.cache[fmt .. ":" .. fname] = common.bin_load(fname)
|
|
return common.img_load(fname, fmt)
|
|
end
|
|
end
|
|
|
|
-- Some direct functions
|
|
state.e.common.time = common.time
|
|
state.e.common.img_get_dims = common.img_get_dims
|
|
state.e.common.img_free = common.img_free
|
|
state.e.common.model_bone_find = common.model_bone_find
|
|
state.e.common.model_bone_get = common.model_bone_get
|
|
state.e.common.model_new = common.model_new
|
|
state.e.common.model_bone_new = common.model_bone_new
|
|
state.e.common.model_bone_set = common.model_bone_set
|
|
state.e.common.map_get_dims = common.map_get_dims
|
|
state.e.common.img_new = common.img_new
|
|
state.e.common.map_pillar_get = common.map_pillar_get
|
|
state.e.common.img_pixel_set = common.img_pixel_set
|
|
state.e.common.net_unpack = common.net_unpack
|
|
--state.e.common.@ = common.@
|
|
--state.e.common.@ = common.@
|
|
|
|
-- client.screen_get_dims: 800, 600
|
|
function state.e.client.screen_get_dims() return 800, 600 end
|
|
|
|
-- client.mk_set_title: dummy
|
|
function state.e.client.mk_set_title() end
|
|
|
|
-- client.wav_cube_size: dummy
|
|
function state.e.client.wav_cube_size() end
|
|
|
|
-- client.va_make: dummy
|
|
function state.e.client.va_make() end
|
|
function state.e.common.va_make() end
|
|
|
|
-- client.img_*: dummy
|
|
function state.e.client.img_fill() end
|
|
function state.e.client.img_rect_fill() end
|
|
function state.e.common.img_rect_fill() end
|
|
function state.e.client.img_blit_to() end
|
|
|
|
-- common.fetch_block: Need to cache all the things, except for the things that we can't
|
|
local function fetch_block(typ, fname)
|
|
print("fetch", typ, fname)
|
|
|
|
if fname:find("clsave/pub/skin/", 1, true) == 1 then
|
|
return nil
|
|
end
|
|
|
|
if typ == "lua" then
|
|
return loadfile_wrap(fname)
|
|
elseif typ == "png" and fname == "*MAPIMG" then
|
|
return common.img_new(800, 600)
|
|
else
|
|
state.cache[typ .. ":" .. fname] = common.bin_load(fname)
|
|
return common.fetch_block(typ, fname)
|
|
end
|
|
end
|
|
state.e.common.fetch_block = fetch_block
|
|
|
|
-- common.bin_load: Call fetch_block instead
|
|
function state.e.common.bin_load(fname)
|
|
return fetch_block("bin", fname)
|
|
end
|
|
|
|
-- common.mus_load_it: Call fetch_block instead
|
|
function state.e.common.mus_load_it(fname)
|
|
return fetch_block("it", fname)
|
|
end
|
|
|
|
-- common.fetch_start: Call fetch_block instead
|
|
function state.e.common.fetch_start(ftype, fname)
|
|
print(ftype, fname)
|
|
return fetch_block(ftype, fname)
|
|
end
|
|
|
|
|
|
-- Make copies of the common functions we're using
|
|
for k,v in pairs(state.e.common) do
|
|
state.e.client[k] = v
|
|
--state.e.server[k] = v
|
|
end
|
|
|
|
-- Load and run.
|
|
state.e.dofile("pkg/base/main_client.lua")
|
|
state.e.dofile("pkg/base/client_start.lua")
|
|
|
|
-- Restore the current map
|
|
common.map_set(svmap)
|
|
|
|
print("Destroying map copy!")
|
|
common.map_free(svmap_copy)
|
|
|
|
print("Cache analysed.")
|
|
|
|
local cstr = ""
|
|
local clist = {}
|
|
for k,v in pairs(state.cache) do
|
|
cstr = cstr .. " " .. k
|
|
clist[1+#clist] = k
|
|
end
|
|
print("Cached files:"..cstr)
|
|
|
|
common.json_write("svsave/vol/fastload.json", {
|
|
files = clist,
|
|
})
|
|
|
|
local clcmp = common.json_load("svsave/vol/fastload.json")
|
|
print(clcmp.files[1])
|
|
|
|
print("Filenames dumped to svsave/vol/fastload.json")
|
|
end
|
|
|
|
function fastload_pack_client()
|
|
local r1, r2
|
|
r1, r2 = pcall(function ()
|
|
return common.json_load("svsave/vol/fastload.json")
|
|
end)
|
|
|
|
if not r1 then
|
|
print("Error loading fastload names: "..r2)
|
|
print("Run the server with the -flcache flag to generate svsave/vol/fastload.json")
|
|
return string.char(0)
|
|
elseif not r2 then
|
|
print("Error loading fastload names - file not found")
|
|
print("Run the server with the -flcache flag to generate svsave/vol/fastload.json")
|
|
return string.char(0)
|
|
end
|
|
|
|
print("Generating fastload pack")
|
|
|
|
local dat = ""
|
|
|
|
local k,v
|
|
|
|
for k,v in pairs(r2.files) do
|
|
local r1, r2
|
|
r1, r2 = pcall(function ()
|
|
local pivot = v:find(":", 1, true)
|
|
local fmt = v:sub(1, pivot-1)
|
|
local fname = v:sub(pivot+1)
|
|
print("load:", fmt, fname)
|
|
|
|
local body = common.fetch_block("bin", fname)
|
|
if body == nil then error("fetch_block returned nil") end
|
|
|
|
dat = dat .. string.char(#v) .. v
|
|
|
|
dat = dat .. string.char(math.floor(((#body) / (2^0)) % 256))
|
|
dat = dat .. string.char(math.floor(((#body) / (2^8)) % 256))
|
|
dat = dat .. string.char(math.floor(((#body) / (2^16)) % 256))
|
|
dat = dat .. string.char(math.floor(((#body) / (2^24)) % 256))
|
|
dat = dat .. body
|
|
end)
|
|
|
|
if not r1 then
|
|
print("ERROR: Fastload failed to pack file \"" .. v .. "\"! (Is the cache outdated?)")
|
|
end
|
|
end
|
|
|
|
dat = dat .. string.char(0)
|
|
print(string.format("fastload data size: %i bytes", #dat))
|
|
common.bin_save("svsave/vol/fldata.bin", dat)
|
|
end
|
|
|
|
local fldata_int = nil
|
|
function fastload_fetch()
|
|
local body = common.bin_load("*FASTLOAD")
|
|
if body == nil then
|
|
print("ERROR: Server does not provide fastload. Loading more slowly now!")
|
|
return
|
|
end
|
|
fldata_int = {}
|
|
|
|
local i = 1
|
|
while body:byte(i) ~= 0 do
|
|
local len = body:byte(i)
|
|
i = i + 1
|
|
local fnp = body:sub(i, i+len-1)
|
|
i = i + len
|
|
local dlen = (body:byte(i+0) * (2^0)
|
|
+ body:byte(i+1) * (2^8)
|
|
+ body:byte(i+2) * (2^16)
|
|
+ body:byte(i+3) * (2^24))
|
|
i = i + 4
|
|
local dat = body:sub(i, i+dlen-1)
|
|
i = i + dlen
|
|
print("fastload data: fnpair", len, fnp, #fnp, dlen, #dat)
|
|
common.bin_save("clsave/vol/fastload.tmp", dat)
|
|
local pivot = fnp:find(":", 1, true)
|
|
local fmt = fnp:sub(1, pivot-1)
|
|
local r1,r2
|
|
r1,r2 = pcall(function ()
|
|
fldata_int[fnp] = common.fetch_block(fmt, "clsave/vol/fastload.tmp")
|
|
end)
|
|
|
|
if not r1 then
|
|
print("ERROR: failed to preload \"" ..fnp.. "\": ".. r2)
|
|
end
|
|
end
|
|
end
|
|
|
|
function fastload_check(fmt, fname)
|
|
if fldata_int == nil then return nil end
|
|
local pname = fmt..":"..fname
|
|
return fldata_int[pname]
|
|
end
|
|
|