mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01: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)
|
if(datasize < 4)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u16 time = readU16(&data[2]);
|
u16 time_of_day = readU16(&data[2]);
|
||||||
time = time % 24000;
|
time_of_day = time_of_day % 24000;
|
||||||
m_time_of_day = time;
|
//dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
|
||||||
//dstream<<"Client: time="<<time<<std::endl;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Day/night
|
|
||||||
|
|
||||||
time_of_day:
|
time_of_day:
|
||||||
0 = midnight
|
0 = midnight
|
||||||
12000 = midday
|
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
|
<<", dr="<<dr
|
||||||
<<std::endl;
|
<<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"
|
#include "collision.h"
|
||||||
|
|
||||||
|
|
||||||
Environment::Environment()
|
Environment::Environment():
|
||||||
|
m_time_of_day(9000)
|
||||||
{
|
{
|
||||||
m_daynight_ratio = 0.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment::~Environment()
|
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()
|
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_map(map),
|
||||||
m_server(server),
|
m_server(server),
|
||||||
m_random_spawn_timer(3),
|
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()
|
ServerEnvironment::~ServerEnvironment()
|
||||||
{
|
{
|
||||||
/*
|
// Clear active block list.
|
||||||
Convert all objects to static (thus delete the active objects)
|
// This makes the next one delete all active objects.
|
||||||
*/
|
m_active_blocks.clear();
|
||||||
deactivateFarObjects(-1);
|
|
||||||
|
// Convert all objects to static and delete the active objects
|
||||||
|
deactivateFarObjects(true);
|
||||||
|
|
||||||
// Drop/delete map
|
// Drop/delete map
|
||||||
m_map->drop();
|
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
|
#if 0
|
||||||
|
// This is probably very useless
|
||||||
void spawnRandomObjects(MapBlock *block)
|
void spawnRandomObjects(MapBlock *block)
|
||||||
{
|
{
|
||||||
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
|
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
|
||||||
@ -440,9 +578,21 @@ void ServerEnvironment::step(float dtime)
|
|||||||
//TimeTaker timer("ServerEnv step");
|
//TimeTaker timer("ServerEnv step");
|
||||||
|
|
||||||
// Get some settings
|
// Get some settings
|
||||||
//bool free_move = g_settings.getBool("free_move");
|
|
||||||
bool footprints = g_settings.getBool("footprints");
|
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()");
|
//TimeTaker timer("Server m_map->timerUpdate()");
|
||||||
m_map->timerUpdate(dtime);
|
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
|
Step active objects
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
//TimeTaker timer("Step active objects");
|
//TimeTaker timer("Step active objects");
|
||||||
|
|
||||||
|
// This helps the objects to send data at the same time
|
||||||
bool send_recommended = false;
|
bool send_recommended = false;
|
||||||
m_send_recommended_timer += dtime;
|
m_send_recommended_timer += dtime;
|
||||||
if(m_send_recommended_timer > 0.15)
|
if(m_send_recommended_timer > 0.15)
|
||||||
@ -505,33 +831,23 @@ void ServerEnvironment::step(float dtime)
|
|||||||
i.atEnd()==false; i++)
|
i.atEnd()==false; i++)
|
||||||
{
|
{
|
||||||
ServerActiveObject* obj = i.getNode()->getValue();
|
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
|
// Step object, putting messages directly to the queue
|
||||||
obj->step(dtime, m_active_object_messages, send_recommended);
|
obj->step(dtime, m_active_object_messages, send_recommended);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Manage active objects
|
||||||
|
*/
|
||||||
if(m_object_management_interval.step(dtime, 0.5))
|
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)
|
Remove objects that satisfy (m_removed && m_known_by_count==0)
|
||||||
*/
|
*/
|
||||||
removeRemovedObjects();
|
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"))
|
if(g_settings.getBool("enable_experimental"))
|
||||||
@ -791,11 +1107,18 @@ void ServerEnvironment::removeRemovedObjects()
|
|||||||
objects_to_remove.push_back(id);
|
objects_to_remove.push_back(id);
|
||||||
continue;
|
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;
|
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);
|
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
|
||||||
if(block)
|
if(block)
|
||||||
@ -804,9 +1127,11 @@ void ServerEnvironment::removeRemovedObjects()
|
|||||||
block->setChangedFlag();
|
block->setChangedFlag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If m_known_by_count > 0, don't actually remove.
|
// If m_known_by_count > 0, don't actually remove.
|
||||||
if(obj->m_known_by_count > 0)
|
if(obj->m_known_by_count > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
delete obj;
|
delete obj;
|
||||||
// Id to be removed from m_active_objects
|
// Id to be removed from m_active_objects
|
||||||
@ -823,35 +1148,15 @@ void ServerEnvironment::removeRemovedObjects()
|
|||||||
/*
|
/*
|
||||||
Convert stored objects from blocks near the players to active.
|
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++)
|
|
||||||
{
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
v3s16 blockpos(x,y,z);
|
|
||||||
MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
|
|
||||||
if(block==NULL)
|
if(block==NULL)
|
||||||
continue;
|
return;
|
||||||
// Ignore if no stored objects (to not set changed flag)
|
// Ignore if no stored objects (to not set changed flag)
|
||||||
if(block->m_static_objects.m_stored.size() == 0)
|
if(block->m_static_objects.m_stored.size() == 0)
|
||||||
continue;
|
return;
|
||||||
// This will contain the leftovers of the stored list
|
// A list for objects that couldn't be converted to static for some
|
||||||
|
// reason. They will be stored back.
|
||||||
core::list<StaticObject> new_stored;
|
core::list<StaticObject> new_stored;
|
||||||
// Loop through stored static objects
|
// Loop through stored static objects
|
||||||
for(core::list<StaticObject>::Iterator
|
for(core::list<StaticObject>::Iterator
|
||||||
@ -864,10 +1169,9 @@ void ServerEnvironment::activateNearObjects(s16 range_blocks)
|
|||||||
// Create an active object from the data
|
// Create an active object from the data
|
||||||
ServerActiveObject *obj = ServerActiveObject::create
|
ServerActiveObject *obj = ServerActiveObject::create
|
||||||
(s_obj.type, this, 0, s_obj.pos, s_obj.data);
|
(s_obj.type, this, 0, s_obj.pos, s_obj.data);
|
||||||
|
// If couldn't create object, store static data back.
|
||||||
if(obj==NULL)
|
if(obj==NULL)
|
||||||
{
|
{
|
||||||
// This is necessary to preserve stuff during bugs
|
|
||||||
// and errors
|
|
||||||
new_stored.push_back(s_obj);
|
new_stored.push_back(s_obj);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -877,7 +1181,7 @@ void ServerEnvironment::activateNearObjects(s16 range_blocks)
|
|||||||
}
|
}
|
||||||
// Clear stored list
|
// Clear stored list
|
||||||
block->m_static_objects.m_stored.clear();
|
block->m_static_objects.m_stored.clear();
|
||||||
// Add leftover stuff to stored list
|
// Add leftover failed stuff to stored list
|
||||||
for(core::list<StaticObject>::Iterator
|
for(core::list<StaticObject>::Iterator
|
||||||
i = new_stored.begin();
|
i = new_stored.begin();
|
||||||
i != new_stored.end(); i++)
|
i != new_stored.end(); i++)
|
||||||
@ -885,20 +1189,21 @@ void ServerEnvironment::activateNearObjects(s16 range_blocks)
|
|||||||
StaticObject &s_obj = *i;
|
StaticObject &s_obj = *i;
|
||||||
block->m_static_objects.m_stored.push_back(s_obj);
|
block->m_static_objects.m_stored.push_back(s_obj);
|
||||||
}
|
}
|
||||||
|
// Block has been modified
|
||||||
block->setChangedFlag();
|
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
|
If m_known_by_count != 0, active object is not deleted, but static
|
||||||
by a player.
|
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;
|
core::list<u16> objects_to_remove;
|
||||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||||
i = m_active_objects.getIterator();
|
i = m_active_objects.getIterator();
|
||||||
@ -917,46 +1222,15 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(force_everything == false)
|
// The block in which the object resides in
|
||||||
{
|
|
||||||
// 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));
|
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||||
|
|
||||||
if(blockpos_p.X >= blockpos_o.X - range_blocks
|
// If block is active, don't remove
|
||||||
&& blockpos_p.Y >= blockpos_o.Y - range_blocks
|
if(m_active_blocks.contains(blockpos_o))
|
||||||
&& 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;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update the static data and remove the active object.
|
Update the static data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Delete old static object
|
// Delete old static object
|
||||||
@ -971,7 +1245,7 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
|||||||
oldblock = block;
|
oldblock = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add new static object
|
// Create new static object
|
||||||
std::string staticdata = obj->getStaticData();
|
std::string staticdata = obj->getStaticData();
|
||||||
StaticObject s_obj(obj->getType(), objectpos, staticdata);
|
StaticObject s_obj(obj->getType(), objectpos, staticdata);
|
||||||
// Add to the block where the object is located in
|
// 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;
|
obj->m_static_exists = false;
|
||||||
continue;
|
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."
|
/*dstream<<"INFO: Server: Stored static data. Deleting object."
|
||||||
<<std::endl;*/
|
<<std::endl;*/
|
||||||
// Delete active object
|
// Delete active object
|
||||||
@ -1005,6 +1292,7 @@ void ServerEnvironment::deactivateFarObjects(s16 range_blocks)
|
|||||||
// Id to be removed from m_active_objects
|
// Id to be removed from m_active_objects
|
||||||
objects_to_remove.push_back(id);
|
objects_to_remove.push_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove references from m_active_objects
|
// Remove references from m_active_objects
|
||||||
for(core::list<u16>::Iterator i = objects_to_remove.begin();
|
for(core::list<u16>::Iterator i = objects_to_remove.begin();
|
||||||
i != objects_to_remove.end(); i++)
|
i != objects_to_remove.end(); i++)
|
||||||
@ -1230,7 +1518,7 @@ void ClientEnvironment::step(float dtime)
|
|||||||
// Get node at head
|
// Get node at head
|
||||||
v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
|
v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
|
||||||
MapNode n = m_map->getNode(p);
|
MapNode n = m_map->getNode(p);
|
||||||
light = n.getLightBlend(m_daynight_ratio);
|
light = n.getLightBlend(getDayNightRatio());
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e) {}
|
catch(InvalidPositionException &e) {}
|
||||||
player->updateLight(light);
|
player->updateLight(light);
|
||||||
@ -1254,7 +1542,7 @@ void ClientEnvironment::step(float dtime)
|
|||||||
{
|
{
|
||||||
v3s16 p_blocks = getNodeBlockPos(bottompos);
|
v3s16 p_blocks = getNodeBlockPos(bottompos);
|
||||||
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
|
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
|
||||||
//b->updateMesh(m_daynight_ratio);
|
//b->updateMesh(getDayNightRatio());
|
||||||
b->setMeshExpired(true);
|
b->setMeshExpired(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1283,7 +1571,7 @@ void ClientEnvironment::step(float dtime)
|
|||||||
// Get node at head
|
// Get node at head
|
||||||
v3s16 p = obj->getLightPosition();
|
v3s16 p = obj->getLightPosition();
|
||||||
MapNode n = m_map->getNode(p);
|
MapNode n = m_map->getNode(p);
|
||||||
light = n.getLightBlend(m_daynight_ratio);
|
light = n.getLightBlend(getDayNightRatio());
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e) {}
|
catch(InvalidPositionException &e) {}
|
||||||
obj->updateLight(light);
|
obj->updateLight(light);
|
||||||
@ -1292,7 +1580,7 @@ void ClientEnvironment::step(float dtime)
|
|||||||
|
|
||||||
void ClientEnvironment::updateMeshes(v3s16 blockpos)
|
void ClientEnvironment::updateMeshes(v3s16 blockpos)
|
||||||
{
|
{
|
||||||
m_map->updateMeshes(blockpos, m_daynight_ratio);
|
m_map->updateMeshes(blockpos, getDayNightRatio());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
|
void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
|
||||||
|
@ -64,14 +64,52 @@ public:
|
|||||||
core::list<Player*> getPlayers(bool ignore_disconnected);
|
core::list<Player*> getPlayers(bool ignore_disconnected);
|
||||||
void printPlayers(std::ostream &o);
|
void printPlayers(std::ostream &o);
|
||||||
|
|
||||||
void setDayNightRatio(u32 r);
|
//void setDayNightRatio(u32 r);
|
||||||
u32 getDayNightRatio();
|
u32 getDayNightRatio();
|
||||||
|
|
||||||
|
// 0-23999
|
||||||
|
virtual void setTimeOfDay(u32 time)
|
||||||
|
{
|
||||||
|
m_time_of_day = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 getTimeOfDay()
|
||||||
|
{
|
||||||
|
return m_time_of_day;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// peer_ids in here should be unique, except that there may be many 0s
|
// peer_ids in here should be unique, except that there may be many 0s
|
||||||
core::list<Player*> m_players;
|
core::list<Player*> m_players;
|
||||||
// Brightness
|
// 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:
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -107,9 +145,18 @@ public:
|
|||||||
|
|
||||||
void step(f32 dtime);
|
void step(f32 dtime);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Save players
|
||||||
|
*/
|
||||||
void serializePlayers(const std::string &savedir);
|
void serializePlayers(const std::string &savedir);
|
||||||
void deSerializePlayers(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
|
ActiveObjects
|
||||||
*/
|
*/
|
||||||
@ -153,25 +200,48 @@ private:
|
|||||||
Remove all objects that satisfy (m_removed && m_known_by_count==0)
|
Remove all objects that satisfy (m_removed && m_known_by_count==0)
|
||||||
*/
|
*/
|
||||||
void removeRemovedObjects();
|
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.
|
Convert stored objects from block to active
|
||||||
*/
|
*/
|
||||||
void deactivateFarObjects(s16 range_blocks);
|
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;
|
ServerMap *m_map;
|
||||||
|
// Pointer to server (which is handling this environment)
|
||||||
Server *m_server;
|
Server *m_server;
|
||||||
|
// Active object list
|
||||||
core::map<u16, ServerActiveObject*> m_active_objects;
|
core::map<u16, ServerActiveObject*> m_active_objects;
|
||||||
|
// Outgoing network message buffer for active objects
|
||||||
Queue<ActiveObjectMessage> m_active_object_messages;
|
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;
|
float m_send_recommended_timer;
|
||||||
IntervalLimiter m_object_management_interval;
|
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
|
#ifndef SERVER
|
||||||
@ -228,6 +298,20 @@ public:
|
|||||||
void updateMeshes(v3s16 blockpos);
|
void updateMeshes(v3s16 blockpos);
|
||||||
void expireMeshes(bool only_daynight_diffed);
|
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
|
ActiveObjects
|
||||||
*/
|
*/
|
||||||
|
49
src/main.cpp
49
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
|
NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the
|
||||||
hardware buffer (it is not freed automatically)
|
hardware buffer (it is not freed automatically)
|
||||||
|
|
||||||
Random suggeestions (AKA very old suggestions that haven't been done):
|
Old, wild and random suggestions that probably won't be done:
|
||||||
----------------------------------------------------------------------
|
-------------------------------------------------------------
|
||||||
|
|
||||||
SUGG: Fix address to be ipv6 compatible
|
|
||||||
|
|
||||||
SUGG: If player is on ground, mainly fetch ground-level blocks
|
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: 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:
|
Gaming ideas:
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@ -137,6 +139,8 @@ Build system / running:
|
|||||||
Networking and serialization:
|
Networking and serialization:
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
SUGG: Fix address to be ipv6 compatible
|
||||||
|
|
||||||
User Interface:
|
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
|
FIXME: The new optimized map sending doesn't sometimes send enough blocks
|
||||||
from big caves and such
|
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:
|
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.
|
SUGG: MovingObject::move and Player::move are basically the same.
|
||||||
combine them.
|
combine them.
|
||||||
- NOTE: Player::move is more up-to-date.
|
- NOTE: Player::move is more up-to-date.
|
||||||
- NOTE: There is a simple move implementation now in collision.{h,cpp}
|
- NOTE: There is a simple move implementation now in collision.{h,cpp}
|
||||||
|
- NOTE: MovingObject will be deleted (MapBlockObject)
|
||||||
SUGG: Server-side objects could be moved based on nodes to enable very
|
|
||||||
lightweight operation and simple AI
|
|
||||||
|
|
||||||
Map:
|
Map:
|
||||||
----
|
----
|
||||||
|
57
src/map.cpp
57
src/map.cpp
@ -607,13 +607,13 @@ s16 Map::propagateSunlight(v3s16 start,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Turn mud into grass
|
/*// Turn mud into grass
|
||||||
if(n.d == CONTENT_MUD)
|
if(n.d == CONTENT_MUD)
|
||||||
{
|
{
|
||||||
n.d = CONTENT_GRASS;
|
n.d = CONTENT_GRASS;
|
||||||
block->setNode(relpos, n);
|
block->setNode(relpos, n);
|
||||||
modified_blocks.insert(blockpos, block);
|
modified_blocks.insert(blockpos, block);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Sunlight goes no further
|
// Sunlight goes no further
|
||||||
break;
|
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,
|
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
||||||
core::map<v3s16, MapBlock*> &modified_blocks)
|
core::map<v3s16, MapBlock*> &modified_blocks)
|
||||||
@ -878,11 +875,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
/*
|
/*
|
||||||
If the new node doesn't propagate sunlight and there is
|
If the new node is solid and there is grass below, change it to mud
|
||||||
grass below, change it to mud
|
|
||||||
*/
|
*/
|
||||||
if(content_features(n.d).sunlight_propagates == false)
|
if(content_features(n.d).walkable == true)
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
MapNode bottomnode = getNode(bottompos);
|
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
|
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);
|
o.write((char*)&version, 1);
|
||||||
|
|
||||||
|
// Write basic data
|
||||||
block->serialize(o, version);
|
block->serialize(o, version);
|
||||||
|
|
||||||
/*
|
// Write extra data stored on disk
|
||||||
Versions up from 9 have block objects.
|
block->serializeDiskExtra(o, version);
|
||||||
*/
|
|
||||||
if(version >= 9)
|
|
||||||
{
|
|
||||||
block->serializeObjects(o, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// We just wrote it to the disk so clear modified flag
|
||||||
Versions up from 15 have static objects.
|
|
||||||
*/
|
|
||||||
if(version >= 15)
|
|
||||||
{
|
|
||||||
block->m_static_objects.serialize(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We just wrote it to the disk
|
|
||||||
block->resetChangedFlag();
|
block->resetChangedFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5515,33 +5501,20 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
|||||||
created_new = true;
|
created_new = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// deserialize block data
|
// Read basic data
|
||||||
block->deSerialize(is, version);
|
block->deSerialize(is, version);
|
||||||
|
|
||||||
/*
|
// Read extra data stored on disk
|
||||||
Versions up from 9 have block objects.
|
block->deSerializeDiskExtra(is, version);
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If it's a new block, insert it to the map
|
||||||
if(created_new)
|
if(created_new)
|
||||||
sector->insertBlock(block);
|
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)
|
if(version < SER_FMT_VER_HIGHEST || save_after_load)
|
||||||
{
|
{
|
||||||
saveBlock(block);
|
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_lighting_expired(true),
|
||||||
m_day_night_differs(false),
|
m_day_night_differs(false),
|
||||||
//m_not_fully_generated(false),
|
//m_not_fully_generated(false),
|
||||||
m_objects(this)
|
m_objects(this),
|
||||||
|
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED)
|
||||||
{
|
{
|
||||||
data = NULL;
|
data = NULL;
|
||||||
if(dummy == false)
|
if(dummy == false)
|
||||||
@ -1720,17 +1721,17 @@ void MapBlock::replaceMesh(scene::SMesh *mesh_new)
|
|||||||
Propagates sunlight down through the block.
|
Propagates sunlight down through the block.
|
||||||
Doesn't modify nodes that are not affected by sunlight.
|
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.
|
Returns true if bottom block doesn't exist.
|
||||||
|
|
||||||
If there is a block above, continues from it.
|
If there is a block above, continues from it.
|
||||||
If there is no block above, assumes there is sunlight, unless
|
If there is no block above, assumes there is sunlight, unless
|
||||||
is_underground is set or highest node is water.
|
is_underground is set or highest node is water.
|
||||||
|
|
||||||
At the moment, all sunlighted nodes are added to light_sources.
|
All sunlighted nodes are added to light_sources.
|
||||||
- SUGG: This could be optimized
|
|
||||||
|
|
||||||
Turns sunglighted mud into grass.
|
If grow_grass==true, turns sunglighted mud into grass.
|
||||||
|
|
||||||
if remove_light==true, sets non-sunlighted nodes black.
|
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);
|
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();
|
setChangedFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2359,6 +2321,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
|
|||||||
/*
|
/*
|
||||||
Translate nodes as specified in the translate_to fields of
|
Translate nodes as specified in the translate_to fields of
|
||||||
node features
|
node features
|
||||||
|
|
||||||
|
NOTE: This isn't really used. Should it be removed?
|
||||||
*/
|
*/
|
||||||
for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
|
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
|
//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 "nodemetadata.h"
|
||||||
#include "staticobject.h"
|
#include "staticobject.h"
|
||||||
|
|
||||||
|
#define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
|
||||||
|
|
||||||
// Named by looking towards z+
|
// Named by looking towards z+
|
||||||
enum{
|
enum{
|
||||||
@ -244,24 +245,28 @@ public:
|
|||||||
reallocate();
|
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()
|
void resetChangedFlag()
|
||||||
{
|
{
|
||||||
changed = false;
|
changed = false;
|
||||||
}
|
}
|
||||||
void setChangedFlag()
|
bool getChangedFlag()
|
||||||
{
|
{
|
||||||
changed = true;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getIsUnderground()
|
bool getIsUnderground()
|
||||||
{
|
{
|
||||||
return is_underground;
|
return is_underground;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIsUnderground(bool a_is_underground)
|
void setIsUnderground(bool a_is_underground)
|
||||||
{
|
{
|
||||||
is_underground = a_is_underground;
|
is_underground = a_is_underground;
|
||||||
@ -359,6 +364,15 @@ public:
|
|||||||
return getNode(p.X, p.Y, p.Z);
|
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)
|
void setNode(s16 x, s16 y, s16 z, MapNode & n)
|
||||||
{
|
{
|
||||||
if(data == NULL)
|
if(data == NULL)
|
||||||
@ -444,47 +458,19 @@ public:
|
|||||||
face_dir);
|
face_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER // Only on client
|
||||||
// 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);*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
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.
|
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);
|
void updateMesh(u32 daynight_ratio);
|
||||||
#endif
|
#endif
|
||||||
|
// Replace the mesh with a new one
|
||||||
void replaceMesh(scene::SMesh *mesh_new);
|
void replaceMesh(scene::SMesh *mesh_new);
|
||||||
|
#endif
|
||||||
#endif // !SERVER
|
|
||||||
|
|
||||||
// See comments in mapblock.cpp
|
// See comments in mapblock.cpp
|
||||||
bool propagateSunlight(core::map<v3s16, bool> & light_sources,
|
bool propagateSunlight(core::map<v3s16, bool> & light_sources,
|
||||||
@ -498,6 +484,7 @@ public:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
MapBlockObject stuff
|
MapBlockObject stuff
|
||||||
|
DEPRECATED
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void serializeObjects(std::ostream &os, u8 version)
|
void serializeObjects(std::ostream &os, u8 version)
|
||||||
@ -545,13 +532,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void stepObjects(float dtime, bool server, u32 daynight_ratio);
|
void stepObjects(float dtime, bool server, u32 daynight_ratio);
|
||||||
|
|
||||||
/*void wrapObject(MapBlockObject *object)
|
|
||||||
{
|
|
||||||
m_objects.wrapObject(object);
|
|
||||||
|
|
||||||
setChangedFlag();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// origin is relative to block
|
// origin is relative to block
|
||||||
void getObjects(v3f origin, f32 max_d,
|
void getObjects(v3f origin, f32 max_d,
|
||||||
core::array<DistanceSortedObject> &dest)
|
core::array<DistanceSortedObject> &dest)
|
||||||
@ -564,7 +544,7 @@ public:
|
|||||||
return m_objects.getCount();
|
return m_objects.getCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER // Only on client
|
||||||
/*
|
/*
|
||||||
Methods for setting temporary modifications to nodes for
|
Methods for setting temporary modifications to nodes for
|
||||||
drawing
|
drawing
|
||||||
@ -639,14 +619,30 @@ public:
|
|||||||
*/
|
*/
|
||||||
s16 getGroundLevel(v2s16 p2d);
|
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
|
Serialization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Doesn't write version by itself
|
// These don't write or read version by itself
|
||||||
void serialize(std::ostream &os, u8 version);
|
void serialize(std::ostream &os, u8 version);
|
||||||
|
|
||||||
void deSerialize(std::istream &is, 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:
|
private:
|
||||||
/*
|
/*
|
||||||
@ -676,7 +672,7 @@ public:
|
|||||||
Public member variables
|
Public member variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER // Only on client
|
||||||
scene::SMesh *mesh;
|
scene::SMesh *mesh;
|
||||||
JMutex mesh_mutex;
|
JMutex mesh_mutex;
|
||||||
#endif
|
#endif
|
||||||
@ -729,12 +725,9 @@ private:
|
|||||||
// Whether day and night lighting differs
|
// Whether day and night lighting differs
|
||||||
bool m_day_night_differs;
|
bool m_day_night_differs;
|
||||||
|
|
||||||
// TODO: Remove this
|
// DEPRECATED
|
||||||
MapBlockObjectList m_objects;
|
MapBlockObjectList m_objects;
|
||||||
|
|
||||||
// Object spawning stuff
|
|
||||||
//float m_spawn_timer;
|
|
||||||
|
|
||||||
#ifndef SERVER // Only on client
|
#ifndef SERVER // Only on client
|
||||||
/*
|
/*
|
||||||
Set to true if the mesh has been ordered to be updated
|
Set to true if the mesh has been ordered to be updated
|
||||||
@ -748,6 +741,12 @@ private:
|
|||||||
NodeModMap m_temp_mods;
|
NodeModMap m_temp_mods;
|
||||||
JMutex m_temp_mods_mutex;
|
JMutex m_temp_mods_mutex;
|
||||||
#endif
|
#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)
|
inline bool blockpos_over_limit(v3s16 p)
|
||||||
|
@ -148,6 +148,8 @@ struct ContentFeatures
|
|||||||
bool light_propagates;
|
bool light_propagates;
|
||||||
bool sunlight_propagates;
|
bool sunlight_propagates;
|
||||||
u8 solidness; // Used when choosing which face is drawn
|
u8 solidness; // Used when choosing which face is drawn
|
||||||
|
// This is used for collision detection.
|
||||||
|
// Also for general solidness queries.
|
||||||
bool walkable;
|
bool walkable;
|
||||||
bool pointable;
|
bool pointable;
|
||||||
bool diggable;
|
bool diggable;
|
||||||
|
@ -26,53 +26,55 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "utility.h"
|
#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
|
NOTE: The goal is to increment this so that saved maps will be
|
||||||
loadable by any version. Other compatibility is not
|
loadable by any version. Other compatibility is not
|
||||||
maintained.
|
maintained.
|
||||||
Serialization format versions (for raw map data (blocks, nodes, sectors)):
|
|
||||||
== Unsupported ==
|
|
||||||
0: original networked test with 1-byte nodes
|
0: original networked test with 1-byte nodes
|
||||||
1: update with 2-byte nodes
|
1: update with 2-byte nodes
|
||||||
== Supported ==
|
|
||||||
2: lighting is transmitted in param
|
2: lighting is transmitted in param
|
||||||
3: optional fetching of far blocks
|
3: optional fetching of far blocks
|
||||||
4: block compression
|
4: block compression
|
||||||
5: sector objects NOTE: block compression was left accidentally out
|
5: sector objects NOTE: block compression was left accidentally out
|
||||||
6: failed attempt at switching block compression on again
|
6: failed attempt at switching block compression on again
|
||||||
7: block compression switched on again
|
7: block compression switched on again
|
||||||
8: (dev) server-initiated block transfers and all kinds of stuff
|
8: server-initiated block transfers and all kinds of stuff
|
||||||
9: (dev) block objects
|
9: block objects
|
||||||
10: (dev) water pressure
|
10: water pressure
|
||||||
11: (dev) zlib'd blocks, block flags
|
11: zlib'd blocks, block flags
|
||||||
12: (dev) UnlimitedHeightmap now uses interpolated areas
|
12: UnlimitedHeightmap now uses interpolated areas
|
||||||
13: (dev) Mapgen v2
|
13: Mapgen v2
|
||||||
14: (dev) NodeMetadata
|
14: NodeMetadata
|
||||||
15: (dev) StaticObjects
|
15: StaticObjects
|
||||||
16: (dev) larger maximum size of node metadata, and compression
|
16: larger maximum size of node metadata, and compression
|
||||||
|
17: MapBlocks contain timestamp
|
||||||
*/
|
*/
|
||||||
// This represents an uninitialized or invalid format
|
// This represents an uninitialized or invalid format
|
||||||
#define SER_FMT_VER_INVALID 255
|
#define SER_FMT_VER_INVALID 255
|
||||||
// Highest supported serialization version
|
// Highest supported serialization version
|
||||||
#define SER_FMT_VER_HIGHEST 16
|
#define SER_FMT_VER_HIGHEST 17
|
||||||
// Lowest supported serialization version
|
// Lowest supported serialization version
|
||||||
#define SER_FMT_VER_LOWEST 0
|
#define SER_FMT_VER_LOWEST 0
|
||||||
|
|
||||||
#define ser_ver_supported(v) (v >= SER_FMT_VER_LOWEST && v <= SER_FMT_VER_HIGHEST)
|
#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(SharedBuffer<u8> data, std::ostream &os);
|
||||||
void compressZlib(const std::string &data, std::ostream &os);
|
void compressZlib(const std::string &data, std::ostream &os);
|
||||||
void decompressZlib(std::istream &is, 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(SharedBuffer<u8> data, std::ostream &os, u8 version);
|
||||||
//void compress(const std::string &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);
|
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
|
#endif
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "mineral.h"
|
#include "mineral.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "servercommand.h"
|
#include "servercommand.h"
|
||||||
|
#include "filesys.h"
|
||||||
|
|
||||||
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
|
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
|
||||||
|
|
||||||
@ -798,7 +799,7 @@ void RemoteClient::SendObjectData(
|
|||||||
*/
|
*/
|
||||||
if(stepped_blocks.find(p) == NULL)
|
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);
|
stepped_blocks.insert(p, true);
|
||||||
block->setChangedFlag();
|
block->setChangedFlag();
|
||||||
}
|
}
|
||||||
@ -968,7 +969,6 @@ Server::Server(
|
|||||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||||
m_thread(this),
|
m_thread(this),
|
||||||
m_emergethread(this),
|
m_emergethread(this),
|
||||||
m_time_of_day(9000),
|
|
||||||
m_time_counter(0),
|
m_time_counter(0),
|
||||||
m_time_of_day_send_timer(0),
|
m_time_of_day_send_timer(0),
|
||||||
m_uptime(0),
|
m_uptime(0),
|
||||||
@ -988,9 +988,18 @@ Server::Server(
|
|||||||
m_step_dtime_mutex.Init();
|
m_step_dtime_mutex.Init();
|
||||||
m_step_dtime = 0.0;
|
m_step_dtime = 0.0;
|
||||||
|
|
||||||
|
// Register us to receive map edit events
|
||||||
m_env.getMap().addEventReceiver(this);
|
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
|
// Load players
|
||||||
|
dstream<<"Server: Loading players"<<std::endl;
|
||||||
m_env.deSerializePlayers(m_mapsavedir);
|
m_env.deSerializePlayers(m_mapsavedir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1033,6 +1042,12 @@ Server::~Server()
|
|||||||
dstream<<"Server: Saving players"<<std::endl;
|
dstream<<"Server: Saving players"<<std::endl;
|
||||||
m_env.serializePlayers(m_mapsavedir);
|
m_env.serializePlayers(m_mapsavedir);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Save environment metadata
|
||||||
|
*/
|
||||||
|
dstream<<"Server: Saving environment metadata"<<std::endl;
|
||||||
|
m_env.saveMeta(m_mapsavedir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Stop threads
|
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;
|
m_time_counter += dtime;
|
||||||
f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
|
f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
|
||||||
u32 units = (u32)(m_time_counter*speed);
|
u32 units = (u32)(m_time_counter*speed);
|
||||||
m_time_counter -= (f32)units / 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;
|
//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);
|
//Player *player = m_env.getPlayer(client->peer_id);
|
||||||
|
|
||||||
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
|
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
|
||||||
m_time_of_day.get());
|
m_env.getTimeOfDay());
|
||||||
// Send as reliable
|
// Send as reliable
|
||||||
m_con.Send(client->peer_id, 0, data, true);
|
m_con.Send(client->peer_id, 0, data, true);
|
||||||
}
|
}
|
||||||
@ -1654,6 +1672,9 @@ void Server::AsyncRunStep()
|
|||||||
|
|
||||||
// Save players
|
// Save players
|
||||||
m_env.serializePlayers(m_mapsavedir);
|
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
|
// Send time of day
|
||||||
{
|
{
|
||||||
SharedBuffer<u8> data = makePacket_TOCLIENT_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);
|
m_con.Send(peer->id, 0, data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
82
src/server.h
82
src/server.h
@ -382,20 +382,21 @@ public:
|
|||||||
|
|
||||||
core::list<PlayerInfo> getPlayerInfo();
|
core::list<PlayerInfo> getPlayerInfo();
|
||||||
|
|
||||||
u32 getDayNightRatio()
|
/*u32 getDayNightRatio()
|
||||||
{
|
{
|
||||||
return time_to_daynight_ratio(m_time_of_day.get());
|
return time_to_daynight_ratio(m_time_of_day.get());
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
// Environment must be locked when called
|
||||||
void setTimeOfDay(u32 time)
|
void setTimeOfDay(u32 time)
|
||||||
{
|
{
|
||||||
m_time_of_day.set(time);
|
m_env.setTimeOfDay(time);
|
||||||
m_time_of_day_send_timer = 0;
|
m_time_of_day_send_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getShutdownRequested()
|
bool getShutdownRequested()
|
||||||
{
|
{
|
||||||
return m_shutdown_requested.get();
|
return m_shutdown_requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -416,7 +417,7 @@ public:
|
|||||||
|
|
||||||
void requestShutdown(void)
|
void requestShutdown(void)
|
||||||
{
|
{
|
||||||
m_shutdown_requested.set(true);
|
m_shutdown_requested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -426,7 +427,8 @@ public:
|
|||||||
|
|
||||||
private:
|
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.
|
// As of now, these create and remove clients and players.
|
||||||
void peerAdded(con::Peer *peer);
|
void peerAdded(con::Peer *peer);
|
||||||
void deletingPeer(con::Peer *peer, bool timeout);
|
void deletingPeer(con::Peer *peer, bool timeout);
|
||||||
@ -484,21 +486,16 @@ private:
|
|||||||
*/
|
*/
|
||||||
Player *emergePlayer(const char *name, const char *password, u16 peer_id);
|
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
|
// Locks environment and connection by its own
|
||||||
struct PeerChange;
|
struct PeerChange;
|
||||||
void handlePeerChange(PeerChange &c);
|
void handlePeerChange(PeerChange &c);
|
||||||
void handlePeerChanges();
|
void handlePeerChanges();
|
||||||
|
|
||||||
//float m_flowwater_timer;
|
/*
|
||||||
|
Variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Some timers
|
||||||
float m_liquid_transform_timer;
|
float m_liquid_transform_timer;
|
||||||
float m_print_info_timer;
|
float m_print_info_timer;
|
||||||
float m_objectdata_timer;
|
float m_objectdata_timer;
|
||||||
@ -507,50 +504,81 @@ private:
|
|||||||
|
|
||||||
// NOTE: If connection and environment are both to be locked,
|
// NOTE: If connection and environment are both to be locked,
|
||||||
// environment shall be locked first.
|
// environment shall be locked first.
|
||||||
JMutex m_env_mutex;
|
|
||||||
|
// Environment
|
||||||
ServerEnvironment m_env;
|
ServerEnvironment m_env;
|
||||||
|
JMutex m_env_mutex;
|
||||||
|
|
||||||
JMutex m_con_mutex;
|
// Connection
|
||||||
con::Connection m_con;
|
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;
|
float m_step_dtime;
|
||||||
JMutex m_step_dtime_mutex;
|
JMutex m_step_dtime_mutex;
|
||||||
|
|
||||||
|
// The server mainly operates in this thread
|
||||||
ServerThread m_thread;
|
ServerThread m_thread;
|
||||||
|
// This thread fetches and generates map
|
||||||
EmergeThread m_emergethread;
|
EmergeThread m_emergethread;
|
||||||
|
// Queue of block coordinates to be processed by the emerge thread
|
||||||
BlockEmergeQueue m_emerge_queue;
|
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
|
// 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
|
// Used to buffer dtime for adding to m_time_of_day
|
||||||
float m_time_counter;
|
float m_time_counter;
|
||||||
|
// Timer for sending time of day over network
|
||||||
float m_time_of_day_send_timer;
|
float m_time_of_day_send_timer;
|
||||||
|
// Uptime of server in seconds
|
||||||
MutexedVariable<double> m_uptime;
|
MutexedVariable<double> m_uptime;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Peer change queue.
|
||||||
|
Queues stuff from peerAdded() and deletingPeer() to
|
||||||
|
handlePeerChanges()
|
||||||
|
*/
|
||||||
enum PeerChangeType
|
enum PeerChangeType
|
||||||
{
|
{
|
||||||
PEER_ADDED,
|
PEER_ADDED,
|
||||||
PEER_REMOVED
|
PEER_REMOVED
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PeerChange
|
struct PeerChange
|
||||||
{
|
{
|
||||||
PeerChangeType type;
|
PeerChangeType type;
|
||||||
u16 peer_id;
|
u16 peer_id;
|
||||||
bool timeout;
|
bool timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
Queue<PeerChange> m_peer_change_queue;
|
Queue<PeerChange> m_peer_change_queue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Random stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Map directory
|
||||||
std::string m_mapsavedir;
|
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
|
Queue of map edits from the environment for sending to the clients
|
||||||
|
@ -29,6 +29,7 @@ ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos):
|
|||||||
ActiveObject(id),
|
ActiveObject(id),
|
||||||
m_known_by_count(0),
|
m_known_by_count(0),
|
||||||
m_removed(false),
|
m_removed(false),
|
||||||
|
m_pending_deactivation(false),
|
||||||
m_static_exists(false),
|
m_static_exists(false),
|
||||||
m_static_block(1337,1337,1337),
|
m_static_block(1337,1337,1337),
|
||||||
m_env(env),
|
m_env(env),
|
||||||
|
@ -106,8 +106,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual u16 punch(const std::string &toolname){return 0;}
|
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;
|
u16 m_known_by_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- Whether this object is to be removed when nobody knows about
|
- Whether this object is to be removed when nobody knows about
|
||||||
it anymore.
|
it anymore.
|
||||||
@ -119,6 +124,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool m_removed;
|
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
|
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);
|
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)
|
inline void writeF1000(std::ostream &os, f32 p)
|
||||||
{
|
{
|
||||||
char buf[2];
|
char buf[2];
|
||||||
|
Loading…
Reference in New Issue
Block a user