From b4c189ab1b6233c7e7e260446e80b789f375b5d6 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Sat, 11 Feb 2023 15:33:13 +0000 Subject: change from random worldgen to be based on a hash of position; implement serverside chunk unloading --- client/main.lua | 2 +- server/chunk.lua | 3 ++- server/map.lua | 5 +---- server/noise.lua | 24 ++++++++++++++++++++---- server/server.lua | 31 +++++++++++++++++++++++++------ server/worldgen.lua | 18 +++++++++--------- 6 files changed, 58 insertions(+), 25 deletions(-) diff --git a/client/main.lua b/client/main.lua index a544250..03df16a 100644 --- a/client/main.lua +++ b/client/main.lua @@ -89,7 +89,7 @@ function love.update(dt) update_local_player(local_player,dt) if love.keyboard.isScancodeDown"q" then camera.zoom = camera.zoom*1.05 end if love.keyboard.isScancodeDown"e" then camera.zoom = camera.zoom/1.05 end - camera.zoom = math.max(2.25,math.min(50,camera.zoom)) + camera.zoom = math.max(1,math.min(50,camera.zoom)) sync_local_player(local_player) end diff --git a/server/chunk.lua b/server/chunk.lua index 4fb2960..1e2e135 100644 --- a/server/chunk.lua +++ b/server/chunk.lua @@ -5,7 +5,7 @@ local json = require"common.dkjson" local ChunkS = class.extend(Chunk) function ChunkS.make(cls,...) local self = Chunk.make(cls,...) - self.dirty = true + self.dirty = false return self end function ChunkS.load_from_disk(cls,cp) @@ -26,6 +26,7 @@ function ChunkS.save_if_dirty(self) f:write(self:data_packet()) f:flush() f:close() + self.dirty = false end end function ChunkS.set_at(self,...) diff --git a/server/map.lua b/server/map.lua index 9627de9..3d7f377 100644 --- a/server/map.lua +++ b/server/map.lua @@ -29,15 +29,12 @@ function MapS.obtain(self,cp) end function MapS.save_chunk(self,cp) + -- will only actually save anything if anything needs saving. -- any attempt to save not-loaded chunks is silently ignored local ch = self:chunk(cp) if not ch then return end ch:save_if_dirty() end -function MapS.save_and_unload(self,cp) - self:save_chunk(cp) - self:remove_chunk(cp) -end return {MapS=MapS} diff --git a/server/noise.lua b/server/noise.lua index fe254ac..bf7ac2e 100644 --- a/server/noise.lua +++ b/server/noise.lua @@ -1,13 +1,29 @@ local Pos = require"common.coords".Pos local class = require"common.class" +local bit = require"bit" local tau = 2*math.pi math.randomseed(os.time()) -local function random_unit_vec() + +local function hash_list(t) + local h = #t + for _,x in ipairs(t) do + x = bit.bxor(bit.rshift(x,16),x) * 0x45d9f3b + x = bit.bxor(bit.rshift(x,16),x) * 0x45d9f3b + x = bit.bxor(bit.rshift(x,16),x) + h = bit.bxor(h,x + 0x9e3779b9 + bit.lshift(h,6) + bit.rshift(h,2)) + end + return h +end + +local function hash_to_unit_vec(t) + local h = hash_list(t) + math.randomseed(h) local theta = math.random()*tau return Pos:make(math.cos(theta),math.sin(theta)) end + local function lerp(a,b,t) return (1-t)*a + t*b end local function smoothstep(x) if x<0 then return 0 end @@ -17,15 +33,15 @@ end local function slerp(a,b,t) return lerp(a,b,smoothstep(t)) end local PerlinNoise = class() -function PerlinNoise.make(cls) +function PerlinNoise.make(cls,ind_seed) local grid = {} setmetatable(grid,{__index=function(t,k) t[k] = {} return t[k] end}) - return setmetatable({grid=grid},cls) + return setmetatable({grid=grid,ind_seed=ind_seed},cls) end function PerlinNoise.vertex(self,ix,iy) local v = self.grid[ix][iy] if v then return v end - local vv = random_unit_vec() + local vv = hash_to_unit_vec{ix,iy,self.ind_seed} self.grid[ix][iy] = vv return vv end diff --git a/server/server.lua b/server/server.lua index cc9903e..88f4efe 100644 --- a/server/server.lua +++ b/server/server.lua @@ -3,6 +3,7 @@ local json = require"common.dkjson" local chunk = require"common.chunk" local noise = require"noise" local coords = require"common.coords" +local Pos = coords.Pos local worldgen = require"worldgen" local MapS = require"map".MapS local posix_time = require"posix.time" @@ -34,7 +35,7 @@ local function random_color() return {math.random(),math.random(),math.random()} end local function make_player(peer) - local p = {pos={0,0},color=random_color(),peer=peer,id=nextid} + local p = {pos=Pos:make(0,0),color=random_color(),peer=peer,id=nextid} nextid = nextid + 1 return p end @@ -42,8 +43,8 @@ end local function player_info_part(player) return { id=player.id, - x=player.pos[1], - y=player.pos[2], + x=player.pos.x, + y=player.pos.y, color=player.color, } end @@ -95,8 +96,7 @@ local function handle_ev(ev) local op = j.t if op == "ppos" then local x,y = j.x,j.y - player.pos[1] = x - player.pos[2] = y + player.pos = coords.Pos:make(x,y) -- print(player.id,"-->",player.pos[1],player.pos[2]) for i,otherplayer in ipairs(playerlist) do if otherplayer ~= player then @@ -157,11 +157,30 @@ local ndts = 100 local ntick = 0 +local function player_near_chunk(cp) + -- true: chunk at cp should stay loaded (because of a nearby player), + -- false: no players nearby, can be unloaded + -- this is kind of inefficient at the moment + for _,player in ipairs(playerlist) do + local pcp = player.pos:to_hex():containing_chunk() + for _,neighb in ipairs(pcp:neighborhood()) do + if neighb == cp then + return true + end + end + end + return false +end + local function tick(ntick) if ntick % 30 == 0 then - print("saving things...") + print("saving things") for cp,ch in map:iter_chunks() do map:save_chunk(cp) + if not player_near_chunk(cp) then + print("unloading chunk",cp) + map:remove_chunk(cp) + end end end end diff --git a/server/worldgen.lua b/server/worldgen.lua index 2ef1ac0..0a8485b 100644 --- a/server/worldgen.lua +++ b/server/worldgen.lua @@ -4,18 +4,18 @@ local chunk = require"common.chunk" local ChunkS = require"chunk".ChunkS local CHUNK_SIZE = require"common.constants".CHUNK_SIZE -local function p(amp,scale) return {scale=scale,amp=amp,gen=noise.PerlinNoise:make()} end --- local ng = noise.NoiseAgg:make{ --- p(1,20), --- -- p(0.7,2), --- p(0.5,15), --- --p(2,200), --- } +local function p(amp,scale,seed) + return { + scale=scale, + amp=amp, + gen=noise.PerlinNoise:make(seed) + } +end -- whether there is a tile there or not -local surface_ng = noise.NoiseAgg:make{p(1,20),p(0.5,15)} +local surface_ng = noise.NoiseAgg:make{p(1,20,1),p(0.7,5,2)} -- if there is a tile there, what color should it be -local color_ng = noise.NoiseAgg:make{p(1,20),p(0.5,15)} +local color_ng = noise.NoiseAgg:make{p(1,20,3),p(0.5,15,4)} local function gen_chunk(chpos) -- cgit v1.2.3