mainly work on object scripting api
This commit is contained in:
parent
eef7bc3570
commit
9778347c7f
|
@ -1,7 +1,7 @@
|
||||||
-- Client-side code of the test lua object
|
-- Client-side code of the test lua object
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Some helper functions
|
-- Some helper functions and classes
|
||||||
--
|
--
|
||||||
|
|
||||||
function split(str, pat)
|
function split(str, pat)
|
||||||
|
@ -23,6 +23,7 @@ function split(str, pat)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- For debugging
|
||||||
function dump(o)
|
function dump(o)
|
||||||
if type(o) == 'table' then
|
if type(o) == 'table' then
|
||||||
local s = '{ '
|
local s = '{ '
|
||||||
|
@ -36,29 +37,90 @@ function dump(o)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function vector_subtract(a, b)
|
||||||
|
return {X=a.X-b.X, Y=a.Y-b.Y, Z=a.Z-b.Z}
|
||||||
|
end
|
||||||
|
|
||||||
|
function vector_add(a, b)
|
||||||
|
return {X=a.X+b.X, Y=a.Y+b.Y, Z=a.Z+b.Z}
|
||||||
|
end
|
||||||
|
|
||||||
|
function vector_multiply(a, d)
|
||||||
|
return {X=a.X*d, Y=a.Y*d, Z=a.Z*d}
|
||||||
|
end
|
||||||
|
|
||||||
|
SmoothTranslator = {}
|
||||||
|
SmoothTranslator.__index = SmoothTranslator
|
||||||
|
|
||||||
|
function SmoothTranslator.create()
|
||||||
|
local obj = {}
|
||||||
|
setmetatable(obj, SmoothTranslator)
|
||||||
|
obj.vect_old = {X=0, Y=0, Z=0}
|
||||||
|
obj.anim_counter = 0
|
||||||
|
obj.anim_time = 0
|
||||||
|
obj.anim_time_counter = 0
|
||||||
|
obj.vect_show = {X=0, Y=0, Z=0}
|
||||||
|
obj.vect_aim = {X=0, Y=0, Z=0}
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
function SmoothTranslator:update(vect_new)
|
||||||
|
self.vect_old = self.vect_show
|
||||||
|
self.vect_aim = vect_new
|
||||||
|
if self.anim_time < 0.001 or self.anim_time > 1.0 then
|
||||||
|
self.anim_time = self.anim_time_counter
|
||||||
|
else
|
||||||
|
self.anim_time = self.anim_time * 0.9 + self.anim_time_counter * 0.1
|
||||||
|
end
|
||||||
|
self.anim_time_counter = 0
|
||||||
|
self.anim_counter = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function SmoothTranslator:translate(dtime)
|
||||||
|
self.anim_time_counter = self.anim_time_counter + dtime
|
||||||
|
self.anim_counter = self.anim_counter + dtime
|
||||||
|
vect_move = vector_subtract(self.vect_aim, self.vect_old)
|
||||||
|
moveratio = 1.0
|
||||||
|
if self.anim_time > 0.001 then
|
||||||
|
moveratio = self.anim_time_counter / self.anim_time
|
||||||
|
end
|
||||||
|
if moveratio > 1.5 then
|
||||||
|
moveratio = 1.5
|
||||||
|
end
|
||||||
|
self.vect_show = vector_add(self.vect_old, vector_multiply(vect_move, moveratio))
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Actual code
|
-- Actual code
|
||||||
--
|
--
|
||||||
|
|
||||||
function step(self, dtime)
|
pos_trans = SmoothTranslator.create()
|
||||||
-- Some smoother animation could be done here
|
rot_trans = SmoothTranslator.create()
|
||||||
|
|
||||||
|
-- Callback functions
|
||||||
|
|
||||||
|
function on_step(self, dtime)
|
||||||
|
pos_trans:translate(dtime)
|
||||||
|
rot_trans:translate(dtime)
|
||||||
|
object_set_position(self, pos_trans.vect_show)
|
||||||
|
object_set_rotation(self, rot_trans.vect_show)
|
||||||
end
|
end
|
||||||
|
|
||||||
function process_message(self, data)
|
function on_process_message(self, data)
|
||||||
--print("client got message: " .. data)
|
--print("client got message: " .. data)
|
||||||
|
|
||||||
-- Receive our custom messages
|
-- Receive our custom messages
|
||||||
|
|
||||||
sp = split(data, " ")
|
sp = split(data, " ")
|
||||||
if sp[1] == "pos" then
|
if sp[1] == "pos" then
|
||||||
object_set_position(self, sp[2], sp[3], sp[4])
|
pos_trans:update({X=sp[2], Y=sp[3], Z=sp[4]})
|
||||||
end
|
end
|
||||||
if sp[1] == "rot" then
|
if sp[1] == "rot" then
|
||||||
object_set_rotation(self, sp[2], sp[3], sp[4])
|
rot_trans:update({X=sp[2], Y=sp[3], Z=sp[4]})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function initialize(self, data)
|
function on_initialize(self, data)
|
||||||
print("client object got initialization: " .. data)
|
print("client object got initialization: " .. data)
|
||||||
|
|
||||||
corners = {
|
corners = {
|
||||||
|
|
|
@ -1,24 +1,42 @@
|
||||||
-- Server-side code of the test lua object
|
-- Server-side code of the test lua object
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Some helper functions and classes
|
||||||
|
--
|
||||||
|
|
||||||
|
function vector_subtract(a, b)
|
||||||
|
return {X=a.X-b.X, Y=a.Y-b.Y, Z=a.Z-b.Z}
|
||||||
|
end
|
||||||
|
|
||||||
|
function vector_add(a, b)
|
||||||
|
return {X=a.X+b.X, Y=a.Y+b.Y, Z=a.Z+b.Z}
|
||||||
|
end
|
||||||
|
|
||||||
|
function vector_multiply(a, d)
|
||||||
|
return {X=a.X*d, Y=a.Y*d, Z=a.Z*d}
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Actual code
|
||||||
|
--
|
||||||
|
|
||||||
counter = 0
|
counter = 0
|
||||||
counter2 = 0
|
counter2 = 0
|
||||||
|
counter3 = 0
|
||||||
|
counter4 = 0
|
||||||
death_counter = 0
|
death_counter = 0
|
||||||
position = {X=math.random(-2,2),Y=6,Z=math.random(-2,2)}
|
-- This is got in initialization from object_get_base_position(self)
|
||||||
|
position = {X=0,Y=0,Z=0}
|
||||||
rotation = {X=0, Y=math.random(0,360), Z=0}
|
rotation = {X=0, Y=math.random(0,360), Z=0}
|
||||||
dir = 1
|
dir = 1
|
||||||
|
temp1 = 0
|
||||||
|
|
||||||
function step(self, dtime)
|
function on_step(self, dtime)
|
||||||
--[[if position.Y > 9.5 then
|
--[[if position.Y > 9.5 then
|
||||||
position.Y = 6
|
position.Y = 6
|
||||||
end
|
end
|
||||||
if position.Y < 5.5 then
|
if position.Y < 5.5 then
|
||||||
position.Y = 9
|
position.Y = 9]]
|
||||||
|
|
||||||
counter2 = counter2 - dtime
|
|
||||||
if counter2 < 0 then
|
|
||||||
counter2 = counter2 + 3
|
|
||||||
dir = -dir
|
|
||||||
end]]
|
|
||||||
|
|
||||||
-- Limit step to a sane value; it jumps a lot while the map generator
|
-- Limit step to a sane value; it jumps a lot while the map generator
|
||||||
-- is in action
|
-- is in action
|
||||||
|
@ -27,16 +45,19 @@ function step(self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returned value has these fields:
|
-- Returned value has these fields:
|
||||||
-- * bool walkable
|
|
||||||
-- * int content
|
-- * int content
|
||||||
n = object_get_node(self, position.X,position.Y-0.35,position.Z)
|
-- * int param1
|
||||||
if n.walkable then
|
-- * int param2
|
||||||
|
p = {X=position.X, Y=position.Y-0.35, Z=position.Z}
|
||||||
|
n = object_get_node(self, p)
|
||||||
|
f = get_content_features(n.content)
|
||||||
|
if f.walkable then
|
||||||
dir = 1
|
dir = 1
|
||||||
else
|
else
|
||||||
dir = -1
|
dir = -1
|
||||||
end
|
end
|
||||||
-- Keep the object approximately at ground level
|
-- Keep the object approximately at ground level
|
||||||
position.Y = position.Y + dtime * 1.0 * dir
|
position.Y = position.Y + dtime * 2.0 * dir
|
||||||
|
|
||||||
-- Move the object around
|
-- Move the object around
|
||||||
position.X = position.X + math.cos(math.pi+rotation.Y/180*math.pi)
|
position.X = position.X + math.cos(math.pi+rotation.Y/180*math.pi)
|
||||||
|
@ -46,15 +67,32 @@ function step(self, dtime)
|
||||||
|
|
||||||
-- This value has to be set; it determines to which player the
|
-- This value has to be set; it determines to which player the
|
||||||
-- object is near to and such
|
-- object is near to and such
|
||||||
object_set_base_position(self, position.X,position.Y,position.Z)
|
object_set_base_position(self, position)
|
||||||
|
|
||||||
rotation.Y = rotation.Y + dtime * 180
|
counter4 = counter4 - dtime
|
||||||
|
if counter4 < 0 then
|
||||||
|
counter4 = counter4 + math.random(0.5,8)
|
||||||
|
-- Mess around with the map
|
||||||
|
np = vector_add(position, {X=0,Y=0,Z=0})
|
||||||
|
object_place_node(self, np, {content=0})
|
||||||
|
-- A node could be digged out with this:
|
||||||
|
-- object_dig_node(self, np)
|
||||||
|
end
|
||||||
|
|
||||||
|
counter3 = counter3 - dtime
|
||||||
|
if counter3 < 0 then
|
||||||
|
counter3 = counter3 + math.random(1,4)
|
||||||
|
rotation.Y = rotation.Y + math.random(-180, 180)
|
||||||
|
end
|
||||||
|
|
||||||
-- Send some custom messages at a custom interval
|
-- Send some custom messages at a custom interval
|
||||||
|
|
||||||
counter = counter - dtime
|
counter = counter - dtime
|
||||||
if counter < 0 then
|
if counter < 0 then
|
||||||
counter = counter + 0.175
|
counter = counter + 0.25
|
||||||
|
if counter < 0 then
|
||||||
|
counter = 0
|
||||||
|
end
|
||||||
|
|
||||||
message = "pos " .. position.X .. " " .. position.Y .. " " .. position.Z
|
message = "pos " .. position.X .. " " .. position.Y .. " " .. position.Z
|
||||||
object_add_message(self, message)
|
object_add_message(self, message)
|
||||||
|
@ -63,6 +101,20 @@ function step(self, dtime)
|
||||||
object_add_message(self, message)
|
object_add_message(self, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Mess around with the map
|
||||||
|
--[[counter2 = counter2 - dtime
|
||||||
|
if counter2 < 0 then
|
||||||
|
counter2 = counter2 + 3
|
||||||
|
if temp1 == 0 then
|
||||||
|
temp1 = 1
|
||||||
|
object_dig_node(self, {X=0,Y=1,Z=0})
|
||||||
|
else
|
||||||
|
temp1 = 0
|
||||||
|
n = {content=1}
|
||||||
|
object_place_node(self, {X=0,Y=5,Z=0}, n)
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
-- Remove the object after some time
|
-- Remove the object after some time
|
||||||
death_counter = death_counter + dtime
|
death_counter = death_counter + dtime
|
||||||
if death_counter > 30 then
|
if death_counter > 30 then
|
||||||
|
@ -72,19 +124,31 @@ function step(self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This stuff is passed to a newly created client-side counterpart of this object
|
-- This stuff is passed to a newly created client-side counterpart of this object
|
||||||
function get_client_init_data(self)
|
function on_get_client_init_data(self)
|
||||||
|
-- Just return some data for testing
|
||||||
return "result of get_client_init_data"
|
return "result of get_client_init_data"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This should return some data that mostly saves the state of this object
|
-- This should return some data that mostly saves the state of this object
|
||||||
-- Not implemented yet
|
-- Not completely implemented yet
|
||||||
function get_server_init_data(self)
|
function on_get_server_init_data(self)
|
||||||
|
-- Just return some data for testing
|
||||||
return "result of get_server_init_data"
|
return "result of get_server_init_data"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- At reload time, the output of get_server_init_data is passed to this
|
-- When the object is loaded from scratch, this is called before the first
|
||||||
-- Not implemented yet
|
-- on_step(). Data is an empty string or the output of an object spawner
|
||||||
function initialize(self, data)
|
-- hook, but such things are not yet implemented.
|
||||||
|
--
|
||||||
|
-- At reload time, the last output of get_server_init_data is passed as data.
|
||||||
|
--
|
||||||
|
-- This should initialize the position of the object to the value returned
|
||||||
|
-- by object_get_base_position(self)
|
||||||
|
--
|
||||||
|
-- Not completely implemented yet
|
||||||
|
--
|
||||||
|
function on_initialize(self, data)
|
||||||
print("server object got initialization: " .. data)
|
print("server object got initialization: " .. data)
|
||||||
|
position = object_get_base_position(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#screenW = 800
|
#screenW = 800
|
||||||
#screenH = 600
|
#screenH = 600
|
||||||
#port = 30000
|
#port = 30000
|
||||||
#address = kray.dy.fi
|
#address =
|
||||||
#name =
|
#name =
|
||||||
|
|
||||||
# Whether to try to fog out the border of the visible area
|
# Whether to try to fog out the border of the visible area
|
||||||
|
@ -44,14 +44,14 @@
|
||||||
# Server side stuff
|
# Server side stuff
|
||||||
#
|
#
|
||||||
|
|
||||||
#map-dir = /home/palle/custom_map
|
# Set to true to enable experimental features
|
||||||
|
#enable_experimental = false
|
||||||
|
|
||||||
#plants_amount = 1.0
|
#map-dir = /home/palle/custom_map
|
||||||
#ravines_amount = 1.0
|
|
||||||
#coal_amount = 1.0
|
|
||||||
|
|
||||||
# Set to true to enable creative mode (unlimited inventory)
|
# Set to true to enable creative mode (unlimited inventory)
|
||||||
#creative_mode = false
|
#creative_mode = false
|
||||||
|
|
||||||
# Player and object positions are sent at intervals specified by this
|
# Player and object positions are sent at intervals specified by this
|
||||||
#objectdata_inverval = 0.2
|
#objectdata_inverval = 0.2
|
||||||
|
|
||||||
|
|
|
@ -989,27 +989,14 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||||
12000 = midday
|
12000 = midday
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
const s32 daylength = 16;
|
u32 dr = time_to_daynight_ratio(m_time_of_day.get());
|
||||||
const s32 nightlength = 6;
|
|
||||||
const s32 daytimelength = 8;
|
|
||||||
s32 d = daylength;
|
|
||||||
s32 t = (((m_time_of_day.get())%24000)/(24000/d));
|
|
||||||
u32 dr;
|
|
||||||
if(t < nightlength/2 || t >= d - nightlength/2)
|
|
||||||
dr = 300;
|
|
||||||
else if(t >= d/2 - daytimelength/2 && t < d/2 + daytimelength/2)
|
|
||||||
dr = 1000;
|
|
||||||
else
|
|
||||||
dr = 750;
|
|
||||||
|
|
||||||
dstream<<"time_of_day="<<m_time_of_day.get()
|
dstream<<"Client: time_of_day="<<m_time_of_day.get()
|
||||||
<<", t="<<t
|
|
||||||
<<", dr="<<dr
|
<<", dr="<<dr
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
if(dr != m_env.getDayNightRatio())
|
if(dr != m_env.getDayNightRatio())
|
||||||
{
|
{
|
||||||
//dstream<<"dr="<<dr<<std::endl;
|
|
||||||
dout_client<<DTIME<<"Client: changing day-night ratio"<<std::endl;
|
dout_client<<DTIME<<"Client: changing day-night ratio"<<std::endl;
|
||||||
m_env.setDayNightRatio(dr);
|
m_env.setDayNightRatio(dr);
|
||||||
m_env.expireMeshes(true);
|
m_env.expireMeshes(true);
|
||||||
|
@ -1595,7 +1582,7 @@ void Client::addNode(v3s16 p, MapNode n)
|
||||||
|
|
||||||
void Client::updateCamera(v3f pos, v3f dir)
|
void Client::updateCamera(v3f pos, v3f dir)
|
||||||
{
|
{
|
||||||
m_env.getMap().updateCamera(pos, dir);
|
m_env.getClientMap().updateCamera(pos, dir);
|
||||||
camera_position = pos;
|
camera_position = pos;
|
||||||
camera_direction = dir;
|
camera_direction = dir;
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,35 +175,36 @@ extern "C"{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Functions for calling from script:
|
|
||||||
|
|
||||||
object_set_position(self, x, y, z)
|
|
||||||
object_set_rotation(self, x, y, z)
|
|
||||||
object_add_to_mesh(self, image, corners, backface_culling)
|
|
||||||
object_clear_mesh(self)
|
|
||||||
|
|
||||||
Callbacks in script:
|
Callbacks in script:
|
||||||
|
|
||||||
step(self, dtime)
|
on_step(self, dtime)
|
||||||
process_message(self, data)
|
on_process_message(self, data)
|
||||||
initialize(self, data)
|
on_initialize(self, data)
|
||||||
TODO:
|
TODO:
|
||||||
string status_text(self)
|
string on_get_info_text(self)
|
||||||
|
on_block_removed_near({X=,Y=,Z=}, node)
|
||||||
|
on_block_placed_near({X=,Y=,Z=}, node)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object_set_position(self, x, y, z)
|
object_set_position(self, p)
|
||||||
*/
|
*/
|
||||||
static int lf_object_set_position(lua_State *L)
|
static int lf_object_set_position(lua_State *L)
|
||||||
{
|
{
|
||||||
// 4: z
|
// 2: position
|
||||||
lua_Number z = lua_tonumber(L, -1);
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number x = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 3: y
|
lua_pushstring(L, "Y");
|
||||||
|
lua_gettable(L, -2);
|
||||||
lua_Number y = lua_tonumber(L, -1);
|
lua_Number y = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 2: x
|
lua_pushstring(L, "Z");
|
||||||
lua_Number x = lua_tonumber(L, -1);
|
lua_gettable(L, -2);
|
||||||
|
lua_Number z = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 1: self
|
// 1: self
|
||||||
LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
|
LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
|
||||||
|
@ -217,18 +218,24 @@ static int lf_object_set_position(lua_State *L)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object_set_rotation(self, x, y, z)
|
object_set_rotation(self, p)
|
||||||
*/
|
*/
|
||||||
static int lf_object_set_rotation(lua_State *L)
|
static int lf_object_set_rotation(lua_State *L)
|
||||||
{
|
{
|
||||||
// 4: z
|
// 2: position
|
||||||
lua_Number z = lua_tonumber(L, -1);
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number x = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 3: y
|
lua_pushstring(L, "Y");
|
||||||
|
lua_gettable(L, -2);
|
||||||
lua_Number y = lua_tonumber(L, -1);
|
lua_Number y = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 2: x
|
lua_pushstring(L, "Z");
|
||||||
lua_Number x = lua_tonumber(L, -1);
|
lua_gettable(L, -2);
|
||||||
|
lua_Number z = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 1: self
|
// 1: self
|
||||||
LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
|
LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
|
||||||
|
@ -381,7 +388,7 @@ void LuaCAO::step(float dtime)
|
||||||
Call step(self, dtime) from lua
|
Call step(self, dtime) from lua
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *funcname = "step";
|
const char *funcname = "on_step";
|
||||||
lua_getglobal(L, funcname);
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
|
@ -413,7 +420,7 @@ void LuaCAO::processMessage(const std::string &data)
|
||||||
Call process_message(self, data) from lua
|
Call process_message(self, data) from lua
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *funcname = "process_message";
|
const char *funcname = "on_process_message";
|
||||||
lua_getglobal(L, funcname);
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
|
@ -462,7 +469,7 @@ void LuaCAO::initialize(const std::string &data)
|
||||||
Call initialize(self, data) in the script
|
Call initialize(self, data) in the script
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *funcname = "initialize";
|
const char *funcname = "on_initialize";
|
||||||
lua_getglobal(L, funcname);
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,7 +51,9 @@ void set_default_settings()
|
||||||
g_settings.setDefault("fast_move", "false");
|
g_settings.setDefault("fast_move", "false");
|
||||||
|
|
||||||
// Server stuff
|
// Server stuff
|
||||||
g_settings.setDefault("creative_mode", "false");
|
g_settings.setDefault("fast_move", "false");
|
||||||
|
|
||||||
|
g_settings.setDefault("enable_experimental", "false");
|
||||||
|
|
||||||
g_settings.setDefault("objectdata_interval", "0.2");
|
g_settings.setDefault("objectdata_interval", "0.2");
|
||||||
g_settings.setDefault("active_object_range", "2");
|
g_settings.setDefault("active_object_range", "2");
|
||||||
|
|
|
@ -96,6 +96,25 @@ Player * Environment::getPlayer(const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Player * Environment::getRandomConnectedPlayer()
|
||||||
|
{
|
||||||
|
core::list<Player*> connected_players = getPlayers(true);
|
||||||
|
u32 chosen_one = myrand() % connected_players.size();
|
||||||
|
u32 j = 0;
|
||||||
|
for(core::list<Player*>::Iterator
|
||||||
|
i = connected_players.begin();
|
||||||
|
i != connected_players.end(); i++)
|
||||||
|
{
|
||||||
|
if(j == chosen_one)
|
||||||
|
{
|
||||||
|
Player *player = *i;
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
core::list<Player*> Environment::getPlayers()
|
core::list<Player*> Environment::getPlayers()
|
||||||
{
|
{
|
||||||
return m_players;
|
return m_players;
|
||||||
|
@ -147,8 +166,9 @@ u32 Environment::getDayNightRatio()
|
||||||
ServerEnvironment
|
ServerEnvironment
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ServerEnvironment::ServerEnvironment(ServerMap *map):
|
ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
|
||||||
m_map(map),
|
m_map(map),
|
||||||
|
m_server(server),
|
||||||
m_random_spawn_timer(0)
|
m_random_spawn_timer(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -382,6 +402,9 @@ void ServerEnvironment::step(float dtime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(g_settings.getBool("enable_experimental"))
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Step active objects
|
Step active objects
|
||||||
*/
|
*/
|
||||||
|
@ -445,19 +468,36 @@ void ServerEnvironment::step(float dtime)
|
||||||
v3f(myrand_range(-2*BS,2*BS), BS*5, myrand_range(-2*BS,2*BS)));*/
|
v3f(myrand_range(-2*BS,2*BS), BS*5, myrand_range(-2*BS,2*BS)));*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create a Lua ServerActiveObject somewhere near the origin
|
Find some position
|
||||||
*/
|
*/
|
||||||
LuaSAO *obj = new LuaSAO(this, 0,
|
|
||||||
v3f(myrand_range(-2*BS,2*BS),
|
/*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
|
||||||
myrand_range(2*BS,9*BS),
|
s16 y = 1 + getServerMap().findGroundLevel(p2d);
|
||||||
myrand_range(-2*BS,2*BS))
|
v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
|
||||||
|
|
||||||
|
Player *player = getRandomConnectedPlayer();
|
||||||
|
v3f pos(0,0,0);
|
||||||
|
if(player)
|
||||||
|
pos = player->getPosition();
|
||||||
|
pos += v3f(
|
||||||
|
myrand_range(-5,5)*BS,
|
||||||
|
0,
|
||||||
|
myrand_range(-5,5)*BS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a LuaSAO (ServerActiveObject)
|
||||||
|
*/
|
||||||
|
|
||||||
|
LuaSAO *obj = new LuaSAO(this, 0, pos);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Select a random type for it
|
Select a random type for it
|
||||||
*/
|
*/
|
||||||
std::string objectdir = porting::getDataPath("luaobjects");
|
std::string objectdir = porting::getDataPath("luaobjects");
|
||||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(objectdir);
|
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(objectdir);
|
||||||
|
if(dirlist.size() > 0)
|
||||||
|
{
|
||||||
u32 selected_i = myrand_range(0, dirlist.size()-1);
|
u32 selected_i = myrand_range(0, dirlist.size()-1);
|
||||||
std::string selected_name = "";
|
std::string selected_name = "";
|
||||||
selected_name = dirlist[selected_i].name;
|
selected_name = dirlist[selected_i].name;
|
||||||
|
@ -469,11 +509,14 @@ void ServerEnvironment::step(float dtime)
|
||||||
/*
|
/*
|
||||||
Load the scripts for the type
|
Load the scripts for the type
|
||||||
*/
|
*/
|
||||||
obj->loadScripts(selected_name.c_str());
|
obj->initializeFromNothing(selected_name.c_str());
|
||||||
|
|
||||||
// Add the object to the environment
|
// Add the object to the environment
|
||||||
addActiveObject(obj);
|
addActiveObject(obj);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // enable_experimental
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
|
ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
void removePlayer(u16 peer_id);
|
void removePlayer(u16 peer_id);
|
||||||
Player * getPlayer(u16 peer_id);
|
Player * getPlayer(u16 peer_id);
|
||||||
Player * getPlayer(const char *name);
|
Player * getPlayer(const char *name);
|
||||||
|
Player * getRandomConnectedPlayer();
|
||||||
core::list<Player*> getPlayers();
|
core::list<Player*> getPlayers();
|
||||||
core::list<Player*> getPlayers(bool ignore_disconnected);
|
core::list<Player*> getPlayers(bool ignore_disconnected);
|
||||||
void printPlayers(std::ostream &o);
|
void printPlayers(std::ostream &o);
|
||||||
|
@ -79,10 +80,12 @@ protected:
|
||||||
|
|
||||||
#include "serverobject.h"
|
#include "serverobject.h"
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
class ServerEnvironment : public Environment
|
class ServerEnvironment : public Environment
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ServerEnvironment(ServerMap *map);
|
ServerEnvironment(ServerMap *map, Server *server);
|
||||||
~ServerEnvironment();
|
~ServerEnvironment();
|
||||||
|
|
||||||
Map & getMap()
|
Map & getMap()
|
||||||
|
@ -95,6 +98,11 @@ public:
|
||||||
return *m_map;
|
return *m_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Server * getServer()
|
||||||
|
{
|
||||||
|
return m_server;
|
||||||
|
}
|
||||||
|
|
||||||
void step(f32 dtime);
|
void step(f32 dtime);
|
||||||
|
|
||||||
void serializePlayers(const std::string &savedir);
|
void serializePlayers(const std::string &savedir);
|
||||||
|
@ -140,6 +148,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ServerMap *m_map;
|
ServerMap *m_map;
|
||||||
|
Server *m_server;
|
||||||
core::map<u16, ServerActiveObject*> m_active_objects;
|
core::map<u16, ServerActiveObject*> m_active_objects;
|
||||||
Queue<ActiveObjectMessage> m_active_object_messages;
|
Queue<ActiveObjectMessage> m_active_object_messages;
|
||||||
float m_random_spawn_timer;
|
float m_random_spawn_timer;
|
||||||
|
|
27
src/main.cpp
27
src/main.cpp
|
@ -199,15 +199,6 @@ FIXME: Server went into some infinite PeerNotFoundException loop
|
||||||
Objects:
|
Objects:
|
||||||
--------
|
--------
|
||||||
|
|
||||||
TODO: Better handling of objects and mobs
|
|
||||||
- Scripting?
|
|
||||||
- There has to be some way to do it with less messy code
|
|
||||||
- Make separate classes for client and server
|
|
||||||
- Client should not discriminate between blocks, server should
|
|
||||||
- Make other players utilize the same framework
|
|
||||||
- This is also needed for objects that don't get sent to client
|
|
||||||
but are used for triggers etc
|
|
||||||
|
|
||||||
TODO: There has to be some better way to handle static objects than to
|
TODO: There has to be some better way to handle static objects than to
|
||||||
send them all the time. This affects signs and item objects.
|
send them all the time. This affects signs and item objects.
|
||||||
SUGG: Signs could be done in the same way as torches. For this, blocks
|
SUGG: Signs could be done in the same way as torches. For this, blocks
|
||||||
|
@ -262,6 +253,7 @@ Doing now (most important at the top):
|
||||||
* not done
|
* not done
|
||||||
|
|
||||||
=== Fixmes
|
=== Fixmes
|
||||||
|
* Check the fixmes in the list above
|
||||||
* Make server find the spawning place from the real map data, not from
|
* Make server find the spawning place from the real map data, not from
|
||||||
the heightmap
|
the heightmap
|
||||||
- But the changing borders of chunk have to be avoided, because
|
- But the changing borders of chunk have to be avoided, because
|
||||||
|
@ -269,13 +261,16 @@ Doing now (most important at the top):
|
||||||
* Make the generator to run in background and not blocking block
|
* Make the generator to run in background and not blocking block
|
||||||
placement and transfer
|
placement and transfer
|
||||||
* only_from_disk might not work anymore - check and fix it.
|
* only_from_disk might not work anymore - check and fix it.
|
||||||
* Check the fixmes in the list above
|
|
||||||
|
|
||||||
=== Making it more portable
|
=== Making it more portable
|
||||||
* Some MSVC: std::sto* are defined without a namespace and collide
|
* Some MSVC: std::sto* are defined without a namespace and collide
|
||||||
with the ones in utility.h
|
with the ones in utility.h
|
||||||
|
|
||||||
=== Features
|
=== Features
|
||||||
|
* Map should make the appropriate MapEditEvents
|
||||||
|
* Add a global Lua spawn handler and such
|
||||||
|
* Get rid of MapBlockObjects
|
||||||
|
* Other players could be sent to clients as LuaCAOs
|
||||||
* Add mud underground
|
* Add mud underground
|
||||||
* Make an "environment metafile" to store at least time of day
|
* Make an "environment metafile" to store at least time of day
|
||||||
* Move digging property stuff from material.{h,cpp} to mapnode.cpp...
|
* Move digging property stuff from material.{h,cpp} to mapnode.cpp...
|
||||||
|
@ -283,17 +278,15 @@ Doing now (most important at the top):
|
||||||
* Add some kind of erosion and other stuff that now is possible
|
* Add some kind of erosion and other stuff that now is possible
|
||||||
* Make client to fetch stuff asynchronously
|
* Make client to fetch stuff asynchronously
|
||||||
- Needs method SyncProcessData
|
- Needs method SyncProcessData
|
||||||
* Fix the problem with the server constantly saving one or a few
|
|
||||||
blocks? List the first saved block, maybe it explains.
|
|
||||||
- It is probably caused by oscillating water
|
|
||||||
* Water doesn't start flowing after map generation like it should
|
|
||||||
- Are there still problems?
|
|
||||||
* Better water generation (spread it to underwater caverns but don't
|
* Better water generation (spread it to underwater caverns but don't
|
||||||
fill dungeons that don't touch big water masses)
|
fill dungeons that don't touch big water masses)
|
||||||
* When generating a chunk and the neighboring chunk doesn't have mud
|
* When generating a chunk and the neighboring chunk doesn't have mud
|
||||||
and stuff yet and the ground is fairly flat, the mud will flow to
|
and stuff yet and the ground is fairly flat, the mud will flow to
|
||||||
the other chunk making nasty straight walls when the other chunk
|
the other chunk making nasty straight walls when the other chunk
|
||||||
is generated. Fix it.
|
is generated. Fix it.
|
||||||
|
* Fix the problem with the server constantly saving one or a few
|
||||||
|
blocks? List the first saved block, maybe it explains.
|
||||||
|
- It is probably caused by oscillating water
|
||||||
* Make a small history check to transformLiquids to detect and log
|
* Make a small history check to transformLiquids to detect and log
|
||||||
continuous oscillations, in such detail that they can be fixed.
|
continuous oscillations, in such detail that they can be fixed.
|
||||||
* Combine meshes to bigger ones in ClientMap and set them EHM_STATIC
|
* Combine meshes to bigger ones in ClientMap and set them EHM_STATIC
|
||||||
|
@ -1796,7 +1789,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
dstream<<"Created main menu"<<std::endl;
|
dstream<<"Created main menu"<<std::endl;
|
||||||
|
|
||||||
while(g_device->run())
|
while(g_device->run() && kill == false)
|
||||||
{
|
{
|
||||||
// Run global IrrlichtWrapper's main thread processing stuff
|
// Run global IrrlichtWrapper's main thread processing stuff
|
||||||
g_irrlicht->Run();
|
g_irrlicht->Run();
|
||||||
|
@ -1811,7 +1804,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Break out of menu-game loop to shut down cleanly
|
// Break out of menu-game loop to shut down cleanly
|
||||||
if(g_device->run() == false)
|
if(g_device->run() == false || kill == true)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
dstream<<"Dropping main menu"<<std::endl;
|
dstream<<"Dropping main menu"<<std::endl;
|
||||||
|
|
202
src/map.cpp
202
src/map.cpp
|
@ -34,30 +34,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
Map::Map(std::ostream &dout):
|
Map::Map(std::ostream &dout):
|
||||||
m_dout(dout),
|
m_dout(dout),
|
||||||
m_camera_position(0,0,0),
|
|
||||||
m_camera_direction(0,0,1),
|
|
||||||
m_sector_cache(NULL)
|
m_sector_cache(NULL)
|
||||||
{
|
{
|
||||||
m_sector_mutex.Init();
|
m_sector_mutex.Init();
|
||||||
m_camera_mutex.Init();
|
|
||||||
assert(m_sector_mutex.IsInitialized());
|
assert(m_sector_mutex.IsInitialized());
|
||||||
assert(m_camera_mutex.IsInitialized());
|
|
||||||
|
|
||||||
// Get this so that the player can stay on it at first
|
|
||||||
//getSector(v2s16(0,0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map::~Map()
|
Map::~Map()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Stop updater thread
|
Free all MapSectors
|
||||||
*/
|
|
||||||
/*updater.setRun(false);
|
|
||||||
while(updater.IsRunning())
|
|
||||||
sleep_s(1);*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Free all MapSectors.
|
|
||||||
*/
|
*/
|
||||||
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
|
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
|
||||||
for(; i.atEnd() == false; i++)
|
for(; i.atEnd() == false; i++)
|
||||||
|
@ -67,6 +53,29 @@ Map::~Map()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::addEventReceiver(MapEventReceiver *event_receiver)
|
||||||
|
{
|
||||||
|
m_event_receivers.insert(event_receiver, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::removeEventReceiver(MapEventReceiver *event_receiver)
|
||||||
|
{
|
||||||
|
if(m_event_receivers.find(event_receiver) == NULL)
|
||||||
|
return;
|
||||||
|
m_event_receivers.remove(event_receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::dispatchEvent(MapEditEvent *event)
|
||||||
|
{
|
||||||
|
for(core::map<MapEventReceiver*, bool>::Iterator
|
||||||
|
i = m_event_receivers.getIterator();
|
||||||
|
i.atEnd()==false; i++)
|
||||||
|
{
|
||||||
|
MapEventReceiver* event_receiver = i.getNode()->getKey();
|
||||||
|
event_receiver->onMapEditEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
|
MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
|
||||||
{
|
{
|
||||||
if(m_sector_cache != NULL && p == m_sector_cache_p){
|
if(m_sector_cache != NULL && p == m_sector_cache_p){
|
||||||
|
@ -145,34 +154,6 @@ MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
|
||||||
return block;
|
return block;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
f32 Map::getGroundHeight(v2s16 p, bool generate)
|
|
||||||
{
|
|
||||||
try{
|
|
||||||
v2s16 sectorpos = getNodeSectorPos(p);
|
|
||||||
MapSector * sref = getSectorNoGenerate(sectorpos);
|
|
||||||
v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
|
|
||||||
f32 y = sref->getGroundHeight(relpos);
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
catch(InvalidPositionException &e)
|
|
||||||
{
|
|
||||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Map::setGroundHeight(v2s16 p, f32 y, bool generate)
|
|
||||||
{
|
|
||||||
/*m_dout<<DTIME<<"Map::setGroundHeight(("
|
|
||||||
<<p.X<<","<<p.Y
|
|
||||||
<<"), "<<y<<")"<<std::endl;*/
|
|
||||||
v2s16 sectorpos = getNodeSectorPos(p);
|
|
||||||
MapSector * sref = getSectorNoGenerate(sectorpos);
|
|
||||||
v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
|
|
||||||
//sref->mutex.Lock();
|
|
||||||
sref->setGroundHeight(relpos, y);
|
|
||||||
//sref->mutex.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Map::isNodeUnderground(v3s16 p)
|
bool Map::isNodeUnderground(v3s16 p)
|
||||||
{
|
{
|
||||||
v3s16 blockpos = getNodeBlockPos(p);
|
v3s16 blockpos = getNodeBlockPos(p);
|
||||||
|
@ -947,8 +928,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
||||||
assert(block != NULL);
|
assert(block != NULL);
|
||||||
modified_blocks.insert(blockpos, block);
|
modified_blocks.insert(blockpos, block);
|
||||||
|
|
||||||
if(isValidPosition(p) == false)
|
assert(isValidPosition(p));
|
||||||
throw;
|
|
||||||
|
|
||||||
// Unlight neighbours of node.
|
// Unlight neighbours of node.
|
||||||
// This means setting light of all consequent dimmer nodes
|
// This means setting light of all consequent dimmer nodes
|
||||||
|
@ -1161,7 +1141,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
catch(InvalidPositionException &e)
|
||||||
{
|
{
|
||||||
throw;
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,6 +1201,63 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Map::addNodeWithEvent(v3s16 p, MapNode n)
|
||||||
|
{
|
||||||
|
MapEditEvent event;
|
||||||
|
event.type = MEET_ADDNODE;
|
||||||
|
event.p = p;
|
||||||
|
event.n = n;
|
||||||
|
|
||||||
|
bool succeeded = true;
|
||||||
|
try{
|
||||||
|
core::map<v3s16, MapBlock*> modified_blocks;
|
||||||
|
addNodeAndUpdate(p, n, modified_blocks);
|
||||||
|
|
||||||
|
// Copy modified_blocks to event
|
||||||
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
|
i = modified_blocks.getIterator();
|
||||||
|
i.atEnd()==false; i++)
|
||||||
|
{
|
||||||
|
event.modified_blocks.insert(i.getNode()->getKey(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(InvalidPositionException &e){
|
||||||
|
succeeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(&event);
|
||||||
|
|
||||||
|
return succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Map::removeNodeWithEvent(v3s16 p)
|
||||||
|
{
|
||||||
|
MapEditEvent event;
|
||||||
|
event.type = MEET_REMOVENODE;
|
||||||
|
event.p = p;
|
||||||
|
|
||||||
|
bool succeeded = true;
|
||||||
|
try{
|
||||||
|
core::map<v3s16, MapBlock*> modified_blocks;
|
||||||
|
removeNodeAndUpdate(p, modified_blocks);
|
||||||
|
|
||||||
|
// Copy modified_blocks to event
|
||||||
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
|
i = modified_blocks.getIterator();
|
||||||
|
i.atEnd()==false; i++)
|
||||||
|
{
|
||||||
|
event.modified_blocks.insert(i.getNode()->getKey(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(InvalidPositionException &e){
|
||||||
|
succeeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(&event);
|
||||||
|
|
||||||
|
return succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
bool Map::dayNightDiffed(v3s16 blockpos)
|
bool Map::dayNightDiffed(v3s16 blockpos)
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
|
@ -4535,6 +4572,42 @@ MapBlock * ServerMap::emergeBlock(
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s16 ServerMap::findGroundLevel(v2s16 p2d)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Uh, just do something random...
|
||||||
|
*/
|
||||||
|
// Find existing map from top to down
|
||||||
|
s16 max=63;
|
||||||
|
s16 min=-64;
|
||||||
|
v3s16 p(p2d.X, max, p2d.Y);
|
||||||
|
for(; p.Y>min; p.Y--)
|
||||||
|
{
|
||||||
|
MapNode n = getNodeNoEx(p);
|
||||||
|
if(n.d != CONTENT_IGNORE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(p.Y == min)
|
||||||
|
goto plan_b;
|
||||||
|
// If this node is not air, go to plan b
|
||||||
|
if(getNodeNoEx(p).d != CONTENT_AIR)
|
||||||
|
goto plan_b;
|
||||||
|
// Search existing walkable and return it
|
||||||
|
for(; p.Y>min; p.Y--)
|
||||||
|
{
|
||||||
|
MapNode n = getNodeNoEx(p);
|
||||||
|
if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
|
||||||
|
return p.Y;
|
||||||
|
}
|
||||||
|
// Move to plan b
|
||||||
|
plan_b:
|
||||||
|
/*
|
||||||
|
Plan B: Get from map generator perlin noise function
|
||||||
|
*/
|
||||||
|
double level = base_rock_level_2d(m_seed, p2d);
|
||||||
|
return (s16)level;
|
||||||
|
}
|
||||||
|
|
||||||
void ServerMap::createDir(std::string path)
|
void ServerMap::createDir(std::string path)
|
||||||
{
|
{
|
||||||
if(fs::CreateDir(path) == false)
|
if(fs::CreateDir(path) == false)
|
||||||
|
@ -5122,28 +5195,6 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets from master heightmap
|
|
||||||
void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
|
|
||||||
{
|
|
||||||
dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
|
|
||||||
//assert(m_heightmap != NULL);
|
|
||||||
/*
|
|
||||||
Corner definition:
|
|
||||||
v2s16(0,0),
|
|
||||||
v2s16(1,0),
|
|
||||||
v2s16(1,1),
|
|
||||||
v2s16(0,1),
|
|
||||||
*/
|
|
||||||
/*corners[0] = m_heightmap->getGroundHeight
|
|
||||||
((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
|
|
||||||
corners[1] = m_heightmap->getGroundHeight
|
|
||||||
((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
|
|
||||||
corners[2] = m_heightmap->getGroundHeight
|
|
||||||
((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
|
|
||||||
corners[3] = m_heightmap->getGroundHeight
|
|
||||||
((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerMap::PrintInfo(std::ostream &out)
|
void ServerMap::PrintInfo(std::ostream &out)
|
||||||
{
|
{
|
||||||
out<<"ServerMap: ";
|
out<<"ServerMap: ";
|
||||||
|
@ -5165,20 +5216,15 @@ ClientMap::ClientMap(
|
||||||
Map(dout_client),
|
Map(dout_client),
|
||||||
scene::ISceneNode(parent, mgr, id),
|
scene::ISceneNode(parent, mgr, id),
|
||||||
m_client(client),
|
m_client(client),
|
||||||
m_control(control)
|
m_control(control),
|
||||||
|
m_camera_position(0,0,0),
|
||||||
|
m_camera_direction(0,0,1)
|
||||||
{
|
{
|
||||||
//mesh_mutex.Init();
|
m_camera_mutex.Init();
|
||||||
|
assert(m_camera_mutex.IsInitialized());
|
||||||
|
|
||||||
/*m_box = core::aabbox3d<f32>(0,0,0,
|
|
||||||
map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
|
|
||||||
/*m_box = core::aabbox3d<f32>(0,0,0,
|
|
||||||
map->getSizeNodes().X * BS,
|
|
||||||
map->getSizeNodes().Y * BS,
|
|
||||||
map->getSizeNodes().Z * BS);*/
|
|
||||||
m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
|
m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
|
||||||
BS*1000000,BS*1000000,BS*1000000);
|
BS*1000000,BS*1000000,BS*1000000);
|
||||||
|
|
||||||
//setPosition(v3f(BS,BS,BS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientMap::~ClientMap()
|
ClientMap::~ClientMap()
|
||||||
|
|
105
src/map.h
105
src/map.h
|
@ -44,6 +44,51 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#define MAPTYPE_SERVER 1
|
#define MAPTYPE_SERVER 1
|
||||||
#define MAPTYPE_CLIENT 2
|
#define MAPTYPE_CLIENT 2
|
||||||
|
|
||||||
|
enum MapEditEventType{
|
||||||
|
MEET_ADDNODE,
|
||||||
|
MEET_REMOVENODE,
|
||||||
|
MEET_OTHER
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MapEditEvent
|
||||||
|
{
|
||||||
|
MapEditEventType type;
|
||||||
|
v3s16 p;
|
||||||
|
MapNode n;
|
||||||
|
core::map<v3s16, bool> modified_blocks;
|
||||||
|
u16 already_known_by_peer;
|
||||||
|
|
||||||
|
MapEditEvent():
|
||||||
|
type(MEET_OTHER),
|
||||||
|
already_known_by_peer(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MapEditEvent * clone()
|
||||||
|
{
|
||||||
|
MapEditEvent *event = new MapEditEvent();
|
||||||
|
event->type = type;
|
||||||
|
event->p = p;
|
||||||
|
event->n = n;
|
||||||
|
for(core::map<v3s16, bool>::Iterator
|
||||||
|
i = modified_blocks.getIterator();
|
||||||
|
i.atEnd()==false; i++)
|
||||||
|
{
|
||||||
|
v3s16 p = i.getNode()->getKey();
|
||||||
|
bool v = i.getNode()->getValue();
|
||||||
|
event->modified_blocks.insert(p, v);
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MapEventReceiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// event shall be deleted by caller after the call.
|
||||||
|
virtual void onMapEditEvent(MapEditEvent *event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Map : public NodeContainer
|
class Map : public NodeContainer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -69,24 +114,10 @@ public:
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateCamera(v3f pos, v3f dir)
|
void addEventReceiver(MapEventReceiver *event_receiver);
|
||||||
{
|
void removeEventReceiver(MapEventReceiver *event_receiver);
|
||||||
JMutexAutoLock lock(m_camera_mutex);
|
// event shall be deleted by caller after the call.
|
||||||
m_camera_position = pos;
|
void dispatchEvent(MapEditEvent *event);
|
||||||
m_camera_direction = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
static core::aabbox3d<f32> getNodeBox(v3s16 p)
|
|
||||||
{
|
|
||||||
return core::aabbox3d<f32>(
|
|
||||||
(float)p.X * BS - 0.5*BS,
|
|
||||||
(float)p.Y * BS - 0.5*BS,
|
|
||||||
(float)p.Z * BS - 0.5*BS,
|
|
||||||
(float)p.X * BS + 0.5*BS,
|
|
||||||
(float)p.Y * BS + 0.5*BS,
|
|
||||||
(float)p.Z * BS + 0.5*BS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// On failure returns NULL
|
// On failure returns NULL
|
||||||
MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
|
MapSector * getSectorNoGenerateNoExNoLock(v2s16 p2d);
|
||||||
|
@ -112,10 +143,6 @@ public:
|
||||||
// Gets an existing block or creates an empty one
|
// Gets an existing block or creates an empty one
|
||||||
//MapBlock * getBlockCreate(v3s16 p);
|
//MapBlock * getBlockCreate(v3s16 p);
|
||||||
|
|
||||||
// Returns InvalidPositionException if not found
|
|
||||||
f32 getGroundHeight(v2s16 p, bool generate=false);
|
|
||||||
void setGroundHeight(v2s16 p, f32 y, bool generate=false);
|
|
||||||
|
|
||||||
// Returns InvalidPositionException if not found
|
// Returns InvalidPositionException if not found
|
||||||
bool isNodeUnderground(v3s16 p);
|
bool isNodeUnderground(v3s16 p);
|
||||||
|
|
||||||
|
@ -212,6 +239,14 @@ public:
|
||||||
void removeNodeAndUpdate(v3s16 p,
|
void removeNodeAndUpdate(v3s16 p,
|
||||||
core::map<v3s16, MapBlock*> &modified_blocks);
|
core::map<v3s16, MapBlock*> &modified_blocks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Wrappers for the latter ones.
|
||||||
|
These emit events.
|
||||||
|
Return true if succeeded, false if not.
|
||||||
|
*/
|
||||||
|
bool addNodeWithEvent(v3s16 p, MapNode n);
|
||||||
|
bool removeNodeWithEvent(v3s16 p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Takes the blocks at the edges into account
|
Takes the blocks at the edges into account
|
||||||
*/
|
*/
|
||||||
|
@ -249,13 +284,12 @@ protected:
|
||||||
|
|
||||||
std::ostream &m_dout;
|
std::ostream &m_dout;
|
||||||
|
|
||||||
|
core::map<MapEventReceiver*, bool> m_event_receivers;
|
||||||
|
|
||||||
|
// Mutex is important because on client map is accessed asynchronously
|
||||||
core::map<v2s16, MapSector*> m_sectors;
|
core::map<v2s16, MapSector*> m_sectors;
|
||||||
JMutex m_sector_mutex;
|
JMutex m_sector_mutex;
|
||||||
|
|
||||||
v3f m_camera_position;
|
|
||||||
v3f m_camera_direction;
|
|
||||||
JMutex m_camera_mutex;
|
|
||||||
|
|
||||||
// Be sure to set this to NULL when the cached sector is deleted
|
// Be sure to set this to NULL when the cached sector is deleted
|
||||||
MapSector *m_sector_cache;
|
MapSector *m_sector_cache;
|
||||||
v2s16 m_sector_cache_p;
|
v2s16 m_sector_cache_p;
|
||||||
|
@ -445,6 +479,9 @@ public:
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Helper for placing objects on ground level
|
||||||
|
s16 findGroundLevel(v2s16 p2d);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Misc. helper functions for fiddling with directory and file
|
Misc. helper functions for fiddling with directory and file
|
||||||
names when saving
|
names when saving
|
||||||
|
@ -489,10 +526,6 @@ public:
|
||||||
// This will generate a sector with getSector if not found.
|
// This will generate a sector with getSector if not found.
|
||||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
||||||
|
|
||||||
// Gets from master heightmap
|
|
||||||
// DEPRECATED?
|
|
||||||
void getSectorCorners(v2s16 p2d, s16 *corners);
|
|
||||||
|
|
||||||
// For debug printing
|
// For debug printing
|
||||||
virtual void PrintInfo(std::ostream &out);
|
virtual void PrintInfo(std::ostream &out);
|
||||||
|
|
||||||
|
@ -573,6 +606,13 @@ public:
|
||||||
ISceneNode::drop();
|
ISceneNode::drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateCamera(v3f pos, v3f dir)
|
||||||
|
{
|
||||||
|
JMutexAutoLock lock(m_camera_mutex);
|
||||||
|
m_camera_position = pos;
|
||||||
|
m_camera_direction = dir;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Forcefully get a sector from somewhere
|
Forcefully get a sector from somewhere
|
||||||
*/
|
*/
|
||||||
|
@ -640,6 +680,11 @@ private:
|
||||||
//JMutex mesh_mutex;
|
//JMutex mesh_mutex;
|
||||||
|
|
||||||
MapDrawControl &m_control;
|
MapDrawControl &m_control;
|
||||||
|
|
||||||
|
v3f m_camera_position;
|
||||||
|
v3f m_camera_direction;
|
||||||
|
JMutex m_camera_mutex;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,10 +19,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
#include "mapblockobject.h"
|
#include "mapblockobject.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
// Only for ::getNodeBox, TODO: Get rid of this
|
// For object wrapping
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
#include "irrlichtwrapper.h"
|
#include "irrlichtwrapper.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MapBlockObject
|
MapBlockObject
|
||||||
|
@ -168,8 +169,7 @@ void MovingObject::move(float dtime, v3f acceleration)
|
||||||
// walking over map borders
|
// walking over map borders
|
||||||
}
|
}
|
||||||
|
|
||||||
core::aabbox3d<f32> nodebox = Map::getNodeBox(
|
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
|
||||||
v3s16(x,y,z));
|
|
||||||
|
|
||||||
// See if the object is touching ground
|
// See if the object is touching ground
|
||||||
if(
|
if(
|
||||||
|
|
|
@ -428,8 +428,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||||
// walking over map borders
|
// walking over map borders
|
||||||
}
|
}
|
||||||
|
|
||||||
core::aabbox3d<f32> nodebox = Map::getNodeBox(
|
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
|
||||||
v3s16(x,y,z));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
See if the player is touching ground.
|
See if the player is touching ground.
|
||||||
|
|
|
@ -51,7 +51,7 @@ void sigint_handler(int sig)
|
||||||
dstream<<DTIME<<"INFO: sigint_handler(): "
|
dstream<<DTIME<<"INFO: sigint_handler(): "
|
||||||
<<"Ctrl-C pressed, shutting down."<<std::endl;
|
<<"Ctrl-C pressed, shutting down."<<std::endl;
|
||||||
|
|
||||||
dstream<<DTIME<<"INFO: siging_handler(): "
|
dstream<<DTIME<<"INFO: sigint_handler(): "
|
||||||
<<"Printing debug stacks"<<std::endl;
|
<<"Printing debug stacks"<<std::endl;
|
||||||
debug_stacks_print();
|
debug_stacks_print();
|
||||||
|
|
||||||
|
|
287
src/server.cpp
287
src/server.cpp
|
@ -893,7 +893,7 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
||||||
Server::Server(
|
Server::Server(
|
||||||
std::string mapsavedir
|
std::string mapsavedir
|
||||||
):
|
):
|
||||||
m_env(new ServerMap(mapsavedir)),
|
m_env(new ServerMap(mapsavedir), this),
|
||||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||||
m_thread(this),
|
m_thread(this),
|
||||||
m_emergethread(this),
|
m_emergethread(this),
|
||||||
|
@ -902,9 +902,10 @@ Server::Server(
|
||||||
m_time_of_day_send_timer(0),
|
m_time_of_day_send_timer(0),
|
||||||
m_uptime(0),
|
m_uptime(0),
|
||||||
m_mapsavedir(mapsavedir),
|
m_mapsavedir(mapsavedir),
|
||||||
m_shutdown_requested(false)
|
m_shutdown_requested(false),
|
||||||
|
m_ignore_map_edit_events(false),
|
||||||
|
m_ignore_map_edit_events_peer_id(0)
|
||||||
{
|
{
|
||||||
//m_flowwater_timer = 0.0;
|
|
||||||
m_liquid_transform_timer = 0.0;
|
m_liquid_transform_timer = 0.0;
|
||||||
m_print_info_timer = 0.0;
|
m_print_info_timer = 0.0;
|
||||||
m_objectdata_timer = 0.0;
|
m_objectdata_timer = 0.0;
|
||||||
|
@ -916,6 +917,8 @@ Server::Server(
|
||||||
m_step_dtime_mutex.Init();
|
m_step_dtime_mutex.Init();
|
||||||
m_step_dtime = 0.0;
|
m_step_dtime = 0.0;
|
||||||
|
|
||||||
|
m_env.getMap().addEventReceiver(this);
|
||||||
|
|
||||||
// Load players
|
// Load players
|
||||||
m_env.deSerializePlayers(m_mapsavedir);
|
m_env.deSerializePlayers(m_mapsavedir);
|
||||||
}
|
}
|
||||||
|
@ -1191,6 +1194,9 @@ void Server::AsyncRunStep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(g_settings.getBool("enable_experimental"))
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check added and deleted active objects
|
Check added and deleted active objects
|
||||||
*/
|
*/
|
||||||
|
@ -1198,14 +1204,18 @@ void Server::AsyncRunStep()
|
||||||
JMutexAutoLock envlock(m_env_mutex);
|
JMutexAutoLock envlock(m_env_mutex);
|
||||||
JMutexAutoLock conlock(m_con_mutex);
|
JMutexAutoLock conlock(m_con_mutex);
|
||||||
|
|
||||||
|
// Radius inside which objects are active
|
||||||
|
s16 radius = 32;
|
||||||
|
|
||||||
for(core::map<u16, RemoteClient*>::Iterator
|
for(core::map<u16, RemoteClient*>::Iterator
|
||||||
i = m_clients.getIterator();
|
i = m_clients.getIterator();
|
||||||
i.atEnd() == false; i++)
|
i.atEnd() == false; i++)
|
||||||
{
|
{
|
||||||
RemoteClient *client = i.getNode()->getValue();
|
RemoteClient *client = i.getNode()->getValue();
|
||||||
Player *player = m_env.getPlayer(client->peer_id);
|
Player *player = m_env.getPlayer(client->peer_id);
|
||||||
|
if(player==NULL)
|
||||||
|
continue;
|
||||||
v3s16 pos = floatToInt(player->getPosition(), BS);
|
v3s16 pos = floatToInt(player->getPosition(), BS);
|
||||||
s16 radius = 32;
|
|
||||||
|
|
||||||
core::map<u16, bool> removed_objects;
|
core::map<u16, bool> removed_objects;
|
||||||
core::map<u16, bool> added_objects;
|
core::map<u16, bool> added_objects;
|
||||||
|
@ -1407,8 +1417,44 @@ void Server::AsyncRunStep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // enable_experimental
|
||||||
|
|
||||||
|
/*
|
||||||
|
Send queued-for-sending map edit events.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
while(m_unsent_map_edit_queue.size() != 0)
|
||||||
|
{
|
||||||
|
MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
|
||||||
|
|
||||||
|
if(event->type == MEET_ADDNODE)
|
||||||
|
{
|
||||||
|
dstream<<"Server: MEET_ADDNODE"<<std::endl;
|
||||||
|
sendAddNode(event->p, event->n, event->already_known_by_peer);
|
||||||
|
}
|
||||||
|
else if(event->type == MEET_REMOVENODE)
|
||||||
|
{
|
||||||
|
dstream<<"Server: MEET_REMOVENODE"<<std::endl;
|
||||||
|
sendRemoveNode(event->p, event->already_known_by_peer);
|
||||||
|
}
|
||||||
|
else if(event->type == MEET_OTHER)
|
||||||
|
{
|
||||||
|
dstream<<"WARNING: Server: MEET_OTHER not implemented"
|
||||||
|
<<std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstream<<"WARNING: Server: Unknown MapEditEvent "
|
||||||
|
<<((u32)event->type)<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Send object positions
|
Send object positions
|
||||||
|
TODO: Get rid of MapBlockObjects
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
float &counter = m_objectdata_timer;
|
float &counter = m_objectdata_timer;
|
||||||
|
@ -1964,32 +2010,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
/*
|
/*
|
||||||
Send the removal to all other clients
|
Send the removal to all other clients
|
||||||
*/
|
*/
|
||||||
|
sendRemoveNode(p_over, peer_id);
|
||||||
// Create packet
|
|
||||||
u32 replysize = 8;
|
|
||||||
SharedBuffer<u8> reply(replysize);
|
|
||||||
writeU16(&reply[0], TOCLIENT_REMOVENODE);
|
|
||||||
writeS16(&reply[2], p_under.X);
|
|
||||||
writeS16(&reply[4], p_under.Y);
|
|
||||||
writeS16(&reply[6], p_under.Z);
|
|
||||||
|
|
||||||
for(core::map<u16, RemoteClient*>::Iterator
|
|
||||||
i = m_clients.getIterator();
|
|
||||||
i.atEnd() == false; i++)
|
|
||||||
{
|
|
||||||
// Get client and check that it is valid
|
|
||||||
RemoteClient *client = i.getNode()->getValue();
|
|
||||||
assert(client->peer_id == i.getNode()->getKey());
|
|
||||||
if(client->serialization_version == SER_FMT_VER_INVALID)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Don't send if it's the same one
|
|
||||||
if(peer_id == client->peer_id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Send as reliable
|
|
||||||
m_con.Send(client->peer_id, 0, reply, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update and send inventory
|
Update and send inventory
|
||||||
|
@ -2063,33 +2084,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
Remove the node
|
Remove the node
|
||||||
(this takes some time so it is done after the quick stuff)
|
(this takes some time so it is done after the quick stuff)
|
||||||
*/
|
*/
|
||||||
|
m_ignore_map_edit_events = true;
|
||||||
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
||||||
|
m_ignore_map_edit_events = false;
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
Update water
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Update water pressure around modification
|
|
||||||
// This also adds it to m_flow_active_nodes if appropriate
|
|
||||||
|
|
||||||
MapVoxelManipulator v(&m_env.getMap());
|
|
||||||
v.m_disable_water_climb =
|
|
||||||
g_settings.getBool("disable_water_climb");
|
|
||||||
|
|
||||||
VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
v.updateAreaWaterPressure(area, m_flow_active_nodes);
|
|
||||||
}
|
|
||||||
catch(ProcessingLimitException &e)
|
|
||||||
{
|
|
||||||
dstream<<"Processing limit reached (1)"<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
v.blitBack(modified_blocks);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2151,16 +2148,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
if(content_features(n.d).wall_mounted)
|
if(content_features(n.d).wall_mounted)
|
||||||
n.dir = packDir(p_under - p_over);
|
n.dir = packDir(p_under - p_over);
|
||||||
|
|
||||||
// Create packet
|
/*
|
||||||
u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver);
|
Send to all players
|
||||||
SharedBuffer<u8> reply(replysize);
|
*/
|
||||||
writeU16(&reply[0], TOCLIENT_ADDNODE);
|
sendAddNode(p_over, n, 0);
|
||||||
writeS16(&reply[2], p_over.X);
|
|
||||||
writeS16(&reply[4], p_over.Y);
|
|
||||||
writeS16(&reply[6], p_over.Z);
|
|
||||||
n.serialize(&reply[8], peer_ser_ver);
|
|
||||||
// Send as reliable
|
|
||||||
m_con.SendToAll(0, reply, true);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handle inventory
|
Handle inventory
|
||||||
|
@ -2183,7 +2174,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
This takes some time so it is done after the quick stuff
|
This takes some time so it is done after the quick stuff
|
||||||
*/
|
*/
|
||||||
core::map<v3s16, MapBlock*> modified_blocks;
|
core::map<v3s16, MapBlock*> modified_blocks;
|
||||||
|
m_ignore_map_edit_events = true;
|
||||||
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
|
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
|
||||||
|
m_ignore_map_edit_events = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate special events
|
Calculate special events
|
||||||
|
@ -2595,41 +2588,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void Server::Send(u16 peer_id, u16 channelnum,
|
void Server::onMapEditEvent(MapEditEvent *event)
|
||||||
SharedBuffer<u8> data, bool reliable)
|
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_con_mutex);
|
dstream<<"Server::onMapEditEvent()"<<std::endl;
|
||||||
m_con.Send(peer_id, channelnum, data, reliable);
|
if(m_ignore_map_edit_events)
|
||||||
}*/
|
return;
|
||||||
|
MapEditEvent *e = event->clone();
|
||||||
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
|
m_unsent_map_edit_queue.push_back(e);
|
||||||
{
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
|
||||||
/*
|
|
||||||
Create a packet with the block in the right format
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::ostringstream os(std::ios_base::binary);
|
|
||||||
block->serialize(os, ver);
|
|
||||||
std::string s = os.str();
|
|
||||||
SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
|
|
||||||
|
|
||||||
u32 replysize = 8 + blockdata.getSize();
|
|
||||||
SharedBuffer<u8> reply(replysize);
|
|
||||||
v3s16 p = block->getPos();
|
|
||||||
writeU16(&reply[0], TOCLIENT_BLOCKDATA);
|
|
||||||
writeS16(&reply[2], p.X);
|
|
||||||
writeS16(&reply[4], p.Y);
|
|
||||||
writeS16(&reply[6], p.Z);
|
|
||||||
memcpy(&reply[8], *blockdata, blockdata.getSize());
|
|
||||||
|
|
||||||
/*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
|
||||||
<<": \tpacket size: "<<replysize<<std::endl;*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Send packet
|
|
||||||
*/
|
|
||||||
m_con.Send(peer_id, 1, reply, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
core::list<PlayerInfo> Server::getPlayerInfo()
|
core::list<PlayerInfo> Server::getPlayerInfo()
|
||||||
|
@ -2759,6 +2724,10 @@ void Server::SendPlayerInfos()
|
||||||
m_con.SendToAll(0, data, true);
|
m_con.SendToAll(0, data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Craft checking system
|
||||||
|
*/
|
||||||
|
|
||||||
enum ItemSpecType
|
enum ItemSpecType
|
||||||
{
|
{
|
||||||
ITEM_NONE,
|
ITEM_NONE,
|
||||||
|
@ -3109,6 +3078,97 @@ void Server::BroadcastChatMessage(const std::wstring &message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Server::sendRemoveNode(v3s16 p, u16 ignore_id)
|
||||||
|
{
|
||||||
|
JMutexAutoLock conlock(m_con_mutex);
|
||||||
|
|
||||||
|
// Create packet
|
||||||
|
u32 replysize = 8;
|
||||||
|
SharedBuffer<u8> reply(replysize);
|
||||||
|
writeU16(&reply[0], TOCLIENT_REMOVENODE);
|
||||||
|
writeS16(&reply[2], p.X);
|
||||||
|
writeS16(&reply[4], p.Y);
|
||||||
|
writeS16(&reply[6], p.Z);
|
||||||
|
|
||||||
|
for(core::map<u16, RemoteClient*>::Iterator
|
||||||
|
i = m_clients.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
// Get client and check that it is valid
|
||||||
|
RemoteClient *client = i.getNode()->getValue();
|
||||||
|
assert(client->peer_id == i.getNode()->getKey());
|
||||||
|
if(client->serialization_version == SER_FMT_VER_INVALID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Don't send if it's the same one
|
||||||
|
if(client->peer_id == ignore_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Send as reliable
|
||||||
|
m_con.Send(client->peer_id, 0, reply, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id)
|
||||||
|
{
|
||||||
|
for(core::map<u16, RemoteClient*>::Iterator
|
||||||
|
i = m_clients.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
// Get client and check that it is valid
|
||||||
|
RemoteClient *client = i.getNode()->getValue();
|
||||||
|
assert(client->peer_id == i.getNode()->getKey());
|
||||||
|
if(client->serialization_version == SER_FMT_VER_INVALID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Don't send if it's the same one
|
||||||
|
if(client->peer_id == ignore_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Create packet
|
||||||
|
u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
|
||||||
|
SharedBuffer<u8> reply(replysize);
|
||||||
|
writeU16(&reply[0], TOCLIENT_ADDNODE);
|
||||||
|
writeS16(&reply[2], p.X);
|
||||||
|
writeS16(&reply[4], p.Y);
|
||||||
|
writeS16(&reply[6], p.Z);
|
||||||
|
n.serialize(&reply[8], client->serialization_version);
|
||||||
|
|
||||||
|
// Send as reliable
|
||||||
|
m_con.Send(client->peer_id, 0, reply, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
|
||||||
|
{
|
||||||
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
/*
|
||||||
|
Create a packet with the block in the right format
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
block->serialize(os, ver);
|
||||||
|
std::string s = os.str();
|
||||||
|
SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
|
||||||
|
|
||||||
|
u32 replysize = 8 + blockdata.getSize();
|
||||||
|
SharedBuffer<u8> reply(replysize);
|
||||||
|
v3s16 p = block->getPos();
|
||||||
|
writeU16(&reply[0], TOCLIENT_BLOCKDATA);
|
||||||
|
writeS16(&reply[2], p.X);
|
||||||
|
writeS16(&reply[4], p.Y);
|
||||||
|
writeS16(&reply[6], p.Z);
|
||||||
|
memcpy(&reply[8], *blockdata, blockdata.getSize());
|
||||||
|
|
||||||
|
/*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||||
|
<<": \tpacket size: "<<replysize<<std::endl;*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Send packet
|
||||||
|
*/
|
||||||
|
m_con.Send(peer_id, 1, reply, true);
|
||||||
|
}
|
||||||
|
|
||||||
void Server::SendBlocks(float dtime)
|
void Server::SendBlocks(float dtime)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
@ -3316,16 +3376,16 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||||
<<player->getName()<<"\""<<std::endl;
|
<<player->getName()<<"\""<<std::endl;
|
||||||
|
|
||||||
v2s16 nodepos;
|
v2s16 nodepos;
|
||||||
#if 1
|
#if 0
|
||||||
player->setPosition(intToFloat(v3s16(
|
player->setPosition(intToFloat(v3s16(
|
||||||
0,
|
0,
|
||||||
45, //64,
|
45, //64,
|
||||||
0
|
0
|
||||||
), BS));
|
), BS));
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 1
|
||||||
f32 groundheight = 0;
|
s16 groundheight = 0;
|
||||||
#if 0
|
#if 1
|
||||||
// Try to find a good place a few times
|
// Try to find a good place a few times
|
||||||
for(s32 i=0; i<500; i++)
|
for(s32 i=0; i<500; i++)
|
||||||
{
|
{
|
||||||
|
@ -3334,12 +3394,20 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||||
nodepos = v2s16(-range + (myrand()%(range*2)),
|
nodepos = v2s16(-range + (myrand()%(range*2)),
|
||||||
-range + (myrand()%(range*2)));
|
-range + (myrand()%(range*2)));
|
||||||
v2s16 sectorpos = getNodeSectorPos(nodepos);
|
v2s16 sectorpos = getNodeSectorPos(nodepos);
|
||||||
|
/*
|
||||||
|
Ignore position if it is near a chunk edge.
|
||||||
|
Otherwise it would cause excessive loading time at
|
||||||
|
initial generation
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(m_env.getServerMap().sector_to_chunk(sectorpos+v2s16(1,1))
|
||||||
|
!= m_env.getServerMap().sector_to_chunk(sectorpos+v2s16(-1,-1)))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Get sector
|
// Get sector
|
||||||
m_env.getMap().emergeSector(sectorpos);
|
m_env.getMap().emergeSector(sectorpos);
|
||||||
// Get ground height at point
|
// Get ground height at point
|
||||||
groundheight = m_env.getMap().getGroundHeight(nodepos, true);
|
groundheight = m_env.getServerMap().findGroundLevel(nodepos);
|
||||||
// The sector should have been generated -> groundheight exists
|
|
||||||
assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
|
|
||||||
// Don't go underwater
|
// Don't go underwater
|
||||||
if(groundheight < WATER_LEVEL)
|
if(groundheight < WATER_LEVEL)
|
||||||
{
|
{
|
||||||
|
@ -3384,10 +3452,9 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||||
|
|
||||||
player->setPosition(intToFloat(v3s16(
|
player->setPosition(intToFloat(v3s16(
|
||||||
nodepos.X,
|
nodepos.X,
|
||||||
//groundheight + 1,
|
groundheight + 1,
|
||||||
groundheight + 15,
|
|
||||||
nodepos.Y
|
nodepos.Y
|
||||||
)));
|
), BS));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
48
src/server.h
48
src/server.h
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
struct QueuedBlockEmerge
|
struct QueuedBlockEmerge
|
||||||
{
|
{
|
||||||
|
@ -341,12 +342,13 @@ private:
|
||||||
u32 m_excess_gotblocks;
|
u32 m_excess_gotblocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Server : public con::PeerHandler
|
class Server : public con::PeerHandler, public MapEventReceiver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
NOTE: Every public method should be thread-safe
|
NOTE: Every public method should be thread-safe
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Server(
|
Server(
|
||||||
std::string mapsavedir
|
std::string mapsavedir
|
||||||
);
|
);
|
||||||
|
@ -361,23 +363,11 @@ public:
|
||||||
void Receive();
|
void Receive();
|
||||||
void ProcessData(u8 *data, u32 datasize, u16 peer_id);
|
void ProcessData(u8 *data, u32 datasize, u16 peer_id);
|
||||||
|
|
||||||
// Environment and Connection must be locked when called
|
|
||||||
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
core::list<PlayerInfo> getPlayerInfo();
|
core::list<PlayerInfo> getPlayerInfo();
|
||||||
|
|
||||||
u32 getDayNightRatio()
|
u32 getDayNightRatio()
|
||||||
{
|
{
|
||||||
s32 d = 8;
|
return time_to_daynight_ratio(m_time_of_day.get());
|
||||||
s32 t = (((m_time_of_day.get() + 24000/d/2)%24000)/(24000/d));
|
|
||||||
if(t == d/4 || t == (d-d/4))
|
|
||||||
return 600;
|
|
||||||
else if(t < d/4 || t > (d-d/4))
|
|
||||||
return 300;
|
|
||||||
else
|
|
||||||
return 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getShutdownRequested()
|
bool getShutdownRequested()
|
||||||
|
@ -385,6 +375,13 @@ public:
|
||||||
return m_shutdown_requested.get();
|
return m_shutdown_requested.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shall be called with the environment locked.
|
||||||
|
This is accessed by the map, which is inside the environment,
|
||||||
|
so it shouldn't be a problem.
|
||||||
|
*/
|
||||||
|
void onMapEditEvent(MapEditEvent *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Virtual methods from con::PeerHandler.
|
// Virtual methods from con::PeerHandler.
|
||||||
|
@ -398,6 +395,11 @@ private:
|
||||||
void SendInventory(u16 peer_id);
|
void SendInventory(u16 peer_id);
|
||||||
void SendChatMessage(u16 peer_id, const std::wstring &message);
|
void SendChatMessage(u16 peer_id, const std::wstring &message);
|
||||||
void BroadcastChatMessage(const std::wstring &message);
|
void BroadcastChatMessage(const std::wstring &message);
|
||||||
|
void sendRemoveNode(v3s16 p, u16 ignore_id=0);
|
||||||
|
void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0);
|
||||||
|
|
||||||
|
// Environment and Connection must be locked when called
|
||||||
|
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
|
||||||
|
|
||||||
// Sends blocks to clients
|
// Sends blocks to clients
|
||||||
void SendBlocks(float dtime);
|
void SendBlocks(float dtime);
|
||||||
|
@ -485,6 +487,24 @@ private:
|
||||||
|
|
||||||
MutexedVariable<bool> m_shutdown_requested;
|
MutexedVariable<bool> m_shutdown_requested;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Queue of map edits from the environment for sending to the clients
|
||||||
|
This is behind m_env_mutex
|
||||||
|
*/
|
||||||
|
Queue<MapEditEvent*> m_unsent_map_edit_queue;
|
||||||
|
/*
|
||||||
|
Set to true when the server itself is modifying the map and does
|
||||||
|
all sending of information by itself.
|
||||||
|
This is behind m_env_mutex
|
||||||
|
*/
|
||||||
|
bool m_ignore_map_edit_events;
|
||||||
|
/*
|
||||||
|
If set to !=0, the incoming MapEditEvents are modified to have
|
||||||
|
this peed id as the disabled recipient
|
||||||
|
This is behind m_env_mutex
|
||||||
|
*/
|
||||||
|
u16 m_ignore_map_edit_events_peer_id;
|
||||||
|
|
||||||
friend class EmergeThread;
|
friend class EmergeThread;
|
||||||
friend class RemoteClient;
|
friend class RemoteClient;
|
||||||
};
|
};
|
||||||
|
|
|
@ -88,35 +88,33 @@ extern "C"{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Functions for calling from script:
|
|
||||||
|
|
||||||
object_set_base_position(self, x,y,z)
|
|
||||||
x,y,z = object_get_base_position(self)
|
|
||||||
object_add_message(self, data)
|
|
||||||
n = object_get_node(self, x,y,z)
|
|
||||||
object_remove(self)
|
|
||||||
|
|
||||||
Callbacks in script:
|
Callbacks in script:
|
||||||
|
|
||||||
step(self, dtime)
|
on_step(self, dtime)
|
||||||
get_client_init_data(self)
|
on_get_client_init_data(self)
|
||||||
get_server_init_data(self)
|
on_get_server_init_data(self)
|
||||||
initialize(self, data)
|
on_initialize(self, data)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object_set_base_position(self, x, y, z)
|
object_set_base_position(self, {X=,Y=,Z=})
|
||||||
*/
|
*/
|
||||||
static int lf_object_set_base_position(lua_State *L)
|
static int lf_object_set_base_position(lua_State *L)
|
||||||
{
|
{
|
||||||
// 4: z
|
// 2: position
|
||||||
lua_Number z = lua_tonumber(L, -1);
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number x = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 3: y
|
lua_pushstring(L, "Y");
|
||||||
|
lua_gettable(L, -2);
|
||||||
lua_Number y = lua_tonumber(L, -1);
|
lua_Number y = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 2: x
|
lua_pushstring(L, "Z");
|
||||||
lua_Number x = lua_tonumber(L, -1);
|
lua_gettable(L, -2);
|
||||||
|
lua_Number z = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 1: self
|
// 1: self
|
||||||
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
||||||
|
@ -130,7 +128,7 @@ static int lf_object_set_base_position(lua_State *L)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object_get_base_position(self)
|
{X=,Y=,Z=} object_get_base_position(self)
|
||||||
*/
|
*/
|
||||||
static int lf_object_get_base_position(lua_State *L)
|
static int lf_object_get_base_position(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -142,10 +140,21 @@ static int lf_object_get_base_position(lua_State *L)
|
||||||
|
|
||||||
v3f pos = self->getBasePosition();
|
v3f pos = self->getBasePosition();
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
lua_pushstring(L, "X");
|
||||||
lua_pushnumber(L, pos.X/BS);
|
lua_pushnumber(L, pos.X/BS);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "Y");
|
||||||
lua_pushnumber(L, pos.Y/BS);
|
lua_pushnumber(L, pos.Y/BS);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "Z");
|
||||||
lua_pushnumber(L, pos.Z/BS);
|
lua_pushnumber(L, pos.Z/BS);
|
||||||
return 3; // Number of return values
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
return 1; // Number of return values
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -178,18 +187,24 @@ static int lf_object_add_message(lua_State *L)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object_get_node(self, x,y,z)
|
object_get_node(self, {X=,Y=,Z=})
|
||||||
*/
|
*/
|
||||||
static int lf_object_get_node(lua_State *L)
|
static int lf_object_get_node(lua_State *L)
|
||||||
{
|
{
|
||||||
// 4: z
|
// 2: position
|
||||||
lua_Number z = lua_tonumber(L, -1);
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number x = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 3: y
|
lua_pushstring(L, "Y");
|
||||||
|
lua_gettable(L, -2);
|
||||||
lua_Number y = lua_tonumber(L, -1);
|
lua_Number y = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 2: x
|
lua_pushstring(L, "Z");
|
||||||
lua_Number x = lua_tonumber(L, -1);
|
lua_gettable(L, -2);
|
||||||
|
lua_Number z = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 1: self
|
// 1: self
|
||||||
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
||||||
|
@ -217,9 +232,6 @@ static int lf_object_get_node(lua_State *L)
|
||||||
lua_pushstring(L, "param2");
|
lua_pushstring(L, "param2");
|
||||||
lua_pushinteger(L, n.param2);
|
lua_pushinteger(L, n.param2);
|
||||||
lua_settable(L, -3);
|
lua_settable(L, -3);
|
||||||
lua_pushstring(L, "walkable");
|
|
||||||
lua_pushboolean(L, content_features(n.d).walkable);
|
|
||||||
lua_settable(L, -3);
|
|
||||||
|
|
||||||
// Return the table
|
// Return the table
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -227,39 +239,82 @@ static int lf_object_get_node(lua_State *L)
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/*
|
/*
|
||||||
object_set_node(self, x,y,z, n)
|
get_node_features(node)
|
||||||
|
node = {content=,param1=,param2=}
|
||||||
*/
|
*/
|
||||||
static int lf_object_set_node(lua_State *L)
|
static int lf_get_node_features(lua_State *L)
|
||||||
{
|
{
|
||||||
MapNode n;
|
MapNode n;
|
||||||
|
|
||||||
// 5: n
|
// 1: node
|
||||||
// Get fields of table
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "content");
|
||||||
lua_pushinteger(L, "content");
|
|
||||||
lua_gettable(L, -2);
|
lua_gettable(L, -2);
|
||||||
n.d = lua_tonumber(L, -1);
|
n.d = lua_tointeger(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "param1");
|
||||||
lua_pushinteger(L, "param1");
|
|
||||||
lua_gettable(L, -2);
|
lua_gettable(L, -2);
|
||||||
n.param = lua_tonumber(L, -1);
|
n.param = lua_tointeger(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "param2");
|
||||||
lua_pushinteger(L, "param2");
|
|
||||||
lua_gettable(L, -2);
|
lua_gettable(L, -2);
|
||||||
n.param2 = lua_tonumber(L, -1);
|
n.param2 = lua_tointeger(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
ContentFeatures &f = content_features(n.d);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
get_content_features(content)
|
||||||
|
*/
|
||||||
|
static int lf_get_content_features(lua_State *L)
|
||||||
|
{
|
||||||
|
MapNode n;
|
||||||
|
|
||||||
|
// 1: content
|
||||||
|
n.d = lua_tointeger(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 4: z
|
|
||||||
lua_Number z = lua_tonumber(L, -1);
|
// Get and return information
|
||||||
|
ContentFeatures &f = content_features(n.d);
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushstring(L, "walkable");
|
||||||
|
lua_pushboolean(L, f.walkable);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "diggable");
|
||||||
|
lua_pushboolean(L, f.diggable);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "buildable_to");
|
||||||
|
lua_pushboolean(L, f.buildable_to);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool object_dig_node(self, {X=,Y=,Z=})
|
||||||
|
Return true on success
|
||||||
|
*/
|
||||||
|
static int lf_object_dig_node(lua_State *L)
|
||||||
|
{
|
||||||
|
// 2: position
|
||||||
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number x = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 3: y
|
lua_pushstring(L, "Y");
|
||||||
|
lua_gettable(L, -2);
|
||||||
lua_Number y = lua_tonumber(L, -1);
|
lua_Number y = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 2: x
|
lua_pushstring(L, "Z");
|
||||||
lua_Number x = lua_tonumber(L, -1);
|
lua_gettable(L, -2);
|
||||||
|
lua_Number z = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// 1: self
|
// 1: self
|
||||||
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
||||||
|
@ -269,26 +324,79 @@ static int lf_object_set_node(lua_State *L)
|
||||||
|
|
||||||
v3s16 pos = floatToInt(v3f(x,y,z), 1.0);
|
v3s16 pos = floatToInt(v3f(x,y,z), 1.0);
|
||||||
|
|
||||||
/*dstream<<"Checking node from pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z
|
/*
|
||||||
<<")"<<std::endl;*/
|
Do stuff.
|
||||||
|
This gets sent to the server by the map through the edit
|
||||||
|
event system.
|
||||||
|
*/
|
||||||
|
bool succeeded = self->getEnv()->getMap().removeNodeWithEvent(pos);
|
||||||
|
|
||||||
// Get the node
|
lua_pushboolean(L, succeeded);
|
||||||
MapNode n(CONTENT_IGNORE);
|
return 1;
|
||||||
n = self->getEnv()->getMap().getNodeNoEx(pos);
|
}
|
||||||
|
|
||||||
// Create a table with some data about the node
|
/*
|
||||||
lua_newtable(L);
|
bool object_place_node(self, {X=,Y=,Z=}, node)
|
||||||
lua_pushstring(L, "content");
|
node={content=,param1=,param2=}
|
||||||
lua_pushinteger(L, n.d);
|
param1 and param2 are optional
|
||||||
lua_settable(L, -3);
|
Return true on success
|
||||||
lua_pushstring(L, "walkable");
|
*/
|
||||||
lua_pushboolean(L, content_features(n.d).walkable);
|
static int lf_object_place_node(lua_State *L)
|
||||||
lua_settable(L, -3);
|
{
|
||||||
|
// 3: node
|
||||||
// Return the table
|
MapNode n(CONTENT_STONE);
|
||||||
|
assert(lua_istable(L, -1));
|
||||||
|
{
|
||||||
|
lua_pushstring(L, "content");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
if(lua_isnumber(L, -1))
|
||||||
|
n.d = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "param1");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
if(lua_isnumber(L, -1))
|
||||||
|
n.param = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "param2");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
if(lua_isnumber(L, -1))
|
||||||
|
n.param2 = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
// 2: position
|
||||||
|
assert(lua_istable(L, -1));
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number x = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "Y");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number y = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "Z");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
lua_Number z = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
// 1: self
|
||||||
|
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
v3s16 pos = floatToInt(v3f(x,y,z), 1.0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Do stuff.
|
||||||
|
This gets sent to the server by the map through the edit
|
||||||
|
event system.
|
||||||
|
*/
|
||||||
|
bool succeeded = self->getEnv()->getMap().addNodeWithEvent(pos, n);
|
||||||
|
|
||||||
|
lua_pushboolean(L, succeeded);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object_remove(x,y,z)
|
object_remove(x,y,z)
|
||||||
|
@ -306,6 +414,38 @@ static int lf_object_remove(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{X=,Y=,Z=} object_get_nearest_player_position(self)
|
||||||
|
*/
|
||||||
|
/*static int lf_object_get_nearest_player_position(lua_State *L)
|
||||||
|
{
|
||||||
|
// 1: self
|
||||||
|
LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
ServerEnvironment *env = self->getEnv();
|
||||||
|
env->
|
||||||
|
v3f pos = ;
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
lua_pushstring(L, "X");
|
||||||
|
lua_pushnumber(L, pos.X/BS);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "Y");
|
||||||
|
lua_pushnumber(L, pos.Y/BS);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "Z");
|
||||||
|
lua_pushnumber(L, pos.Z/BS);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
return 1; // Number of return values
|
||||||
|
}*/
|
||||||
|
|
||||||
LuaSAO::LuaSAO(ServerEnvironment *env, u16 id, v3f pos):
|
LuaSAO::LuaSAO(ServerEnvironment *env, u16 id, v3f pos):
|
||||||
ServerActiveObject(env, id, pos),
|
ServerActiveObject(env, id, pos),
|
||||||
L(NULL)
|
L(NULL)
|
||||||
|
@ -329,6 +469,9 @@ LuaSAO::LuaSAO(ServerEnvironment *env, u16 id, v3f pos):
|
||||||
lua_register(L, "object_get_base_position", lf_object_get_base_position);
|
lua_register(L, "object_get_base_position", lf_object_get_base_position);
|
||||||
lua_register(L, "object_add_message", lf_object_add_message);
|
lua_register(L, "object_add_message", lf_object_add_message);
|
||||||
lua_register(L, "object_get_node", lf_object_get_node);
|
lua_register(L, "object_get_node", lf_object_get_node);
|
||||||
|
lua_register(L, "get_content_features", lf_get_content_features);
|
||||||
|
lua_register(L, "object_dig_node", lf_object_dig_node);
|
||||||
|
lua_register(L, "object_place_node", lf_object_place_node);
|
||||||
lua_register(L, "object_remove", lf_object_remove);
|
lua_register(L, "object_remove", lf_object_remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +515,7 @@ std::string LuaSAO::getClientInitializationData()
|
||||||
|
|
||||||
do{
|
do{
|
||||||
|
|
||||||
const char *funcname = "get_client_init_data";
|
const char *funcname = "on_get_client_init_data";
|
||||||
lua_getglobal(L, funcname);
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
|
@ -430,7 +573,7 @@ std::string LuaSAO::getServerInitializationData()
|
||||||
|
|
||||||
do{
|
do{
|
||||||
|
|
||||||
const char *funcname = "get_server_init_data";
|
const char *funcname = "on_get_server_init_data";
|
||||||
lua_getglobal(L, funcname);
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
|
@ -474,7 +617,41 @@ std::string LuaSAO::getServerInitializationData()
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaSAO::initialize(const std::string &data)
|
void LuaSAO::initializeFromNothing(const std::string &script_name)
|
||||||
|
{
|
||||||
|
loadScripts(script_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Call on_initialize(self, data) in the script
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *funcname = "on_initialize";
|
||||||
|
lua_getglobal(L, funcname);
|
||||||
|
if(!lua_isfunction(L,-1))
|
||||||
|
{
|
||||||
|
lua_pop(L,1);
|
||||||
|
dstream<<"WARNING: LuaSAO: Function not found: "
|
||||||
|
<<funcname<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameters:
|
||||||
|
// 1: self
|
||||||
|
lua_pushlightuserdata(L, this);
|
||||||
|
// 2: data (other)
|
||||||
|
lua_pushstring(L, "");
|
||||||
|
|
||||||
|
// Call (2 parameters, 0 result)
|
||||||
|
if(lua_pcall(L, 2, 0, 0))
|
||||||
|
{
|
||||||
|
dstream<<"WARNING: LuaSAO: Error running function "
|
||||||
|
<<funcname<<": "
|
||||||
|
<<lua_tostring(L,-1)<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaSAO::initializeFromSave(const std::string &data)
|
||||||
{
|
{
|
||||||
std::istringstream is(data, std::ios::binary);
|
std::istringstream is(data, std::ios::binary);
|
||||||
std::string script_name = deSerializeString(is);
|
std::string script_name = deSerializeString(is);
|
||||||
|
@ -483,10 +660,10 @@ void LuaSAO::initialize(const std::string &data)
|
||||||
loadScripts(script_name);
|
loadScripts(script_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Call initialize(self, data) in the script
|
Call on_initialize(self, data) in the script
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *funcname = "initialize";
|
const char *funcname = "on_initialize";
|
||||||
lua_getglobal(L, funcname);
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
|
@ -548,11 +725,13 @@ void LuaSAO::loadScripts(const std::string &script_name)
|
||||||
|
|
||||||
void LuaSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
|
void LuaSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
|
||||||
{
|
{
|
||||||
lua_getglobal(L, "step");
|
const char *funcname = "on_step";
|
||||||
|
lua_getglobal(L, funcname);
|
||||||
if(!lua_isfunction(L,-1))
|
if(!lua_isfunction(L,-1))
|
||||||
{
|
{
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
dstream<<"WARNING: LuaSAO::step(): step function not found"<<std::endl;
|
dstream<<"WARNING: LuaSAO::step(): Function not found: "
|
||||||
|
<<funcname<<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +744,8 @@ void LuaSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
|
||||||
// Call (2 parameters, 0 result)
|
// Call (2 parameters, 0 result)
|
||||||
if(lua_pcall(L, 2, 0, 0))
|
if(lua_pcall(L, 2, 0, 0))
|
||||||
{
|
{
|
||||||
dstream<<"WARNING: LuaSAO::step(): Error running function step(): "
|
dstream<<"WARNING: LuaSAO::step(): Error running function "
|
||||||
|
<<funcname<<": "
|
||||||
<<lua_tostring(L,-1)<<std::endl;
|
<<lua_tostring(L,-1)<<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,10 +131,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string getClientInitializationData();
|
virtual std::string getClientInitializationData();
|
||||||
|
|
||||||
virtual std::string getServerInitializationData();
|
virtual std::string getServerInitializationData();
|
||||||
|
|
||||||
void initialize(const std::string &data);
|
void initializeFromNothing(const std::string &script_name);
|
||||||
|
void initializeFromSave(const std::string &data);
|
||||||
|
|
||||||
void loadScripts(const std::string &script_name);
|
void loadScripts(const std::string &script_name);
|
||||||
|
|
||||||
|
|
|
@ -1832,7 +1832,11 @@ inline std::string deSerializeString(std::istream &is)
|
||||||
{
|
{
|
||||||
char buf[2];
|
char buf[2];
|
||||||
is.read(buf, 2);
|
is.read(buf, 2);
|
||||||
|
if(is.gcount() != 2)
|
||||||
|
throw SerializationError("deSerializeString: size not read");
|
||||||
u16 s_size = readU16((u8*)buf);
|
u16 s_size = readU16((u8*)buf);
|
||||||
|
if(s_size == 0)
|
||||||
|
return "";
|
||||||
Buffer<char> buf2(s_size);
|
Buffer<char> buf2(s_size);
|
||||||
is.read(&buf2[0], s_size);
|
is.read(&buf2[0], s_size);
|
||||||
std::string s;
|
std::string s;
|
||||||
|
@ -1867,7 +1871,11 @@ inline std::string deSerializeLongString(std::istream &is)
|
||||||
{
|
{
|
||||||
char buf[4];
|
char buf[4];
|
||||||
is.read(buf, 4);
|
is.read(buf, 4);
|
||||||
|
if(is.gcount() != 4)
|
||||||
|
throw SerializationError("deSerializeLongString: size not read");
|
||||||
u32 s_size = readU32((u8*)buf);
|
u32 s_size = readU32((u8*)buf);
|
||||||
|
if(s_size == 0)
|
||||||
|
return "";
|
||||||
Buffer<char> buf2(s_size);
|
Buffer<char> buf2(s_size);
|
||||||
is.read(&buf2[0], s_size);
|
is.read(&buf2[0], s_size);
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
Loading…
Reference in New Issue