Make node timers more efficient
parent
27aff22a9b
commit
559dd99469
|
@ -186,7 +186,7 @@ void content_nodemeta_deserialize_legacy(std::istream &is,
|
||||||
meta->set(p, data);
|
meta->set(p, data);
|
||||||
|
|
||||||
if(need_timer)
|
if(need_timer)
|
||||||
timers->set(p, NodeTimer(1., 0.));
|
timers->set(NodeTimer(1., 0., p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1030,17 +1030,17 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
|
||||||
m_lbm_mgr.applyLBMs(this, block, stamp);
|
m_lbm_mgr.applyLBMs(this, block, stamp);
|
||||||
|
|
||||||
// Run node timers
|
// Run node timers
|
||||||
std::map<v3s16, NodeTimer> elapsed_timers =
|
std::vector<NodeTimer> elapsed_timers =
|
||||||
block->m_node_timers.step((float)dtime_s);
|
block->m_node_timers.step((float)dtime_s);
|
||||||
if(!elapsed_timers.empty()){
|
if (!elapsed_timers.empty()) {
|
||||||
MapNode n;
|
MapNode n;
|
||||||
for(std::map<v3s16, NodeTimer>::iterator
|
for (std::vector<NodeTimer>::iterator
|
||||||
i = elapsed_timers.begin();
|
i = elapsed_timers.begin();
|
||||||
i != elapsed_timers.end(); ++i){
|
i != elapsed_timers.end(); ++i){
|
||||||
n = block->getNodeNoEx(i->first);
|
n = block->getNodeNoEx(i->position);
|
||||||
v3s16 p = i->first + block->getPosRelative();
|
v3s16 p = i->position + block->getPosRelative();
|
||||||
if(m_script->node_on_timer(p,n,i->second.elapsed))
|
if (m_script->node_on_timer(p, n, i->elapsed))
|
||||||
block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
|
block->setNodeTimer(NodeTimer(i->timeout, 0, i->position));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1434,17 +1434,19 @@ void ServerEnvironment::step(float dtime)
|
||||||
MOD_REASON_BLOCK_EXPIRED);
|
MOD_REASON_BLOCK_EXPIRED);
|
||||||
|
|
||||||
// Run node timers
|
// Run node timers
|
||||||
std::map<v3s16, NodeTimer> elapsed_timers =
|
std::vector<NodeTimer> elapsed_timers =
|
||||||
block->m_node_timers.step((float)dtime);
|
block->m_node_timers.step((float)dtime);
|
||||||
if(!elapsed_timers.empty()){
|
if (!elapsed_timers.empty()) {
|
||||||
MapNode n;
|
MapNode n;
|
||||||
for(std::map<v3s16, NodeTimer>::iterator
|
for (std::vector<NodeTimer>::iterator
|
||||||
i = elapsed_timers.begin();
|
i = elapsed_timers.begin();
|
||||||
i != elapsed_timers.end(); ++i){
|
i != elapsed_timers.end(); ++i) {
|
||||||
n = block->getNodeNoEx(i->first);
|
n = block->getNodeNoEx(i->position);
|
||||||
p = i->first + block->getPosRelative();
|
p = i->position + block->getPosRelative();
|
||||||
if(m_script->node_on_timer(p,n,i->second.elapsed))
|
if (m_script->node_on_timer(p, n, i->elapsed)) {
|
||||||
block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
|
block->setNodeTimer(NodeTimer(
|
||||||
|
i->timeout, 0, i->position));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2087,11 +2087,13 @@ NodeTimer Map::getNodeTimer(v3s16 p)
|
||||||
return NodeTimer();
|
return NodeTimer();
|
||||||
}
|
}
|
||||||
NodeTimer t = block->m_node_timers.get(p_rel);
|
NodeTimer t = block->m_node_timers.get(p_rel);
|
||||||
return t;
|
NodeTimer nt(t.timeout, t.elapsed, p);
|
||||||
|
return nt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::setNodeTimer(v3s16 p, NodeTimer t)
|
void Map::setNodeTimer(const NodeTimer &t)
|
||||||
{
|
{
|
||||||
|
v3s16 p = t.position;
|
||||||
v3s16 blockpos = getNodeBlockPos(p);
|
v3s16 blockpos = getNodeBlockPos(p);
|
||||||
v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
|
v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
|
||||||
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
||||||
|
@ -2105,7 +2107,8 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t)
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
block->m_node_timers.set(p_rel, t);
|
NodeTimer nt(t.timeout, t.elapsed, p_rel);
|
||||||
|
block->m_node_timers.set(nt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::removeNodeTimer(v3s16 p)
|
void Map::removeNodeTimer(v3s16 p)
|
||||||
|
|
|
@ -327,7 +327,7 @@ public:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NodeTimer getNodeTimer(v3s16 p);
|
NodeTimer getNodeTimer(v3s16 p);
|
||||||
void setNodeTimer(v3s16 p, NodeTimer t);
|
void setNodeTimer(const NodeTimer &t);
|
||||||
void removeNodeTimer(v3s16 p);
|
void removeNodeTimer(v3s16 p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -488,9 +488,9 @@ public:
|
||||||
m_node_timers.remove(p);
|
m_node_timers.remove(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setNodeTimer(v3s16 p, NodeTimer t)
|
inline void setNodeTimer(const NodeTimer &t)
|
||||||
{
|
{
|
||||||
m_node_timers.set(p,t);
|
m_node_timers.set(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void clearNodeTimers()
|
inline void clearNodeTimers()
|
||||||
|
|
|
@ -47,36 +47,38 @@ void NodeTimerList::serialize(std::ostream &os, u8 map_format_version) const
|
||||||
{
|
{
|
||||||
if (map_format_version == 24) {
|
if (map_format_version == 24) {
|
||||||
// Version 0 is a placeholder for "nothing to see here; go away."
|
// Version 0 is a placeholder for "nothing to see here; go away."
|
||||||
if (m_data.empty()) {
|
if (m_timers.empty()) {
|
||||||
writeU8(os, 0); // version
|
writeU8(os, 0); // version
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
writeU8(os, 1); // version
|
writeU8(os, 1); // version
|
||||||
writeU16(os, m_data.size());
|
writeU16(os, m_timers.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map_format_version >= 25) {
|
if (map_format_version >= 25) {
|
||||||
writeU8(os, 2 + 4 + 4); // length of the data for a single timer
|
writeU8(os, 2 + 4 + 4); // length of the data for a single timer
|
||||||
writeU16(os, m_data.size());
|
writeU16(os, m_timers.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::map<v3s16, NodeTimer>::const_iterator
|
for (std::multimap<double, NodeTimer>::const_iterator
|
||||||
i = m_data.begin();
|
i = m_timers.begin();
|
||||||
i != m_data.end(); ++i) {
|
i != m_timers.end(); ++i) {
|
||||||
v3s16 p = i->first;
|
|
||||||
NodeTimer t = i->second;
|
NodeTimer t = i->second;
|
||||||
|
NodeTimer nt = NodeTimer(t.timeout,
|
||||||
|
t.timeout - (f32)(i->first - m_time), t.position);
|
||||||
|
v3s16 p = t.position;
|
||||||
|
|
||||||
u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X;
|
u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X;
|
||||||
writeU16(os, p16);
|
writeU16(os, p16);
|
||||||
t.serialize(os);
|
nt.serialize(os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||||
{
|
{
|
||||||
m_data.clear();
|
clear();
|
||||||
|
|
||||||
if(map_format_version == 24){
|
if (map_format_version == 24) {
|
||||||
u8 timer_version = readU8(is);
|
u8 timer_version = readU8(is);
|
||||||
if(timer_version == 0)
|
if(timer_version == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -84,7 +86,7 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||||
throw SerializationError("unsupported NodeTimerList version");
|
throw SerializationError("unsupported NodeTimerList version");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(map_format_version >= 25){
|
if (map_format_version >= 25) {
|
||||||
u8 timer_data_len = readU8(is);
|
u8 timer_data_len = readU8(is);
|
||||||
if(timer_data_len != 2+4+4)
|
if(timer_data_len != 2+4+4)
|
||||||
throw SerializationError("unsupported NodeTimer data length");
|
throw SerializationError("unsupported NodeTimer data length");
|
||||||
|
@ -92,8 +94,7 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||||
|
|
||||||
u16 count = readU16(is);
|
u16 count = readU16(is);
|
||||||
|
|
||||||
for(u16 i=0; i<count; i++)
|
for (u16 i = 0; i < count; i++) {
|
||||||
{
|
|
||||||
u16 p16 = readU16(is);
|
u16 p16 = readU16(is);
|
||||||
|
|
||||||
v3s16 p;
|
v3s16 p;
|
||||||
|
@ -103,11 +104,10 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||||
p16 &= MAP_BLOCKSIZE - 1;
|
p16 &= MAP_BLOCKSIZE - 1;
|
||||||
p.X = p16;
|
p.X = p16;
|
||||||
|
|
||||||
NodeTimer t;
|
NodeTimer t(p);
|
||||||
t.deSerialize(is);
|
t.deSerialize(is);
|
||||||
|
|
||||||
if(t.timeout <= 0)
|
if (t.timeout <= 0) {
|
||||||
{
|
|
||||||
warningstream<<"NodeTimerList::deSerialize(): "
|
warningstream<<"NodeTimerList::deSerialize(): "
|
||||||
<<"invalid data at position"
|
<<"invalid data at position"
|
||||||
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
|
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
|
||||||
|
@ -115,8 +115,7 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_data.find(p) != m_data.end())
|
if (m_iterators.find(p) != m_iterators.end()) {
|
||||||
{
|
|
||||||
warningstream<<"NodeTimerList::deSerialize(): "
|
warningstream<<"NodeTimerList::deSerialize(): "
|
||||||
<<"already set data at position"
|
<<"already set data at position"
|
||||||
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
|
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
|
||||||
|
@ -124,31 +123,30 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.insert(std::make_pair(p, t));
|
insert(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<v3s16, NodeTimer> NodeTimerList::step(float dtime)
|
std::vector<NodeTimer> NodeTimerList::step(float dtime)
|
||||||
{
|
{
|
||||||
std::map<v3s16, NodeTimer> elapsed_timers;
|
std::vector<NodeTimer> elapsed_timers;
|
||||||
// Increment timers
|
m_time += dtime;
|
||||||
for(std::map<v3s16, NodeTimer>::iterator
|
if (m_next_trigger_time == -1. || m_time < m_next_trigger_time) {
|
||||||
i = m_data.begin();
|
return elapsed_timers;
|
||||||
i != m_data.end(); ++i){
|
}
|
||||||
v3s16 p = i->first;
|
std::multimap<double, NodeTimer>::iterator i = m_timers.begin();
|
||||||
|
// Process timers
|
||||||
|
for (; i != m_timers.end() && i->first <= m_time; ++i) {
|
||||||
NodeTimer t = i->second;
|
NodeTimer t = i->second;
|
||||||
t.elapsed += dtime;
|
t.elapsed = t.timeout + (f32)(m_time - i->first);
|
||||||
if(t.elapsed >= t.timeout)
|
elapsed_timers.push_back(t);
|
||||||
elapsed_timers.insert(std::make_pair(p, t));
|
m_iterators.erase(t.position);
|
||||||
else
|
|
||||||
i->second = t;
|
|
||||||
}
|
}
|
||||||
// Delete elapsed timers
|
// Delete elapsed timers
|
||||||
for(std::map<v3s16, NodeTimer>::const_iterator
|
m_timers.erase(m_timers.begin(), i);
|
||||||
i = elapsed_timers.begin();
|
if (m_timers.empty())
|
||||||
i != elapsed_timers.end(); ++i){
|
m_next_trigger_time = -1.;
|
||||||
v3s16 p = i->first;
|
else
|
||||||
m_data.erase(p);
|
m_next_trigger_time = m_timers.begin()->first;
|
||||||
}
|
|
||||||
return elapsed_timers;
|
return elapsed_timers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "irr_v3d.h"
|
#include "irr_v3d.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NodeTimer provides per-node timed callback functionality.
|
NodeTimer provides per-node timed callback functionality.
|
||||||
|
@ -36,8 +37,10 @@ class NodeTimer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodeTimer(): timeout(0.), elapsed(0.) {}
|
NodeTimer(): timeout(0.), elapsed(0.) {}
|
||||||
NodeTimer(f32 timeout_, f32 elapsed_):
|
NodeTimer(const v3s16 &position_):
|
||||||
timeout(timeout_), elapsed(elapsed_) {}
|
timeout(0.), elapsed(0.), position(position_) {}
|
||||||
|
NodeTimer(f32 timeout_, f32 elapsed_, v3s16 position_):
|
||||||
|
timeout(timeout_), elapsed(elapsed_), position(position_) {}
|
||||||
~NodeTimer() {}
|
~NodeTimer() {}
|
||||||
|
|
||||||
void serialize(std::ostream &os) const;
|
void serialize(std::ostream &os) const;
|
||||||
|
@ -45,6 +48,7 @@ public:
|
||||||
|
|
||||||
f32 timeout;
|
f32 timeout;
|
||||||
f32 elapsed;
|
f32 elapsed;
|
||||||
|
v3s16 position;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -54,37 +58,78 @@ public:
|
||||||
class NodeTimerList
|
class NodeTimerList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodeTimerList() {}
|
NodeTimerList(): m_next_trigger_time(-1.), m_time(0.) {}
|
||||||
~NodeTimerList() {}
|
~NodeTimerList() {}
|
||||||
|
|
||||||
void serialize(std::ostream &os, u8 map_format_version) const;
|
void serialize(std::ostream &os, u8 map_format_version) const;
|
||||||
void deSerialize(std::istream &is, u8 map_format_version);
|
void deSerialize(std::istream &is, u8 map_format_version);
|
||||||
|
|
||||||
// Get timer
|
// Get timer
|
||||||
NodeTimer get(v3s16 p){
|
NodeTimer get(const v3s16 &p) {
|
||||||
std::map<v3s16, NodeTimer>::iterator n = m_data.find(p);
|
std::map<v3s16, std::multimap<double, NodeTimer>::iterator>::iterator n =
|
||||||
if(n == m_data.end())
|
m_iterators.find(p);
|
||||||
|
if (n == m_iterators.end())
|
||||||
return NodeTimer();
|
return NodeTimer();
|
||||||
return n->second;
|
NodeTimer t = n->second->second;
|
||||||
|
t.elapsed = t.timeout - (n->second->first - m_time);
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
// Deletes timer
|
// Deletes timer
|
||||||
void remove(v3s16 p){
|
void remove(v3s16 p) {
|
||||||
m_data.erase(p);
|
std::map<v3s16, std::multimap<double, NodeTimer>::iterator>::iterator n =
|
||||||
|
m_iterators.find(p);
|
||||||
|
if(n != m_iterators.end()) {
|
||||||
|
double removed_time = n->second->first;
|
||||||
|
m_timers.erase(n->second);
|
||||||
|
m_iterators.erase(n);
|
||||||
|
// Yes, this is float equality, but it is not a problem
|
||||||
|
// since we only test equality of floats as an ordered type
|
||||||
|
// and thus we never lose precision
|
||||||
|
if (removed_time == m_next_trigger_time) {
|
||||||
|
if (m_timers.empty())
|
||||||
|
m_next_trigger_time = -1.;
|
||||||
|
else
|
||||||
|
m_next_trigger_time = m_timers.begin()->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Undefined behaviour if there already is a timer
|
||||||
|
void insert(NodeTimer timer) {
|
||||||
|
v3s16 p = timer.position;
|
||||||
|
double trigger_time = m_time + (double)(timer.timeout - timer.elapsed);
|
||||||
|
std::multimap<double, NodeTimer>::iterator it =
|
||||||
|
m_timers.insert(std::pair<double, NodeTimer>(
|
||||||
|
trigger_time, timer
|
||||||
|
));
|
||||||
|
m_iterators.insert(
|
||||||
|
std::pair<v3s16, std::multimap<double, NodeTimer>::iterator>(p, it));
|
||||||
|
if (m_next_trigger_time == -1. || trigger_time < m_next_trigger_time)
|
||||||
|
m_next_trigger_time = trigger_time;
|
||||||
}
|
}
|
||||||
// Deletes old timer and sets a new one
|
// Deletes old timer and sets a new one
|
||||||
void set(v3s16 p, NodeTimer t){
|
inline void set(const NodeTimer &timer) {
|
||||||
m_data[p] = t;
|
remove(timer.position);
|
||||||
|
insert(timer);
|
||||||
}
|
}
|
||||||
// Deletes all timers
|
// Deletes all timers
|
||||||
void clear(){
|
void clear() {
|
||||||
m_data.clear();
|
m_timers.clear();
|
||||||
|
m_iterators.clear();
|
||||||
|
m_next_trigger_time = -1.;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A step in time. Returns map of elapsed timers.
|
inline double getNextTriggerTime() {
|
||||||
std::map<v3s16, NodeTimer> step(float dtime);
|
return m_next_trigger_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move forward in time, returns elapsed timers
|
||||||
|
std::vector<NodeTimer> step(float dtime);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<v3s16, NodeTimer> m_data;
|
std::multimap<double, NodeTimer> m_timers;
|
||||||
|
std::map<v3s16, std::multimap<double, NodeTimer>::iterator> m_iterators;
|
||||||
|
double m_next_trigger_time;
|
||||||
|
double m_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,7 +45,7 @@ int NodeTimerRef::l_set(lua_State *L)
|
||||||
if(env == NULL) return 0;
|
if(env == NULL) return 0;
|
||||||
f32 t = luaL_checknumber(L,2);
|
f32 t = luaL_checknumber(L,2);
|
||||||
f32 e = luaL_checknumber(L,3);
|
f32 e = luaL_checknumber(L,3);
|
||||||
env->getMap().setNodeTimer(o->m_p,NodeTimer(t,e));
|
env->getMap().setNodeTimer(NodeTimer(t, e, o->m_p));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ int NodeTimerRef::l_start(lua_State *L)
|
||||||
ServerEnvironment *env = o->m_env;
|
ServerEnvironment *env = o->m_env;
|
||||||
if(env == NULL) return 0;
|
if(env == NULL) return 0;
|
||||||
f32 t = luaL_checknumber(L,2);
|
f32 t = luaL_checknumber(L,2);
|
||||||
env->getMap().setNodeTimer(o->m_p,NodeTimer(t,0));
|
env->getMap().setNodeTimer(NodeTimer(t, 0, o->m_p));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue