mirror of
https://github.com/minetest/minetest.git
synced 2024-08-20 05:24:15 +02:00
Temporary commit; lots of test code and stuff
This commit is contained in:
parent
f5ff378dd0
commit
c57637b4c3
BIN
data/grass.png
BIN
data/grass.png
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 966 B |
BIN
data/stone.png
BIN
data/stone.png
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 846 B |
@ -50,6 +50,7 @@ configure_file(
|
||||
)
|
||||
|
||||
set(common_SRCS
|
||||
serverobject.cpp
|
||||
noise.cpp
|
||||
mineral.cpp
|
||||
porting.cpp
|
||||
@ -75,8 +76,10 @@ set(common_SRCS
|
||||
test.cpp
|
||||
)
|
||||
|
||||
# Client sources
|
||||
set(minetest_SRCS
|
||||
${common_SRCS}
|
||||
clientobject.cpp
|
||||
guiMainMenu.cpp
|
||||
guiMessageMenu.cpp
|
||||
guiTextInputMenu.cpp
|
||||
@ -88,6 +91,7 @@ set(minetest_SRCS
|
||||
main.cpp
|
||||
)
|
||||
|
||||
# Server sources
|
||||
set(minetestserver_SRCS
|
||||
${common_SRCS}
|
||||
servermain.cpp
|
||||
|
71
src/activeobject.h
Normal file
71
src/activeobject.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef ACTIVEOBJECT_HEADER
|
||||
#define ACTIVEOBJECT_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include <string>
|
||||
|
||||
struct ActiveObjectMessage
|
||||
{
|
||||
ActiveObjectMessage(u16 id_, bool reliable_=true, std::string data_=""):
|
||||
id(id_),
|
||||
reliable(reliable_),
|
||||
datastring(data_)
|
||||
{}
|
||||
|
||||
u16 id;
|
||||
bool reliable;
|
||||
std::string datastring;
|
||||
};
|
||||
|
||||
#define ACTIVEOBJECT_TYPE_INVALID 0
|
||||
#define ACTIVEOBJECT_TYPE_TEST 1
|
||||
#define ACTIVEOBJECT_TYPE_LUA 2
|
||||
|
||||
/*
|
||||
Parent class for ServerActiveObject and ClientActiveObject
|
||||
*/
|
||||
class ActiveObject
|
||||
{
|
||||
public:
|
||||
ActiveObject(u16 id):
|
||||
m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
u16 getId()
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void setId(u16 id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
virtual u8 getType() const = 0;
|
||||
|
||||
protected:
|
||||
u16 m_id; // 0 is invalid, "no id"
|
||||
};
|
||||
|
||||
#endif
|
||||
|
158
src/client.cpp
158
src/client.cpp
@ -56,10 +56,12 @@ Client::Client(
|
||||
const char *playername,
|
||||
MapDrawControl &control):
|
||||
m_thread(this),
|
||||
m_env(new ClientMap(this, control,
|
||||
m_env(
|
||||
new ClientMap(this, control,
|
||||
device->getSceneManager()->getRootSceneNode(),
|
||||
device->getSceneManager(), 666),
|
||||
dout_client),
|
||||
device->getSceneManager()
|
||||
),
|
||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||
m_device(device),
|
||||
camera_position(0,0,0),
|
||||
@ -82,20 +84,25 @@ Client::Client(
|
||||
m_step_dtime_mutex.Init();
|
||||
|
||||
m_thread.Start();
|
||||
|
||||
|
||||
/*
|
||||
Add local player
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
//m_env.getMap().StartUpdater();
|
||||
|
||||
Player *player = new LocalPlayer();
|
||||
|
||||
player->updateName(playername);
|
||||
|
||||
/*f32 y = BS*2 + BS*20;
|
||||
player->setPosition(v3f(0, y, 0));*/
|
||||
//player->setPosition(v3f(0, y, 30900*BS)); // DEBUG
|
||||
m_env.addPlayer(player);
|
||||
}
|
||||
|
||||
// Add some active objects for testing
|
||||
/*{
|
||||
ClientActiveObject *obj = new TestCAO(0, v3f(0, 10*BS, 0));
|
||||
m_env.addActiveObject(obj);
|
||||
}*/
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
@ -493,7 +500,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
v3s16 playerpos_s16(0, BS*2+BS*20, 0);
|
||||
if(datasize >= 2+1+6)
|
||||
playerpos_s16 = readV3S16(&data[2+1]);
|
||||
v3f playerpos_f = intToFloat(playerpos_s16) - v3f(0, BS/2, 0);
|
||||
v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
|
||||
|
||||
{ //envlock
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
@ -1037,6 +1044,99 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
|
||||
m_chat_queue.push_back(message);
|
||||
}
|
||||
else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
|
||||
{
|
||||
/*
|
||||
u16 command
|
||||
u16 count of removed objects
|
||||
for all removed objects {
|
||||
u16 id
|
||||
}
|
||||
u16 count of added objects
|
||||
for all added objects {
|
||||
u16 id
|
||||
u8 type
|
||||
}
|
||||
*/
|
||||
|
||||
char buf[6];
|
||||
// Get all data except the command number
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
// Throw them in an istringstream
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
// Read stuff
|
||||
|
||||
// Read removed objects
|
||||
is.read(buf, 2);
|
||||
u16 removed_count = readU16((u8*)buf);
|
||||
for(u16 i=0; i<removed_count; i++)
|
||||
{
|
||||
is.read(buf, 2);
|
||||
u16 id = readU16((u8*)buf);
|
||||
// Remove it
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
m_env.removeActiveObject(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Read added objects
|
||||
is.read(buf, 2);
|
||||
u16 added_count = readU16((u8*)buf);
|
||||
for(u16 i=0; i<added_count; i++)
|
||||
{
|
||||
is.read(buf, 2);
|
||||
u16 id = readU16((u8*)buf);
|
||||
is.read(buf, 1);
|
||||
u8 type = readU8((u8*)buf);
|
||||
// Add it
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
m_env.addActiveObject(id, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
|
||||
{
|
||||
/*
|
||||
u16 command
|
||||
for all objects
|
||||
{
|
||||
u16 id
|
||||
u16 message length
|
||||
string message
|
||||
}
|
||||
*/
|
||||
char buf[6];
|
||||
// Get all data except the command number
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
// Throw them in an istringstream
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
while(is.eof() == false)
|
||||
{
|
||||
// Read stuff
|
||||
is.read(buf, 2);
|
||||
u16 id = readU16((u8*)buf);
|
||||
if(is.eof())
|
||||
break;
|
||||
is.read(buf, 2);
|
||||
u16 message_size = readU16((u8*)buf);
|
||||
std::string message;
|
||||
message.reserve(message_size);
|
||||
for(u16 i=0; i<message_size; i++)
|
||||
{
|
||||
is.read(buf, 1);
|
||||
message.append(buf, 1);
|
||||
}
|
||||
// Pass on to the environment
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
m_env.processActiveObjectMessage(id, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Default to queueing it (for slow commands)
|
||||
else
|
||||
{
|
||||
@ -1197,7 +1297,7 @@ bool Client::AsyncProcessPacket()
|
||||
main thread, from which is will want to retrieve textures.
|
||||
*/
|
||||
|
||||
m_env.getMap().updateMeshes(block->getPos(), getDayNightRatio());
|
||||
m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1464,7 +1564,7 @@ void Client::removeNode(v3s16 p)
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
m_env.getMap().updateMeshes(p, m_env.getDayNightRatio());
|
||||
m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1486,7 +1586,7 @@ void Client::addNode(v3s16 p, MapNode n)
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
m_env.getMap().updateMeshes(p, m_env.getDayNightRatio());
|
||||
m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1503,36 +1603,6 @@ MapNode Client::getNode(v3s16 p)
|
||||
return m_env.getMap().getNode(p);
|
||||
}
|
||||
|
||||
/*void Client::getNode(v3s16 p, MapNode n)
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
m_env.getMap().setNode(p, n);
|
||||
}*/
|
||||
|
||||
/*f32 Client::getGroundHeight(v2s16 p)
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
return m_env.getMap().getGroundHeight(p);
|
||||
}*/
|
||||
|
||||
/*bool Client::isNodeUnderground(v3s16 p)
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
return m_env.getMap().isNodeUnderground(p);
|
||||
}*/
|
||||
|
||||
/*Player * Client::getLocalPlayer()
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
return m_env.getLocalPlayer();
|
||||
}*/
|
||||
|
||||
/*core::list<Player*> Client::getPlayers()
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
return m_env.getPlayers();
|
||||
}*/
|
||||
|
||||
v3f Client::getPlayerPosition()
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
@ -1597,7 +1667,7 @@ MapBlockObject * Client::getSelectedObject(
|
||||
|
||||
// Calculate from_pos relative to block
|
||||
v3s16 block_pos_i_on_map = block->getPosRelative();
|
||||
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
|
||||
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
|
||||
v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
|
||||
|
||||
block->getObjects(from_pos_f_on_block, max_d, objects);
|
||||
@ -1617,7 +1687,7 @@ MapBlockObject * Client::getSelectedObject(
|
||||
|
||||
// Calculate shootline relative to block
|
||||
v3s16 block_pos_i_on_map = block->getPosRelative();
|
||||
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
|
||||
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
|
||||
core::line3d<f32> shootline_on_block(
|
||||
shootline_on_map.start - block_pos_f_on_map,
|
||||
shootline_on_map.end - block_pos_f_on_map
|
||||
@ -1672,7 +1742,7 @@ u32 Client::getDayNightRatio()
|
||||
v3f playerpos = player->getPosition();
|
||||
v3f playerspeed = player->getSpeed();
|
||||
|
||||
v3s16 center_nodepos = floatToInt(playerpos);
|
||||
v3s16 center_nodepos = floatToInt(playerpos, BS);
|
||||
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||
|
||||
u32 counter = 0;
|
||||
|
33
src/client.h
33
src/client.h
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "common_irrlicht.h"
|
||||
#include "jmutex.h"
|
||||
#include <ostream>
|
||||
#include "clientobject.h"
|
||||
|
||||
class ClientNotReadyException : public BaseException
|
||||
{
|
||||
@ -165,11 +166,6 @@ public:
|
||||
|
||||
// Returns InvalidPositionException if not found
|
||||
MapNode getNode(v3s16 p);
|
||||
// Returns InvalidPositionException if not found
|
||||
//void setNode(v3s16 p, MapNode n);
|
||||
|
||||
// Returns InvalidPositionException if not found
|
||||
//f32 getGroundHeight(v2s16 p);
|
||||
|
||||
v3f getPlayerPosition();
|
||||
|
||||
@ -192,7 +188,6 @@ public:
|
||||
// Prints a line or two of info
|
||||
void printDebugInfo(std::ostream &os);
|
||||
|
||||
//s32 getDayNightIndex();
|
||||
u32 getDayNightRatio();
|
||||
|
||||
//void updateSomeExpiredMeshes();
|
||||
@ -230,27 +225,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void setTempMod(v3s16 p, NodeMod mod)
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
|
||||
bool changed = false;
|
||||
v3s16 blockpos = ((ClientMap&)m_env.getMap()).setTempMod(p, mod, &changed);
|
||||
if(changed)
|
||||
m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
|
||||
}
|
||||
void clearTempMod(v3s16 p)
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
|
||||
bool changed = false;
|
||||
v3s16 blockpos = ((ClientMap&)m_env.getMap()).clearTempMod(p, &changed);
|
||||
if(changed)
|
||||
m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
|
||||
}
|
||||
#endif
|
||||
|
||||
float getAvgRtt()
|
||||
{
|
||||
JMutexAutoLock lock(m_con_mutex);
|
||||
@ -302,15 +276,12 @@ private:
|
||||
// NOTE: If connection and environment are both to be locked,
|
||||
// environment shall be locked first.
|
||||
|
||||
Environment m_env;
|
||||
ClientEnvironment m_env;
|
||||
JMutex m_env_mutex;
|
||||
|
||||
con::Connection m_con;
|
||||
JMutex m_con_mutex;
|
||||
|
||||
/*core::map<v3s16, float> m_fetchblock_history;
|
||||
JMutex m_fetchblock_mutex;*/
|
||||
|
||||
core::list<IncomingPacket> m_incoming_queue;
|
||||
JMutex m_incoming_queue_mutex;
|
||||
|
||||
|
169
src/clientobject.cpp
Normal file
169
src/clientobject.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "clientobject.h"
|
||||
#include "debug.h"
|
||||
#include "porting.h"
|
||||
#include "constants.h"
|
||||
#include "utility.h"
|
||||
|
||||
ClientActiveObject::ClientActiveObject(u16 id):
|
||||
ActiveObject(id)
|
||||
{
|
||||
}
|
||||
|
||||
ClientActiveObject::~ClientActiveObject()
|
||||
{
|
||||
removeFromScene();
|
||||
}
|
||||
|
||||
ClientActiveObject* ClientActiveObject::create(u8 type)
|
||||
{
|
||||
if(type == ACTIVEOBJECT_TYPE_INVALID)
|
||||
{
|
||||
dstream<<"ClientActiveObject::create(): passed "
|
||||
<<"ACTIVEOBJECT_TYPE_INVALID"<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
else if(type == ACTIVEOBJECT_TYPE_TEST)
|
||||
{
|
||||
dstream<<"ClientActiveObject::create(): passed "
|
||||
<<"ACTIVEOBJECT_TYPE_TEST"<<std::endl;
|
||||
return new TestCAO(0);
|
||||
}
|
||||
else if(type == ACTIVEOBJECT_TYPE_LUA)
|
||||
{
|
||||
dstream<<"ClientActiveObject::create(): passed "
|
||||
<<"ACTIVEOBJECT_TYPE_LUA"<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstream<<"ClientActiveObject::create(): passed "
|
||||
<<"unknown type="<<type<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TestCAO
|
||||
*/
|
||||
|
||||
TestCAO::TestCAO(u16 id):
|
||||
ClientActiveObject(id),
|
||||
m_node(NULL),
|
||||
m_position(v3f(0,10*BS,0))
|
||||
{
|
||||
}
|
||||
|
||||
TestCAO::~TestCAO()
|
||||
{
|
||||
}
|
||||
|
||||
void TestCAO::addToScene(scene::ISceneManager *smgr)
|
||||
{
|
||||
if(m_node != NULL)
|
||||
return;
|
||||
|
||||
video::IVideoDriver* driver = smgr->getVideoDriver();
|
||||
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
video::SColor c(255,255,255,255);
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
|
||||
};
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
// Set material
|
||||
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
|
||||
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
buf->getMaterial().setTexture
|
||||
(0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
|
||||
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
|
||||
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
m_node = smgr->addMeshSceneNode(mesh, NULL);
|
||||
mesh->drop();
|
||||
updateNodePos();
|
||||
}
|
||||
|
||||
void TestCAO::removeFromScene()
|
||||
{
|
||||
if(m_node == NULL)
|
||||
return;
|
||||
|
||||
m_node->remove();
|
||||
m_node = NULL;
|
||||
}
|
||||
|
||||
void TestCAO::updateLight(u8 light_at_pos)
|
||||
{
|
||||
}
|
||||
|
||||
v3s16 TestCAO::getLightPosition()
|
||||
{
|
||||
return floatToInt(m_position, BS);
|
||||
}
|
||||
|
||||
void TestCAO::updateNodePos()
|
||||
{
|
||||
if(m_node == NULL)
|
||||
return;
|
||||
|
||||
m_node->setPosition(m_position);
|
||||
//m_node->setRotation(v3f(0, 45, 0));
|
||||
}
|
||||
|
||||
void TestCAO::step(float dtime)
|
||||
{
|
||||
if(m_node)
|
||||
{
|
||||
v3f rot = m_node->getRotation();
|
||||
//dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
|
||||
rot.Y += dtime * 180;
|
||||
m_node->setRotation(rot);
|
||||
}
|
||||
}
|
||||
|
||||
void TestCAO::processMessage(const std::string &data)
|
||||
{
|
||||
//dstream<<"TestCAO: Got data: "<<data<<std::endl;
|
||||
std::istringstream is(data, std::ios::binary);
|
||||
u16 cmd;
|
||||
is>>cmd;
|
||||
if(cmd == 0)
|
||||
{
|
||||
v3f newpos;
|
||||
is>>newpos.X;
|
||||
is>>newpos.Y;
|
||||
is>>newpos.Z;
|
||||
m_position = newpos;
|
||||
updateNodePos();
|
||||
}
|
||||
}
|
||||
|
||||
|
88
src/clientobject.h
Normal file
88
src/clientobject.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENTOBJECT_HEADER
|
||||
#define CLIENTOBJECT_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "activeobject.h"
|
||||
|
||||
/*
|
||||
|
||||
Some planning
|
||||
-------------
|
||||
|
||||
* Client receives a network packet with information of added objects
|
||||
in it
|
||||
* Client supplies the information to its ClientEnvironment
|
||||
* The environment adds the specified objects to itself
|
||||
|
||||
*/
|
||||
|
||||
class ClientActiveObject : public ActiveObject
|
||||
{
|
||||
public:
|
||||
ClientActiveObject(u16 id);
|
||||
virtual ~ClientActiveObject();
|
||||
|
||||
virtual void addToScene(scene::ISceneManager *smgr){}
|
||||
virtual void removeFromScene(){}
|
||||
// 0 <= light_at_pos <= LIGHT_SUN
|
||||
virtual void updateLight(u8 light_at_pos){}
|
||||
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
||||
|
||||
// Step object in time
|
||||
virtual void step(float dtime){}
|
||||
|
||||
// Process a message sent by the server side object
|
||||
virtual void processMessage(const std::string &data){}
|
||||
|
||||
static ClientActiveObject* create(u8 type);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
class TestCAO : public ClientActiveObject
|
||||
{
|
||||
public:
|
||||
TestCAO(u16 id);
|
||||
virtual ~TestCAO();
|
||||
|
||||
u8 getType() const
|
||||
{
|
||||
return ACTIVEOBJECT_TYPE_TEST;
|
||||
}
|
||||
|
||||
void addToScene(scene::ISceneManager *smgr);
|
||||
void removeFromScene();
|
||||
void updateLight(u8 light_at_pos);
|
||||
v3s16 getLightPosition();
|
||||
void updateNodePos();
|
||||
|
||||
void step(float dtime);
|
||||
|
||||
void processMessage(const std::string &data);
|
||||
|
||||
private:
|
||||
scene::IMeshSceneNode *m_node;
|
||||
v3f m_position;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -106,6 +106,31 @@ enum ToClientCommand
|
||||
wstring message
|
||||
*/
|
||||
|
||||
TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD = 0x31,
|
||||
/*
|
||||
u16 command
|
||||
u16 count of removed objects
|
||||
for all removed objects {
|
||||
u16 id
|
||||
}
|
||||
u16 count of added objects
|
||||
for all added objects {
|
||||
u16 id
|
||||
u8 type
|
||||
}
|
||||
*/
|
||||
|
||||
TOCLIENT_ACTIVE_OBJECT_MESSAGES = 0x32,
|
||||
/*
|
||||
u16 command
|
||||
for all objects
|
||||
{
|
||||
u16 id
|
||||
u16 message length
|
||||
string message
|
||||
}
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
enum ToServerCommand
|
||||
|
@ -20,11 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "environment.h"
|
||||
#include "filesys.h"
|
||||
|
||||
Environment::Environment(Map *map, std::ostream &dout):
|
||||
m_dout(dout)
|
||||
Environment::Environment()
|
||||
{
|
||||
m_map = map;
|
||||
m_daynight_ratio = 0.2;
|
||||
m_daynight_ratio = 0.5;
|
||||
}
|
||||
|
||||
Environment::~Environment()
|
||||
@ -35,183 +33,16 @@ Environment::~Environment()
|
||||
{
|
||||
delete (*i);
|
||||
}
|
||||
|
||||
// The map is removed by the SceneManager
|
||||
m_map->drop();
|
||||
//delete m_map;
|
||||
}
|
||||
|
||||
void Environment::step(float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
/*
|
||||
Run Map's timers
|
||||
*/
|
||||
//TimeTaker maptimerupdatetimer("m_map->timerUpdate()", g_device);
|
||||
// 0ms
|
||||
m_map->timerUpdate(dtime);
|
||||
//maptimerupdatetimer.stop();
|
||||
|
||||
/*
|
||||
Get the highest speed some player is going
|
||||
*/
|
||||
//TimeTaker playerspeed("playerspeed", g_device);
|
||||
// 0ms
|
||||
f32 maximum_player_speed = 0.001; // just some small value
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
f32 speed = (*i)->getSpeed().getLength();
|
||||
if(speed > maximum_player_speed)
|
||||
maximum_player_speed = speed;
|
||||
}
|
||||
//playerspeed.stop();
|
||||
|
||||
/*
|
||||
Maximum position increment
|
||||
*/
|
||||
//f32 position_max_increment = 0.05*BS;
|
||||
f32 position_max_increment = 0.1*BS;
|
||||
|
||||
// Maximum time increment (for collision detection etc)
|
||||
// time = distance / speed
|
||||
f32 dtime_max_increment = position_max_increment / maximum_player_speed;
|
||||
// Maximum time increment is 10ms or lower
|
||||
if(dtime_max_increment > 0.01)
|
||||
dtime_max_increment = 0.01;
|
||||
|
||||
//TimeTaker playerupdate("playerupdate", g_device);
|
||||
|
||||
/*
|
||||
Stuff that has a maximum time increment
|
||||
*/
|
||||
// Don't allow overly huge dtime
|
||||
if(dtime > 0.5)
|
||||
dtime = 0.5;
|
||||
|
||||
u32 loopcount = 0;
|
||||
do
|
||||
{
|
||||
loopcount++;
|
||||
|
||||
f32 dtime_part;
|
||||
if(dtime > dtime_max_increment)
|
||||
dtime_part = dtime_max_increment;
|
||||
else
|
||||
dtime_part = dtime;
|
||||
dtime -= dtime_part;
|
||||
|
||||
/*
|
||||
Handle players
|
||||
*/
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
|
||||
v3f playerpos = player->getPosition();
|
||||
|
||||
// Apply physics to local player
|
||||
bool free_move = g_settings.getBool("free_move");
|
||||
if(player->isLocal() && free_move == false)
|
||||
{
|
||||
// Apply gravity to local player
|
||||
v3f speed = player->getSpeed();
|
||||
if(player->swimming_up == false)
|
||||
speed.Y -= 9.81 * BS * dtime_part * 2;
|
||||
|
||||
/*
|
||||
Apply water resistance
|
||||
*/
|
||||
if(player->in_water_stable || player->in_water)
|
||||
{
|
||||
f32 max_down = 2.0*BS;
|
||||
if(speed.Y < -max_down) speed.Y = -max_down;
|
||||
|
||||
f32 max = 2.5*BS;
|
||||
if(speed.getLength() > max)
|
||||
{
|
||||
speed = speed / speed.getLength() * max;
|
||||
}
|
||||
}
|
||||
|
||||
player->setSpeed(speed);
|
||||
}
|
||||
|
||||
/*
|
||||
Move the player.
|
||||
For local player, this also calculates collision detection.
|
||||
*/
|
||||
player->move(dtime_part, *m_map, position_max_increment);
|
||||
|
||||
/*
|
||||
Update lighting on remote players on client
|
||||
*/
|
||||
u8 light = LIGHT_MAX;
|
||||
try{
|
||||
// Get node at feet
|
||||
v3s16 p = floatToInt(playerpos + v3f(0,BS/4,0));
|
||||
MapNode n = m_map->getNode(p);
|
||||
light = n.getLightBlend(m_daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e) {}
|
||||
player->updateLight(light);
|
||||
|
||||
/*
|
||||
Add footsteps to grass
|
||||
*/
|
||||
if(g_settings.getBool("footprints"))
|
||||
{
|
||||
// Get node that is at BS/4 under player
|
||||
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
|
||||
try{
|
||||
MapNode n = m_map->getNode(bottompos);
|
||||
if(n.d == CONTENT_GRASS)
|
||||
{
|
||||
n.d = CONTENT_GRASS_FOOTSTEPS;
|
||||
m_map->setNode(bottompos, n);
|
||||
#ifndef SERVER
|
||||
// Update mesh on client
|
||||
if(m_map->mapType() == MAPTYPE_CLIENT)
|
||||
{
|
||||
v3s16 p_blocks = getNodeBlockPos(bottompos);
|
||||
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
|
||||
b->updateMesh(m_daynight_ratio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while(dtime > 0.001);
|
||||
|
||||
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
|
||||
}
|
||||
|
||||
Map & Environment::getMap()
|
||||
{
|
||||
return *m_map;
|
||||
}
|
||||
|
||||
void Environment::addPlayer(Player *player)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
/*
|
||||
Check that only one local player exists and peer_ids are unique.
|
||||
Check that peer_ids are unique.
|
||||
Also check that names are unique.
|
||||
Exception: there can be multiple players with peer_id=0
|
||||
*/
|
||||
#ifndef SERVER
|
||||
/*
|
||||
It is a failure if player is local and there already is a local
|
||||
player
|
||||
*/
|
||||
assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
|
||||
#endif
|
||||
// If peer id is non-zero, it has to be unique.
|
||||
if(player->peer_id != 0)
|
||||
assert(getPlayer(player->peer_id) == NULL);
|
||||
@ -240,20 +71,6 @@ re_search:
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
LocalPlayer * Environment::getLocalPlayer()
|
||||
{
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
if(player->isLocal())
|
||||
return (LocalPlayer*)player;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
Player * Environment::getPlayer(u16 peer_id)
|
||||
{
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
@ -315,7 +132,38 @@ void Environment::printPlayers(std::ostream &o)
|
||||
}
|
||||
}
|
||||
|
||||
void Environment::serializePlayers(const std::string &savedir)
|
||||
void Environment::setDayNightRatio(u32 r)
|
||||
{
|
||||
m_daynight_ratio = r;
|
||||
}
|
||||
|
||||
u32 Environment::getDayNightRatio()
|
||||
{
|
||||
return m_daynight_ratio;
|
||||
}
|
||||
|
||||
/*
|
||||
ServerEnvironment
|
||||
*/
|
||||
|
||||
ServerEnvironment::ServerEnvironment(ServerMap *map):
|
||||
m_map(map),
|
||||
m_random_spawn_timer(0)
|
||||
{
|
||||
/*
|
||||
TEST CODE
|
||||
*/
|
||||
TestSAO *obj = new TestSAO(0, v3f(0, BS*5, 0));
|
||||
addActiveObject(obj);
|
||||
}
|
||||
|
||||
ServerEnvironment::~ServerEnvironment()
|
||||
{
|
||||
// Drop/delete map
|
||||
m_map->drop();
|
||||
}
|
||||
|
||||
void ServerEnvironment::serializePlayers(const std::string &savedir)
|
||||
{
|
||||
std::string players_path = savedir + "/players";
|
||||
fs::CreateDir(players_path);
|
||||
@ -430,7 +278,7 @@ void Environment::serializePlayers(const std::string &savedir)
|
||||
//dstream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
|
||||
}
|
||||
|
||||
void Environment::deSerializePlayers(const std::string &savedir)
|
||||
void ServerEnvironment::deSerializePlayers(const std::string &savedir)
|
||||
{
|
||||
std::string players_path = savedir + "/players";
|
||||
|
||||
@ -492,25 +340,630 @@ void Environment::deSerializePlayers(const std::string &savedir)
|
||||
}
|
||||
}
|
||||
|
||||
void ServerEnvironment::step(float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
// Get some settings
|
||||
//bool free_move = g_settings.getBool("free_move");
|
||||
bool footprints = g_settings.getBool("footprints");
|
||||
|
||||
{
|
||||
//TimeTaker timer("Server m_map->timerUpdate()", g_device);
|
||||
m_map->timerUpdate(dtime);
|
||||
}
|
||||
|
||||
/*
|
||||
Handle players
|
||||
*/
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
v3f playerpos = player->getPosition();
|
||||
|
||||
// Move
|
||||
player->move(dtime, *m_map, 100*BS);
|
||||
|
||||
/*
|
||||
Add footsteps to grass
|
||||
*/
|
||||
if(footprints)
|
||||
{
|
||||
// Get node that is at BS/4 under player
|
||||
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
|
||||
try{
|
||||
MapNode n = m_map->getNode(bottompos);
|
||||
if(n.d == CONTENT_GRASS)
|
||||
{
|
||||
n.d = CONTENT_GRASS_FOOTSTEPS;
|
||||
m_map->setNode(bottompos, n);
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Step active objects
|
||||
*/
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
// Step object, putting messages directly to the queue
|
||||
obj->step(dtime, m_active_object_messages);
|
||||
}
|
||||
|
||||
/*
|
||||
Remove (m_removed && m_known_by_count==0) objects
|
||||
*/
|
||||
{
|
||||
core::list<u16> objects_to_remove;
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
u16 id = i.getNode()->getKey();
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
// This shouldn't happen but check it
|
||||
if(obj == NULL)
|
||||
{
|
||||
dstream<<"WARNING: NULL object found in ServerEnvironment"
|
||||
<<" while finding removed objects. id="<<id<<std::endl;
|
||||
// Id to be removed from m_active_objects
|
||||
objects_to_remove.push_back(id);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not m_removed, don't remove.
|
||||
if(obj->m_removed == false)
|
||||
continue;
|
||||
// Delete
|
||||
delete obj;
|
||||
// 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++)
|
||||
{
|
||||
m_active_objects.remove(*i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TEST CODE
|
||||
*/
|
||||
m_random_spawn_timer -= dtime;
|
||||
if(m_random_spawn_timer < 0)
|
||||
{
|
||||
m_random_spawn_timer += 0.1;
|
||||
TestSAO *obj = new TestSAO(0,
|
||||
v3f(myrand_range(-2*BS,2*BS), BS*5, myrand_range(-2*BS,2*BS)));
|
||||
addActiveObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
|
||||
{
|
||||
core::map<u16, ServerActiveObject*>::Node *n;
|
||||
n = m_active_objects.find(id);
|
||||
if(n == NULL)
|
||||
return NULL;
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
bool isFreeServerActiveObjectId(u16 id,
|
||||
core::map<u16, ServerActiveObject*> &objects)
|
||||
{
|
||||
if(id == 0)
|
||||
return false;
|
||||
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
if(i.getNode()->getKey() == id)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
u16 getFreeServerActiveObjectId(
|
||||
core::map<u16, ServerActiveObject*> &objects)
|
||||
{
|
||||
u16 new_id = 1;
|
||||
for(;;)
|
||||
{
|
||||
if(isFreeServerActiveObjectId(new_id, objects))
|
||||
return new_id;
|
||||
|
||||
if(new_id == 65535)
|
||||
return 0;
|
||||
|
||||
new_id++;
|
||||
}
|
||||
}
|
||||
|
||||
u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
|
||||
{
|
||||
assert(object);
|
||||
if(object->getId() == 0)
|
||||
{
|
||||
u16 new_id = getFreeServerActiveObjectId(m_active_objects);
|
||||
if(new_id == 0)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
|
||||
<<"no free ids available"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
object->setId(new_id);
|
||||
}
|
||||
if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
|
||||
<<"id is not free ("<<object->getId()<<")"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
dstream<<"INGO: ServerEnvironment::addActiveObject(): "
|
||||
<<"added (id="<<object->getId()<<")"<<std::endl;
|
||||
m_active_objects.insert(object->getId(), object);
|
||||
return object->getId();
|
||||
}
|
||||
|
||||
/*
|
||||
Finds out what new objects have been added to
|
||||
inside a radius around a position
|
||||
*/
|
||||
void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
|
||||
core::map<u16, bool> ¤t_objects,
|
||||
core::map<u16, bool> &added_objects)
|
||||
{
|
||||
v3f pos_f = intToFloat(pos, BS);
|
||||
f32 radius_f = radius * BS;
|
||||
/*
|
||||
Go through the object list,
|
||||
- discard m_removed objects,
|
||||
- discard objects that are too far away,
|
||||
- discard objects that are found in current_objects.
|
||||
- add remaining objects to added_objects
|
||||
*/
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
u16 id = i.getNode()->getKey();
|
||||
// Get object
|
||||
ServerActiveObject *object = i.getNode()->getValue();
|
||||
if(object == NULL)
|
||||
continue;
|
||||
// Discard if removed
|
||||
if(object->m_removed)
|
||||
continue;
|
||||
// Discard if too far
|
||||
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
|
||||
if(distance_f > radius_f)
|
||||
continue;
|
||||
// Discard if already on current_objects
|
||||
core::map<u16, bool>::Node *n;
|
||||
n = current_objects.find(id);
|
||||
if(n != NULL)
|
||||
continue;
|
||||
// Add to added_objects
|
||||
added_objects.insert(id, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Finds out what objects have been removed from
|
||||
inside a radius around a position
|
||||
*/
|
||||
void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
|
||||
core::map<u16, bool> ¤t_objects,
|
||||
core::map<u16, bool> &removed_objects)
|
||||
{
|
||||
v3f pos_f = intToFloat(pos, BS);
|
||||
f32 radius_f = radius * BS;
|
||||
/*
|
||||
Go through current_objects; object is removed if:
|
||||
- object is not found in m_active_objects (this is actually an
|
||||
error condition; objects should be set m_removed=true and removed
|
||||
only after all clients have been informed about removal), or
|
||||
- object has m_removed=true, or
|
||||
- object is too far away
|
||||
*/
|
||||
for(core::map<u16, bool>::Iterator
|
||||
i = current_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
u16 id = i.getNode()->getKey();
|
||||
ServerActiveObject *object = getActiveObject(id);
|
||||
if(object == NULL)
|
||||
{
|
||||
dstream<<"WARNING: ServerEnvironment::getRemovedActiveObjects():"
|
||||
<<" object in current_objects is NULL"<<std::endl;
|
||||
}
|
||||
else if(object->m_removed == false)
|
||||
{
|
||||
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
|
||||
/*dstream<<"removed == false"
|
||||
<<"distance_f = "<<distance_f
|
||||
<<", radius_f = "<<radius_f<<std::endl;*/
|
||||
if(distance_f < radius_f)
|
||||
{
|
||||
// Not removed
|
||||
continue;
|
||||
}
|
||||
}
|
||||
removed_objects.insert(id, false);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
|
||||
{
|
||||
if(m_active_object_messages.size() == 0)
|
||||
return ActiveObjectMessage(0);
|
||||
|
||||
return m_active_object_messages.pop_front();
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
void Environment::updateMeshes(v3s16 blockpos)
|
||||
|
||||
/*
|
||||
ClientEnvironment
|
||||
*/
|
||||
|
||||
ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr):
|
||||
m_map(map),
|
||||
m_smgr(smgr)
|
||||
{
|
||||
assert(m_map);
|
||||
assert(m_smgr);
|
||||
}
|
||||
|
||||
ClientEnvironment::~ClientEnvironment()
|
||||
{
|
||||
// delete active objects
|
||||
for(core::map<u16, ClientActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
delete i.getNode()->getValue();
|
||||
}
|
||||
|
||||
// Drop/delete map
|
||||
m_map->drop();
|
||||
}
|
||||
|
||||
void ClientEnvironment::addPlayer(Player *player)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
/*
|
||||
It is a failure if player is local and there already is a local
|
||||
player
|
||||
*/
|
||||
assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
|
||||
|
||||
Environment::addPlayer(player);
|
||||
}
|
||||
|
||||
LocalPlayer * ClientEnvironment::getLocalPlayer()
|
||||
{
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
if(player->isLocal())
|
||||
return (LocalPlayer*)player;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ClientEnvironment::step(float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
// Get some settings
|
||||
bool free_move = g_settings.getBool("free_move");
|
||||
bool footprints = g_settings.getBool("footprints");
|
||||
|
||||
{
|
||||
//TimeTaker timer("Client m_map->timerUpdate()", g_device);
|
||||
m_map->timerUpdate(dtime);
|
||||
}
|
||||
|
||||
/*
|
||||
Get the speed the player is going
|
||||
*/
|
||||
f32 player_speed = 0.001; // just some small value
|
||||
LocalPlayer *lplayer = getLocalPlayer();
|
||||
if(lplayer)
|
||||
player_speed = lplayer->getSpeed().getLength();
|
||||
|
||||
/*
|
||||
Maximum position increment
|
||||
*/
|
||||
//f32 position_max_increment = 0.05*BS;
|
||||
f32 position_max_increment = 0.1*BS;
|
||||
|
||||
// Maximum time increment (for collision detection etc)
|
||||
// time = distance / speed
|
||||
f32 dtime_max_increment = position_max_increment / player_speed;
|
||||
|
||||
// Maximum time increment is 10ms or lower
|
||||
if(dtime_max_increment > 0.01)
|
||||
dtime_max_increment = 0.01;
|
||||
|
||||
// Don't allow overly huge dtime
|
||||
if(dtime > 0.5)
|
||||
dtime = 0.5;
|
||||
|
||||
f32 dtime_downcount = dtime;
|
||||
|
||||
/*
|
||||
Stuff that has a maximum time increment
|
||||
*/
|
||||
|
||||
u32 loopcount = 0;
|
||||
do
|
||||
{
|
||||
loopcount++;
|
||||
|
||||
f32 dtime_part;
|
||||
if(dtime_downcount > dtime_max_increment)
|
||||
dtime_part = dtime_max_increment;
|
||||
else
|
||||
dtime_part = dtime;
|
||||
dtime_downcount -= dtime_part;
|
||||
|
||||
/*
|
||||
Handle local player
|
||||
*/
|
||||
|
||||
{
|
||||
Player *player = getLocalPlayer();
|
||||
|
||||
v3f playerpos = player->getPosition();
|
||||
|
||||
// Apply physics
|
||||
if(free_move == false)
|
||||
{
|
||||
// Gravity
|
||||
v3f speed = player->getSpeed();
|
||||
if(player->swimming_up == false)
|
||||
speed.Y -= 9.81 * BS * dtime_part * 2;
|
||||
|
||||
// Water resistance
|
||||
if(player->in_water_stable || player->in_water)
|
||||
{
|
||||
f32 max_down = 2.0*BS;
|
||||
if(speed.Y < -max_down) speed.Y = -max_down;
|
||||
|
||||
f32 max = 2.5*BS;
|
||||
if(speed.getLength() > max)
|
||||
{
|
||||
speed = speed / speed.getLength() * max;
|
||||
}
|
||||
}
|
||||
|
||||
player->setSpeed(speed);
|
||||
}
|
||||
|
||||
/*
|
||||
Move the player.
|
||||
This also does collision detection.
|
||||
*/
|
||||
player->move(dtime_part, *m_map, position_max_increment);
|
||||
}
|
||||
}
|
||||
while(dtime_downcount > 0.001);
|
||||
|
||||
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
|
||||
|
||||
/*
|
||||
Stuff that can be done in an arbitarily large dtime
|
||||
*/
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
Player *player = *i;
|
||||
v3f playerpos = player->getPosition();
|
||||
|
||||
/*
|
||||
Handle non-local players
|
||||
*/
|
||||
if(player->isLocal() == false)
|
||||
{
|
||||
// Move
|
||||
player->move(dtime, *m_map, 100*BS);
|
||||
|
||||
// Update lighting on remote players on client
|
||||
u8 light = LIGHT_MAX;
|
||||
try{
|
||||
// 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);
|
||||
}
|
||||
catch(InvalidPositionException &e) {}
|
||||
player->updateLight(light);
|
||||
}
|
||||
|
||||
/*
|
||||
Add footsteps to grass
|
||||
*/
|
||||
if(footprints)
|
||||
{
|
||||
// Get node that is at BS/4 under player
|
||||
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
|
||||
try{
|
||||
MapNode n = m_map->getNode(bottompos);
|
||||
if(n.d == CONTENT_GRASS)
|
||||
{
|
||||
n.d = CONTENT_GRASS_FOOTSTEPS;
|
||||
m_map->setNode(bottompos, n);
|
||||
// Update mesh on client
|
||||
if(m_map->mapType() == MAPTYPE_CLIENT)
|
||||
{
|
||||
v3s16 p_blocks = getNodeBlockPos(bottompos);
|
||||
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
|
||||
b->updateMesh(m_daynight_ratio);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Step active objects
|
||||
*/
|
||||
for(core::map<u16, ClientActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ClientActiveObject* obj = i.getNode()->getValue();
|
||||
// Step object
|
||||
obj->step(dtime);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientEnvironment::updateMeshes(v3s16 blockpos)
|
||||
{
|
||||
m_map->updateMeshes(blockpos, m_daynight_ratio);
|
||||
}
|
||||
|
||||
void Environment::expireMeshes(bool only_daynight_diffed)
|
||||
void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
|
||||
{
|
||||
m_map->expireMeshes(only_daynight_diffed);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Environment::setDayNightRatio(u32 r)
|
||||
ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
|
||||
{
|
||||
m_daynight_ratio = r;
|
||||
core::map<u16, ClientActiveObject*>::Node *n;
|
||||
n = m_active_objects.find(id);
|
||||
if(n == NULL)
|
||||
return NULL;
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
u32 Environment::getDayNightRatio()
|
||||
bool isFreeClientActiveObjectId(u16 id,
|
||||
core::map<u16, ClientActiveObject*> &objects)
|
||||
{
|
||||
return m_daynight_ratio;
|
||||
if(id == 0)
|
||||
return false;
|
||||
|
||||
for(core::map<u16, ClientActiveObject*>::Iterator
|
||||
i = objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
if(i.getNode()->getKey() == id)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
u16 getFreeClientActiveObjectId(
|
||||
core::map<u16, ClientActiveObject*> &objects)
|
||||
{
|
||||
u16 new_id = 1;
|
||||
for(;;)
|
||||
{
|
||||
if(isFreeClientActiveObjectId(new_id, objects))
|
||||
return new_id;
|
||||
|
||||
if(new_id == 65535)
|
||||
return 0;
|
||||
|
||||
new_id++;
|
||||
}
|
||||
}
|
||||
|
||||
u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
|
||||
{
|
||||
assert(object);
|
||||
if(object->getId() == 0)
|
||||
{
|
||||
u16 new_id = getFreeClientActiveObjectId(m_active_objects);
|
||||
if(new_id == 0)
|
||||
{
|
||||
dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
|
||||
<<"no free ids available"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
object->setId(new_id);
|
||||
}
|
||||
if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
|
||||
{
|
||||
dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
|
||||
<<"id is not free ("<<object->getId()<<")"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
dstream<<"INGO: ClientEnvironment::addActiveObject(): "
|
||||
<<"added (id="<<object->getId()<<")"<<std::endl;
|
||||
m_active_objects.insert(object->getId(), object);
|
||||
object->addToScene(m_smgr);
|
||||
return object->getId();
|
||||
}
|
||||
|
||||
void ClientEnvironment::addActiveObject(u16 id, u8 type)
|
||||
{
|
||||
ClientActiveObject* obj = ClientActiveObject::create(type);
|
||||
if(obj == NULL)
|
||||
{
|
||||
dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
|
||||
<<"id="<<id<<" type="<<type<<": Couldn't create object"
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
obj->setId(id);
|
||||
|
||||
addActiveObject(obj);
|
||||
}
|
||||
|
||||
void ClientEnvironment::removeActiveObject(u16 id)
|
||||
{
|
||||
dstream<<"ClientEnvironment::removeActiveObject(): "
|
||||
<<"id="<<id<<std::endl;
|
||||
ClientActiveObject* obj = getActiveObject(id);
|
||||
if(obj == NULL)
|
||||
{
|
||||
dstream<<"WARNING: ClientEnvironment::removeActiveObject(): "
|
||||
<<"id="<<id<<" not found"<<std::endl;
|
||||
return;
|
||||
}
|
||||
obj->removeFromScene();
|
||||
delete obj;
|
||||
m_active_objects.remove(id);
|
||||
}
|
||||
|
||||
void ClientEnvironment::processActiveObjectMessage(u16 id,
|
||||
const std::string &data)
|
||||
{
|
||||
ClientActiveObject* obj = getActiveObject(id);
|
||||
if(obj == NULL)
|
||||
{
|
||||
dstream<<"WARNING: ClientEnvironment::processActiveObjectMessage():"
|
||||
<<" got message for id="<<id<<", which doesn't exist."
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
obj->processMessage(data);
|
||||
}
|
||||
|
||||
#endif // #ifndef SERVER
|
||||
|
||||
|
||||
|
@ -26,7 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
- The map
|
||||
- Players
|
||||
- Other objects
|
||||
- The current time in the game, etc.
|
||||
- The current time in the game (actually it only contains the brightness)
|
||||
- etc.
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
@ -39,51 +40,175 @@ class Environment
|
||||
{
|
||||
public:
|
||||
// Environment will delete the map passed to the constructor
|
||||
Environment(Map *map, std::ostream &dout);
|
||||
~Environment();
|
||||
/*
|
||||
This can do anything to the environment, such as removing
|
||||
timed-out players.
|
||||
Also updates Map's timers.
|
||||
*/
|
||||
void step(f32 dtime);
|
||||
|
||||
Map & getMap();
|
||||
Environment();
|
||||
virtual ~Environment();
|
||||
|
||||
/*
|
||||
Environment deallocates players after use.
|
||||
Step everything in environment.
|
||||
- Move players
|
||||
- Step mobs
|
||||
- Run timers of map
|
||||
*/
|
||||
void addPlayer(Player *player);
|
||||
virtual void step(f32 dtime) = 0;
|
||||
|
||||
virtual Map & getMap() = 0;
|
||||
|
||||
virtual void addPlayer(Player *player);
|
||||
void removePlayer(u16 peer_id);
|
||||
#ifndef SERVER
|
||||
LocalPlayer * getLocalPlayer();
|
||||
#endif
|
||||
Player * getPlayer(u16 peer_id);
|
||||
Player * getPlayer(const char *name);
|
||||
core::list<Player*> getPlayers();
|
||||
core::list<Player*> getPlayers(bool ignore_disconnected);
|
||||
void printPlayers(std::ostream &o);
|
||||
|
||||
void serializePlayers(const std::string &savedir);
|
||||
// This loads players as ServerRemotePlayers
|
||||
void deSerializePlayers(const std::string &savedir);
|
||||
|
||||
#ifndef SERVER
|
||||
void updateMeshes(v3s16 blockpos);
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
#endif
|
||||
void setDayNightRatio(u32 r);
|
||||
u32 getDayNightRatio();
|
||||
|
||||
private:
|
||||
Map *m_map;
|
||||
// peer_ids in here should be unique, except that there may be
|
||||
// many 0s
|
||||
protected:
|
||||
// peer_ids in here should be unique, except that there may be many 0s
|
||||
core::list<Player*> m_players;
|
||||
// Debug output goes here
|
||||
std::ostream &m_dout;
|
||||
// Brightness
|
||||
u32 m_daynight_ratio;
|
||||
};
|
||||
|
||||
/*
|
||||
The server-side environment.
|
||||
|
||||
This is not thread-safe. Server uses an environment mutex.
|
||||
*/
|
||||
|
||||
#include "serverobject.h"
|
||||
|
||||
class ServerEnvironment : public Environment
|
||||
{
|
||||
public:
|
||||
ServerEnvironment(ServerMap *map);
|
||||
~ServerEnvironment();
|
||||
|
||||
Map & getMap()
|
||||
{
|
||||
return *m_map;
|
||||
}
|
||||
|
||||
ServerMap & getServerMap()
|
||||
{
|
||||
return *m_map;
|
||||
}
|
||||
|
||||
void step(f32 dtime);
|
||||
|
||||
void serializePlayers(const std::string &savedir);
|
||||
void deSerializePlayers(const std::string &savedir);
|
||||
|
||||
/*
|
||||
ActiveObjects
|
||||
*/
|
||||
|
||||
ServerActiveObject* getActiveObject(u16 id);
|
||||
|
||||
/*
|
||||
Adds an active object to the environment.
|
||||
Environment handles deletion of object.
|
||||
Object may be deleted by environment immediately.
|
||||
If id of object is 0, assigns a free id to it.
|
||||
Returns the id of the object.
|
||||
Returns 0 if not added and thus deleted.
|
||||
*/
|
||||
u16 addActiveObject(ServerActiveObject *object);
|
||||
|
||||
/*
|
||||
Finds out what new objects have been added to
|
||||
inside a radius around a position
|
||||
*/
|
||||
void getAddedActiveObjects(v3s16 pos, s16 radius,
|
||||
core::map<u16, bool> ¤t_objects,
|
||||
core::map<u16, bool> &added_objects);
|
||||
|
||||
/*
|
||||
Finds out what new objects have been removed from
|
||||
inside a radius around a position
|
||||
*/
|
||||
void getRemovedActiveObjects(v3s16 pos, s16 radius,
|
||||
core::map<u16, bool> ¤t_objects,
|
||||
core::map<u16, bool> &removed_objects);
|
||||
|
||||
/*
|
||||
Gets the next message emitted by some active object.
|
||||
Returns a message with id=0 if no messages are available.
|
||||
*/
|
||||
ActiveObjectMessage getActiveObjectMessage();
|
||||
|
||||
private:
|
||||
ServerMap *m_map;
|
||||
core::map<u16, ServerActiveObject*> m_active_objects;
|
||||
Queue<ActiveObjectMessage> m_active_object_messages;
|
||||
float m_random_spawn_timer;
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
#include "clientobject.h"
|
||||
|
||||
/*
|
||||
The client-side environment.
|
||||
|
||||
This is not thread-safe.
|
||||
Must be called from main (irrlicht) thread (uses the SceneManager)
|
||||
Client uses an environment mutex.
|
||||
*/
|
||||
|
||||
class ClientEnvironment : public Environment
|
||||
{
|
||||
public:
|
||||
ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr);
|
||||
~ClientEnvironment();
|
||||
|
||||
Map & getMap()
|
||||
{
|
||||
return *m_map;
|
||||
}
|
||||
|
||||
ClientMap & getClientMap()
|
||||
{
|
||||
return *m_map;
|
||||
}
|
||||
|
||||
void step(f32 dtime);
|
||||
|
||||
virtual void addPlayer(Player *player);
|
||||
LocalPlayer * getLocalPlayer();
|
||||
|
||||
void updateMeshes(v3s16 blockpos);
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
|
||||
/*
|
||||
ActiveObjects
|
||||
*/
|
||||
|
||||
ClientActiveObject* getActiveObject(u16 id);
|
||||
|
||||
/*
|
||||
Adds an active object to the environment.
|
||||
Environment handles deletion of object.
|
||||
Object may be deleted by environment immediately.
|
||||
If id of object is 0, assigns a free id to it.
|
||||
Returns the id of the object.
|
||||
Returns 0 if not added and thus deleted.
|
||||
*/
|
||||
u16 addActiveObject(ClientActiveObject *object);
|
||||
|
||||
void addActiveObject(u16 id, u8 type);
|
||||
void removeActiveObject(u16 id);
|
||||
|
||||
void processActiveObjectMessage(u16 id, const std::string &data);
|
||||
|
||||
private:
|
||||
ClientMap *m_map;
|
||||
scene::ISceneManager *m_smgr;
|
||||
core::map<u16, ClientActiveObject*> m_active_objects;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
#endif // _WIN32_WCE
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
// CriticalSection is way faster than the alternative
|
||||
#define JMUTEX_CRITICALSECTION
|
||||
#else // using pthread
|
||||
#include <pthread.h>
|
||||
|
91
src/main.cpp
91
src/main.cpp
@ -160,32 +160,23 @@ TODO: Make fetching sector's blocks more efficient when rendering
|
||||
|
||||
TODO: Flowing water animation
|
||||
|
||||
NOTE(FIXED): A lock condition is possible:
|
||||
1) MapBlock::updateMesh() is called from client asynchronously:
|
||||
- AsyncProcessData() -> Map::updateMeshes()
|
||||
2) Asynchronous locks m_temp_mods_mutex
|
||||
3) MapBlock::updateMesh() is called from client synchronously:
|
||||
- Client::step() -> Environment::step()
|
||||
4) Synchronous starts waiting for m_temp_mods_mutex
|
||||
5) Asynchronous calls getTexture, which starts waiting for main thread
|
||||
|
||||
Configuration:
|
||||
--------------
|
||||
|
||||
TODO: Make the video backend selectable
|
||||
|
||||
Client:
|
||||
-------
|
||||
|
||||
TODO: Untie client network operations from framerate
|
||||
- Needs some input queues or something
|
||||
|
||||
TODO: Make morning and evening transition more smooth and maybe shorter
|
||||
SUGG: Make morning and evening transition more smooth and maybe shorter
|
||||
|
||||
TODO: Don't update all meshes always on single node changes, but
|
||||
SUGG: Don't update all meshes always on single node changes, but
|
||||
check which ones should be updated
|
||||
- implement Map::updateNodeMeshes()
|
||||
|
||||
TODO: Remove IrrlichtWrapper
|
||||
|
||||
Server:
|
||||
-------
|
||||
|
||||
@ -194,16 +185,13 @@ TODO: When player dies, throw items on map
|
||||
TODO: Make an option to the server to disable building and digging near
|
||||
the starting position
|
||||
|
||||
TODO: Save players with inventories to disk
|
||||
TODO: Players to be saved as text in map/players/<name>
|
||||
|
||||
TODO: Copy the text of the last picked sign to inventory in creative
|
||||
mode
|
||||
|
||||
TODO: Check what goes wrong with caching map to disk (Kray)
|
||||
- Nothing?
|
||||
|
||||
TODO: When server sees that client is removing an inexistent block to
|
||||
TODO: When server sees that client is removing an inexistent block in
|
||||
an existent position, resend the MapBlock.
|
||||
|
||||
FIXME: Server went into some infinite PeerNotFoundException loop
|
||||
@ -237,6 +225,11 @@ Block object server side:
|
||||
- TODO: For incoming blocks, time difference is calculated and
|
||||
objects are stepped according to it.
|
||||
|
||||
- When an active object goes far from a player, either delete
|
||||
it or store it statically.
|
||||
- When a statically stored active object comes near a player,
|
||||
recreate the active object
|
||||
|
||||
Map:
|
||||
----
|
||||
|
||||
@ -345,18 +338,18 @@ Doing now (most important at the top):
|
||||
#include <fstream>
|
||||
#include <jmutexautolock.h>
|
||||
#include <locale.h>
|
||||
#include "main.h"
|
||||
#include "common_irrlicht.h"
|
||||
#include "debug.h"
|
||||
#include "map.h"
|
||||
#include "player.h"
|
||||
#include "main.h"
|
||||
#include "test.h"
|
||||
#include "environment.h"
|
||||
//#include "environment.h"
|
||||
#include "server.h"
|
||||
#include "client.h"
|
||||
#include "serialization.h"
|
||||
//#include "serialization.h"
|
||||
#include "constants.h"
|
||||
#include "strfnd.h"
|
||||
//#include "strfnd.h"
|
||||
#include "porting.h"
|
||||
#include "irrlichtwrapper.h"
|
||||
#include "gettime.h"
|
||||
@ -905,8 +898,12 @@ class RandomInputHandler : public InputHandler
|
||||
public:
|
||||
RandomInputHandler()
|
||||
{
|
||||
leftdown = false;
|
||||
rightdown = false;
|
||||
leftclicked = false;
|
||||
rightclicked = false;
|
||||
leftreleased = false;
|
||||
rightreleased = false;
|
||||
for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
|
||||
keydown[i] = false;
|
||||
}
|
||||
@ -925,11 +922,11 @@ public:
|
||||
|
||||
virtual bool getLeftState()
|
||||
{
|
||||
return false;
|
||||
return leftdown;
|
||||
}
|
||||
virtual bool getRightState()
|
||||
{
|
||||
return false;
|
||||
return rightdown;
|
||||
}
|
||||
|
||||
virtual bool getLeftClicked()
|
||||
@ -951,37 +948,23 @@ public:
|
||||
|
||||
virtual bool getLeftReleased()
|
||||
{
|
||||
return false;
|
||||
return leftreleased;
|
||||
}
|
||||
virtual bool getRightReleased()
|
||||
{
|
||||
return false;
|
||||
return rightreleased;
|
||||
}
|
||||
virtual void resetLeftReleased()
|
||||
{
|
||||
leftreleased = false;
|
||||
}
|
||||
virtual void resetRightReleased()
|
||||
{
|
||||
rightreleased = false;
|
||||
}
|
||||
|
||||
virtual void step(float dtime)
|
||||
{
|
||||
{
|
||||
static float counter1 = 0;
|
||||
counter1 -= dtime;
|
||||
if(counter1 < 0.0)
|
||||
{
|
||||
counter1 = 0.1*Rand(1,10);
|
||||
/*if(g_selected_material < USEFUL_CONTENT_COUNT-1)
|
||||
g_selected_material++;
|
||||
else
|
||||
g_selected_material = 0;*/
|
||||
if(g_selected_item < PLAYER_INVENTORY_SIZE-1)
|
||||
g_selected_item++;
|
||||
else
|
||||
g_selected_item = 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
static float counter1 = 0;
|
||||
counter1 -= dtime;
|
||||
@ -1033,7 +1016,11 @@ public:
|
||||
if(counter1 < 0.0)
|
||||
{
|
||||
counter1 = 0.1*Rand(1, 30);
|
||||
leftclicked = true;
|
||||
leftdown = !leftdown;
|
||||
if(leftdown)
|
||||
leftclicked = true;
|
||||
if(!leftdown)
|
||||
leftreleased = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -1041,8 +1028,12 @@ public:
|
||||
counter1 -= dtime;
|
||||
if(counter1 < 0.0)
|
||||
{
|
||||
counter1 = 0.1*Rand(1, 20);
|
||||
rightclicked = true;
|
||||
counter1 = 0.1*Rand(1, 15);
|
||||
rightdown = !rightdown;
|
||||
if(rightdown)
|
||||
rightclicked = true;
|
||||
if(!rightdown)
|
||||
rightreleased = true;
|
||||
}
|
||||
}
|
||||
mousepos += mousespeed;
|
||||
@ -1056,8 +1047,12 @@ private:
|
||||
bool keydown[KEY_KEY_CODES_COUNT];
|
||||
v2s32 mousepos;
|
||||
v2s32 mousespeed;
|
||||
bool leftdown;
|
||||
bool rightdown;
|
||||
bool leftclicked;
|
||||
bool rightclicked;
|
||||
bool leftreleased;
|
||||
bool rightreleased;
|
||||
};
|
||||
|
||||
void updateViewingRange(f32 frametime_in, Client *client)
|
||||
@ -2486,11 +2481,9 @@ int main(int argc, char *argv[])
|
||||
camera->setTarget(camera_position + camera_direction * 100.0);
|
||||
|
||||
if(FIELD_OF_VIEW_TEST){
|
||||
//client.m_env.getMap().updateCamera(v3f(0,0,0), v3f(0,0,1));
|
||||
client.updateCamera(v3f(0,0,0), v3f(0,0,1));
|
||||
}
|
||||
else{
|
||||
//client.m_env.getMap().updateCamera(camera_position, camera_direction);
|
||||
//TimeTaker timer("client.updateCamera");
|
||||
client.updateCamera(camera_position, camera_direction);
|
||||
}
|
||||
@ -2585,7 +2578,7 @@ int main(int argc, char *argv[])
|
||||
core::aabbox3d<f32> nodehilightbox;
|
||||
f32 mindistance = BS * 1001;
|
||||
|
||||
v3s16 pos_i = floatToInt(player_position);
|
||||
v3s16 pos_i = floatToInt(player_position, BS);
|
||||
|
||||
/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
|
||||
<<std::endl;*/
|
||||
@ -2615,7 +2608,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
v3s16 np(x,y,z);
|
||||
v3f npf = intToFloat(np);
|
||||
v3f npf = intToFloat(np, BS);
|
||||
|
||||
f32 d = 0.01;
|
||||
|
||||
@ -2723,7 +2716,7 @@ int main(int argc, char *argv[])
|
||||
const float d = 0.502;
|
||||
core::aabbox3d<f32> nodebox
|
||||
(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
|
||||
v3f nodepos_f = intToFloat(nodepos);
|
||||
v3f nodepos_f = intToFloat(nodepos, BS);
|
||||
nodebox.MinEdge += nodepos_f;
|
||||
nodebox.MaxEdge += nodepos_f;
|
||||
nodehilightbox = nodebox;
|
||||
|
177
src/map.cpp
177
src/map.cpp
@ -1221,95 +1221,6 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
void Map::expireMeshes(bool only_daynight_diffed)
|
||||
{
|
||||
TimeTaker timer("expireMeshes()");
|
||||
|
||||
core::map<v2s16, MapSector*>::Iterator si;
|
||||
si = m_sectors.getIterator();
|
||||
for(; si.atEnd() == false; si++)
|
||||
{
|
||||
MapSector *sector = si.getNode()->getValue();
|
||||
|
||||
core::list< MapBlock * > sectorblocks;
|
||||
sector->getBlocks(sectorblocks);
|
||||
|
||||
core::list< MapBlock * >::Iterator i;
|
||||
for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
|
||||
{
|
||||
MapBlock *block = *i;
|
||||
|
||||
if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
if(block->mesh != NULL)
|
||||
{
|
||||
/*block->mesh->drop();
|
||||
block->mesh = NULL;*/
|
||||
block->setMeshExpired(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Map::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
|
||||
{
|
||||
assert(mapType() == MAPTYPE_CLIENT);
|
||||
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
// Leading edge
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(-1,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,-1,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,-1);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
/*// Trailing edge
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(1,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,1,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,1);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}*/
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Map::dayNightDiffed(v3s16 blockpos)
|
||||
{
|
||||
try{
|
||||
@ -4371,7 +4282,7 @@ continue_generating:
|
||||
//if(!is_ground_content(block->getNode(cp).d))
|
||||
if(1)
|
||||
{
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
|
||||
block->addObject(obj);
|
||||
}
|
||||
}
|
||||
@ -5667,6 +5578,92 @@ bool ClientMap::clearTempMod(v3s16 p,
|
||||
return changed;
|
||||
}
|
||||
|
||||
void ClientMap::expireMeshes(bool only_daynight_diffed)
|
||||
{
|
||||
TimeTaker timer("expireMeshes()");
|
||||
|
||||
core::map<v2s16, MapSector*>::Iterator si;
|
||||
si = m_sectors.getIterator();
|
||||
for(; si.atEnd() == false; si++)
|
||||
{
|
||||
MapSector *sector = si.getNode()->getValue();
|
||||
|
||||
core::list< MapBlock * > sectorblocks;
|
||||
sector->getBlocks(sectorblocks);
|
||||
|
||||
core::list< MapBlock * >::Iterator i;
|
||||
for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
|
||||
{
|
||||
MapBlock *block = *i;
|
||||
|
||||
if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
if(block->mesh != NULL)
|
||||
{
|
||||
/*block->mesh->drop();
|
||||
block->mesh = NULL;*/
|
||||
block->setMeshExpired(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
|
||||
{
|
||||
assert(mapType() == MAPTYPE_CLIENT);
|
||||
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
// Leading edge
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(-1,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,-1,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,-1);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
/*// Trailing edge
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(1,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,1,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,1);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
catch(InvalidPositionException &e){}*/
|
||||
}
|
||||
|
||||
void ClientMap::PrintInfo(std::ostream &out)
|
||||
{
|
||||
out<<"ClientMap: ";
|
||||
|
30
src/map.h
30
src/map.h
@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#endif
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
//#include "heightmap.h"
|
||||
#include "mapnode.h"
|
||||
#include "mapblock.h"
|
||||
#include "mapsector.h"
|
||||
@ -61,7 +60,10 @@ public:
|
||||
{
|
||||
return MAPTYPE_BASE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Drop (client) or delete (server) the map.
|
||||
*/
|
||||
virtual void drop()
|
||||
{
|
||||
delete this;
|
||||
@ -211,19 +213,6 @@ public:
|
||||
void removeNodeAndUpdate(v3s16 p,
|
||||
core::map<v3s16, MapBlock*> &modified_blocks);
|
||||
|
||||
#ifndef SERVER
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
|
||||
/*
|
||||
Update the faces of the given block and blocks on the
|
||||
leading edge.
|
||||
*/
|
||||
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
|
||||
|
||||
// Update meshes that touch the node
|
||||
//void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Takes the blocks at the edges into account
|
||||
*/
|
||||
@ -628,6 +617,17 @@ public:
|
||||
// Efficient implementation needs a cache of TempMods
|
||||
//void clearTempMods();
|
||||
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
|
||||
/*
|
||||
Update the faces of the given block and blocks on the
|
||||
leading edge.
|
||||
*/
|
||||
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
|
||||
|
||||
// Update meshes that touch the node
|
||||
//void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
|
||||
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
||||
|
@ -822,7 +822,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
if(dir == v3s16(0,1,0))
|
||||
vertices[i].Pos.rotateXZBy(-45);
|
||||
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative());
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
|
||||
}
|
||||
|
||||
// Set material
|
||||
@ -1066,7 +1066,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
if(dir == v3s16(1,0,-0))
|
||||
vertices[j].Pos.rotateXZBy(-90);
|
||||
|
||||
vertices[j].Pos += intToFloat(p + getPosRelative());
|
||||
vertices[j].Pos += intToFloat(p + getPosRelative(), BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
@ -1105,7 +1105,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
|
||||
s32 j = corner_resolve[i];
|
||||
vertices[i].Pos.Y += corner_levels[j];
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative());
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
@ -1155,7 +1155,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
for(s32 i=0; i<4; i++)
|
||||
{
|
||||
vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative());
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
@ -1222,7 +1222,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
|
||||
for(u16 i=0; i<4; i++)
|
||||
{
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative());
|
||||
vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
@ -1596,7 +1596,7 @@ void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
|
||||
if(getNode(p).d == CONTENT_AIR
|
||||
&& getNode(p).getLightBlend(daynight_ratio) <= 11)
|
||||
{
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(p));
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(p, BS));
|
||||
addObject(obj);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ v3f MapBlockObject::getAbsolutePos()
|
||||
return m_pos;
|
||||
|
||||
// getPosRelative gets nodepos relative to map origin
|
||||
v3f blockpos = intToFloat(m_block->getPosRelative());
|
||||
v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
|
||||
return blockpos + m_pos;
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ v3f MovingObject::getAbsoluteShowPos()
|
||||
return m_pos;
|
||||
|
||||
// getPosRelative gets nodepos relative to map origin
|
||||
v3f blockpos = intToFloat(m_block->getPosRelative());
|
||||
v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
|
||||
return blockpos + m_showpos;
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ void MovingObject::move(float dtime, v3f acceleration)
|
||||
acceleration.X, acceleration.Y, acceleration.Z
|
||||
);
|
||||
|
||||
v3s16 oldpos_i = floatToInt(m_pos);
|
||||
v3s16 oldpos_i = floatToInt(m_pos, BS);
|
||||
|
||||
if(m_block->isValidPosition(oldpos_i) == false)
|
||||
{
|
||||
@ -137,7 +137,7 @@ void MovingObject::move(float dtime, v3f acceleration)
|
||||
Collision detection
|
||||
*/
|
||||
|
||||
v3s16 pos_i = floatToInt(position);
|
||||
v3s16 pos_i = floatToInt(position, BS);
|
||||
|
||||
// The loop length is limited to the object moving a distance
|
||||
f32 d = (float)BS * 0.15;
|
||||
@ -614,7 +614,7 @@ void MapBlockObjectList::update(std::istream &is, u8 version,
|
||||
{
|
||||
u8 light = LIGHT_MAX;
|
||||
try{
|
||||
v3s16 relpos_i = floatToInt(obj->m_pos);
|
||||
v3s16 relpos_i = floatToInt(obj->m_pos, BS);
|
||||
MapNode n = m_block->getNodeParent(relpos_i);
|
||||
light = n.getLightBlend(daynight_ratio);
|
||||
}
|
||||
@ -772,7 +772,7 @@ void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
|
||||
// Update light
|
||||
u8 light = LIGHT_MAX;
|
||||
try{
|
||||
v3s16 relpos_i = floatToInt(obj->m_pos);
|
||||
v3s16 relpos_i = floatToInt(obj->m_pos, BS);
|
||||
MapNode n = m_block->getNodeParent(relpos_i);
|
||||
light = n.getLightBlend(daynight_ratio);
|
||||
}
|
||||
@ -824,7 +824,7 @@ void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
|
||||
{
|
||||
MapBlockObject *obj = i.getNode()->getValue();
|
||||
|
||||
v3s16 pos_i = floatToInt(obj->m_pos);
|
||||
v3s16 pos_i = floatToInt(obj->m_pos, BS);
|
||||
|
||||
if(m_block->isValidPosition(pos_i))
|
||||
{
|
||||
@ -871,7 +871,7 @@ bool MapBlockObjectList::wrapObject(MapBlockObject *object)
|
||||
// Calculate blockpos on map
|
||||
v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
|
||||
v3f pos_f_on_oldblock = object->m_pos;
|
||||
v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock);
|
||||
v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock, BS);
|
||||
v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
|
||||
v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
|
||||
|
||||
@ -905,9 +905,9 @@ bool MapBlockObjectList::wrapObject(MapBlockObject *object)
|
||||
}
|
||||
|
||||
// Calculate position on new block
|
||||
v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map);
|
||||
v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map, BS);
|
||||
v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
|
||||
v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map);
|
||||
v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map, BS);
|
||||
v3f pos_f_on_newblock = pos_f_on_oldblock
|
||||
- newblock_pos_f_on_map + oldblock_pos_f_on_map;
|
||||
|
||||
|
@ -683,32 +683,6 @@ struct MapNode
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns integer position of the node in given
|
||||
floating point position.
|
||||
*/
|
||||
inline v3s16 floatToInt(v3f p)
|
||||
{
|
||||
v3s16 p2(
|
||||
(p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
|
||||
(p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
|
||||
(p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
|
||||
return p2;
|
||||
}
|
||||
|
||||
/*
|
||||
The same thing backwards
|
||||
*/
|
||||
inline v3f intToFloat(v3s16 p)
|
||||
{
|
||||
v3f p2(
|
||||
p.X * BS,
|
||||
p.Y * BS,
|
||||
p.Z * BS
|
||||
);
|
||||
return p2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -273,7 +273,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
{
|
||||
v3f position = getPosition();
|
||||
v3f oldpos = position;
|
||||
v3s16 oldpos_i = floatToInt(oldpos);
|
||||
v3s16 oldpos_i = floatToInt(oldpos, BS);
|
||||
|
||||
/*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
|
||||
<<oldpos_i.Z<<")"<<std::endl;*/
|
||||
@ -296,7 +296,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
*/
|
||||
|
||||
// Player position in nodes
|
||||
v3s16 pos_i = floatToInt(position);
|
||||
v3s16 pos_i = floatToInt(position, BS);
|
||||
|
||||
/*
|
||||
Check if player is in water (the oscillating value)
|
||||
@ -305,13 +305,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
// If in water, the threshold of coming out is at higher y
|
||||
if(in_water)
|
||||
{
|
||||
v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0));
|
||||
v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
|
||||
in_water = content_liquid(map.getNode(pp).d);
|
||||
}
|
||||
// If not in water, the threshold of going in is at lower y
|
||||
else
|
||||
{
|
||||
v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0));
|
||||
v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
|
||||
in_water = content_liquid(map.getNode(pp).d);
|
||||
}
|
||||
}
|
||||
@ -324,7 +324,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
Check if player is in water (the stable value)
|
||||
*/
|
||||
try{
|
||||
v3s16 pp = floatToInt(position + v3f(0,0,0));
|
||||
v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
|
||||
in_water_stable = content_liquid(map.getNode(pp).d);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
@ -363,7 +363,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
if(control.sneak && m_sneak_node_exists)
|
||||
{
|
||||
f32 maxd = 0.5*BS + sneak_max;
|
||||
v3f lwn_f = intToFloat(m_sneak_node);
|
||||
v3f lwn_f = intToFloat(m_sneak_node, BS);
|
||||
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
|
||||
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
|
||||
|
||||
@ -537,13 +537,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
player is sneaking from, if any.
|
||||
*/
|
||||
{
|
||||
v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0));
|
||||
v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS);
|
||||
v2f player_p2df(position.X, position.Z);
|
||||
f32 min_distance_f = 100000.0*BS;
|
||||
// If already seeking from some node, compare to it.
|
||||
/*if(m_sneak_node_exists)
|
||||
{
|
||||
v3f sneaknode_pf = intToFloat(m_sneak_node);
|
||||
v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
|
||||
v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
|
||||
f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
|
||||
f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
|
||||
@ -556,7 +556,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
for(s16 z=-1; z<=1; z++)
|
||||
{
|
||||
v3s16 p = pos_i_bottom + v3s16(x,0,z);
|
||||
v3f pf = intToFloat(p);
|
||||
v3f pf = intToFloat(p, BS);
|
||||
v2f node_p2df(pf.X, pf.Z);
|
||||
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
|
||||
f32 max_axis_distance_f = MYMAX(
|
||||
|
10
src/player.h
10
src/player.h
@ -132,6 +132,10 @@ protected:
|
||||
v3f m_position;
|
||||
};
|
||||
|
||||
/*
|
||||
Player on the server
|
||||
*/
|
||||
|
||||
class ServerRemotePlayer : public Player
|
||||
{
|
||||
public:
|
||||
@ -150,12 +154,16 @@ public:
|
||||
virtual void move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
/*
|
||||
All the other players on the client are these
|
||||
*/
|
||||
|
||||
class RemotePlayer : public Player, public scene::ISceneNode
|
||||
{
|
||||
public:
|
||||
|
484
src/server.cpp
484
src/server.cpp
@ -283,21 +283,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
// Increment timers
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
m_nearest_unsent_reset_timer += dtime;
|
||||
}
|
||||
m_nearest_unsent_reset_timer += dtime;
|
||||
|
||||
// Won't send anything if already sending
|
||||
if(m_blocks_sending.size() >= g_settings.getU16
|
||||
("max_simultaneous_block_sends_per_client"))
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
|
||||
if(m_blocks_sending.size() >= g_settings.getU16
|
||||
("max_simultaneous_block_sends_per_client"))
|
||||
{
|
||||
//dstream<<"Not sending any blocks, Queue full."<<std::endl;
|
||||
return;
|
||||
}
|
||||
//dstream<<"Not sending any blocks, Queue full."<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Player *player = server->m_env.getPlayer(peer_id);
|
||||
@ -307,7 +300,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
v3f playerpos = player->getPosition();
|
||||
v3f playerspeed = player->getSpeed();
|
||||
|
||||
v3s16 center_nodepos = floatToInt(playerpos);
|
||||
v3s16 center_nodepos = floatToInt(playerpos, BS);
|
||||
|
||||
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||
|
||||
@ -323,29 +316,26 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
*/
|
||||
s16 last_nearest_unsent_d;
|
||||
s16 d_start;
|
||||
|
||||
if(m_last_center != center)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
|
||||
if(m_last_center != center)
|
||||
{
|
||||
m_nearest_unsent_d = 0;
|
||||
m_last_center = center;
|
||||
}
|
||||
|
||||
/*dstream<<"m_nearest_unsent_reset_timer="
|
||||
<<m_nearest_unsent_reset_timer<<std::endl;*/
|
||||
if(m_nearest_unsent_reset_timer > 5.0)
|
||||
{
|
||||
m_nearest_unsent_reset_timer = 0;
|
||||
m_nearest_unsent_d = 0;
|
||||
//dstream<<"Resetting m_nearest_unsent_d"<<std::endl;
|
||||
}
|
||||
|
||||
last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
|
||||
d_start = m_nearest_unsent_d;
|
||||
m_nearest_unsent_d = 0;
|
||||
m_last_center = center;
|
||||
}
|
||||
|
||||
/*dstream<<"m_nearest_unsent_reset_timer="
|
||||
<<m_nearest_unsent_reset_timer<<std::endl;*/
|
||||
if(m_nearest_unsent_reset_timer > 5.0)
|
||||
{
|
||||
m_nearest_unsent_reset_timer = 0;
|
||||
m_nearest_unsent_d = 0;
|
||||
//dstream<<"Resetting m_nearest_unsent_d"<<std::endl;
|
||||
}
|
||||
|
||||
last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
|
||||
d_start = m_nearest_unsent_d;
|
||||
|
||||
u16 maximum_simultaneous_block_sends_setting = g_settings.getU16
|
||||
("max_simultaneous_block_sends_per_client");
|
||||
u16 maximum_simultaneous_block_sends =
|
||||
@ -356,24 +346,15 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
|
||||
Decrease send rate if player is building stuff.
|
||||
*/
|
||||
m_time_from_building += dtime;
|
||||
if(m_time_from_building < g_settings.getFloat(
|
||||
"full_block_send_enable_min_time_from_building"))
|
||||
{
|
||||
SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
|
||||
m_time_from_building.m_value += dtime;
|
||||
/*if(m_time_from_building.m_value
|
||||
< FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)*/
|
||||
if(m_time_from_building.m_value < g_settings.getFloat(
|
||||
"full_block_send_enable_min_time_from_building"))
|
||||
{
|
||||
maximum_simultaneous_block_sends
|
||||
= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
|
||||
}
|
||||
maximum_simultaneous_block_sends
|
||||
= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
|
||||
}
|
||||
|
||||
u32 num_blocks_selected;
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
num_blocks_selected = m_blocks_sending.size();
|
||||
}
|
||||
u32 num_blocks_selected = m_blocks_sending.size();
|
||||
|
||||
/*
|
||||
next time d will be continued from the d from which the nearest
|
||||
@ -384,11 +365,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
*/
|
||||
s32 new_nearest_unsent_d = -1;
|
||||
|
||||
// Serialization version used
|
||||
//u8 ser_version = serialization_version;
|
||||
|
||||
//bool has_incomplete_blocks = false;
|
||||
|
||||
s16 d_max = g_settings.getS16("max_block_send_distance");
|
||||
s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
|
||||
|
||||
@ -398,20 +374,16 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
{
|
||||
//dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
|
||||
|
||||
//if(has_incomplete_blocks == false)
|
||||
/*
|
||||
If m_nearest_unsent_d was changed by the EmergeThread
|
||||
(it can change it to 0 through SetBlockNotSent),
|
||||
update our d to it.
|
||||
Else update m_nearest_unsent_d
|
||||
*/
|
||||
if(m_nearest_unsent_d != last_nearest_unsent_d)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
/*
|
||||
If m_nearest_unsent_d was changed by the EmergeThread
|
||||
(it can change it to 0 through SetBlockNotSent),
|
||||
update our d to it.
|
||||
Else update m_nearest_unsent_d
|
||||
*/
|
||||
if(m_nearest_unsent_d != last_nearest_unsent_d)
|
||||
{
|
||||
d = m_nearest_unsent_d;
|
||||
last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
}
|
||||
d = m_nearest_unsent_d;
|
||||
last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -443,23 +415,19 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
maximum_simultaneous_block_sends_setting;
|
||||
}
|
||||
|
||||
// Limit is dynamically lowered when building
|
||||
if(num_blocks_selected
|
||||
>= maximum_simultaneous_block_sends_now)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
|
||||
// Limit is dynamically lowered when building
|
||||
if(num_blocks_selected
|
||||
>= maximum_simultaneous_block_sends_now)
|
||||
{
|
||||
/*dstream<<"Not sending more blocks. Queue full. "
|
||||
<<m_blocks_sending.size()
|
||||
<<std::endl;*/
|
||||
goto queue_full;
|
||||
}
|
||||
|
||||
if(m_blocks_sending.find(p) != NULL)
|
||||
continue;
|
||||
/*dstream<<"Not sending more blocks. Queue full. "
|
||||
<<m_blocks_sending.size()
|
||||
<<std::endl;*/
|
||||
goto queue_full;
|
||||
}
|
||||
|
||||
|
||||
if(m_blocks_sending.find(p) != NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
Do not go over-limit
|
||||
*/
|
||||
@ -519,7 +487,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
#endif
|
||||
|
||||
/*
|
||||
Don't draw if not in sight
|
||||
Don't generate or send if not in sight
|
||||
*/
|
||||
|
||||
if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
|
||||
@ -531,8 +499,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
Don't send already sent blocks
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
|
||||
if(m_blocks_sent.find(p) != NULL)
|
||||
continue;
|
||||
}
|
||||
@ -546,12 +512,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
bool block_is_invalid = false;
|
||||
if(block != NULL)
|
||||
{
|
||||
/*if(block->isIncomplete())
|
||||
{
|
||||
has_incomplete_blocks = true;
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if(block->isDummy())
|
||||
{
|
||||
surely_not_found_on_disk = true;
|
||||
@ -567,11 +527,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
v2s16 chunkpos = map->sector_to_chunk(p2d);
|
||||
if(map->chunkNonVolatile(chunkpos) == false)
|
||||
block_is_invalid = true;
|
||||
/*MapChunk *chunk = map->getChunk(chunkpos);
|
||||
if(chunk == NULL)
|
||||
block_is_invalid = true;
|
||||
else if(chunk->getIsVolatile() == true)
|
||||
block_is_invalid = true;*/
|
||||
}
|
||||
|
||||
/*
|
||||
@ -598,11 +553,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
*/
|
||||
if(block == NULL || surely_not_found_on_disk || block_is_invalid)
|
||||
{
|
||||
//dstream<<"asd"<<std::endl;
|
||||
|
||||
/*SharedPtr<JMutexAutoLock> lock
|
||||
(m_num_blocks_in_emerge_queue.getLock());*/
|
||||
|
||||
//TODO: Get value from somewhere
|
||||
// Allow only one block in emerge queue
|
||||
if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
|
||||
@ -624,7 +574,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
}
|
||||
|
||||
/*
|
||||
Add block to queue
|
||||
Add block to send queue
|
||||
*/
|
||||
|
||||
PrioritySortedBlockTransfer q((float)d, p, peer_id);
|
||||
@ -638,7 +588,6 @@ queue_full:
|
||||
|
||||
if(new_nearest_unsent_d != -1)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
m_nearest_unsent_d = new_nearest_unsent_d;
|
||||
}
|
||||
}
|
||||
@ -743,7 +692,7 @@ void RemoteClient::SendObjectData(
|
||||
v3f playerpos = player->getPosition();
|
||||
v3f playerspeed = player->getSpeed();
|
||||
|
||||
v3s16 center_nodepos = floatToInt(playerpos);
|
||||
v3s16 center_nodepos = floatToInt(playerpos, BS);
|
||||
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||
|
||||
s16 d_max = g_settings.getS16("active_object_range");
|
||||
@ -767,7 +716,6 @@ void RemoteClient::SendObjectData(
|
||||
Ignore blocks that haven't been sent to the client
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock sentlock(m_blocks_sent_mutex);
|
||||
if(m_blocks_sent.find(p) == NULL)
|
||||
continue;
|
||||
}
|
||||
@ -861,8 +809,6 @@ skip_subsequent:
|
||||
|
||||
void RemoteClient::GotBlock(v3s16 p)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
JMutexAutoLock lock2(m_blocks_sent_mutex);
|
||||
if(m_blocks_sending.find(p) != NULL)
|
||||
m_blocks_sending.remove(p);
|
||||
else
|
||||
@ -876,13 +822,6 @@ void RemoteClient::GotBlock(v3s16 p)
|
||||
|
||||
void RemoteClient::SentBlock(v3s16 p)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
/*if(m_blocks_sending.size() > 15)
|
||||
{
|
||||
dstream<<"RemoteClient::SentBlock(): "
|
||||
<<"m_blocks_sending.size()="
|
||||
<<m_blocks_sending.size()<<std::endl;
|
||||
}*/
|
||||
if(m_blocks_sending.find(p) == NULL)
|
||||
m_blocks_sending.insert(p, 0.0);
|
||||
else
|
||||
@ -892,9 +831,6 @@ void RemoteClient::SentBlock(v3s16 p)
|
||||
|
||||
void RemoteClient::SetBlockNotSent(v3s16 p)
|
||||
{
|
||||
JMutexAutoLock sendinglock(m_blocks_sending_mutex);
|
||||
JMutexAutoLock sentlock(m_blocks_sent_mutex);
|
||||
|
||||
m_nearest_unsent_d = 0;
|
||||
|
||||
if(m_blocks_sending.find(p) != NULL)
|
||||
@ -905,9 +841,6 @@ void RemoteClient::SetBlockNotSent(v3s16 p)
|
||||
|
||||
void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
|
||||
{
|
||||
JMutexAutoLock sendinglock(m_blocks_sending_mutex);
|
||||
JMutexAutoLock sentlock(m_blocks_sent_mutex);
|
||||
|
||||
m_nearest_unsent_d = 0;
|
||||
|
||||
for(core::map<v3s16, MapBlock*>::Iterator
|
||||
@ -964,7 +897,7 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
||||
Server::Server(
|
||||
std::string mapsavedir
|
||||
):
|
||||
m_env(new ServerMap(mapsavedir), dout_server),
|
||||
m_env(new ServerMap(mapsavedir)),
|
||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||
m_thread(this),
|
||||
m_emergethread(this),
|
||||
@ -1257,11 +1190,8 @@ void Server::AsyncRunStep()
|
||||
}
|
||||
|
||||
/*
|
||||
Update digging
|
||||
|
||||
NOTE: Some of this could be moved to RemoteClient
|
||||
Check added and deleted active objects
|
||||
*/
|
||||
#if 0
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
@ -1272,100 +1202,209 @@ void Server::AsyncRunStep()
|
||||
{
|
||||
RemoteClient *client = i.getNode()->getValue();
|
||||
Player *player = m_env.getPlayer(client->peer_id);
|
||||
v3s16 pos = floatToInt(player->getPosition(), BS);
|
||||
s16 radius = 32;
|
||||
|
||||
JMutexAutoLock digmutex(client->m_dig_mutex);
|
||||
|
||||
if(client->m_dig_tool_item == -1)
|
||||
continue;
|
||||
|
||||
client->m_dig_time_remaining -= dtime;
|
||||
|
||||
if(client->m_dig_time_remaining > 0)
|
||||
{
|
||||
client->m_time_from_building.set(0.0);
|
||||
continue;
|
||||
}
|
||||
|
||||
v3s16 p_under = client->m_dig_position;
|
||||
core::map<u16, bool> removed_objects;
|
||||
core::map<u16, bool> added_objects;
|
||||
m_env.getRemovedActiveObjects(pos, radius,
|
||||
client->m_known_objects, removed_objects);
|
||||
m_env.getAddedActiveObjects(pos, radius,
|
||||
client->m_known_objects, added_objects);
|
||||
|
||||
// Mandatory parameter; actually used for nothing
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
|
||||
u8 material;
|
||||
|
||||
try
|
||||
{
|
||||
// Get material at position
|
||||
material = m_env.getMap().getNode(p_under).d;
|
||||
// If it's not diggable, do nothing
|
||||
if(content_diggable(material) == false)
|
||||
{
|
||||
derr_server<<"Server: Not finishing digging: Node not diggable"
|
||||
<<std::endl;
|
||||
client->m_dig_tool_item = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
derr_server<<"Server: Not finishing digging: Node not found"
|
||||
<<std::endl;
|
||||
client->m_dig_tool_item = -1;
|
||||
break;
|
||||
}
|
||||
// Ignore if nothing happened
|
||||
if(removed_objects.size() == 0 && added_objects.size() == 0)
|
||||
continue;
|
||||
|
||||
// Create packet
|
||||
u32 replysize = 8;
|
||||
SharedBuffer<u8> reply(replysize);
|
||||
writeU16(&reply[0], TOCLIENT_REMOVENODE);
|
||||
writeS16(&reply[2], p_under.X);
|
||||
writeS16(&reply[4], p_under.Y);
|
||||
writeS16(&reply[6], p_under.Z);
|
||||
std::string data_buffer;
|
||||
|
||||
char buf[4];
|
||||
|
||||
// Handle removed objects
|
||||
writeU16((u8*)buf, removed_objects.size());
|
||||
data_buffer.append(buf, 2);
|
||||
for(core::map<u16, bool>::Iterator
|
||||
i = removed_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
// Get object
|
||||
u16 id = i.getNode()->getKey();
|
||||
ServerActiveObject* obj = m_env.getActiveObject(id);
|
||||
|
||||
// Add to data buffer for sending
|
||||
writeU16((u8*)buf, i.getNode()->getKey());
|
||||
data_buffer.append(buf, 2);
|
||||
|
||||
// Remove from known objects
|
||||
client->m_known_objects.remove(i.getNode()->getKey());
|
||||
|
||||
if(obj && obj->m_known_by_count > 0)
|
||||
obj->m_known_by_count--;
|
||||
}
|
||||
|
||||
// Handle added objects
|
||||
writeU16((u8*)buf, added_objects.size());
|
||||
data_buffer.append(buf, 2);
|
||||
for(core::map<u16, bool>::Iterator
|
||||
i = added_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
// Get object
|
||||
u16 id = i.getNode()->getKey();
|
||||
ServerActiveObject* obj = m_env.getActiveObject(id);
|
||||
|
||||
// Get object type
|
||||
u8 type = ACTIVEOBJECT_TYPE_INVALID;
|
||||
if(obj == NULL)
|
||||
dstream<<"WARNING: "<<__FUNCTION_NAME
|
||||
<<": NULL object"<<std::endl;
|
||||
else
|
||||
type = obj->getType();
|
||||
|
||||
// Add to data buffer for sending
|
||||
writeU16((u8*)buf, id);
|
||||
data_buffer.append(buf, 2);
|
||||
writeU8((u8*)buf, type);
|
||||
data_buffer.append(buf, 1);
|
||||
|
||||
// Add to known objects
|
||||
client->m_known_objects.insert(i.getNode()->getKey(), false);
|
||||
|
||||
if(obj)
|
||||
obj->m_known_by_count++;
|
||||
}
|
||||
|
||||
// Send packet
|
||||
SharedBuffer<u8> reply(2 + data_buffer.size());
|
||||
writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
|
||||
memcpy((char*)&reply[2], data_buffer.c_str(),
|
||||
data_buffer.size());
|
||||
// Send as reliable
|
||||
m_con.SendToAll(0, reply, true);
|
||||
|
||||
if(g_settings.getBool("creative_mode") == false)
|
||||
{
|
||||
// Add to inventory and send inventory
|
||||
InventoryItem *item = new MaterialItem(material, 1);
|
||||
player->inventory.addItem("main", item);
|
||||
SendInventory(player->peer_id);
|
||||
}
|
||||
m_con.Send(client->peer_id, 0, reply, true);
|
||||
|
||||
/*
|
||||
Remove the node
|
||||
(this takes some time so it is done after the quick stuff)
|
||||
*/
|
||||
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
||||
|
||||
/*
|
||||
Update water
|
||||
*/
|
||||
|
||||
// Update water pressure around modification
|
||||
// This also adds it to m_flow_active_nodes if appropriate
|
||||
|
||||
MapVoxelManipulator v(&m_env.getMap());
|
||||
v.m_disable_water_climb =
|
||||
g_settings.getBool("disable_water_climb");
|
||||
|
||||
VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
|
||||
|
||||
try
|
||||
{
|
||||
v.updateAreaWaterPressure(area, m_flow_active_nodes);
|
||||
}
|
||||
catch(ProcessingLimitException &e)
|
||||
{
|
||||
dstream<<"Processing limit reached (1)"<<std::endl;
|
||||
}
|
||||
|
||||
v.blitBack(modified_blocks);
|
||||
dstream<<"INFO: Server: Sent object remove/add: "
|
||||
<<removed_objects.size()<<" removed, "
|
||||
<<added_objects.size()<<" added, "
|
||||
<<"packet size is "<<reply.getSize()<<std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send object positions
|
||||
/*
|
||||
Send object messages
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
// Key = object id
|
||||
// Value = data sent by object
|
||||
core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
|
||||
|
||||
// Get active object messages from environment
|
||||
for(;;)
|
||||
{
|
||||
ActiveObjectMessage aom = m_env.getActiveObjectMessage();
|
||||
if(aom.id == 0)
|
||||
break;
|
||||
|
||||
core::list<ActiveObjectMessage>* message_list = NULL;
|
||||
core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
|
||||
n = buffered_messages.find(aom.id);
|
||||
if(n == NULL)
|
||||
{
|
||||
message_list = new core::list<ActiveObjectMessage>;
|
||||
buffered_messages.insert(aom.id, message_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
message_list = n->getValue();
|
||||
}
|
||||
message_list->push_back(aom);
|
||||
}
|
||||
|
||||
// Route data to every client
|
||||
for(core::map<u16, RemoteClient*>::Iterator
|
||||
i = m_clients.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
RemoteClient *client = i.getNode()->getValue();
|
||||
std::string reliable_data;
|
||||
std::string unreliable_data;
|
||||
// Go through all objects in message buffer
|
||||
for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
|
||||
j = buffered_messages.getIterator();
|
||||
j.atEnd()==false; j++)
|
||||
{
|
||||
// If object is not known by client, skip it
|
||||
u16 id = j.getNode()->getKey();
|
||||
if(client->m_known_objects.find(id) == NULL)
|
||||
continue;
|
||||
// Get message list of object
|
||||
core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
|
||||
// Go through every message
|
||||
for(core::list<ActiveObjectMessage>::Iterator
|
||||
k = list->begin(); k != list->end(); k++)
|
||||
{
|
||||
// Compose the full new data with header
|
||||
ActiveObjectMessage aom = *k;
|
||||
std::string new_data;
|
||||
// Add header (object id + length)
|
||||
char header[4];
|
||||
writeU16((u8*)&header[0], aom.id);
|
||||
writeU16((u8*)&header[2], aom.datastring.size());
|
||||
new_data.append(header, 4);
|
||||
// Add data
|
||||
new_data += aom.datastring;
|
||||
// Add data to buffer
|
||||
if(aom.reliable)
|
||||
reliable_data += new_data;
|
||||
else
|
||||
unreliable_data += new_data;
|
||||
}
|
||||
}
|
||||
/*
|
||||
reliable_data and unreliable_data are now ready.
|
||||
Send them.
|
||||
*/
|
||||
if(reliable_data.size() > 0)
|
||||
{
|
||||
SharedBuffer<u8> reply(2 + reliable_data.size());
|
||||
writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
|
||||
memcpy((char*)&reply[2], reliable_data.c_str(),
|
||||
reliable_data.size());
|
||||
// Send as reliable
|
||||
m_con.Send(client->peer_id, 0, reply, true);
|
||||
}
|
||||
if(unreliable_data.size() > 0)
|
||||
{
|
||||
SharedBuffer<u8> reply(2 + unreliable_data.size());
|
||||
writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
|
||||
memcpy((char*)&reply[2], unreliable_data.c_str(),
|
||||
unreliable_data.size());
|
||||
// Send as unreliable
|
||||
m_con.Send(client->peer_id, 0, reply, false);
|
||||
}
|
||||
if(reliable_data.size() > 0 || unreliable_data.size() > 0)
|
||||
{
|
||||
dstream<<"INFO: Server: Size of object message data: "
|
||||
<<"reliable: "<<reliable_data.size()
|
||||
<<", unreliable: "<<unreliable_data.size()
|
||||
<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear buffered_messages
|
||||
for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
|
||||
i = buffered_messages.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
delete i.getNode()->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Send object positions
|
||||
*/
|
||||
{
|
||||
float &counter = m_objectdata_timer;
|
||||
counter += dtime;
|
||||
@ -1485,7 +1524,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
return;
|
||||
}
|
||||
|
||||
//u8 peer_ser_ver = peer->serialization_version;
|
||||
u8 peer_ser_ver = getClient(peer->id)->serialization_version;
|
||||
|
||||
try
|
||||
@ -1595,7 +1633,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
SharedBuffer<u8> reply(2+1+6);
|
||||
writeU16(&reply[0], TOCLIENT_INIT);
|
||||
writeU8(&reply[2], deployed);
|
||||
writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0)));
|
||||
writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, reply, true);
|
||||
|
||||
@ -1892,6 +1930,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
{
|
||||
derr_server<<"Server: Not finishing digging: Node not diggable"
|
||||
<<std::endl;
|
||||
|
||||
// Client probably has wrong data.
|
||||
// Set block not sent, so that client will get
|
||||
// a valid one.
|
||||
dstream<<"Client "<<peer_id<<" tried to dig "
|
||||
<<"node from invalid position; setting"
|
||||
<<" MapBlock not sent."<<std::endl;
|
||||
RemoteClient *client = getClient(peer_id);
|
||||
v3s16 blockpos = getNodeBlockPos(p_under);
|
||||
client->SetBlockNotSent(blockpos);
|
||||
|
||||
return;
|
||||
}
|
||||
// Get mineral
|
||||
@ -2088,7 +2137,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
}
|
||||
|
||||
// Reset build time counter
|
||||
getClient(peer->id)->m_time_from_building.set(0.0);
|
||||
getClient(peer->id)->m_time_from_building = 0.0;
|
||||
|
||||
// Create node data
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
@ -2166,9 +2215,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
}
|
||||
|
||||
v3s16 block_pos_i_on_map = block->getPosRelative();
|
||||
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
|
||||
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
|
||||
|
||||
v3f pos = intToFloat(p_over);
|
||||
v3f pos = intToFloat(p_over, BS);
|
||||
pos -= block_pos_f_on_map;
|
||||
|
||||
/*dout_server<<"pos="
|
||||
@ -3060,6 +3109,7 @@ void Server::SendBlocks(float dtime)
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
//TimeTaker timer("Server::SendBlocks");
|
||||
|
||||
@ -3087,8 +3137,6 @@ void Server::SendBlocks(float dtime)
|
||||
// Lowest is most important.
|
||||
queue.sort();
|
||||
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
for(u32 i=0; i<queue.size(); i++)
|
||||
{
|
||||
//TODO: Calculate limit dynamically
|
||||
@ -3268,7 +3316,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||
0,
|
||||
45, //64,
|
||||
0
|
||||
)));
|
||||
), BS));
|
||||
#endif
|
||||
#if 0
|
||||
f32 groundheight = 0;
|
||||
|
47
src/server.h
47
src/server.h
@ -239,13 +239,6 @@ public:
|
||||
pending_serialization_version = SER_FMT_VER_INVALID;
|
||||
m_nearest_unsent_d = 0;
|
||||
m_nearest_unsent_reset_timer = 0.0;
|
||||
|
||||
m_blocks_sent_mutex.Init();
|
||||
m_blocks_sending_mutex.Init();
|
||||
|
||||
/*m_dig_mutex.Init();
|
||||
m_dig_time_remaining = 0;
|
||||
m_dig_tool_item = -1;*/
|
||||
}
|
||||
~RemoteClient()
|
||||
{
|
||||
@ -279,7 +272,6 @@ public:
|
||||
|
||||
s32 SendingCount()
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
return m_blocks_sending.size();
|
||||
}
|
||||
|
||||
@ -290,8 +282,6 @@ public:
|
||||
|
||||
void PrintInfo(std::ostream &o)
|
||||
{
|
||||
JMutexAutoLock l2(m_blocks_sent_mutex);
|
||||
JMutexAutoLock l3(m_blocks_sending_mutex);
|
||||
o<<"RemoteClient "<<peer_id<<": "
|
||||
<<", m_blocks_sent.size()="<<m_blocks_sent.size()
|
||||
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
|
||||
@ -302,30 +292,21 @@ public:
|
||||
}
|
||||
|
||||
// Time from last placing or removing blocks
|
||||
MutexedVariable<float> m_time_from_building;
|
||||
float m_time_from_building;
|
||||
|
||||
/*JMutex m_dig_mutex;
|
||||
float m_dig_time_remaining;
|
||||
// -1 = not digging
|
||||
s16 m_dig_tool_item;
|
||||
v3s16 m_dig_position;*/
|
||||
|
||||
/*
|
||||
List of active objects that the client knows of.
|
||||
Value is dummy.
|
||||
*/
|
||||
core::map<u16, bool> m_known_objects;
|
||||
|
||||
private:
|
||||
/*
|
||||
All members that are accessed by many threads should
|
||||
obviously be behind a mutex. The threads include:
|
||||
- main thread (calls step())
|
||||
- server thread (calls AsyncRunStep() and Receive())
|
||||
- emerge thread
|
||||
*/
|
||||
|
||||
//TODO: core::map<v3s16, MapBlock*> m_active_blocks
|
||||
//NOTE: Not here, it should be server-wide!
|
||||
|
||||
// Number of blocks in the emerge queue that have this client as
|
||||
// a receiver. Used for throttling network usage.
|
||||
//MutexedVariable<s16> m_num_blocks_in_emerge_queue;
|
||||
|
||||
/*
|
||||
Blocks that have been sent to client.
|
||||
- These don't have to be sent again.
|
||||
@ -339,7 +320,7 @@ private:
|
||||
s16 m_nearest_unsent_d;
|
||||
v3s16 m_last_center;
|
||||
float m_nearest_unsent_reset_timer;
|
||||
JMutex m_blocks_sent_mutex;
|
||||
|
||||
/*
|
||||
Blocks that are currently on the line.
|
||||
This is used for throttling the sending of blocks.
|
||||
@ -349,7 +330,6 @@ private:
|
||||
Value is time from sending. (not used at the moment)
|
||||
*/
|
||||
core::map<v3s16, float> m_blocks_sending;
|
||||
JMutex m_blocks_sending_mutex;
|
||||
|
||||
/*
|
||||
Count of excess GotBlocks().
|
||||
@ -361,15 +341,6 @@ private:
|
||||
u32 m_excess_gotblocks;
|
||||
};
|
||||
|
||||
/*struct ServerSettings
|
||||
{
|
||||
ServerSettings()
|
||||
{
|
||||
creative_mode = false;
|
||||
}
|
||||
bool creative_mode;
|
||||
};*/
|
||||
|
||||
class Server : public con::PeerHandler
|
||||
{
|
||||
public:
|
||||
@ -470,7 +441,7 @@ private:
|
||||
// NOTE: If connection and environment are both to be locked,
|
||||
// environment shall be locked first.
|
||||
JMutex m_env_mutex;
|
||||
Environment m_env;
|
||||
ServerEnvironment m_env;
|
||||
|
||||
JMutex m_con_mutex;
|
||||
con::Connection m_con;
|
||||
|
75
src/serverobject.cpp
Normal file
75
src/serverobject.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "serverobject.h"
|
||||
|
||||
ServerActiveObject::ServerActiveObject(u16 id, v3f pos):
|
||||
ActiveObject(id),
|
||||
m_known_by_count(0),
|
||||
m_removed(false),
|
||||
m_base_position(pos)
|
||||
{
|
||||
}
|
||||
|
||||
ServerActiveObject::~ServerActiveObject()
|
||||
{
|
||||
}
|
||||
|
||||
TestSAO::TestSAO(u16 id, v3f pos):
|
||||
ServerActiveObject(id, pos),
|
||||
m_timer1(0),
|
||||
m_age(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
|
||||
{
|
||||
m_age += dtime;
|
||||
if(m_age > 10)
|
||||
{
|
||||
m_removed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_base_position.Y += dtime * BS * 2;
|
||||
if(m_base_position.Y > 8*BS)
|
||||
m_base_position.Y = 2*BS;
|
||||
|
||||
m_timer1 -= dtime;
|
||||
if(m_timer1 < 0.0)
|
||||
{
|
||||
m_timer1 += 0.125;
|
||||
//dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
|
||||
|
||||
std::string data;
|
||||
|
||||
data += itos(0); // 0 = position
|
||||
data += " ";
|
||||
data += itos(m_base_position.X);
|
||||
data += " ";
|
||||
data += itos(m_base_position.Y);
|
||||
data += " ";
|
||||
data += itos(m_base_position.Z);
|
||||
|
||||
//ActiveObjectMessage aom(getId(), true, data);
|
||||
ActiveObjectMessage aom(getId(), false, data);
|
||||
messages.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
87
src/serverobject.h
Normal file
87
src/serverobject.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVEROBJECT_HEADER
|
||||
#define SERVEROBJECT_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "activeobject.h"
|
||||
#include "utility.h"
|
||||
|
||||
/*
|
||||
|
||||
Some planning
|
||||
-------------
|
||||
|
||||
* Server environment adds an active object, which gets the id 1
|
||||
* The active object list is scanned for each client once in a while,
|
||||
and it finds out what objects have been added that are not known
|
||||
by the client yet. This scan is initiated by the server and the
|
||||
result ends up directly to the server.
|
||||
* A network packet is created with the info and sent to the client.
|
||||
|
||||
*/
|
||||
|
||||
class ServerActiveObject : public ActiveObject
|
||||
{
|
||||
public:
|
||||
ServerActiveObject(u16 id, v3f pos=v3f(0,0,0));
|
||||
virtual ~ServerActiveObject();
|
||||
|
||||
v3f getBasePosition()
|
||||
{
|
||||
return m_base_position;
|
||||
}
|
||||
|
||||
/*
|
||||
Step object in time.
|
||||
Messages added to messages are sent to client over network.
|
||||
*/
|
||||
virtual void step(float dtime, Queue<ActiveObjectMessage> &messages){}
|
||||
|
||||
// Number of players which know about this one
|
||||
u16 m_known_by_count;
|
||||
/*
|
||||
Whether this object is to be removed when nobody knows about
|
||||
it anymore.
|
||||
Removal is delayed to preserve the id for the time during which
|
||||
it could be confused to some other object by some client.
|
||||
*/
|
||||
bool m_removed;
|
||||
|
||||
protected:
|
||||
v3f m_base_position;
|
||||
};
|
||||
|
||||
class TestSAO : public ServerActiveObject
|
||||
{
|
||||
public:
|
||||
TestSAO(u16 id, v3f pos);
|
||||
u8 getType() const
|
||||
{
|
||||
return ACTIVEOBJECT_TYPE_TEST;
|
||||
}
|
||||
void step(float dtime, Queue<ActiveObjectMessage> &messages);
|
||||
private:
|
||||
float m_timer1;
|
||||
float m_age;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1738,5 +1738,30 @@ inline std::string wrap_rows(const std::string &from, u32 rowlen)
|
||||
#define MYMIN(a,b) ((a)<(b)?(a):(b))
|
||||
#define MYMAX(a,b) ((a)>(b)?(a):(b))
|
||||
|
||||
/*
|
||||
Returns integer position of node in given floating point position
|
||||
*/
|
||||
inline v3s16 floatToInt(v3f p, f32 d)
|
||||
{
|
||||
v3s16 p2(
|
||||
(p.X + (p.X>0 ? BS/2 : -BS/2))/d,
|
||||
(p.Y + (p.Y>0 ? BS/2 : -BS/2))/d,
|
||||
(p.Z + (p.Z>0 ? BS/2 : -BS/2))/d);
|
||||
return p2;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns floating point position of node in given integer position
|
||||
*/
|
||||
inline v3f intToFloat(v3s16 p, f32 d)
|
||||
{
|
||||
v3f p2(
|
||||
(f32)p.X * d,
|
||||
(f32)p.Y * d,
|
||||
(f32)p.Z * d
|
||||
);
|
||||
return p2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user