nodecore-skyblock/nc_sky_isgen/init.lua

533 lines
14 KiB
Lua
Raw Normal View History

2019-10-23 03:57:37 +02:00
--nothing--
2019-12-20 19:50:58 +01:00
local S = minetest.get_translator("nc_sky_isgen")
2019-10-23 03:57:37 +02:00
local grass = "nc_terrain:dirt_with_grass"
local dirt = "nc_terrain:dirt"
local tree = "nc_tree:eggcorn_planted"
2019-10-23 03:57:37 +02:00
local stone = "nc_terrain:stone"
local queue = {}
2019-12-20 19:50:58 +01:00
local cooldown = 120
local cooldowns = {}
2019-10-23 03:57:37 +02:00
local function maxval(octaves,persistence,scale)
2019-12-20 19:50:58 +01:00
local m = 1
local poc = 1
2019-10-23 03:57:37 +02:00
if octaves > 1 then
for n=2,octaves do
poc = poc*persistence
m=m+poc
end
end
2019-12-20 19:50:58 +01:00
return scale/m
2019-10-23 03:57:37 +02:00
end
2019-12-20 19:50:58 +01:00
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"
}
2019-10-23 03:57:37 +02:00
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
2019-10-23 03:57:37 +02:00
local n = 0
local c = 0
local cm = (r*2+1)^3
2019-12-20 19:50:58 +01:00
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)
2019-10-23 03:57:37 +02:00
end
local grasses = {}
2019-12-20 19:50:58 +01:00
local stones = {}
2019-10-23 03:57:37 +02:00
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
2019-12-20 19:50:58 +01:00
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}))
2019-10-23 03:57:37 +02:00
local oc = (o > 0.4)
local oc2 = o2 > 0.4
2019-12-20 19:50:58 +01:00
local og = (o > 0.5) and o2 > 0.4
2019-10-23 03:57:37 +02:00
if oc then
n=n+1
local nam = dirt
if not og and not oc2 then
nam = grass
2019-12-20 19:50:58 +01:00
table.insert(grasses,ppos)
2019-10-23 03:57:37 +02:00
end
if og then
nam = stone
2019-12-20 19:50:58 +01:00
table.insert(stones,ppos)
2019-10-23 03:57:37 +02:00
end
2019-12-20 19:50:58 +01:00
minetest.set_node(ppos,{name=nam})
2019-10-23 03:57:37 +02:00
else
n=n+0.01
end
if n > 1000 then
n=0
--coroutine.yield()
end
end
end
end
2019-12-20 19:50:58 +01:00
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})
2019-12-05 06:01:18 +01:00
local meta = minetest.get_meta(v)
meta:set_float("growth",5000)
end
end
end)
2019-10-23 03:57:37 +02:00
end
2019-12-05 06:01:18 +01:00
local f,abs = math.floor, math.abs
2019-10-23 03:57:37 +02:00
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)}
2019-12-20 19:50:58 +01:00
island(pos,48,name)
ref:set_pos({x=pos.x,y=pos.y+256,z=pos.z})
2019-10-23 03:57:37 +02:00
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()
2019-10-23 03:57:37 +02:00
end
local air_c = minetest.get_content_id("air")
2019-12-20 19:50:58 +01:00
local ignore_c = minetest.get_content_id("ignore")
local function island_range(x,y,z)
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
local d = dat[ar:index(x,y,z)]
if d ~= air_c and d ~= ignore_c then
return false
end
end
end
2019-10-23 03:57:37 +02:00
end
return true
2019-10-23 03:57:37 +02:00
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
2019-10-23 03:57:37 +02:00
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
2019-12-21 06:14:08 +01:00
x,z = x+math.random(-32,32),z+math.random(-32,32)
y=256+math.random(-64,64)
local ok = checkpos(x,y,z)
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
while not ok do
2019-12-21 06:14:08 +01:00
x,z = x+math.random(-32,32),z+math.random(-32,32)
y=256+math.random(-64,64)
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()
2019-10-23 03:57:37 +02:00
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()
2019-12-21 06:14:08 +01:00
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", {
2019-12-20 19:50:58 +01:00
description = S"Register island",
privs = {server = true},
func = function(name,param)
if get_standing_island(name) then
2019-12-20 19:50:58 +01:00
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()
2019-12-20 19:50:58 +01:00
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", {
2019-12-20 19:50:58 +01:00
description = S"Unregister island",
privs = {server = true},
func = function(name,param)
local is = get_standing_island(name)
if not is then
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"OK")
save()
end
})
minetest.register_chatcommand("assign", {
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"OK")
save()
end
})
minetest.register_chatcommand("unassign", {
2019-12-20 19:50:58 +01:00
description = S"Unassign this island",
privs = {server = true},
func = function(name,param)
local is = get_standing_island(name)
if not is then
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"No island here")
return
end
if is.t == cells then
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"OK")
save()
end
})
minetest.register_chatcommand("validate", {
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"OK")
else
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"No island here")
return
end
save()
end
})
minetest.register_chatcommand("invalidate", {
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"OK")
else
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"No island here")
return
end
save()
end
})
minetest.register_chatcommand("query", {
2019-12-20 19:50:58 +01:00
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
2019-12-20 19:50:58 +01:00
minetest.chat_send_player(name,S"No island here")
end
save()
end
})
minetest.register_chatcommand("reset",{
2019-12-20 19:50:58 +01:00
description = S"Get a new island",
privs = {interact = true},
func = function(name)
2019-12-20 19:50:58 +01:00
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
})
2019-10-23 03:57:37 +02:00
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)
2019-12-15 19:29:23 +01:00
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
2019-10-23 03:57:37 +02:00
end
end)