mirror of
https://github.com/minetest/minetest.git
synced 2024-08-21 05:54:09 +02:00
Preliminary "active block" stuff + set up test code to grow grass.
This commit is contained in:
parent
af7d50e910
commit
0af5311538
@ -1193,31 +1193,23 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
if(datasize < 4)
|
||||
return;
|
||||
|
||||
u16 time = readU16(&data[2]);
|
||||
time = time % 24000;
|
||||
m_time_of_day = time;
|
||||
//dstream<<"Client: time="<<time<<std::endl;
|
||||
u16 time_of_day = readU16(&data[2]);
|
||||
time_of_day = time_of_day % 24000;
|
||||
//dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
|
||||
|
||||
/*
|
||||
Day/night
|
||||
|
||||
time_of_day:
|
||||
0 = midnight
|
||||
12000 = midday
|
||||
*/
|
||||
{
|
||||
u32 dr = time_to_daynight_ratio(m_time_of_day);
|
||||
m_env.setTimeOfDay(time_of_day);
|
||||
|
||||
dstream<<"Client: time_of_day="<<m_time_of_day
|
||||
u32 dr = m_env.getDayNightRatio();
|
||||
|
||||
dstream<<"Client: time_of_day="<<time_of_day
|
||||
<<", dr="<<dr
|
||||
<<std::endl;
|
||||
|
||||
if(dr != m_env.getDayNightRatio())
|
||||
{
|
||||
dout_client<<DTIME<<"Client: changing day-night ratio"<<std::endl;
|
||||
m_env.setDayNightRatio(dr);
|
||||
m_env.expireMeshes(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "collision.h"
|
||||
|
||||
|
||||
Environment::Environment()
|
||||
Environment::Environment():
|
||||
m_time_of_day(9000)
|
||||
{
|
||||
m_daynight_ratio = 0.5;
|
||||
}
|
||||
|
||||
Environment::~Environment()
|
||||
@ -174,14 +174,84 @@ void Environment::printPlayers(std::ostream &o)
|
||||
}
|
||||
}
|
||||
|
||||
void Environment::setDayNightRatio(u32 r)
|
||||
/*void Environment::setDayNightRatio(u32 r)
|
||||
{
|
||||
m_daynight_ratio = r;
|
||||
}
|
||||
getDayNightRatio() = r;
|
||||
}*/
|
||||
|
||||
u32 Environment::getDayNightRatio()
|
||||
{
|
||||
return m_daynight_ratio;
|
||||
//return getDayNightRatio();
|
||||
return time_to_daynight_ratio(m_time_of_day);
|
||||
}
|
||||
|
||||
/*
|
||||
ActiveBlockList
|
||||
*/
|
||||
|
||||
void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list)
|
||||
{
|
||||
v3s16 p;
|
||||
for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
|
||||
for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
|
||||
for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
|
||||
{
|
||||
// Set in list
|
||||
list[p] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveBlockList::update(core::list<v3s16> &active_positions,
|
||||
s16 radius,
|
||||
core::map<v3s16, bool> &blocks_removed,
|
||||
core::map<v3s16, bool> &blocks_added)
|
||||
{
|
||||
/*
|
||||
Create the new list
|
||||
*/
|
||||
core::map<v3s16, bool> newlist;
|
||||
for(core::list<v3s16>::Iterator i = active_positions.begin();
|
||||
i != active_positions.end(); i++)
|
||||
{
|
||||
fillRadiusBlock(*i, radius, newlist);
|
||||
}
|
||||
|
||||
/*
|
||||
Find out which blocks on the old list are not on the new list
|
||||
*/
|
||||
// Go through old list
|
||||
for(core::map<v3s16, bool>::Iterator i = m_list.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
// If not on new list, it's been removed
|
||||
if(newlist.find(p) == NULL)
|
||||
blocks_removed.insert(p, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Find out which blocks on the new list are not on the old list
|
||||
*/
|
||||
// Go through new list
|
||||
for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
// If not on old list, it's been added
|
||||
if(m_list.find(p) == NULL)
|
||||
blocks_added.insert(p, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Update m_list
|
||||
*/
|
||||
m_list.clear();
|
||||
for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
m_list.insert(p, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -192,16 +262,20 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
|
||||
m_map(map),
|
||||
m_server(server),
|
||||
m_random_spawn_timer(3),
|
||||
m_send_recommended_timer(0)
|
||||
m_send_recommended_timer(0),
|
||||
m_game_time(0),
|
||||
m_game_time_fraction_counter(0)
|
||||
{
|
||||
}
|
||||
|
||||
ServerEnvironment::~ServerEnvironment()
|
||||
{
|
||||
/*
|
||||
Convert all objects to static (thus delete the active objects)
|
||||
*/
|
||||
deactivateFarObjects(-1);
|
||||
// Clear active block list.
|
||||
// This makes the next one delete all active objects.
|
||||
m_active_blocks.clear();
|
||||
|
||||
// Convert all objects to static and delete the active objects
|
||||
deactivateFarObjects(true);
|
||||
|
||||
// Drop/delete map
|
||||
m_map->drop();
|
||||
@ -384,7 +458,71 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
|
||||
}
|
||||
}
|
||||
|
||||
void ServerEnvironment::saveMeta(const std::string &savedir)
|
||||
{
|
||||
std::string path = savedir + "/env_meta.txt";
|
||||
|
||||
// Open file and serialize
|
||||
std::ofstream os(path.c_str(), std::ios_base::binary);
|
||||
if(os.good() == false)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::saveMeta(): Failed to open "
|
||||
<<path<<std::endl;
|
||||
throw SerializationError("Couldn't save env meta");
|
||||
}
|
||||
|
||||
Settings args;
|
||||
args.setU64("game_time", m_game_time);
|
||||
args.setU64("time_of_day", getTimeOfDay());
|
||||
args.writeLines(os);
|
||||
os<<"EnvArgsEnd\n";
|
||||
}
|
||||
|
||||
void ServerEnvironment::loadMeta(const std::string &savedir)
|
||||
{
|
||||
std::string path = savedir + "/env_meta.txt";
|
||||
|
||||
// Open file and deserialize
|
||||
std::ifstream is(path.c_str(), std::ios_base::binary);
|
||||
if(is.good() == false)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::loadMeta(): Failed to open "
|
||||
<<path<<std::endl;
|
||||
throw SerializationError("Couldn't load env meta");
|
||||
}
|
||||
|
||||
Settings args;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(is.eof())
|
||||
throw SerializationError
|
||||
("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
std::string trimmedline = trim(line);
|
||||
if(trimmedline == "EnvArgsEnd")
|
||||
break;
|
||||
args.parseConfigLine(line);
|
||||
}
|
||||
|
||||
try{
|
||||
m_game_time = args.getU64("game_time");
|
||||
}catch(SettingNotFoundException &e){
|
||||
// Getting this is crucial, otherwise timestamps are useless
|
||||
throw SerializationError("Couldn't load env meta game_time");
|
||||
}
|
||||
|
||||
try{
|
||||
m_time_of_day = args.getU64("time_of_day");
|
||||
}catch(SettingNotFoundException &e){
|
||||
// This is not as important
|
||||
m_time_of_day = 9000;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// This is probably very useless
|
||||
void spawnRandomObjects(MapBlock *block)
|
||||
{
|
||||
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
|
||||
@ -440,9 +578,21 @@ void ServerEnvironment::step(float dtime)
|
||||
//TimeTaker timer("ServerEnv step");
|
||||
|
||||
// Get some settings
|
||||
//bool free_move = g_settings.getBool("free_move");
|
||||
bool footprints = g_settings.getBool("footprints");
|
||||
|
||||
/*
|
||||
Increment game time
|
||||
*/
|
||||
{
|
||||
m_game_time_fraction_counter += dtime;
|
||||
u32 inc_i = (u32)m_game_time_fraction_counter;
|
||||
m_game_time += inc_i;
|
||||
m_game_time_fraction_counter -= (float)inc_i;
|
||||
}
|
||||
|
||||
/*
|
||||
Let map update it's timers
|
||||
*/
|
||||
{
|
||||
//TimeTaker timer("Server m_map->timerUpdate()");
|
||||
m_map->timerUpdate(dtime);
|
||||
@ -486,12 +636,188 @@ void ServerEnvironment::step(float dtime)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Manage active block list
|
||||
*/
|
||||
if(m_active_blocks_management_interval.step(dtime, 2.0))
|
||||
{
|
||||
/*
|
||||
Get player block positions
|
||||
*/
|
||||
core::list<v3s16> players_blockpos;
|
||||
for(core::list<Player*>::Iterator
|
||||
i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
// Ignore disconnected players
|
||||
if(player->peer_id == 0)
|
||||
continue;
|
||||
v3s16 blockpos = getNodeBlockPos(
|
||||
floatToInt(player->getPosition(), BS));
|
||||
players_blockpos.push_back(blockpos);
|
||||
}
|
||||
|
||||
/*
|
||||
Update list of active blocks, collecting changes
|
||||
*/
|
||||
const s16 active_block_range = 5;
|
||||
core::map<v3s16, bool> blocks_removed;
|
||||
core::map<v3s16, bool> blocks_added;
|
||||
m_active_blocks.update(players_blockpos, active_block_range,
|
||||
blocks_removed, blocks_added);
|
||||
|
||||
/*
|
||||
Handle removed blocks
|
||||
*/
|
||||
|
||||
// Convert active objects that are no more in active blocks to static
|
||||
deactivateFarObjects(false);
|
||||
|
||||
for(core::map<v3s16, bool>::Iterator
|
||||
i = blocks_removed.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
|
||||
/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
|
||||
<<") became inactive"<<std::endl;*/
|
||||
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
|
||||
// Set current time as timestamp
|
||||
block->setTimestamp(m_game_time);
|
||||
}
|
||||
|
||||
/*
|
||||
Handle added blocks
|
||||
*/
|
||||
|
||||
for(core::map<v3s16, bool>::Iterator
|
||||
i = blocks_added.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
|
||||
/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
|
||||
<<") became active"<<std::endl;*/
|
||||
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
|
||||
// Get time difference
|
||||
u32 dtime_s = 0;
|
||||
u32 stamp = block->getTimestamp();
|
||||
if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
|
||||
dtime_s = m_game_time - block->getTimestamp();
|
||||
|
||||
// Set current time as timestamp
|
||||
block->setTimestamp(m_game_time);
|
||||
|
||||
//dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
|
||||
|
||||
// Activate stored objects
|
||||
activateObjects(block);
|
||||
|
||||
// TODO: Do something
|
||||
|
||||
// Here's a quick demonstration
|
||||
v3s16 p0;
|
||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
|
||||
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
|
||||
{
|
||||
v3s16 p = p0 + block->getPosRelative();
|
||||
MapNode n = block->getNodeNoEx(p0);
|
||||
// Test something:
|
||||
// Convert all mud under proper day lighting to grass
|
||||
if(n.d == CONTENT_MUD)
|
||||
{
|
||||
if(1)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(content_features(n_top.d).walkable == false &&
|
||||
n_top.getLight(LIGHTBANK_DAY) >= 13)
|
||||
{
|
||||
n.d = CONTENT_GRASS;
|
||||
m_map->addNodeWithEvent(p, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Mess around in active blocks
|
||||
*/
|
||||
if(m_active_blocks_test_interval.step(dtime, 5.0))
|
||||
{
|
||||
for(core::map<v3s16, bool>::Iterator
|
||||
i = m_active_blocks.m_list.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
|
||||
/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
|
||||
<<") being handled"<<std::endl;*/
|
||||
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
|
||||
// Set current time as timestamp
|
||||
block->setTimestamp(m_game_time);
|
||||
|
||||
/*
|
||||
Do stuff!
|
||||
|
||||
Note that map modifications should be done using the event-
|
||||
making map methods so that the server gets information
|
||||
about them.
|
||||
|
||||
Reading can be done quickly directly from the block.
|
||||
|
||||
Everything should bind to inside this single content
|
||||
searching loop to keep things fast.
|
||||
*/
|
||||
|
||||
v3s16 p0;
|
||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
|
||||
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
|
||||
{
|
||||
v3s16 p = p0 + block->getPosRelative();
|
||||
MapNode n = block->getNodeNoEx(p0);
|
||||
// Test something:
|
||||
// Convert mud under proper lighting to grass
|
||||
if(n.d == CONTENT_MUD)
|
||||
{
|
||||
if(myrand()%4 == 0)
|
||||
{
|
||||
MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
|
||||
if(content_features(n_top.d).walkable == false &&
|
||||
n_top.getLightBlend(getDayNightRatio()) >= 13)
|
||||
{
|
||||
n.d = CONTENT_GRASS;
|
||||
m_map->addNodeWithEvent(p, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Step active objects
|
||||
*/
|
||||
{
|
||||
//TimeTaker timer("Step active objects");
|
||||
|
||||
|
||||
// This helps the objects to send data at the same time
|
||||
bool send_recommended = false;
|
||||
m_send_recommended_timer += dtime;
|
||||
if(m_send_recommended_timer > 0.15)
|
||||
@ -505,33 +831,23 @@ void ServerEnvironment::step(float dtime)
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
// Don't step if is to be removed or stored statically
|
||||
if(obj->m_removed || obj->m_pending_deactivation)
|
||||
continue;
|
||||
// Step object, putting messages directly to the queue
|
||||
obj->step(dtime, m_active_object_messages, send_recommended);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Manage active objects
|
||||
*/
|
||||
if(m_object_management_interval.step(dtime, 0.5))
|
||||
{
|
||||
//TimeTaker timer("ServerEnv object management");
|
||||
|
||||
const s16 to_active_range_blocks = 3;
|
||||
const s16 to_static_range_blocks = 4;
|
||||
//const f32 to_static_max_f = (to_active_max_blocks+2)*MAP_BLOCKSIZE*BS;
|
||||
|
||||
/*
|
||||
Remove objects that satisfy (m_removed && m_known_by_count==0)
|
||||
*/
|
||||
removeRemovedObjects();
|
||||
|
||||
/*
|
||||
Convert stored objects from blocks near the players to active.
|
||||
*/
|
||||
activateNearObjects(to_active_range_blocks);
|
||||
|
||||
/*
|
||||
Convert objects that are far away from all the players to static.
|
||||
*/
|
||||
deactivateFarObjects(to_static_range_blocks);
|
||||
}
|
||||
|
||||
if(g_settings.getBool("enable_experimental"))
|
||||
@ -791,11 +1107,18 @@ void ServerEnvironment::removeRemovedObjects()
|
||||
objects_to_remove.push_back(id);
|
||||
continue;
|
||||
}
|
||||
// If not m_removed, don't remove.
|
||||
if(obj->m_removed == false)
|
||||
|
||||
/*
|
||||
We will delete objects that are marked as removed or thatare
|
||||
waiting for deletion after deactivation
|
||||
*/
|
||||
if(obj->m_removed == false && obj->m_pending_deactivation == false)
|
||||
continue;
|
||||
// Delete static data from block
|
||||
if(obj->m_static_exists)
|
||||
|
||||
/*
|
||||
Delete static data from block if is marked as removed
|
||||
*/
|
||||
if(obj->m_static_exists && obj->m_removed)
|
||||
{
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
|
||||
if(block)
|
||||
@ -804,9 +1127,11 @@ void ServerEnvironment::removeRemovedObjects()
|
||||
block->setChangedFlag();
|
||||
}
|
||||
}
|
||||
|
||||
// If m_known_by_count > 0, don't actually remove.
|
||||
if(obj->m_known_by_count > 0)
|
||||
continue;
|
||||
|
||||
// Delete
|
||||
delete obj;
|
||||
// Id to be removed from m_active_objects
|
||||
@ -823,82 +1148,62 @@ void ServerEnvironment::removeRemovedObjects()
|
||||
/*
|
||||
Convert stored objects from blocks near the players to active.
|
||||
*/
|
||||
void ServerEnvironment::activateNearObjects(s16 range_blocks)
|
||||
void ServerEnvironment::activateObjects(MapBlock *block)
|
||||
{
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
if(block==NULL)
|
||||
return;
|
||||
// Ignore if no stored objects (to not set changed flag)
|
||||
if(block->m_static_objects.m_stored.size() == 0)
|
||||
return;
|
||||
// A list for objects that couldn't be converted to static for some
|
||||
// reason. They will be stored back.
|
||||
core::list<StaticObject> new_stored;
|
||||
// Loop through stored static objects
|
||||
for(core::list<StaticObject>::Iterator
|
||||
i = block->m_static_objects.m_stored.begin();
|
||||
i != block->m_static_objects.m_stored.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
|
||||
// Ignore disconnected players
|
||||
if(player->peer_id == 0)
|
||||
continue;
|
||||
|
||||
v3f playerpos = player->getPosition();
|
||||
|
||||
v3s16 blockpos0 = getNodeBlockPos(floatToInt(playerpos, BS));
|
||||
v3s16 bpmin = blockpos0 - v3s16(1,1,1)*range_blocks;
|
||||
v3s16 bpmax = blockpos0 + v3s16(1,1,1)*range_blocks;
|
||||
// Loop through all nearby blocks
|
||||
for(s16 x=bpmin.X; x<=bpmax.X; x++)
|
||||
for(s16 y=bpmin.Y; y<=bpmax.Y; y++)
|
||||
for(s16 z=bpmin.Z; z<=bpmax.Z; z++)
|
||||
/*dstream<<"INFO: Server: Creating an active object from "
|
||||
<<"static data"<<std::endl;*/
|
||||
StaticObject &s_obj = *i;
|
||||
// Create an active object from the data
|
||||
ServerActiveObject *obj = ServerActiveObject::create
|
||||
(s_obj.type, this, 0, s_obj.pos, s_obj.data);
|
||||
// If couldn't create object, store static data back.
|
||||
if(obj==NULL)
|
||||
{
|
||||
v3s16 blockpos(x,y,z);
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
|
||||
if(block==NULL)
|
||||
continue;
|
||||
// Ignore if no stored objects (to not set changed flag)
|
||||
if(block->m_static_objects.m_stored.size() == 0)
|
||||
continue;
|
||||
// This will contain the leftovers of the stored list
|
||||
core::list<StaticObject> new_stored;
|
||||
// Loop through stored static objects
|
||||
for(core::list<StaticObject>::Iterator
|
||||
i = block->m_static_objects.m_stored.begin();
|
||||
i != block->m_static_objects.m_stored.end(); i++)
|
||||
{
|
||||
/*dstream<<"INFO: Server: Creating an active object from "
|
||||
<<"static data"<<std::endl;*/
|
||||
StaticObject &s_obj = *i;
|
||||
// Create an active object from the data
|
||||
ServerActiveObject *obj = ServerActiveObject::create
|
||||
(s_obj.type, this, 0, s_obj.pos, s_obj.data);
|
||||
if(obj==NULL)
|
||||
{
|
||||
// This is necessary to preserve stuff during bugs
|
||||
// and errors
|
||||
new_stored.push_back(s_obj);
|
||||
continue;
|
||||
}
|
||||
// This will also add the object to the active static list
|
||||
addActiveObject(obj);
|
||||
//u16 id = addActiveObject(obj);
|
||||
}
|
||||
// Clear stored list
|
||||
block->m_static_objects.m_stored.clear();
|
||||
// Add leftover stuff to stored list
|
||||
for(core::list<StaticObject>::Iterator
|
||||
i = new_stored.begin();
|
||||
i != new_stored.end(); i++)
|
||||
{
|
||||
StaticObject &s_obj = *i;
|
||||
block->m_static_objects.m_stored.push_back(s_obj);
|
||||
}
|
||||
block->setChangedFlag();
|
||||
new_stored.push_back(s_obj);
|
||||
continue;
|
||||
}
|
||||
// This will also add the object to the active static list
|
||||
addActiveObject(obj);
|
||||
//u16 id = addActiveObject(obj);
|
||||
}
|
||||
// Clear stored list
|
||||
block->m_static_objects.m_stored.clear();
|
||||
// Add leftover failed stuff to stored list
|
||||
for(core::list<StaticObject>::Iterator
|
||||
i = new_stored.begin();
|
||||
i != new_stored.end(); i++)
|
||||
{
|
||||
StaticObject &s_obj = *i;
|
||||
block->m_static_objects.m_stored.push_back(s_obj);
|
||||
}
|
||||
// Block has been modified
|
||||
block->setChangedFlag();
|
||||
}
|
||||
|
||||
/*
|
||||
Convert objects that are far away from all the players to static.
|
||||
Convert objects that are not in active blocks to static.
|
||||
|
||||
If range_blocks == -1, convert everything to static even if known
|
||||
by a player.
|
||||
If m_known_by_count != 0, active object is not deleted, but static
|
||||
data is still updated.
|
||||
|
||||
If force_delete is set, active object is deleted nevertheless. It
|
||||
shall only be set so in the destructor of the environment.
|
||||
*/
|
||||
void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
||||
void ServerEnvironment::deactivateFarObjects(bool force_delete)
|
||||
{
|
||||
bool force_everything = (range_blocks == -1);
|
||||
core::list<u16> objects_to_remove;
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
@ -917,46 +1222,15 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(force_everything == false)
|
||||
{
|
||||
// If known by some client, don't convert to static.
|
||||
if(obj->m_known_by_count > 0)
|
||||
continue;
|
||||
|
||||
// If close to some player, don't convert to static.
|
||||
bool close_to_player = false;
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
|
||||
// Ignore disconnected players
|
||||
if(player->peer_id == 0)
|
||||
continue;
|
||||
|
||||
v3f playerpos = player->getPosition();
|
||||
|
||||
v3s16 blockpos_p = getNodeBlockPos(floatToInt(playerpos, BS));
|
||||
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||
|
||||
if(blockpos_p.X >= blockpos_o.X - range_blocks
|
||||
&& blockpos_p.Y >= blockpos_o.Y - range_blocks
|
||||
&& blockpos_p.Z >= blockpos_o.Z - range_blocks
|
||||
&& blockpos_p.X <= blockpos_o.X + range_blocks
|
||||
&& blockpos_p.Y <= blockpos_o.Y + range_blocks
|
||||
&& blockpos_p.Z <= blockpos_o.Z + range_blocks)
|
||||
{
|
||||
close_to_player = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(close_to_player)
|
||||
continue;
|
||||
}
|
||||
// The block in which the object resides in
|
||||
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||
|
||||
// If block is active, don't remove
|
||||
if(m_active_blocks.contains(blockpos_o))
|
||||
continue;
|
||||
|
||||
/*
|
||||
Update the static data and remove the active object.
|
||||
Update the static data
|
||||
*/
|
||||
|
||||
// Delete old static object
|
||||
@ -971,7 +1245,7 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
||||
oldblock = block;
|
||||
}
|
||||
}
|
||||
// Add new static object
|
||||
// Create new static object
|
||||
std::string staticdata = obj->getStaticData();
|
||||
StaticObject s_obj(obj->getType(), objectpos, staticdata);
|
||||
// Add to the block where the object is located in
|
||||
@ -998,6 +1272,19 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
||||
obj->m_static_exists = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Delete active object if not known by some client,
|
||||
else set pending deactivation
|
||||
*/
|
||||
|
||||
// If known by some client, don't delete.
|
||||
if(obj->m_known_by_count > 0 && force_delete == false)
|
||||
{
|
||||
obj->m_pending_deactivation = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*dstream<<"INFO: Server: Stored static data. Deleting object."
|
||||
<<std::endl;*/
|
||||
// Delete active object
|
||||
@ -1005,6 +1292,7 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
||||
// Id to be removed from m_active_objects
|
||||
objects_to_remove.push_back(id);
|
||||
}
|
||||
|
||||
// Remove references from m_active_objects
|
||||
for(core::list<u16>::Iterator i = objects_to_remove.begin();
|
||||
i != objects_to_remove.end(); i++)
|
||||
@ -1230,7 +1518,7 @@ void ClientEnvironment::step(float dtime)
|
||||
// Get node at head
|
||||
v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
|
||||
MapNode n = m_map->getNode(p);
|
||||
light = n.getLightBlend(m_daynight_ratio);
|
||||
light = n.getLightBlend(getDayNightRatio());
|
||||
}
|
||||
catch(InvalidPositionException &e) {}
|
||||
player->updateLight(light);
|
||||
@ -1254,7 +1542,7 @@ void ClientEnvironment::step(float dtime)
|
||||
{
|
||||
v3s16 p_blocks = getNodeBlockPos(bottompos);
|
||||
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
|
||||
//b->updateMesh(m_daynight_ratio);
|
||||
//b->updateMesh(getDayNightRatio());
|
||||
b->setMeshExpired(true);
|
||||
}
|
||||
}
|
||||
@ -1283,7 +1571,7 @@ void ClientEnvironment::step(float dtime)
|
||||
// Get node at head
|
||||
v3s16 p = obj->getLightPosition();
|
||||
MapNode n = m_map->getNode(p);
|
||||
light = n.getLightBlend(m_daynight_ratio);
|
||||
light = n.getLightBlend(getDayNightRatio());
|
||||
}
|
||||
catch(InvalidPositionException &e) {}
|
||||
obj->updateLight(light);
|
||||
@ -1292,7 +1580,7 @@ void ClientEnvironment::step(float dtime)
|
||||
|
||||
void ClientEnvironment::updateMeshes(v3s16 blockpos)
|
||||
{
|
||||
m_map->updateMeshes(blockpos, m_daynight_ratio);
|
||||
m_map->updateMeshes(blockpos, getDayNightRatio());
|
||||
}
|
||||
|
||||
void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
|
||||
|
@ -64,14 +64,52 @@ public:
|
||||
core::list<Player*> getPlayers(bool ignore_disconnected);
|
||||
void printPlayers(std::ostream &o);
|
||||
|
||||
void setDayNightRatio(u32 r);
|
||||
//void setDayNightRatio(u32 r);
|
||||
u32 getDayNightRatio();
|
||||
|
||||
// 0-23999
|
||||
virtual void setTimeOfDay(u32 time)
|
||||
{
|
||||
m_time_of_day = time;
|
||||
}
|
||||
|
||||
u32 getTimeOfDay()
|
||||
{
|
||||
return m_time_of_day;
|
||||
}
|
||||
|
||||
protected:
|
||||
// peer_ids in here should be unique, except that there may be many 0s
|
||||
core::list<Player*> m_players;
|
||||
// Brightness
|
||||
u32 m_daynight_ratio;
|
||||
//u32 m_daynight_ratio;
|
||||
// Time of day in milli-hours (0-23999); determines day and night
|
||||
u32 m_time_of_day;
|
||||
};
|
||||
|
||||
/*
|
||||
List of active blocks, used by ServerEnvironment
|
||||
*/
|
||||
|
||||
class ActiveBlockList
|
||||
{
|
||||
public:
|
||||
void update(core::list<v3s16> &active_positions,
|
||||
s16 radius,
|
||||
core::map<v3s16, bool> &blocks_removed,
|
||||
core::map<v3s16, bool> &blocks_added);
|
||||
|
||||
bool contains(v3s16 p){
|
||||
return (m_list.find(p) != NULL);
|
||||
}
|
||||
|
||||
void clear(){
|
||||
m_list.clear();
|
||||
}
|
||||
|
||||
core::map<v3s16, bool> m_list;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/*
|
||||
@ -106,10 +144,19 @@ public:
|
||||
}
|
||||
|
||||
void step(f32 dtime);
|
||||
|
||||
|
||||
/*
|
||||
Save players
|
||||
*/
|
||||
void serializePlayers(const std::string &savedir);
|
||||
void deSerializePlayers(const std::string &savedir);
|
||||
|
||||
/*
|
||||
Save and load time of day and game timer
|
||||
*/
|
||||
void saveMeta(const std::string &savedir);
|
||||
void loadMeta(const std::string &savedir);
|
||||
|
||||
/*
|
||||
ActiveObjects
|
||||
*/
|
||||
@ -153,25 +200,48 @@ private:
|
||||
Remove all objects that satisfy (m_removed && m_known_by_count==0)
|
||||
*/
|
||||
void removeRemovedObjects();
|
||||
/*
|
||||
Convert stored objects from blocks near the players to active.
|
||||
*/
|
||||
void activateNearObjects(s16 range_blocks);
|
||||
/*
|
||||
Convert objects that are far away from all the players to static.
|
||||
|
||||
If range_blocks == -1, convert everything to static even if known
|
||||
by a player.
|
||||
*/
|
||||
void deactivateFarObjects(s16 range_blocks);
|
||||
|
||||
/*
|
||||
Convert stored objects from block to active
|
||||
*/
|
||||
void activateObjects(MapBlock *block);
|
||||
|
||||
/*
|
||||
Convert objects that are not in active blocks to static.
|
||||
|
||||
If m_known_by_count != 0, active object is not deleted, but static
|
||||
data is still updated.
|
||||
|
||||
If force_delete is set, active object is deleted nevertheless. It
|
||||
shall only be set so in the destructor of the environment.
|
||||
*/
|
||||
void deactivateFarObjects(bool force_delete);
|
||||
|
||||
/*
|
||||
Member variables
|
||||
*/
|
||||
|
||||
// The map
|
||||
ServerMap *m_map;
|
||||
// Pointer to server (which is handling this environment)
|
||||
Server *m_server;
|
||||
// Active object list
|
||||
core::map<u16, ServerActiveObject*> m_active_objects;
|
||||
// Outgoing network message buffer for active objects
|
||||
Queue<ActiveObjectMessage> m_active_object_messages;
|
||||
float m_random_spawn_timer;
|
||||
// Some timers
|
||||
float m_random_spawn_timer; // used for experimental code
|
||||
float m_send_recommended_timer;
|
||||
IntervalLimiter m_object_management_interval;
|
||||
// List of active blocks
|
||||
ActiveBlockList m_active_blocks;
|
||||
IntervalLimiter m_active_blocks_management_interval;
|
||||
IntervalLimiter m_active_blocks_test_interval;
|
||||
// Time from the beginning of the game in seconds.
|
||||
// Incremented in step().
|
||||
u32 m_game_time;
|
||||
// A helper variable for incrementing the latter
|
||||
float m_game_time_fraction_counter;
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
@ -228,6 +298,20 @@ public:
|
||||
void updateMeshes(v3s16 blockpos);
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
|
||||
void setTimeOfDay(u32 time)
|
||||
{
|
||||
u32 old_dr = getDayNightRatio();
|
||||
|
||||
Environment::setTimeOfDay(time);
|
||||
|
||||
if(getDayNightRatio() != old_dr)
|
||||
{
|
||||
dout_client<<DTIME<<"ClientEnvironment: DayNightRatio changed"
|
||||
<<" -> expiring meshes"<<std::endl;
|
||||
expireMeshes(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
ActiveObjects
|
||||
*/
|
||||
|
53
src/main.cpp
53
src/main.cpp
@ -27,10 +27,8 @@ NOTE: Global locale is now set at initialization
|
||||
NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the
|
||||
hardware buffer (it is not freed automatically)
|
||||
|
||||
Random suggeestions (AKA very old suggestions that haven't been done):
|
||||
----------------------------------------------------------------------
|
||||
|
||||
SUGG: Fix address to be ipv6 compatible
|
||||
Old, wild and random suggestions that probably won't be done:
|
||||
-------------------------------------------------------------
|
||||
|
||||
SUGG: If player is on ground, mainly fetch ground-level blocks
|
||||
|
||||
@ -83,6 +81,10 @@ SUGG: Background music based on cellular automata?
|
||||
|
||||
SUGG: Simple light color information to air
|
||||
|
||||
SUGG: Server-side objects could be moved based on nodes to enable very
|
||||
lightweight operation and simple AI
|
||||
- Not practical; client would still need to show smooth movement.
|
||||
|
||||
Gaming ideas:
|
||||
-------------
|
||||
|
||||
@ -137,6 +139,8 @@ Build system / running:
|
||||
Networking and serialization:
|
||||
-----------------------------
|
||||
|
||||
SUGG: Fix address to be ipv6 compatible
|
||||
|
||||
User Interface:
|
||||
---------------
|
||||
|
||||
@ -207,18 +211,47 @@ FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
|
||||
FIXME: The new optimized map sending doesn't sometimes send enough blocks
|
||||
from big caves and such
|
||||
|
||||
TODO: A list of "active blocks" in which stuff happens.
|
||||
+ Add a never-resetted game timer to the server
|
||||
+ Add a timestamp value to blocks
|
||||
+ The simple rule: All blocks near some player are "active"
|
||||
- Do stuff in real time in active blocks
|
||||
+ Handle objects
|
||||
TODO: Make proper hooks in here
|
||||
- Grow grass, delete leaves without a tree
|
||||
- Spawn some mobs based on some rules
|
||||
- Transform cobble to mossy cobble near water
|
||||
- Run a custom script
|
||||
- ...And all kinds of other dynamic stuff
|
||||
+ Keep track of when a block becomes active and becomes inactive
|
||||
+ When a block goes inactive:
|
||||
+ Store objects statically to block
|
||||
+ Store timer value as the timestamp
|
||||
+ When a block goes active:
|
||||
+ Create active objects out of static objects
|
||||
TODO: Make proper hooks in here
|
||||
- Simulate the results of what would have happened if it would have
|
||||
been active for all the time
|
||||
- Grow a lot of grass and so on
|
||||
+ Initially it is fine to send information about every active object
|
||||
to every player. Eventually it should be modified to only send info
|
||||
about the nearest ones.
|
||||
+ This was left to be done by the old system and it sends only the
|
||||
nearest ones.
|
||||
|
||||
Objects:
|
||||
--------
|
||||
|
||||
TODO: Get rid of MapBlockObjects and use ActiveObjects
|
||||
TODO: Get rid of MapBlockObjects and use only ActiveObjects
|
||||
- Skipping the MapBlockObject data is nasty - there is no "total
|
||||
length" stored; have to make a SkipMBOs function which contains
|
||||
enough of the current code to skip them properly.
|
||||
|
||||
SUGG: MovingObject::move and Player::move are basically the same.
|
||||
combine them.
|
||||
- NOTE: Player::move is more up-to-date.
|
||||
- NOTE: There is a simple move implementation now in collision.{h,cpp}
|
||||
|
||||
SUGG: Server-side objects could be moved based on nodes to enable very
|
||||
lightweight operation and simple AI
|
||||
- NOTE: Player::move is more up-to-date.
|
||||
- NOTE: There is a simple move implementation now in collision.{h,cpp}
|
||||
- NOTE: MovingObject will be deleted (MapBlockObject)
|
||||
|
||||
Map:
|
||||
----
|
||||
|
61
src/map.cpp
61
src/map.cpp
@ -607,13 +607,13 @@ s16 Map::propagateSunlight(v3s16 start,
|
||||
}
|
||||
else
|
||||
{
|
||||
// Turn mud into grass
|
||||
/*// Turn mud into grass
|
||||
if(n.d == CONTENT_MUD)
|
||||
{
|
||||
n.d = CONTENT_GRASS;
|
||||
block->setNode(relpos, n);
|
||||
modified_blocks.insert(blockpos, block);
|
||||
}
|
||||
}*/
|
||||
|
||||
// Sunlight goes no further
|
||||
break;
|
||||
@ -838,9 +838,6 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
|
||||
}
|
||||
|
||||
/*
|
||||
This is called after changing a node from transparent to opaque.
|
||||
The lighting value of the node should be left as-is after changing
|
||||
other values. This sets the lighting value to 0.
|
||||
*/
|
||||
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
||||
core::map<v3s16, MapBlock*> &modified_blocks)
|
||||
@ -877,12 +874,12 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
/*
|
||||
If the new node doesn't propagate sunlight and there is
|
||||
grass below, change it to mud
|
||||
If the new node is solid and there is grass below, change it to mud
|
||||
*/
|
||||
if(content_features(n.d).sunlight_propagates == false)
|
||||
if(content_features(n.d).walkable == true)
|
||||
{
|
||||
try{
|
||||
MapNode bottomnode = getNode(bottompos);
|
||||
@ -898,6 +895,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
If the new node is mud and it is under sunlight, change it
|
||||
@ -5452,25 +5450,13 @@ void ServerMap::saveBlock(MapBlock *block)
|
||||
*/
|
||||
o.write((char*)&version, 1);
|
||||
|
||||
// Write basic data
|
||||
block->serialize(o, version);
|
||||
|
||||
// Write extra data stored on disk
|
||||
block->serializeDiskExtra(o, version);
|
||||
|
||||
/*
|
||||
Versions up from 9 have block objects.
|
||||
*/
|
||||
if(version >= 9)
|
||||
{
|
||||
block->serializeObjects(o, version);
|
||||
}
|
||||
|
||||
/*
|
||||
Versions up from 15 have static objects.
|
||||
*/
|
||||
if(version >= 15)
|
||||
{
|
||||
block->m_static_objects.serialize(o);
|
||||
}
|
||||
|
||||
// We just wrote it to the disk
|
||||
// We just wrote it to the disk so clear modified flag
|
||||
block->resetChangedFlag();
|
||||
}
|
||||
|
||||
@ -5515,33 +5501,20 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
||||
created_new = true;
|
||||
}
|
||||
|
||||
// deserialize block data
|
||||
// Read basic data
|
||||
block->deSerialize(is, version);
|
||||
|
||||
/*
|
||||
Versions up from 9 have block objects.
|
||||
*/
|
||||
if(version >= 9)
|
||||
{
|
||||
block->updateObjects(is, version, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Versions up from 15 have static objects.
|
||||
*/
|
||||
if(version >= 15)
|
||||
{
|
||||
block->m_static_objects.deSerialize(is);
|
||||
}
|
||||
// Read extra data stored on disk
|
||||
block->deSerializeDiskExtra(is, version);
|
||||
|
||||
// If it's a new block, insert it to the map
|
||||
if(created_new)
|
||||
sector->insertBlock(block);
|
||||
|
||||
/*
|
||||
Convert old formats to new and save
|
||||
Save blocks loaded in old format in new format
|
||||
*/
|
||||
|
||||
// Save old format blocks in new format
|
||||
if(version < SER_FMT_VER_HIGHEST || save_after_load)
|
||||
{
|
||||
saveBlock(block);
|
||||
|
102
src/mapblock.cpp
102
src/mapblock.cpp
@ -1549,7 +1549,8 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
|
||||
m_lighting_expired(true),
|
||||
m_day_night_differs(false),
|
||||
//m_not_fully_generated(false),
|
||||
m_objects(this)
|
||||
m_objects(this),
|
||||
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED)
|
||||
{
|
||||
data = NULL;
|
||||
if(dummy == false)
|
||||
@ -1720,17 +1721,17 @@ void MapBlock::replaceMesh(scene::SMesh *mesh_new)
|
||||
Propagates sunlight down through the block.
|
||||
Doesn't modify nodes that are not affected by sunlight.
|
||||
|
||||
Returns false if sunlight at bottom block is invalid
|
||||
Returns false if sunlight at bottom block is invalid.
|
||||
Returns true if sunlight at bottom block is valid.
|
||||
Returns true if bottom block doesn't exist.
|
||||
|
||||
If there is a block above, continues from it.
|
||||
If there is no block above, assumes there is sunlight, unless
|
||||
is_underground is set or highest node is water.
|
||||
|
||||
At the moment, all sunlighted nodes are added to light_sources.
|
||||
- SUGG: This could be optimized
|
||||
All sunlighted nodes are added to light_sources.
|
||||
|
||||
Turns sunglighted mud into grass.
|
||||
If grow_grass==true, turns sunglighted mud into grass.
|
||||
|
||||
if remove_light==true, sets non-sunlighted nodes black.
|
||||
|
||||
@ -1948,45 +1949,6 @@ void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
|
||||
*/
|
||||
m_objects.step(dtime, server, daynight_ratio);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Spawn some objects at random.
|
||||
|
||||
Use dayNightDiffed() to approximate being near ground level
|
||||
*/
|
||||
if(m_spawn_timer < -999)
|
||||
{
|
||||
m_spawn_timer = 60;
|
||||
}
|
||||
if(dayNightDiffed() == true && getObjectCount() == 0)
|
||||
{
|
||||
m_spawn_timer -= dtime;
|
||||
if(m_spawn_timer <= 0.0)
|
||||
{
|
||||
m_spawn_timer += myrand() % 300;
|
||||
|
||||
v2s16 p2d(
|
||||
(myrand()%(MAP_BLOCKSIZE-1))+0,
|
||||
(myrand()%(MAP_BLOCKSIZE-1))+0
|
||||
);
|
||||
|
||||
s16 y = getGroundLevel(p2d);
|
||||
|
||||
if(y >= 0)
|
||||
{
|
||||
v3s16 p(p2d.X, y+1, p2d.Y);
|
||||
|
||||
if(getNode(p).d == CONTENT_AIR
|
||||
&& getNode(p).getLightBlend(daynight_ratio) <= 11)
|
||||
{
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(p, BS));
|
||||
addObject(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
setChangedFlag();
|
||||
}
|
||||
|
||||
@ -2359,6 +2321,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
|
||||
/*
|
||||
Translate nodes as specified in the translate_to fields of
|
||||
node features
|
||||
|
||||
NOTE: This isn't really used. Should it be removed?
|
||||
*/
|
||||
for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
|
||||
{
|
||||
@ -2374,5 +2338,55 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
|
||||
}
|
||||
}
|
||||
|
||||
void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
|
||||
{
|
||||
// Versions up from 9 have block objects.
|
||||
if(version >= 9)
|
||||
{
|
||||
serializeObjects(os, version);
|
||||
}
|
||||
|
||||
// Versions up from 15 have static objects.
|
||||
if(version >= 15)
|
||||
{
|
||||
m_static_objects.serialize(os);
|
||||
}
|
||||
|
||||
// Timestamp
|
||||
if(version >= 17)
|
||||
{
|
||||
writeU32(os, getTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
|
||||
{
|
||||
/*
|
||||
Versions up from 9 have block objects.
|
||||
*/
|
||||
if(version >= 9)
|
||||
{
|
||||
updateObjects(is, version, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Versions up from 15 have static objects.
|
||||
*/
|
||||
if(version >= 15)
|
||||
{
|
||||
m_static_objects.deSerialize(is);
|
||||
}
|
||||
|
||||
// Timestamp
|
||||
if(version >= 17)
|
||||
{
|
||||
setTimestamp(readU32(is));
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//END
|
||||
|
107
src/mapblock.h
107
src/mapblock.h
@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "nodemetadata.h"
|
||||
#include "staticobject.h"
|
||||
|
||||
#define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
|
||||
|
||||
// Named by looking towards z+
|
||||
enum{
|
||||
@ -244,24 +245,28 @@ public:
|
||||
reallocate();
|
||||
}
|
||||
|
||||
bool getChangedFlag()
|
||||
/*
|
||||
This is called internally or externally after the block is
|
||||
modified, so that the block is saved and possibly not deleted from
|
||||
memory.
|
||||
*/
|
||||
void setChangedFlag()
|
||||
{
|
||||
return changed;
|
||||
changed = true;
|
||||
}
|
||||
void resetChangedFlag()
|
||||
{
|
||||
changed = false;
|
||||
}
|
||||
void setChangedFlag()
|
||||
bool getChangedFlag()
|
||||
{
|
||||
changed = true;
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool getIsUnderground()
|
||||
{
|
||||
return is_underground;
|
||||
}
|
||||
|
||||
void setIsUnderground(bool a_is_underground)
|
||||
{
|
||||
is_underground = a_is_underground;
|
||||
@ -359,6 +364,15 @@ public:
|
||||
return getNode(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
MapNode getNodeNoEx(v3s16 p)
|
||||
{
|
||||
try{
|
||||
return getNode(p.X, p.Y, p.Z);
|
||||
}catch(InvalidPositionException &e){
|
||||
return MapNode(CONTENT_IGNORE);
|
||||
}
|
||||
}
|
||||
|
||||
void setNode(s16 x, s16 y, s16 z, MapNode & n)
|
||||
{
|
||||
if(data == NULL)
|
||||
@ -444,47 +458,19 @@ public:
|
||||
face_dir);
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
// light = 0...255
|
||||
/*static void makeFastFace(TileSpec tile, u8 light, v3f p,
|
||||
v3s16 dir, v3f scale, v3f posRelative_f,
|
||||
core::array<FastFace> &dest);*/
|
||||
|
||||
/*TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
|
||||
NodeModMap &temp_mods);*/
|
||||
/*u8 getNodeContent(v3s16 p, MapNode mn,
|
||||
NodeModMap &temp_mods);*/
|
||||
#ifndef SERVER // Only on client
|
||||
|
||||
/*
|
||||
Generates the FastFaces of a node row. This has a
|
||||
ridiculous amount of parameters because that way they
|
||||
can be precalculated by the caller.
|
||||
|
||||
translate_dir: unit vector with only one of x, y or z
|
||||
face_dir: unit vector with only one of x, y or z
|
||||
*/
|
||||
/*void updateFastFaceRow(
|
||||
u32 daynight_ratio,
|
||||
v3f posRelative_f,
|
||||
v3s16 startpos,
|
||||
u16 length,
|
||||
v3s16 translate_dir,
|
||||
v3f translate_dir_f,
|
||||
v3s16 face_dir,
|
||||
v3f face_dir_f,
|
||||
core::array<FastFace> &dest,
|
||||
NodeModMap &temp_mods);*/
|
||||
|
||||
#if 1
|
||||
/*
|
||||
Thread-safely updates the whole mesh of the mapblock.
|
||||
NOTE: Prefer generating the mesh separately and then using
|
||||
replaceMesh().
|
||||
*/
|
||||
#if 1
|
||||
void updateMesh(u32 daynight_ratio);
|
||||
#endif
|
||||
|
||||
// Replace the mesh with a new one
|
||||
void replaceMesh(scene::SMesh *mesh_new);
|
||||
|
||||
#endif // !SERVER
|
||||
#endif
|
||||
|
||||
// See comments in mapblock.cpp
|
||||
bool propagateSunlight(core::map<v3s16, bool> & light_sources,
|
||||
@ -498,6 +484,7 @@ public:
|
||||
|
||||
/*
|
||||
MapBlockObject stuff
|
||||
DEPRECATED
|
||||
*/
|
||||
|
||||
void serializeObjects(std::ostream &os, u8 version)
|
||||
@ -545,13 +532,6 @@ public:
|
||||
*/
|
||||
void stepObjects(float dtime, bool server, u32 daynight_ratio);
|
||||
|
||||
/*void wrapObject(MapBlockObject *object)
|
||||
{
|
||||
m_objects.wrapObject(object);
|
||||
|
||||
setChangedFlag();
|
||||
}*/
|
||||
|
||||
// origin is relative to block
|
||||
void getObjects(v3f origin, f32 max_d,
|
||||
core::array<DistanceSortedObject> &dest)
|
||||
@ -564,7 +544,7 @@ public:
|
||||
return m_objects.getCount();
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
#ifndef SERVER // Only on client
|
||||
/*
|
||||
Methods for setting temporary modifications to nodes for
|
||||
drawing
|
||||
@ -639,14 +619,30 @@ public:
|
||||
*/
|
||||
s16 getGroundLevel(v2s16 p2d);
|
||||
|
||||
/*
|
||||
Timestamp (see m_timestamp)
|
||||
NOTE: BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
|
||||
*/
|
||||
void setTimestamp(u32 time)
|
||||
{
|
||||
m_timestamp = time;
|
||||
setChangedFlag();
|
||||
}
|
||||
u32 getTimestamp()
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
/*
|
||||
Serialization
|
||||
*/
|
||||
|
||||
// Doesn't write version by itself
|
||||
// These don't write or read version by itself
|
||||
void serialize(std::ostream &os, u8 version);
|
||||
|
||||
void deSerialize(std::istream &is, u8 version);
|
||||
// Used after the basic ones when writing on disk (serverside)
|
||||
void serializeDiskExtra(std::ostream &os, u8 version);
|
||||
void deSerializeDiskExtra(std::istream &is, u8 version);
|
||||
|
||||
private:
|
||||
/*
|
||||
@ -676,7 +672,7 @@ public:
|
||||
Public member variables
|
||||
*/
|
||||
|
||||
#ifndef SERVER
|
||||
#ifndef SERVER // Only on client
|
||||
scene::SMesh *mesh;
|
||||
JMutex mesh_mutex;
|
||||
#endif
|
||||
@ -729,12 +725,9 @@ private:
|
||||
// Whether day and night lighting differs
|
||||
bool m_day_night_differs;
|
||||
|
||||
// TODO: Remove this
|
||||
// DEPRECATED
|
||||
MapBlockObjectList m_objects;
|
||||
|
||||
// Object spawning stuff
|
||||
//float m_spawn_timer;
|
||||
|
||||
#ifndef SERVER // Only on client
|
||||
/*
|
||||
Set to true if the mesh has been ordered to be updated
|
||||
@ -748,6 +741,12 @@ private:
|
||||
NodeModMap m_temp_mods;
|
||||
JMutex m_temp_mods_mutex;
|
||||
#endif
|
||||
|
||||
/*
|
||||
When block is removed from active blocks, this is set to gametime.
|
||||
Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
|
||||
*/
|
||||
u32 m_timestamp;
|
||||
};
|
||||
|
||||
inline bool blockpos_over_limit(v3s16 p)
|
||||
|
@ -148,6 +148,8 @@ struct ContentFeatures
|
||||
bool light_propagates;
|
||||
bool sunlight_propagates;
|
||||
u8 solidness; // Used when choosing which face is drawn
|
||||
// This is used for collision detection.
|
||||
// Also for general solidness queries.
|
||||
bool walkable;
|
||||
bool pointable;
|
||||
bool diggable;
|
||||
|
@ -26,53 +26,55 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "utility.h"
|
||||
|
||||
/*
|
||||
Map format serialization version
|
||||
--------------------------------
|
||||
|
||||
For map data (blocks, nodes, sectors).
|
||||
|
||||
NOTE: The goal is to increment this so that saved maps will be
|
||||
loadable by any version. Other compatibility is not
|
||||
maintained.
|
||||
Serialization format versions (for raw map data (blocks, nodes, sectors)):
|
||||
== Unsupported ==
|
||||
|
||||
0: original networked test with 1-byte nodes
|
||||
1: update with 2-byte nodes
|
||||
== Supported ==
|
||||
2: lighting is transmitted in param
|
||||
3: optional fetching of far blocks
|
||||
4: block compression
|
||||
5: sector objects NOTE: block compression was left accidentally out
|
||||
6: failed attempt at switching block compression on again
|
||||
7: block compression switched on again
|
||||
8: (dev) server-initiated block transfers and all kinds of stuff
|
||||
9: (dev) block objects
|
||||
10: (dev) water pressure
|
||||
11: (dev) zlib'd blocks, block flags
|
||||
12: (dev) UnlimitedHeightmap now uses interpolated areas
|
||||
13: (dev) Mapgen v2
|
||||
14: (dev) NodeMetadata
|
||||
15: (dev) StaticObjects
|
||||
16: (dev) larger maximum size of node metadata, and compression
|
||||
8: server-initiated block transfers and all kinds of stuff
|
||||
9: block objects
|
||||
10: water pressure
|
||||
11: zlib'd blocks, block flags
|
||||
12: UnlimitedHeightmap now uses interpolated areas
|
||||
13: Mapgen v2
|
||||
14: NodeMetadata
|
||||
15: StaticObjects
|
||||
16: larger maximum size of node metadata, and compression
|
||||
17: MapBlocks contain timestamp
|
||||
*/
|
||||
// This represents an uninitialized or invalid format
|
||||
#define SER_FMT_VER_INVALID 255
|
||||
// Highest supported serialization version
|
||||
#define SER_FMT_VER_HIGHEST 16
|
||||
#define SER_FMT_VER_HIGHEST 17
|
||||
// Lowest supported serialization version
|
||||
#define SER_FMT_VER_LOWEST 0
|
||||
|
||||
#define ser_ver_supported(v) (v >= SER_FMT_VER_LOWEST && v <= SER_FMT_VER_HIGHEST)
|
||||
|
||||
/*
|
||||
Misc. serialization functions
|
||||
*/
|
||||
|
||||
void compressZlib(SharedBuffer<u8> data, std::ostream &os);
|
||||
void compressZlib(const std::string &data, std::ostream &os);
|
||||
void decompressZlib(std::istream &is, std::ostream &os);
|
||||
|
||||
// These choose between zlib and a self-made one according to version
|
||||
void compress(SharedBuffer<u8> data, std::ostream &os, u8 version);
|
||||
//void compress(const std::string &data, std::ostream &os, u8 version);
|
||||
void decompress(std::istream &is, std::ostream &os, u8 version);
|
||||
|
||||
/*class Serializable
|
||||
{
|
||||
public:
|
||||
void serialize(std::ostream &os, u8 version) = 0;
|
||||
void deSerialize(std::istream &istr);
|
||||
};*/
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mineral.h"
|
||||
#include "config.h"
|
||||
#include "servercommand.h"
|
||||
#include "filesys.h"
|
||||
|
||||
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
|
||||
|
||||
@ -798,7 +799,7 @@ void RemoteClient::SendObjectData(
|
||||
*/
|
||||
if(stepped_blocks.find(p) == NULL)
|
||||
{
|
||||
block->stepObjects(dtime, true, server->getDayNightRatio());
|
||||
block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
|
||||
stepped_blocks.insert(p, true);
|
||||
block->setChangedFlag();
|
||||
}
|
||||
@ -968,7 +969,6 @@ Server::Server(
|
||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||
m_thread(this),
|
||||
m_emergethread(this),
|
||||
m_time_of_day(9000),
|
||||
m_time_counter(0),
|
||||
m_time_of_day_send_timer(0),
|
||||
m_uptime(0),
|
||||
@ -987,10 +987,19 @@ Server::Server(
|
||||
m_con_mutex.Init();
|
||||
m_step_dtime_mutex.Init();
|
||||
m_step_dtime = 0.0;
|
||||
|
||||
|
||||
// Register us to receive map edit events
|
||||
m_env.getMap().addEventReceiver(this);
|
||||
|
||||
// If file exists, load environment metadata
|
||||
if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
|
||||
{
|
||||
dstream<<"Server: Loading environment metadata"<<std::endl;
|
||||
m_env.loadMeta(m_mapsavedir);
|
||||
}
|
||||
|
||||
// Load players
|
||||
dstream<<"Server: Loading players"<<std::endl;
|
||||
m_env.deSerializePlayers(m_mapsavedir);
|
||||
}
|
||||
|
||||
@ -1032,6 +1041,12 @@ Server::~Server()
|
||||
*/
|
||||
dstream<<"Server: Saving players"<<std::endl;
|
||||
m_env.serializePlayers(m_mapsavedir);
|
||||
|
||||
/*
|
||||
Save environment metadata
|
||||
*/
|
||||
dstream<<"Server: Saving environment metadata"<<std::endl;
|
||||
m_env.saveMeta(m_mapsavedir);
|
||||
|
||||
/*
|
||||
Stop threads
|
||||
@ -1136,14 +1151,17 @@ void Server::AsyncRunStep()
|
||||
}
|
||||
|
||||
/*
|
||||
Update m_time_of_day
|
||||
Update m_time_of_day and overall game time
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
m_time_counter += dtime;
|
||||
f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
|
||||
u32 units = (u32)(m_time_counter*speed);
|
||||
m_time_counter -= (f32)units / speed;
|
||||
m_time_of_day.set((m_time_of_day.get() + units) % 24000);
|
||||
|
||||
m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
|
||||
|
||||
//dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
|
||||
|
||||
@ -1167,7 +1185,7 @@ void Server::AsyncRunStep()
|
||||
//Player *player = m_env.getPlayer(client->peer_id);
|
||||
|
||||
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
|
||||
m_time_of_day.get());
|
||||
m_env.getTimeOfDay());
|
||||
// Send as reliable
|
||||
m_con.Send(client->peer_id, 0, data, true);
|
||||
}
|
||||
@ -1654,6 +1672,9 @@ void Server::AsyncRunStep()
|
||||
|
||||
// Save players
|
||||
m_env.serializePlayers(m_mapsavedir);
|
||||
|
||||
// Save environment metadata
|
||||
m_env.saveMeta(m_mapsavedir);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1900,7 +1921,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Send time of day
|
||||
{
|
||||
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
|
||||
m_time_of_day.get());
|
||||
m_env.getTimeOfDay());
|
||||
m_con.Send(peer->id, 0, data, true);
|
||||
}
|
||||
|
||||
|
90
src/server.h
90
src/server.h
@ -382,20 +382,21 @@ public:
|
||||
|
||||
core::list<PlayerInfo> getPlayerInfo();
|
||||
|
||||
u32 getDayNightRatio()
|
||||
/*u32 getDayNightRatio()
|
||||
{
|
||||
return time_to_daynight_ratio(m_time_of_day.get());
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
// Environment must be locked when called
|
||||
void setTimeOfDay(u32 time)
|
||||
{
|
||||
m_time_of_day.set(time);
|
||||
m_env.setTimeOfDay(time);
|
||||
m_time_of_day_send_timer = 0;
|
||||
}
|
||||
|
||||
bool getShutdownRequested()
|
||||
{
|
||||
return m_shutdown_requested.get();
|
||||
return m_shutdown_requested;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -416,7 +417,7 @@ public:
|
||||
|
||||
void requestShutdown(void)
|
||||
{
|
||||
m_shutdown_requested.set(true);
|
||||
m_shutdown_requested = true;
|
||||
}
|
||||
|
||||
|
||||
@ -426,7 +427,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
// Virtual methods from con::PeerHandler.
|
||||
// con::PeerHandler implementation.
|
||||
// These queue stuff to be processed by handlePeerChanges().
|
||||
// As of now, these create and remove clients and players.
|
||||
void peerAdded(con::Peer *peer);
|
||||
void deletingPeer(con::Peer *peer, bool timeout);
|
||||
@ -459,7 +461,7 @@ private:
|
||||
void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
|
||||
core::list<u16> *far_players=NULL, float far_d_nodes=100);
|
||||
|
||||
// Environment and Connection must be locked when called
|
||||
// Environment and Connection must be locked when called
|
||||
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
|
||||
|
||||
// Sends blocks to clients
|
||||
@ -483,22 +485,17 @@ private:
|
||||
Call with env and con locked.
|
||||
*/
|
||||
Player *emergePlayer(const char *name, const char *password, u16 peer_id);
|
||||
|
||||
/*
|
||||
Update water pressure.
|
||||
This also adds suitable nodes to active_nodes.
|
||||
|
||||
environment has to be locked when calling.
|
||||
*/
|
||||
/*void UpdateBlockWaterPressure(MapBlock *block,
|
||||
core::map<v3s16, MapBlock*> &modified_blocks);*/
|
||||
|
||||
// Locks environment and connection by its own
|
||||
struct PeerChange;
|
||||
void handlePeerChange(PeerChange &c);
|
||||
void handlePeerChanges();
|
||||
|
||||
/*
|
||||
Variables
|
||||
*/
|
||||
|
||||
//float m_flowwater_timer;
|
||||
// Some timers
|
||||
float m_liquid_transform_timer;
|
||||
float m_print_info_timer;
|
||||
float m_objectdata_timer;
|
||||
@ -507,51 +504,82 @@ private:
|
||||
|
||||
// NOTE: If connection and environment are both to be locked,
|
||||
// environment shall be locked first.
|
||||
JMutex m_env_mutex;
|
||||
|
||||
// Environment
|
||||
ServerEnvironment m_env;
|
||||
|
||||
JMutex m_con_mutex;
|
||||
JMutex m_env_mutex;
|
||||
|
||||
// Connection
|
||||
con::Connection m_con;
|
||||
core::map<u16, RemoteClient*> m_clients; // Behind the con mutex
|
||||
|
||||
JMutex m_con_mutex;
|
||||
// Connected clients (behind the con mutex)
|
||||
core::map<u16, RemoteClient*> m_clients;
|
||||
|
||||
/*
|
||||
Threads
|
||||
*/
|
||||
|
||||
// A buffer for time steps
|
||||
// step() increments and AsyncRunStep() run by m_thread reads it.
|
||||
float m_step_dtime;
|
||||
JMutex m_step_dtime_mutex;
|
||||
|
||||
// The server mainly operates in this thread
|
||||
ServerThread m_thread;
|
||||
// This thread fetches and generates map
|
||||
EmergeThread m_emergethread;
|
||||
|
||||
// Queue of block coordinates to be processed by the emerge thread
|
||||
BlockEmergeQueue m_emerge_queue;
|
||||
|
||||
// Nodes that are destinations of flowing liquid at the moment
|
||||
//core::map<v3s16, u8> m_flow_active_nodes;
|
||||
/*
|
||||
Time related stuff
|
||||
*/
|
||||
|
||||
// 0-23999
|
||||
MutexedVariable<u32> m_time_of_day;
|
||||
//MutexedVariable<u32> m_time_of_day;
|
||||
// Used to buffer dtime for adding to m_time_of_day
|
||||
float m_time_counter;
|
||||
// Timer for sending time of day over network
|
||||
float m_time_of_day_send_timer;
|
||||
|
||||
// Uptime of server in seconds
|
||||
MutexedVariable<double> m_uptime;
|
||||
|
||||
/*
|
||||
Peer change queue.
|
||||
Queues stuff from peerAdded() and deletingPeer() to
|
||||
handlePeerChanges()
|
||||
*/
|
||||
enum PeerChangeType
|
||||
{
|
||||
PEER_ADDED,
|
||||
PEER_REMOVED
|
||||
};
|
||||
|
||||
struct PeerChange
|
||||
{
|
||||
PeerChangeType type;
|
||||
u16 peer_id;
|
||||
bool timeout;
|
||||
};
|
||||
|
||||
Queue<PeerChange> m_peer_change_queue;
|
||||
|
||||
/*
|
||||
Random stuff
|
||||
*/
|
||||
|
||||
// Map directory
|
||||
std::string m_mapsavedir;
|
||||
|
||||
MutexedVariable<bool> m_shutdown_requested;
|
||||
bool m_shutdown_requested;
|
||||
|
||||
/*
|
||||
Map edit event queue. Automatically receives all map edits.
|
||||
The constructor of this class registers us to receive them through
|
||||
onMapEditEvent
|
||||
|
||||
NOTE: Should these be moved to actually be members of
|
||||
ServerEnvironment?
|
||||
*/
|
||||
|
||||
/*
|
||||
Queue of map edits from the environment for sending to the clients
|
||||
This is behind m_env_mutex
|
||||
|
@ -29,6 +29,7 @@ ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos):
|
||||
ActiveObject(id),
|
||||
m_known_by_count(0),
|
||||
m_removed(false),
|
||||
m_pending_deactivation(false),
|
||||
m_static_exists(false),
|
||||
m_static_block(1337,1337,1337),
|
||||
m_env(env),
|
||||
|
@ -106,8 +106,13 @@ public:
|
||||
*/
|
||||
virtual u16 punch(const std::string &toolname){return 0;}
|
||||
|
||||
// Number of players which know about this object
|
||||
/*
|
||||
Number of players which know about this object. Object won't be
|
||||
deleted until this is 0 to keep the id preserved for the right
|
||||
object.
|
||||
*/
|
||||
u16 m_known_by_count;
|
||||
|
||||
/*
|
||||
- Whether this object is to be removed when nobody knows about
|
||||
it anymore.
|
||||
@ -119,6 +124,16 @@ public:
|
||||
*/
|
||||
bool m_removed;
|
||||
|
||||
/*
|
||||
This is set to true when a block should be removed from the active
|
||||
object list but couldn't be removed because the id has to be
|
||||
reserved for some client.
|
||||
|
||||
The environment checks this periodically. If this is true and also
|
||||
m_known_by_count is true,
|
||||
*/
|
||||
bool m_pending_deactivation;
|
||||
|
||||
/*
|
||||
Whether the object's static data has been stored to a block
|
||||
*/
|
||||
|
@ -221,6 +221,19 @@ inline u16 readU16(std::istream &is)
|
||||
return readU16((u8*)buf);
|
||||
}
|
||||
|
||||
inline void writeU32(std::ostream &os, u16 p)
|
||||
{
|
||||
char buf[4];
|
||||
writeU16((u8*)buf, p);
|
||||
os.write(buf, 4);
|
||||
}
|
||||
inline u16 readU32(std::istream &is)
|
||||
{
|
||||
char buf[4];
|
||||
is.read(buf, 4);
|
||||
return readU32((u8*)buf);
|
||||
}
|
||||
|
||||
inline void writeF1000(std::ostream &os, f32 p)
|
||||
{
|
||||
char buf[2];
|
||||
|
Loading…
Reference in New Issue
Block a user