summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2023-02-06 11:46:31 +0000
committerubq323 <ubq323@ubq323.website>2023-02-06 11:46:50 +0000
commitc74c2a3133ad4d1f03b83021e53fb9e8a67b3914 (patch)
tree22d415e85381c9a09c471afa4a0a6f1824f67b87 /server
parentc2184634b6d3c3268c08c8d430506cfb60245fdf (diff)
tick timing in main server loop, refactor, start on saving/loading chunks
Diffstat (limited to 'server')
-rw-r--r--server/map.lua44
-rw-r--r--server/server.lua189
2 files changed, 166 insertions, 67 deletions
diff --git a/server/map.lua b/server/map.lua
new file mode 100644
index 0000000..845c644
--- /dev/null
+++ b/server/map.lua
@@ -0,0 +1,44 @@
+local Map = require"common.map".Map
+local class = require"common.class"
+local worldgen = require"worldgen"
+
+local MapS = class.extend(Map)
+function MapS.obtain(self,cp)
+ -- obtain chunk at chunkpos cp by any means necessary
+ -- if already loaded, just return it
+ -- if available on disk, load that then return it
+ -- otherwise, generate a new chunk, load it, then return it.
+
+ -- false is not used on serverside. yet.
+
+ local ch = self:chunk(cp)
+ if ch then return ch end
+
+ local f = io.open(cp:filename(),"r")
+ if f then
+ local j = json.decode(f:read("a"))
+ ch = Chunk:from_packet_data(j)
+ f:close()
+ else
+ ch = worldgen.gen_chunk(cp)
+ end
+
+ self:add_chunk(ch)
+ return ch
+end
+function MapS.save_chunk(self,cp)
+ -- any attempt to save not-loaded chunks is silently ignored
+ local ch = self:chunk(cp)
+ if not ch then return end
+
+ local f = io.open(cp:filename(),"w")
+ f:write(ch:data_packet())
+ f:flush()
+ f:close()
+end
+function MapS.save_and_unload(self,cp)
+ self:save_chunk(cp)
+ self:remove_chunk(cp)
+end
+
+return {MapS=MapS}
diff --git a/server/server.lua b/server/server.lua
index 3bb0951..eda6258 100644
--- a/server/server.lua
+++ b/server/server.lua
@@ -5,8 +5,8 @@ local Chunk = require"common.chunk".Chunk
local noise = require"noise"
local coords = require"common.coords"
local worldgen = require"worldgen"
-local Map = require"common.map".Map
-
+local MapS = require"map".MapS
+local posix_time = require"posix.time"
math.randomseed(os.time())
local host = enet.host_create("*:8473")
@@ -61,81 +61,136 @@ local function player_move_packet(player,x,y)
return json.encode{t="move",id=player.id,x=x,y=y}
end
+local map = MapS:make()
-local map = Map:make()
-local function get_or_gen_chunk(cp)
- local ch = map:chunk(cp)
- if not ch then
- ch = worldgen.gen_chunk(cp)
- map:add_chunk(ch)
- end
- return ch
-end
-
-while true do
- local ev = host:service(100)
- if ev then
- if ev.type == "connect" then
- local player = make_player(ev.peer)
- table.insert(playerlist,player)
- print("connect",player.peer,player.id)
- player.peer:send(player_you_packet(player))
- local central_chunk = get_or_gen_chunk(coords.ChunkPos:make(0,0))
- player.peer:send(central_chunk:data_packet())
+local function handle_ev(ev)
+ -- handle network event
+ if ev.type == "connect" then
+ local player = make_player(ev.peer)
+ table.insert(playerlist,player)
+ print("connect",player.peer,player.id)
+ player.peer:send(player_you_packet(player))
+ local central_chunk = map:obtain(coords.ChunkPos:make(0,0))
+ player.peer:send(central_chunk:data_packet())
+ for i,otherplayer in ipairs(playerlist) do
+ if otherplayer ~= player then
+ -- tell new player about each other player
+ player.peer:send(player_join_packet(otherplayer))
+ -- tell each other player about new player
+ otherplayer.peer:send(player_join_packet(player))
+ end
+ end
+ elseif ev.type == "disconnect" then
+ local player, idx = player_by_peer(ev.peer)
+ if not player then error("sneeze "..ev.peer) end
+ print("disconnect",player.peer,player.id)
+ table.remove(playerlist,idx)
+ for i,otherplayer in ipairs(playerlist) do
+ otherplayer.peer:send(player_leave_packet(player))
+ end
+ elseif ev.type == "receive" then
+ local player = player_by_peer(ev.peer)
+ if not player then error("sneezey "..ev.peer) end
+ local j = json.decode(ev.data)
+ local op = j.t
+ if op == "ppos" then
+ local x,y = j.x,j.y
+ player.pos[1] = x
+ player.pos[2] = y
+ -- print(player.id,"-->",player.pos[1],player.pos[2])
for i,otherplayer in ipairs(playerlist) do
if otherplayer ~= player then
- -- tell new player about each other player
- player.peer:send(player_join_packet(otherplayer))
- -- tell each other player about new player
- otherplayer.peer:send(player_join_packet(player))
+ otherplayer.peer:send(player_move_packet(player,x,y))
end
end
- elseif ev.type == "disconnect" then
- local player, idx = player_by_peer(ev.peer)
- if not player then error("sneeze "..ev.peer) end
- print("disconnect",player.peer,player.id)
- table.remove(playerlist,idx)
+ elseif op == "settile" then
+ local h = coords.Hex:make(j.q,j.r)
+ map:set_at(h,j.tile)
+ -- print(player.id,"settile",h,j.tile)
for i,otherplayer in ipairs(playerlist) do
- otherplayer.peer:send(player_leave_packet(player))
- end
- elseif ev.type == "receive" then
- local player = player_by_peer(ev.peer)
- if not player then error("sneezey "..ev.peer) end
- local j = json.decode(ev.data)
- local op = j.t
- if op == "ppos" then
- local x,y = j.x,j.y
- player.pos[1] = x
- player.pos[2] = y
- -- print(player.id,"-->",player.pos[1],player.pos[2])
- for i,otherplayer in ipairs(playerlist) do
- if otherplayer ~= player then
- otherplayer.peer:send(player_move_packet(player,x,y))
- end
- end
- elseif op == "settile" then
- local h = coords.Hex:make(j.q,j.r)
- map:set_at(h,j.tile)
- -- print(player.id,"settile",h,j.tile)
- for i,otherplayer in ipairs(playerlist) do
- if otherplayer ~= player then
- -- same packet structure s2c as c2s
- -- when multiple chunks exist and players only get info
- -- about stuff near to them, that won't be the case any more
- otherplayer.peer:send(ev.data)
- end
+ if otherplayer ~= player then
+ -- same packet structure s2c as c2s
+ -- when multiple chunks exist and players only get info
+ -- about stuff near to them, that won't be the case any more
+ otherplayer.peer:send(ev.data)
end
- elseif op == "reqchunk" then
- -- i am not certain this is the best way for this to work
- -- i might change it later
- local cp = coords.ChunkPos:make(j.u,j.v)
- local ch = get_or_gen_chunk(cp)
- player.peer:send(ch:data_packet())
end
+ elseif op == "reqchunk" then
+ -- i am not certain this is the best way for this to work
+ -- i might change it later
+ local cp = coords.ChunkPos:make(j.u,j.v)
+ local ch = map:obtain(cp)
+ player.peer:send(ch:data_packet())
+ end
+ end
+end
+local function timenow()
+ -- monotonic clock, guaranteed to never go backwards
+ local tv = posix_time.clock_gettime(posix_time.CLOCK_MONOTONIC)
+ -- this discards some precision but i don't care
+ return tv.tv_sec + (tv.tv_nsec/1000000000)
+end
+-- do something only every x seconds
+-- returns function(dt) -> bool
+-- which returns true if you should, and false otherwise
+local function every(interval)
+ local time_since = interval+100
+ return function(dt)
+ time_since = time_since + dt
+ if time_since > interval then
+ time_since = 0
+ return true
+ else
+ return false
end
- -- for k,v in pairs(ev) do io.write(tostring(k),":",tostring(v)," ") end
- -- print()
+ end
+end
+
+local tick_interval = 1 -- seconds
+local last_tick_time = timenow()
+
+-- average tps calculation
+local dts = {}
+local ndt = 1
+local ndts = 100
+local ntick = 0
+
+
+local function tick(ntick)
+ if ntick % 30 == 0 then
+ print("saving things...")
+ end
+end
+
+while true do
+ local now = timenow()
+ local dt = now - last_tick_time
+
+ if dt >= tick_interval then
+ dts[ndt] = dt
+ ndt = 1+(ndt%ndts)
+ last_tick_time = now
+ ntick = ntick + 1
+
+ tick(ntick)
+
+ local tps = 0
+ for _,d in ipairs(dts) do tps = tps + 1/d end
+ tps = tps/#dts
+
+
+ print(ndt,ndts)
+ if 1 == ndt%ndts then
+ print("tps",tps)
+ end
+ end
+
+ local now2 = timenow()
+ local time_till_next_tick = (last_tick_time+tick_interval)-now2
+ if time_till_next_tick > 0 then
+ local ev = host:service(time_till_next_tick/1000)
+ if ev then handle_ev(ev) end
end
end