--nothing-- local S = minetest.get_translator("nc_sky_isgen") local grass = "nc_terrain:dirt_with_grass" local dirt = "nc_terrain:dirt" local tree = "nc_tree:eggcorn_planted" local stone = "nc_terrain:stone" local queue = {} local cooldown = 120 local cooldowns = {} local function maxval(octaves,persistence,scale) local m = 1 local poc = 1 if octaves > 1 then for n=2,octaves do poc = poc*persistence m=m+poc end end return scale/m end local function dist(x1,y1,z1, x2,y2,z2) local x,y,z = x2-x1, y2-y1, z2-z1 return (x*x+y*y+z*z)^0.5 end local function cosify(x) return 1-math.cos(x*math.pi/2) end local pers = 0.9 local oct = 4 local noise = PerlinNoise{ scale = maxval(oct,pers,32), spread = {x=64,y=64,z=64}, seed=1297, octaves = oct, persistence = pers, lacunarity = 2, flags = "eased" } local function island(pos,r) local x,y,z = pos.x,pos.y,pos.z minetest.emerge_area({x=x-r,y=y-r,z=z-r},{x=x+r,y=y+r,z=z+r},function(bp,act,crem) if crem > 0 then return end local n = 0 local c = 0 local cm = (r*2+1)^3 local function geto(x1,y1,z1,n) local r1 = 48+n*2-1 local dista = dist(0,0,0,x1,y1*3,z1) local m = math.max(0,1-dista/r1) local r2 = -r1 if y1 <= 0 and y1 >= r2 then local r3 = (1-math.sin(y1/r2*math.pi/2))*r1 local distb = dist(0,y1,0,x1,y1,z1) local m2 = math.max(0,1-distb/r3) m = math.max(m2,m) end return cosify(m) end local grasses = {} local stones = {} for x=-r,r do for z=-r,r do for y=-r,r do local xx,yy,zz = pos.x+x,pos.y+y,pos.z+z local ppos = {x=xx,y=yy,z=zz} local o,o2 = geto(x,y,z,noise:get_3d(ppos)),geto(x,y+1,z,noise:get_3d({x=xx,y=yy+1,z=zz})) local oc = (o > 0.4) local oc2 = o2 > 0.4 local og = (o > 0.5) and o2 > 0.4 if oc then n=n+1 local nam = dirt if not og and not oc2 then nam = grass table.insert(grasses,ppos) end if og then nam = stone table.insert(stones,ppos) end minetest.set_node(ppos,{name=nam}) else n=n+0.01 end if n > 1000 then n=0 --coroutine.yield() end end end end for n=1,24 do if #stones > 1 then local n = math.random(1,#stones) local v = table.remove(stones,n) minetest.set_node(v,{name="nc_crystal:ore"}) end if #stones > 1 then local n = math.random(1,#stones) local v = table.remove(stones,n) minetest.set_node(v,{name="nc_lux:stone"}) end end for n=1,8 do if #grasses > 1 then local n = math.random(1,#grasses) local v = table.remove(grasses,n) minetest.set_node(v,{name=tree}) local meta = minetest.get_meta(v) meta:set_float("growth",5000) end end end) end local f,abs = math.floor, math.abs local function spawn_island(name,pos) local ref = minetest.get_player_by_name(name) pos = {x=f(pos.x),y=f(pos.y),z=f(pos.z)} island(pos,48,name) ref:set_pos({x=pos.x,y=pos.y+256,z=pos.z}) end local store = minetest.get_mod_storage() local players = minetest.deserialize(store:get_string("players")) or {} local cells = minetest.deserialize(store:get_string("cells")) or {} local function save() store:set_string("players",minetest.serialize(players)) store:set_string("cells",minetest.serialize(cells)) end do local c = cells cells = {} for k,v in pairs(c) do if v.island then if v.valid and not v.name or v.name == "" then table.insert(cells,{pos=v.islandpos,valid=v.valid}) end else table.insert(cells,v) end end local p = players players = {} for k,v in pairs(p) do players[k] = {pos=v.islandpos or v.pos, valid = v.valid} end save() end local air_c = minetest.get_content_id("air") local ignore_c = minetest.get_content_id("ignore") local function island_range(x,y,z) return {x=x-64,y=y-64,z=z-64},{x=x+64,y=y+64,z=z+64} end local function checkpos(x,y,z) local vm = VoxelManip(island_range(x,y,z)) local emi,ema = vm:get_emerged_area() local dat = vm:get_data() local ar = VoxelArea:new{MinEdge=emi,MaxEdge=ema} for x = x-32,x+32 do for y = y-32,y+32 do for z = z-32,z+32 do local d = dat[ar:index(x,y,z)] if d ~= air_c and d ~= ignore_c then return false end end end end return true end local function intersect(a,b) local ap1,ap2 = a[1],a[2] local bp1,bp2 = b[1],b[2] local ax1,ay1,az1 = ap1.x,ap1.y,ap1.z local ax2,ay2,az2 = ap2.x,ap2.y,ap2.z local bx1,by1,bz1 = bp1.x,bp1.y,bp1.z local bx2,by2,bz2 = bp2.x,bp2.y,bp2.z return ax1 <= bx2 and ax2 >= bx1 and ay1 <= by2 and ay2 >= by1 and az1 <= bz2 and az2 >= bz1 end local function get_standing_island(name) local ref = minetest.get_player_by_name(name) local pos = ref:get_pos() local islands = {} for k,v in pairs(cells) do if intersect({island_range(v.pos.x,v.pos.y,v.pos.z)},{pos,pos}) then table.insert(islands,{pos=v.pos,owner=nil,valid = not not v.valid,t=cells,k=k}) end end for k,v in pairs(players) do if intersect({island_range(v.pos.x,v.pos.y,v.pos.z)},{pos,pos}) then table.insert(islands,{pos=v.pos,owner=k,valid = not not v.valid,t=players,k=k}) end end if #islands == 0 then return end local closesti = table.remove(islands) local closestl = vector.length(vector.subtract(closesti.pos,pos)) while #islands > 0 do local isl = table.remove(islands) local l = vector.length(vector.subtract(isl.pos,pos)) if l < closestl then closesti = isl closestl = l end end return closesti end local function gen_island_pos(name) local x,y,z = 0,0,0 x,z = x+math.random(-64,64),z+math.random(-64,64) y=256+math.random(-32,32) for k,isl in ipairs(cells) do if isl and isl.valid then table.remove(cells,k) local ip = isl.pos local ref = minetest.get_player_by_name(name) local pos = ip players[name] = {pos = pos, valid = false} save() pos = {x=f(pos.x),y=f(pos.y),z=f(pos.z)} ref:set_pos({x=pos.x,y=pos.y+256,z=pos.z}) return end end local ok = checkpos(x,y,z) while not ok do x,z = x+math.random(-64,64),z+math.random(-64,64) y=256+math.random(-32,32) ok = checkpos(x,y,z) end local ip = {x=x,y=y,z=z} spawn_island(name,ip) local pl = { pos = ip, valid = false } players[name] = pl save() end local updrate = 0.5 local to_upd = updrate minetest.register_globalstep(function(dt) for f,_ in pairs(queue) do local ok,err = coroutine.resume(f) if not ok then print(err) queue[f]=nil end end to_upd = to_upd-dt if to_upd <= 0 then to_upd = to_upd+updrate for k,ref in pairs(minetest.get_connected_players()) do local is = get_standing_island(ref:get_player_name()) if is and is.t == cells and not minetest.check_player_privs(ref,{server = true}) then cells[is.k].valid = false end local p = ref:get_pos() if p.y < -64 then ref:set_hp(ref:get_hp()-2,{reason="set_hp"}) if p.y < -128 then local land = players[ref:get_player_name()] local pos if land then pos = land.pos elseif minetest.check_player_privs(ref,{interact = true}) then gen_island_pos(ref:get_player_name()) end if pos then pos.y=pos.y+256 ref:set_pos(pos) end end end end end end) minetest.register_chatcommand("register", { description = S"Register island", privs = {server = true}, func = function(name,param) if get_standing_island(name) then minetest.chat_send_player(name,S"There is an island already") return end local ref = minetest.get_player_by_name(name) local pos = ref:get_pos() ip = {x=f(pos.x+.5),y=f(pos.y+.5),z=f(pos.z+.5)} table.insert(cells,{pos=ip, valid=false}) minetest.chat_send_player(name,"OK") save() end }) minetest.register_chatcommand("unregister", { description = S"Unregister island", privs = {server = true}, func = function(name,param) local is = get_standing_island(name) if not is then minetest.chat_send_player(name,S"No island here") return end if is.t == cells then cells[is.k] = nil end if is.t == players then local nam = is.owner players[nam] = nil end minetest.chat_send_player(name,S"OK") save() end }) minetest.register_chatcommand("assign", { description = S"Reassign this island", privs = {server = true}, func = function(name,param) local is = get_standing_island(name) if not minetest.get_player_by_name(param) then minetest.chat_send_player(name,S("No player @1",param)) return end if players[param] then local ois = players[param] table.insert(cells,{pos=ois.pos,valid = false}) players[param] = nil end if not is then minetest.chat_send_player(name,S"No island here") return else players[name] = {pos = is.pos, valid = is.valid} is.t[is.k] = nil end minetest.chat_send_player(name,S"OK") save() end }) minetest.register_chatcommand("unassign", { description = S"Unassign this island", privs = {server = true}, func = function(name,param) local is = get_standing_island(name) if not is then minetest.chat_send_player(name,S"No island here") return end if is.t == cells then minetest.chat_send_player(name,S"Island is already unassigned") return end if is.t == players then local nam = is.owner players[nam] = nil table.insert(cells,{pos=is.pos,valid=is.valid}) end minetest.chat_send_player(name,S"OK") save() end }) minetest.register_chatcommand("validate", { description = S"Make this island avaible for newcomers, if not owned by a player", privs = {server = true}, func = function(name,param) local is = get_standing_island(name) if is then is.t[is.k].valid = true minetest.chat_send_player(name,S"OK") else minetest.chat_send_player(name,S"No island here") return end save() end }) minetest.register_chatcommand("invalidate", { description = S"Make this island unavaible for newcomers", privs = {server = true}, func = function(name,param) local is = get_standing_island(name) if is then is.t[is.k].valid = false minetest.chat_send_player(name,S"OK") else minetest.chat_send_player(name,S"No island here") return end save() end }) minetest.register_chatcommand("query", { description = S"Query information about this island", func = function(name,param) local is = get_standing_island(name) if is then minetest.chat_send_player(name,"[") minetest.chat_send_player(name," owner: "..((is.owner == "" and "(none)" or is.owner) or "(none)")) minetest.chat_send_player(name," takeable: "..tostring(is.valid)) minetest.chat_send_player(name," pos: "..minetest.pos_to_string(is.pos)) minetest.chat_send_player(name,"]") else minetest.chat_send_player(name,S"No island here") end save() end }) minetest.register_chatcommand("reset",{ description = S"Get a new island", privs = {interact = true}, func = function(name) local utime = minetest.get_server_uptime() local cd = cooldowns[name] if cd and cd > utime then minetest.chat_send_player(name,S("You can't get a new island yet. Wait @1 secs.",(cd-utime))) return end cooldowns[name] = utime + cooldown local pl = players[name] if pl then players[name] = nil end gen_island_pos(name) end }) minetest.register_on_joinplayer(function(ref) local meta = ref:get_meta() local name = ref:get_player_name() if meta:get_string("islandpos") ~= "" then if not players[name] then local pos = minetest.string_to_pos(meta:get_string("islandpos")) local hascell = false for k,v in pairs(players) do if vector.length(vector.subtract(v.pos,pos)) < 8 then hascell = true break end end while true do local rem = false for k,v in pairs(cells) do if vector.length(vector.subtract(v.pos,pos)) < 8 then table.remove(cells,k) rem = true break end end if not rem then break end end if not hascell then local pl = { pos = pos, valid = false } players[name] = pl else gen_island_pos(name) end end save() meta:set_string("island","") meta:set_string("islandpos","") meta:set_string("islandrange","") else if not players[name] then gen_island_pos(name) save() else local p = players[name] if p.islandpos then players[name] = {pos = p.islandpos, valid = false} save() end local pos = players[name].pos local hascell = false for k,v in pairs(players) do if vector.length(vector.subtract(v.pos,pos)) < 8 and k ~= name then hascell = true break end end while true do local rem = false for k,v in pairs(cells) do if vector.length(vector.subtract(v.pos,pos)) < 8 then table.remove(cells,k) rem = true break end end if not rem then break end end if hascell then players[name] = nil gen_island_pos(name) end end end end)