aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/environment.cpp30
-rw-r--r--src/map.cpp53
-rw-r--r--src/map.h10
-rw-r--r--src/mapblock.cpp14
-rw-r--r--src/mapblock.h20
-rw-r--r--src/nodetimer.cpp16
-rw-r--r--src/nodetimer.h10
-rw-r--r--src/scriptapi.cpp219
-rw-r--r--src/scriptapi.h2
-rw-r--r--src/serialization.h5
-rw-r--r--src/server.cpp2
11 files changed, 338 insertions, 43 deletions
diff --git a/src/environment.cpp b/src/environment.cpp
index b55b3a6cf..02ca1f71b 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -774,10 +774,18 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
activateObjects(block);
// Run node timers
- std::map<v3s16, f32> elapsed_timers =
+ std::map<v3s16, NodeTimer> elapsed_timers =
block->m_node_timers.step((float)dtime_s);
- if(!elapsed_timers.empty())
- errorstream<<"Node timers don't work yet!"<<std::endl;
+ if(!elapsed_timers.empty()){
+ MapNode n;
+ for(std::map<v3s16, NodeTimer>::iterator
+ i = elapsed_timers.begin();
+ i != elapsed_timers.end(); i++){
+ n = block->getNodeNoEx(i->first);
+ if(scriptapi_node_on_timer(m_lua,i->first,n,i->second.elapsed))
+ block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
+ }
+ }
/* Handle ActiveBlockModifiers */
ABMHandler abmhandler(m_abms, dtime_s, this, false);
@@ -1058,10 +1066,18 @@ void ServerEnvironment::step(float dtime)
"Timestamp older than 60s (step)");
// Run node timers
- std::map<v3s16, f32> elapsed_timers =
- block->m_node_timers.step(dtime);
- if(!elapsed_timers.empty())
- errorstream<<"Node timers don't work yet!"<<std::endl;
+ std::map<v3s16, NodeTimer> elapsed_timers =
+ block->m_node_timers.step((float)dtime);
+ if(!elapsed_timers.empty()){
+ MapNode n;
+ for(std::map<v3s16, NodeTimer>::iterator
+ i = elapsed_timers.begin();
+ i != elapsed_timers.end(); i++){
+ n = block->getNodeNoEx(i->first);
+ if(scriptapi_node_on_timer(m_lua,i->first,n,i->second.elapsed))
+ block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
+ }
+ }
}
}
diff --git a/src/map.cpp b/src/map.cpp
index c6e010c45..dc1f45068 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1881,6 +1881,59 @@ void Map::removeNodeMetadata(v3s16 p)
block->m_node_metadata.remove(p_rel);
}
+NodeTimer Map::getNodeTimer(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(!block){
+ infostream<<"Map::getNodeTimer(): Need to emerge "
+ <<PP(blockpos)<<std::endl;
+ block = emergeBlock(blockpos, false);
+ }
+ if(!block)
+ {
+ infostream<<"WARNING: Map::getNodeTimer(): Block not found"
+ <<std::endl;
+ return NodeTimer();
+ }
+ NodeTimer t = block->m_node_timers.get(p_rel);
+ return t;
+}
+
+void Map::setNodeTimer(v3s16 p, NodeTimer t)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(!block){
+ infostream<<"Map::setNodeTimer(): Need to emerge "
+ <<PP(blockpos)<<std::endl;
+ block = emergeBlock(blockpos, false);
+ }
+ if(!block)
+ {
+ infostream<<"WARNING: Map::setNodeTimer(): Block not found"
+ <<std::endl;
+ return;
+ }
+ block->m_node_timers.set(p_rel, t);
+}
+
+void Map::removeNodeTimer(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
+ {
+ infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
+ <<std::endl;
+ return;
+ }
+ block->m_node_timers.remove(p_rel);
+}
+
/*
ServerMap
*/
diff --git a/src/map.h b/src/map.h
index b25c26957..b561e5e72 100644
--- a/src/map.h
+++ b/src/map.h
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h"
#include "modifiedstate.h"
#include "util/container.h"
+#include "nodetimer.h"
extern "C" {
#include "sqlite3.h"
@@ -311,6 +312,15 @@ public:
void removeNodeMetadata(v3s16 p);
/*
+ Node Timers
+ These are basically coordinate wrappers to MapBlock
+ */
+
+ NodeTimer getNodeTimer(v3s16 p);
+ void setNodeTimer(v3s16 p, NodeTimer t);
+ void removeNodeTimer(v3s16 p);
+
+ /*
Misc.
*/
core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index efe628a4e..62c670fd3 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -621,9 +621,9 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
// (this field should have not been added)
if(version == 23)
writeU8(os, 0);
- // Node timers (uncomment when node timers are taken into use)
- /*if(version >= 24)
- m_node_timers.serialize(os);*/
+ // Node timers are in version 24
+ if(version >= 24)
+ m_node_timers.serialize(os);
// Static objects
m_static_objects.serialize(os);
@@ -703,15 +703,15 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
if(disk)
{
// Node timers
- if(version == 23)
+ if(version == 23){
// Read unused zero
readU8(is);
- // Uncomment when node timers are taken into use
- /*else if(version >= 24){
+ }
+ else if(version >= 24){
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
<<": Node timers"<<std::endl);
m_node_timers.deSerialize(is);
- }*/
+ }
// Static objects
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
diff --git a/src/mapblock.h b/src/mapblock.h
index 08fd2c754..adb3324f6 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -430,6 +430,26 @@ public:
{
return m_usage_timer;
}
+
+ /*
+ Node Timers
+ */
+ // Get timer
+ NodeTimer getNodeTimer(v3s16 p){
+ return m_node_timers.get(p);
+ }
+ // Deletes timer
+ void removeNodeTimer(v3s16 p){
+ m_node_timers.remove(p);
+ }
+ // Deletes old timer and sets a new one
+ void setNodeTimer(v3s16 p, NodeTimer t){
+ m_node_timers.set(p,t);
+ }
+ // Deletes all timers
+ void clearNodeTimers(){
+ m_node_timers.clear();
+ }
/*
Serialization
diff --git a/src/nodetimer.cpp b/src/nodetimer.cpp
index 468c177fd..b20bcf578 100644
--- a/src/nodetimer.cpp
+++ b/src/nodetimer.cpp
@@ -28,13 +28,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
void NodeTimer::serialize(std::ostream &os) const
{
- writeF1000(os, duration);
+ writeF1000(os, timeout);
writeF1000(os, elapsed);
}
void NodeTimer::deSerialize(std::istream &is)
{
- duration = readF1000(is);
+ timeout = readF1000(is);
elapsed = readF1000(is);
}
@@ -94,7 +94,7 @@ void NodeTimerList::deSerialize(std::istream &is)
NodeTimer t;
t.deSerialize(is);
- if(t.duration <= 0)
+ if(t.timeout <= 0)
{
infostream<<"WARNING: NodeTimerList::deSerialize(): "
<<"invalid data at position"
@@ -116,9 +116,9 @@ void NodeTimerList::deSerialize(std::istream &is)
}
}
-std::map<v3s16, f32> NodeTimerList::step(float dtime)
+std::map<v3s16, NodeTimer> NodeTimerList::step(float dtime)
{
- std::map<v3s16, f32> elapsed_timers;
+ std::map<v3s16, NodeTimer> elapsed_timers;
// Increment timers
for(std::map<v3s16, NodeTimer>::iterator
i = m_data.begin();
@@ -126,13 +126,13 @@ std::map<v3s16, f32> NodeTimerList::step(float dtime)
v3s16 p = i->first;
NodeTimer t = i->second;
t.elapsed += dtime;
- if(t.elapsed >= t.duration)
- elapsed_timers.insert(std::make_pair(p, t.elapsed));
+ if(t.elapsed >= t.timeout)
+ elapsed_timers.insert(std::make_pair(p, t));
else
i->second = t;
}
// Delete elapsed timers
- for(std::map<v3s16, f32>::const_iterator
+ for(std::map<v3s16, NodeTimer>::const_iterator
i = elapsed_timers.begin();
i != elapsed_timers.end(); i++){
v3s16 p = i->first;
diff --git a/src/nodetimer.h b/src/nodetimer.h
index deb77f10e..f8d3e1c57 100644
--- a/src/nodetimer.h
+++ b/src/nodetimer.h
@@ -35,15 +35,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class NodeTimer
{
public:
- NodeTimer(): duration(0.), elapsed(0.) {}
- NodeTimer(f32 duration_, f32 elapsed_):
- duration(duration_), elapsed(elapsed_) {}
+ NodeTimer(): timeout(0.), elapsed(0.) {}
+ NodeTimer(f32 timeout_, f32 elapsed_):
+ timeout(timeout_), elapsed(elapsed_) {}
~NodeTimer() {}
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
- f32 duration;
+ f32 timeout;
f32 elapsed;
};
@@ -81,7 +81,7 @@ public:
}
// A step in time. Returns map of elapsed timers.
- std::map<v3s16, f32> step(float dtime);
+ std::map<v3s16, NodeTimer> step(float dtime);
private:
std::map<v3s16, NodeTimer> m_data;
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index 6cb701689..12d2a8247 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -3119,6 +3119,162 @@ const luaL_reg LuaPerlinNoise::methods[] = {
};
/*
+ NodeTimerRef
+*/
+
+class NodeTimerRef
+{
+private:
+ v3s16 m_p;
+ ServerEnvironment *m_env;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static int gc_object(lua_State *L) {
+ NodeTimerRef *o = *(NodeTimerRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+ }
+
+ static NodeTimerRef *checkobject(lua_State *L, int narg)
+ {
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(NodeTimerRef**)ud; // unbox pointer
+ }
+
+ static int l_set(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ f32 t = luaL_checknumber(L,2);
+ f32 e = luaL_checknumber(L,3);
+ env->getMap().setNodeTimer(o->m_p,NodeTimer(t,e));
+ return 0;
+ }
+
+ static int l_start(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ f32 t = luaL_checknumber(L,2);
+ env->getMap().setNodeTimer(o->m_p,NodeTimer(t,0));
+ return 0;
+ }
+
+ static int l_stop(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ env->getMap().removeNodeTimer(o->m_p);
+ return 0;
+ }
+
+ static int l_is_started(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ NodeTimer t = env->getMap().getNodeTimer(o->m_p);
+ lua_pushboolean(L,(t.timeout != 0));
+ return 1;
+ }
+
+ static int l_get_timeout(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ NodeTimer t = env->getMap().getNodeTimer(o->m_p);
+ lua_pushnumber(L,t.timeout);
+ return 1;
+ }
+
+ static int l_get_elapsed(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+
+ NodeTimer t = env->getMap().getNodeTimer(o->m_p);
+ lua_pushnumber(L,t.elapsed);
+ return 1;
+ }
+
+public:
+ NodeTimerRef(v3s16 p, ServerEnvironment *env):
+ m_p(p),
+ m_env(env)
+ {
+ }
+
+ ~NodeTimerRef()
+ {
+ }
+
+ // Creates an NodeTimerRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, v3s16 p, ServerEnvironment *env)
+ {
+ NodeTimerRef *o = new NodeTimerRef(p, env);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ }
+
+ static void set_null(lua_State *L)
+ {
+ NodeTimerRef *o = checkobject(L, -1);
+ o->m_env = NULL;
+ }
+
+ static void Register(lua_State *L)
+ {
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+ }
+};
+const char NodeTimerRef::className[] = "NodeTimerRef";
+const luaL_reg NodeTimerRef::methods[] = {
+ method(NodeTimerRef, start),
+ method(NodeTimerRef, set),
+ method(NodeTimerRef, stop),
+ method(NodeTimerRef, is_started),
+ method(NodeTimerRef, get_timeout),
+ method(NodeTimerRef, get_elapsed),
+ {0,0}
+};
+
+/*
EnvRef
*/
@@ -3351,6 +3507,31 @@ private:
return 1;
}
+ // EnvRef:get_meta(pos)
+ static int l_get_meta(lua_State *L)
+ {
+ //infostream<<"EnvRef::l_get_meta()"<<std::endl;
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ v3s16 p = read_v3s16(L, 2);
+ NodeMetaRef::create(L, p, env);
+ return 1;
+ }
+
+ // EnvRef:get_node_timer(pos)
+ static int l_get_node_timer(lua_State *L)
+ {
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ v3s16 p = read_v3s16(L, 2);
+ NodeTimerRef::create(L, p, env);
+ return 1;
+ }
+
// EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
static int l_add_entity(lua_State *L)
@@ -3431,19 +3612,6 @@ private:
return 0;
}
- // EnvRef:get_meta(pos)
- static int l_get_meta(lua_State *L)
- {
- //infostream<<"EnvRef::l_get_meta()"<<std::endl;
- EnvRef *o = checkobject(L, 1);
- ServerEnvironment *env = o->m_env;
- if(env == NULL) return 0;
- // Do it
- v3s16 p = read_v3s16(L, 2);
- NodeMetaRef::create(L, p, env);
- return 1;
- }
-
// EnvRef:get_player_by_name(name)
static int l_get_player_by_name(lua_State *L)
{
@@ -3713,6 +3881,7 @@ const luaL_reg EnvRef::methods[] = {
method(EnvRef, add_rat),
method(EnvRef, add_firefly),
method(EnvRef, get_meta),
+ method(EnvRef, get_node_timer),
method(EnvRef, get_player_by_name),
method(EnvRef, get_objects_inside_radius),
method(EnvRef, set_timeofday),
@@ -4729,6 +4898,7 @@ void scriptapi_export(lua_State *L, Server *server)
LuaItemStack::Register(L);
InvRef::Register(L);
NodeMetaRef::Register(L);
+ NodeTimerRef::Register(L);
ObjectRef::Register(L);
EnvRef::Register(L);
LuaPseudoRandom::Register(L);
@@ -5482,6 +5652,29 @@ void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node)
script_error(L, "error: %s", lua_tostring(L, -1));
}
+bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_timer"))
+ return false;
+
+ // Call function
+ push_v3s16(L, p);
+ lua_pushnumber(L,dtime);
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(lua_isboolean(L,-1) && lua_toboolean(L,-1) == true)
+ return true;
+
+ return false;
+}
+
void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
const std::string &formname,
const std::map<std::string, std::string> &fields,
diff --git a/src/scriptapi.h b/src/scriptapi.h
index 2fe662ddc..2bacdebad 100644
--- a/src/scriptapi.h
+++ b/src/scriptapi.h
@@ -94,6 +94,8 @@ void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node);
void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node);
// Node post-destructor
void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node);
+// Node Timer event
+bool scriptapi_node_on_timer(lua_State *L, v3s16 p, MapNode node, f32 dtime);
// Called when a metadata form returns values
void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
const std::string &formname,
diff --git a/src/serialization.h b/src/serialization.h
index 70b3ee74d..266eada17 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -58,12 +58,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
20: many existing content types translated to extended ones
21: dynamic content type allocation
22: minerals removed, facedir & wallmounted changed
- 23: NodeTimers, new node metadata format
+ 23: new node metadata format
+ 24: NodeTimers
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 23
+#define SER_FMT_VER_HIGHEST 24
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0
diff --git a/src/server.cpp b/src/server.cpp
index 893d03b24..b3cbea6a4 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -843,7 +843,7 @@ queue_full_break:
/*timer_result = timer.stop(true);
if(timer_result != 0)
- infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
+ infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
}
void RemoteClient::GotBlock(v3s16 p)