summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2023-03-24 21:11:10 +0000
committerubq323 <ubq323@ubq323.website>2023-03-24 21:11:10 +0000
commite77609c5bc8b44aa22ef88063246fd05add5e705 (patch)
tree1829e2098e40f7fad82af8707bd8a359edd2be1d
parent0927f9297c06525a453b4aad44fa4c2916c75906 (diff)
use lmdb for world storage; plus other small things
support numpad 8456 for movement in addition to wasd refactor server and add player module update outdated documentation slightly
-rw-r--r--.gitignore3
-rw-r--r--client/game.lua22
-rw-r--r--common/coords.lua5
-rw-r--r--db.lua6
-rw-r--r--net.txt7
-rw-r--r--server/chunk.lua37
-rw-r--r--server/db.lua15
-rw-r--r--server/player.lua31
-rw-r--r--server/server.lua78
9 files changed, 134 insertions, 70 deletions
diff --git a/.gitignore b/.gitignore
index 448f390..0f889b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.love
-server/enet.so
+*.so
+server/data/*
server/world/*
flamegraph.pl
trace*
diff --git a/client/game.lua b/client/game.lua
index fd4ade9..aa2e94c 100644
--- a/client/game.lua
+++ b/client/game.lua
@@ -122,12 +122,17 @@ local remote_players = {}
local function update_local_player(pl,dt)
local SPEED = 8*math.sqrt(3) -- 8 hexagonheights per second
- if love.keyboard.isDown("lshift") then SPEED = SPEED*2 end
- local function kd(code)
- if love.keyboard.isScancodeDown(code) then return 1 else return 0 end
+ if love.keyboard.isDown("lshift") or love.keyboard.isScancodeDown'kpenter' then
+ SPEED = SPEED*2
end
- local dx = kd"d"-kd"a"
- local dy = kd"s"-kd"w"
+ local function kd(codes)
+ for _,code in ipairs(codes) do
+ if love.keyboard.isScancodeDown(code) then return 1 end
+ end
+ return 0
+ end
+ local dx = kd{"d","kp6"}-kd{"a","kp4"}
+ local dy = kd{"s","kp5"}-kd{"w","kp8"}
if dx == 0 and dy == 0 then
return
@@ -262,9 +267,7 @@ local function draw()
draw_player(pl)
end
- love.graphics.setColor(1,0,0)
- love.graphics.rectangle("fill",0,0,1,1)
-
+ -- mouse position (resp. screen, world, hex)
local sm = Pos:make(love.mouse.getPosition())
local wm = camera:screen_to_world(sm)
local hm = wm:to_hex()
@@ -290,7 +293,9 @@ local function draw()
love.graphics.origin()
+ -- selected tile (temp)
util.print_good(tostring(selected_tile), "center",10)
+
if _G.debugmode and local_player then
util.print_good(table.concat({
"ms "..tostring(sm),
@@ -307,6 +312,7 @@ local function draw()
},"\n"),10,10)
end
+
if show_controls then
util.print_good(help_text,"center","center")
end
diff --git a/common/coords.lua b/common/coords.lua
index 420b287..fc4aaa5 100644
--- a/common/coords.lua
+++ b/common/coords.lua
@@ -161,11 +161,6 @@ function ChunkPos.orth_dist(self,other)
local dv = math.abs(self.v-other.v)
return math.max(du,dv)
end
-function ChunkPos.filename(self)
- -- filename of chunk with that cp
- return "world/c_"..self.u.."_"..self.v..".dat"
-end
-
diff --git a/db.lua b/db.lua
new file mode 100644
index 0000000..e87b1b6
--- /dev/null
+++ b/db.lua
@@ -0,0 +1,6 @@
+local lmdb=require'lmdb'
+local env=lmdb.open('data',{maxdbs=16})
+return {
+ env=env,
+ txn=function(...) return env.txn_begin(...) end,
+}
diff --git a/net.txt b/net.txt
index 4a81d7d..d5f5ef1 100644
--- a/net.txt
+++ b/net.txt
@@ -11,6 +11,9 @@ reqchunk {u,v}
chat {msg}
send chat message msg
+handshake {username}
+ sent on join
+
s2c:
playerinfopart:: {id,x,y,color:[r,g,b]}
@@ -26,11 +29,11 @@ leave {id}
move {id,x,y}
player with id id has moved to (x,y)
-chunk {tiles=[array of 128*128 booleans],u,v}
+chunk {tiles=[array of 128*128 tiles],u,v}
chunk at chunkpos u,v has tile data tiles
settile {q,r,tile}
- tile at H(q,r) was set to tile (currently boolean)
+ tile at H(q,r) was set to tile
chat {msg,from}
recieve chat message msg from player with name from.
diff --git a/server/chunk.lua b/server/chunk.lua
index 8e71327..852f1fe 100644
--- a/server/chunk.lua
+++ b/server/chunk.lua
@@ -1,6 +1,7 @@
local class = require"common.class"
local Chunk = require"common.chunk".Chunk
local json = require"common.dkjson"
+local db = require'db'
local ChunkS = class.extend(Chunk)
function ChunkS.make(cls,...)
@@ -8,31 +9,41 @@ function ChunkS.make(cls,...)
self.dirty = false
return self
end
-function ChunkS.load_from_disk(cls,cp)
- -- returns nil if not there
- local filename = cp:filename()
- local f = io.open(filename,"r")
- if not f then return nil end
- local j = json.decode(f:read("a"))
- self = cls:from_packet_data(j)
+
+function ChunkS.apply_migrations(self)
+ -- if tile format has changed and format in db isn't up to date any more
+ -- then perform updates here
for i,t in ipairs(self.tiles) do
if t == false then self.tiles[i] = 0
elseif t == true then self.tiles[i] = 9 end
end
- f:close()
+end
+
+function ChunkS.load_from_disk(cls,cp)
+ -- tries to load from database. returns nil if not there.
+ local txn,dbi = db.get_db('chunks')
+ local d = dbi[tostring(cp)]
+ txn:commit()
+
+ if not d then return nil end
+ local j = json.decode(d)
+
+ local self = cls:from_packet_data(j)
+ self:apply_migrations()
+
return self
end
+
function ChunkS.save_if_dirty(self)
if self.dirty then
print("saving chunk",self.cp)
- local filename = self.cp:filename()
- local f = io.open(filename,"w")
- f:write(self:data_packet())
- f:flush()
- f:close()
+ local txn,dbi = db.get_db('chunks',true)
+ dbi[tostring(self.cp)] = self:data_packet()
+ txn:commit()
self.dirty = false
end
end
+
function ChunkS.set_at(self,...)
Chunk.set_at(self,...)
self.dirty = true
diff --git a/server/db.lua b/server/db.lua
new file mode 100644
index 0000000..4208aeb
--- /dev/null
+++ b/server/db.lua
@@ -0,0 +1,15 @@
+local lmdb = require'lmdb'
+local env = lmdb.open('data',{maxdbs=16})
+local function get_db(dbname, writeable)
+ -- shortcut
+ if writeable == nil then writeable = false end
+ local txn = assert(env:txn_begin(writeable),"couldn't begin txn")
+ local the_db = assert(txn:open(dbname), "couldn't open db")
+ return txn,the_db
+end
+
+
+return {
+ env=env,
+ get_db=get_db,
+}
diff --git a/server/player.lua b/server/player.lua
new file mode 100644
index 0000000..365eadc
--- /dev/null
+++ b/server/player.lua
@@ -0,0 +1,31 @@
+local class = require'common.class'
+local Pos = require'common.coords'.Pos
+
+local nextid = 1
+
+local function random_color()
+ return {math.random(),math.random(),math.random()}
+end
+
+local Player = class()
+function Player.make(cls,peer)
+ local self = {
+ pos = Pos:make(0,0),
+ color = random_color(),
+ peer = peer,
+ id = nextid,
+ }
+ nextid = nextid + 1
+ return setmetatable(self,cls)
+end
+function Player.info_part(self)
+ -- eh
+ return {
+ id=self.id,
+ x=self.pos.x,
+ y=self.pos.y,
+ color=self.color,
+ }
+end
+
+return {Player=Player}
diff --git a/server/server.lua b/server/server.lua
index 24b49ae..2da7988 100644
--- a/server/server.lua
+++ b/server/server.lua
@@ -6,6 +6,7 @@ local coords = require"common.coords"
local Pos = coords.Pos
local worldgen = require"worldgen"
local MapS = require"map".MapS
+local Player=require'player'.Player
local posix_time = require"posix.time"
local posix_signal = require"posix.signal"
@@ -16,7 +17,6 @@ print(host:get_socket_address())
-- sequential list of all players
local playerlist = {}
-local nextid = 1
-- this is maybe suboptimal
-- but it is simplest for now
@@ -33,28 +33,12 @@ local function player_by_peer(peer)
return nil
end
-local function random_color()
- return {math.random(),math.random(),math.random()}
-end
-local function make_player(peer)
- local p = {pos=Pos:make(0,0),color=random_color(),peer=peer,id=nextid}
- nextid = nextid + 1
- return p
-end
-local function player_info_part(player)
- return {
- id=player.id,
- x=player.pos.x,
- y=player.pos.y,
- color=player.color,
- }
-end
local function player_join_packet(player)
- return json.encode{t="join",pl=player_info_part(player)}
+ return json.encode{t="join",pl=player:info_part()}
end
local function player_you_packet(player)
- return json.encode{t="you",pl=player_info_part(player)}
+ return json.encode{t="you",pl=player:info_part()}
end
local function player_leave_packet(player)
return json.encode{t="leave",id=player.id}
@@ -68,32 +52,44 @@ end
local map = MapS:make()
+
+
+local function on_player_connect(ev)
+ local player = Player:make(ev.peer)
+ table.insert(playerlist, player)
+
+ player.peer:send(player_you_packet(player))
+
+ for i,otherplayer in ipairs(playerlist) do
+ if otherplayer ~= player then
+ player.peer:send(player_join_packet(otherplayer))
+ otherplayer.peer:send(player_join_packet(player))
+ end
+ end
+
+ print("connect",player.id,player.peer)
+end
+
+local function on_player_disconnect(ev)
+ local player,idx = player_by_peer(ev.peer)
+ if not player then error("sneeze"..ev.peer) end
+ table.remove(playerlist,idx)
+
+ for i,otherplayer in ipairs(playerlist) do
+ otherplayer.peer:send(player_leave_packet(player))
+ end
+
+ print("disconnect", player.id, player.peer)
+end
+
+
+
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
+ on_player_connect(ev)
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
+ on_player_disconnect(ev)
elseif ev.type == "receive" then
local player = player_by_peer(ev.peer)
if not player then error("sneezey "..ev.peer) end