aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/activeobject.h1
-rw-r--r--src/client.cpp340
-rw-r--r--src/client.h79
-rw-r--r--src/clientobject.cpp179
-rw-r--r--src/clientobject.h45
-rw-r--r--src/clientserver.h45
-rw-r--r--src/collision.cpp1
-rw-r--r--src/collision.h10
-rw-r--r--src/defaultsettings.cpp1
-rw-r--r--src/environment.cpp178
-rw-r--r--src/environment.h32
-rw-r--r--src/inventory.h6
-rw-r--r--src/main.cpp551
-rw-r--r--src/map.cpp36
-rw-r--r--src/map.h10
-rw-r--r--src/mapblock.cpp33
-rw-r--r--src/player.cpp29
-rw-r--r--src/player.h5
-rw-r--r--src/serialization.cpp6
-rw-r--r--src/serialization.h8
-rw-r--r--src/server.cpp864
-rw-r--r--src/server.h27
-rw-r--r--src/serverobject.cpp215
-rw-r--r--src/serverobject.h34
-rw-r--r--src/test.cpp16
-rw-r--r--src/utility.h8
26 files changed, 1837 insertions, 922 deletions
diff --git a/src/activeobject.h b/src/activeobject.h
index e1fc6beaf..382f7f798 100644
--- a/src/activeobject.h
+++ b/src/activeobject.h
@@ -40,6 +40,7 @@ struct ActiveObjectMessage
#define ACTIVEOBJECT_TYPE_TEST 1
#define ACTIVEOBJECT_TYPE_ITEM 2
#define ACTIVEOBJECT_TYPE_RAT 3
+#define ACTIVEOBJECT_TYPE_OERKKI1 4
/*
Parent class for ServerActiveObject and ClientActiveObject
diff --git a/src/client.cpp b/src/client.cpp
index e2877f5fc..702247f66 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -90,6 +90,7 @@ Client::Client(
m_connection_reinit_timer = 0.0;
m_avg_rtt_timer = 0.0;
m_playerpos_send_timer = 0.0;
+ m_ignore_damage_timer = 0.0;
//m_env_mutex.Init();
//m_con_mutex.Init();
@@ -154,6 +155,10 @@ void Client::step(float dtime)
if(dtime > 2.0)
dtime = 2.0;
+ if(m_ignore_damage_timer > dtime)
+ m_ignore_damage_timer -= dtime;
+ else
+ m_ignore_damage_timer = 0.0;
//dstream<<"Client steps "<<dtime<<std::endl;
@@ -311,6 +316,9 @@ void Client::step(float dtime)
Do stuff if connected
*/
+ /*
+ Handle environment
+ */
{
// 0ms
//JMutexAutoLock lock(m_env_mutex); //bulk comment-out
@@ -341,8 +349,37 @@ void Client::step(float dtime)
{
}
}
- }
+ /*
+ Get events
+ */
+ for(;;)
+ {
+ ClientEnvEvent event = m_env.getClientEvent();
+ if(event.type == CEE_NONE)
+ {
+ break;
+ }
+ else if(event.type == CEE_PLAYER_DAMAGE)
+ {
+ if(m_ignore_damage_timer <= 0)
+ {
+ u8 damage = event.player_damage.amount;
+ sendDamage(damage);
+
+ // Add to ClientEvent queue
+ ClientEvent event;
+ event.type = CE_PLAYER_DAMAGE;
+ event.player_damage.amount = damage;
+ m_client_event_queue.push_back(event);
+ }
+ }
+ }
+ }
+
+ /*
+ Print some info
+ */
{
float &counter = m_avg_rtt_timer;
counter += dtime;
@@ -355,6 +392,10 @@ void Client::step(float dtime)
dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
}
}
+
+ /*
+ Send player position to server
+ */
{
float &counter = m_playerpos_send_timer;
counter += dtime;
@@ -388,6 +429,8 @@ void Client::step(float dtime)
}
if(r.ack_block_to_server)
{
+ /*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
+ <<","<<r.p.Z<<")"<<std::endl;*/
/*
Acknowledge block
*/
@@ -447,7 +490,7 @@ void Client::ReceiveAll()
void Client::Receive()
{
DSTACK(__FUNCTION_NAME);
- u32 data_maxsize = 10000;
+ u32 data_maxsize = 200000;
Buffer<u8> data(data_maxsize);
u16 sender_peer_id;
u32 datasize;
@@ -1294,219 +1337,56 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
}
}
- else
- {
- dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
- <<command<<std::endl;
- }
-#if 0
- // Default to queueing it (for slow commands)
- else
+ else if(command == TOCLIENT_HP)
{
- JMutexAutoLock lock(m_incoming_queue_mutex);
-
- IncomingPacket packet(data, datasize);
- m_incoming_queue.push_back(packet);
- }
-#endif
-}
-
-#if 0
-/*
- Returns true if there was something in queue
-*/
-bool Client::AsyncProcessPacket()
-{
- DSTACK(__FUNCTION_NAME);
-
- try //for catching con::PeerNotFoundException
- {
-
- con::Peer *peer;
- {
- //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
- // All data is coming from the server
- peer = m_con.GetPeer(PEER_ID_SERVER);
- }
-
- u8 ser_version = m_server_ser_ver;
-
- IncomingPacket packet = getPacket();
- u8 *data = packet.m_data;
- u32 datasize = packet.m_datalen;
-
- // An empty packet means queue is empty
- if(data == NULL){
- return false;
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+ Player *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ u8 hp = readU8(is);
+ player->hp = hp;
}
-
- if(datasize < 2)
- return true;
-
- ToClientCommand command = (ToClientCommand)readU16(&data[0]);
-
- if(command == TOCLIENT_BLOCKDATA)
+ else if(command == TOCLIENT_MOVE_PLAYER)
{
- // Ignore too small packet
- if(datasize < 8)
- return true;
-
- v3s16 p;
- p.X = readS16(&data[2]);
- p.Y = readS16(&data[4]);
- p.Z = readS16(&data[6]);
-
- /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
- <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
- /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
- <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
- std::string datastring((char*)&data[8], datasize-8);
- std::istringstream istr(datastring, std::ios_base::binary);
-
- MapSector *sector;
- MapBlock *block;
-
- { //envlock
- //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-
- v2s16 p2d(p.X, p.Z);
- sector = m_env.getMap().emergeSector(p2d);
-
- v2s16 sp = sector->getPos();
- if(sp != p2d)
- {
- dstream<<"ERROR: Got sector with getPos()="
- <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
- <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
- }
-
- assert(sp == p2d);
- //assert(sector->getPos() == p2d);
-
- //TimeTaker timer("MapBlock deSerialize");
- // 0ms
-
- try{
- block = sector->getBlockNoCreate(p.Y);
- /*
- Update an existing block
- */
- //dstream<<"Updating"<<std::endl;
- block->deSerialize(istr, ser_version);
- //block->setChangedFlag();
- }
- catch(InvalidPositionException &e)
- {
- /*
- Create a new block
- */
- //dstream<<"Creating new"<<std::endl;
- block = new MapBlock(&m_env.getMap(), p);
- block->deSerialize(istr, ser_version);
- sector->insertBlock(block);
- //block->setChangedFlag();
-
- //DEBUG
- /*NodeMod mod;
- mod.type = NODEMOD_CHANGECONTENT;
- mod.param = CONTENT_MESE;
- block->setTempMod(v3s16(8,10,8), mod);
- block->setTempMod(v3s16(8,9,8), mod);
- block->setTempMod(v3s16(8,8,8), mod);
- block->setTempMod(v3s16(8,7,8), mod);
- block->setTempMod(v3s16(8,6,8), mod);*/
-#if 0
- /*
- Add some coulds
- Well, this is a dumb way to do it, they should just
- be drawn as separate objects. But the looks of them
- can be tested this way.
- */
- if(p.Y == 3)
- {
- NodeMod mod;
- mod.type = NODEMOD_CHANGECONTENT;
- mod.param = CONTENT_CLOUD;
- v3s16 p2;
- p2.Y = 8;
- for(p2.X=3; p2.X<=13; p2.X++)
- for(p2.Z=3; p2.Z<=13; p2.Z++)
- {
- block->setTempMod(p2, mod);
- }
- }
-#endif
- }
- } //envlock
-
- /*
- Acknowledge block.
- */
- /*
- [0] u16 command
- [2] u8 count
- [3] v3s16 pos_0
- [3+6] v3s16 pos_1
- ...
- */
- u32 replysize = 2+1+6;
- SharedBuffer<u8> reply(replysize);
- writeU16(&reply[0], TOSERVER_GOTBLOCKS);
- reply[2] = 1;
- writeV3S16(&reply[3], p);
- // Send as reliable
- m_con.Send(PEER_ID_SERVER, 1, reply, true);
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+ Player *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ v3f pos = readV3F1000(is);
+ f32 pitch = readF1000(is);
+ f32 yaw = readF1000(is);
+ player->setPosition(pos);
+ /*player->setPitch(pitch);
+ player->setYaw(yaw);*/
+
+ dstream<<"Client got TOCLIENT_MOVE_PLAYER"
+ <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
+ <<" pitch="<<pitch
+ <<" yaw="<<yaw
+ <<std::endl;
/*
- Update Mesh of this block and blocks at x-, y- and z-.
- Environment should not be locked as it interlocks with the
- main thread, from which is will want to retrieve textures.
+ Add to ClientEvent queue.
+ This has to be sent to the main program because otherwise
+ it would just force the pitch and yaw values to whatever
+ the camera points to.
*/
-
- //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
-
- MeshMakeData data;
- {
- //TimeTaker timer("data fill");
- // 0ms
- data.fill(getDayNightRatio(), block);
- }
- {
- TimeTaker timer("make mesh");
- scene::SMesh *mesh_new = NULL;
- mesh_new = makeMapBlockMesh(&data);
- block->replaceMesh(mesh_new);
- }
+ ClientEvent event;
+ event.type = CE_PLAYER_FORCE_MOVE;
+ event.player_force_move.pitch = pitch;
+ event.player_force_move.yaw = yaw;
+ m_client_event_queue.push_back(event);
+
+ // Ignore damage for a few seconds, so that the player doesn't
+ // get damage from falling on ground
+ m_ignore_damage_timer = 3.0;
}
else
{
dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
<<command<<std::endl;
}
-
- return true;
-
- } //try
- catch(con::PeerNotFoundException &e)
- {
- /*dout_client<<DTIME<<"Client::AsyncProcessData(): Cancelling: The server"
- " connection doesn't exist (a timeout or not yet connected?)"<<std::endl;*/
- return false;
- }
-}
-
-bool Client::AsyncProcessData()
-{
- for(;;)
- {
- bool r = AsyncProcessPacket();
- if(r == false)
- break;
- }
- return false;
}
-#endif
void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
{
@@ -1514,28 +1394,6 @@ void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
}
-#if 0
-IncomingPacket Client::getPacket()
-{
- JMutexAutoLock lock(m_incoming_queue_mutex);
-
- core::list<IncomingPacket>::Iterator i;
- // Refer to first one
- i = m_incoming_queue.begin();
-
- // If queue is empty, return empty packet
- if(i == m_incoming_queue.end()){
- IncomingPacket packet;
- return packet;
- }
-
- // Pop out first packet and return it
- IncomingPacket packet = *i;
- m_incoming_queue.erase(i);
- return packet;
-}
-#endif
-
void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
v3s16 nodepos_oversurface, u16 item)
{
@@ -1739,6 +1597,21 @@ void Client::sendChatMessage(const std::wstring &message)
Send(0, data, true);
}
+void Client::sendDamage(u8 damage)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOSERVER_DAMAGE);
+ writeU8(os, damage);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ Send(0, data, true);
+}
+
void Client::sendPlayerPos()
{
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
@@ -2061,6 +1934,13 @@ u32 Client::getDayNightRatio()
return m_env.getDayNightRatio();
}
+u16 Client::getHP()
+{
+ Player *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ return player->hp;
+}
+
void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
{
/*dstream<<"Client::addUpdateMeshTask(): "
@@ -2141,3 +2021,15 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
catch(InvalidPositionException &e){}
}
+ClientEvent Client::getClientEvent()
+{
+ if(m_client_event_queue.size() == 0)
+ {
+ ClientEvent event;
+ event.type = CE_NONE;
+ return event;
+ }
+ return m_client_event_queue.pop_front();
+}
+
+
diff --git a/src/client.h b/src/client.h
index ef3dd435a..ee73cc42c 100644
--- a/src/client.h
+++ b/src/client.h
@@ -174,55 +174,28 @@ public:
MutexedQueue<MeshUpdateResult> m_queue_out;
};
-#if 0
-struct IncomingPacket
+enum ClientEventType
{
- IncomingPacket()
- {
- m_data = NULL;
- m_datalen = 0;
- m_refcount = NULL;
- }
- IncomingPacket(const IncomingPacket &a)
- {
- m_data = a.m_data;
- m_datalen = a.m_datalen;
- m_refcount = a.m_refcount;
- if(m_refcount != NULL)
- (*m_refcount)++;
- }
- IncomingPacket(u8 *data, u32 datalen)
- {
- m_data = new u8[datalen];
- memcpy(m_data, data, datalen);
- m_datalen = datalen;
- m_refcount = new s32(1);
- }
- ~IncomingPacket()
- {
- if(m_refcount != NULL){
- assert(*m_refcount > 0);
- (*m_refcount)--;
- if(*m_refcount == 0){
- if(m_data != NULL)
- delete[] m_data;
- delete m_refcount;
- }
- }
- }
- /*IncomingPacket & operator=(IncomingPacket a)
- {
- m_data = a.m_data;
- m_datalen = a.m_datalen;
- m_refcount = a.m_refcount;
- (*m_refcount)++;
- return *this;
- }*/
- u8 *m_data;
- u32 m_datalen;
- s32 *m_refcount;
+ CE_NONE,
+ CE_PLAYER_DAMAGE,
+ CE_PLAYER_FORCE_MOVE
+};
+
+struct ClientEvent
+{
+ ClientEventType type;
+ union{
+ struct{
+ } none;
+ struct{
+ u8 amount;
+ } player_damage;
+ struct{
+ f32 pitch;
+ f32 yaw;
+ } player_force_move;
+ };
};
-#endif
class Client : public con::PeerHandler, public InventoryManager
{
@@ -281,6 +254,7 @@ public:
void sendSignNodeText(v3s16 p, std::string text);
void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message);
+ void sendDamage(u8 damage);
// locks envlock
void removeNode(v3s16 p);
@@ -330,6 +304,8 @@ public:
u32 getDayNightRatio();
+ u16 getHP();
+
//void updateSomeExpiredMeshes();
void setTempMod(v3s16 p, NodeMod mod)
@@ -394,13 +370,13 @@ public:
u64 getMapSeed(){ return m_map_seed; }
- /*
- These are not thread-safe
- */
void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false);
// Including blocks at appropriate edges
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false);
+ // Get event from queue. CE_NONE is returned if queue is empty.
+ ClientEvent getClientEvent();
+
private:
// Virtual methods from con::PeerHandler
@@ -419,6 +395,7 @@ private:
float m_connection_reinit_timer;
float m_avg_rtt_timer;
float m_playerpos_send_timer;
+ float m_ignore_damage_timer; // Used after server moves player
MeshUpdateThread m_mesh_update_thread;
@@ -454,6 +431,8 @@ private:
u64 m_map_seed;
InventoryContext m_inventory_context;
+
+ Queue<ClientEvent> m_client_event_queue;
};
#endif // !SERVER
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index 5b744de6c..78258add8 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -494,7 +494,7 @@ void RatCAO::updateLight(u8 light_at_pos)
v3s16 RatCAO::getLightPosition()
{
- return floatToInt(m_position, BS);
+ return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
}
void RatCAO::updateNodePos()
@@ -552,4 +552,181 @@ void RatCAO::initialize(const std::string &data)
updateNodePos();
}
+/*
+ Oerkki1CAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+Oerkki1CAO proto_Oerkki1CAO;
+
+Oerkki1CAO::Oerkki1CAO():
+ ClientActiveObject(0),
+ m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
+ m_node(NULL),
+ m_position(v3f(0,10*BS,0)),
+ m_yaw(0)
+{
+ ClientActiveObject::registerType(getType(), create);
+}
+
+Oerkki1CAO::~Oerkki1CAO()
+{
+}
+
+ClientActiveObject* Oerkki1CAO::create()
+{
+ return new Oerkki1CAO();
+}
+
+void Oerkki1CAO::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,0,0, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2,BS*2,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, NULL);
+ buf->getMaterial().setTexture
+ (0, driver->getTexture(porting::getDataPath("oerkki1.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();
+ // Set it to use the materials of the meshbuffers directly.
+ // This is needed for changing the texture in the future
+ m_node->setReadOnlyMaterials(true);
+ updateNodePos();
+}
+
+void Oerkki1CAO::removeFromScene()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->remove();
+ m_node = NULL;
+}
+
+void Oerkki1CAO::updateLight(u8 light_at_pos)
+{
+ if(m_node == NULL)
+ return;
+
+ u8 li = decode_light(light_at_pos);
+ video::SColor color(255,li,li,li);
+
+ scene::IMesh *mesh = m_node->getMesh();
+ if(mesh == NULL)
+ return;
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+ u16 vc = buf->getVertexCount();
+ for(u16 i=0; i<vc; i++)
+ {
+ vertices[i].Color = color;
+ }
+ }
+}
+
+v3s16 Oerkki1CAO::getLightPosition()
+{
+ return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
+}
+
+void Oerkki1CAO::updateNodePos()
+{
+ if(m_node == NULL)
+ return;
+
+ //m_node->setPosition(m_position);
+ m_node->setPosition(pos_translator.vect_show);
+
+ v3f rot = m_node->getRotation();
+ rot.Y = 180.0 - m_yaw + 90.0;
+ m_node->setRotation(rot);
+}
+
+void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
+{
+ pos_translator.translate(dtime);
+ updateNodePos();
+
+ LocalPlayer *player = env->getLocalPlayer();
+ assert(player);
+
+ v3f playerpos = player->getPosition();
+ v2f playerpos_2d(playerpos.X,playerpos.Z);
+ v2f objectpos_2d(m_position.X,m_position.Z);
+
+ if(fabs(objectpos_2d.Y - playerpos_2d.Y) < 2.0*BS &&
+ objectpos_2d.getDistanceFrom(playerpos_2d) < 1.0*BS)
+ {
+ if(m_attack_interval.step(dtime, 0.5))
+ {
+ env->damageLocalPlayer(2);
+ }
+ }
+}
+
+void Oerkki1CAO::processMessage(const std::string &data)
+{
+ //dstream<<"Oerkki1CAO: Got message"<<std::endl;
+ std::istringstream is(data, std::ios::binary);
+ // command
+ u8 cmd = readU8(is);
+ if(cmd == 0)
+ {
+ // pos
+ m_position = readV3F1000(is);
+ pos_translator.update(m_position);
+ // yaw
+ m_yaw = readF1000(is);
+ updateNodePos();
+ }
+}
+
+void Oerkki1CAO::initialize(const std::string &data)
+{
+ //dstream<<"Oerkki1CAO: Got init data"<<std::endl;
+
+ {
+ std::istringstream is(data, std::ios::binary);
+ // version
+ u8 version = readU8(is);
+ // check version
+ if(version != 0)
+ return;
+ // pos
+ m_position = readV3F1000(is);
+ pos_translator.init(m_position);
+ }
+
+ updateNodePos();
+}
+
diff --git a/src/clientobject.h b/src/clientobject.h
index 569e9eca6..8d211fef3 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "activeobject.h"
+#include "utility.h"
/*
@@ -267,5 +268,49 @@ private:
SmoothTranslator pos_translator;
};
+/*
+ Oerkki1CAO
+*/
+
+class Oerkki1CAO : public ClientActiveObject
+{
+public:
+ Oerkki1CAO();
+ virtual ~Oerkki1CAO();
+
+ u8 getType() const
+ {
+ return ACTIVEOBJECT_TYPE_OERKKI1;
+ }
+
+ static ClientActiveObject* create();
+
+ void addToScene(scene::ISceneManager *smgr);
+ void removeFromScene();
+ void updateLight(u8 light_at_pos);
+ v3s16 getLightPosition();
+ void updateNodePos();
+
+ void step(float dtime, ClientEnvironment *env);
+
+ void processMessage(const std::string &data);
+
+ void initialize(const std::string &data);
+
+ core::aabbox3d<f32>* getSelectionBox()
+ {return &m_selection_box;}
+ v3f getPosition()
+ {return pos_translator.vect_show;}
+ //{return m_position;}
+
+private:
+ IntervalLimiter m_attack_interval;
+ core::aabbox3d<f32> m_selection_box;
+ scene::IMeshSceneNode *m_node;
+ v3f m_position;
+ float m_yaw;
+ SmoothTranslator pos_translator;
+};
+
#endif
diff --git a/src/clientserver.h b/src/clientserver.h
index fadafed5f..46ffa5eab 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -33,15 +33,18 @@ enum ToClientCommand
[0] u16 TOSERVER_INIT
[2] u8 deployed version
- [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
- [4] u64 map seed (new as of 2011-02-27)
+ [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
+ ([4] u64 map seed (new as of 2011-02-27))
+
+ NOTE: The position in here is deprecated; position is
+ explicitly sent afterwards
*/
TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks
TOCLIENT_ADDNODE = 0x21,
TOCLIENT_REMOVENODE = 0x22,
- TOCLIENT_PLAYERPOS = 0x23,
+ TOCLIENT_PLAYERPOS = 0x23, // Obsolete
/*
[0] u16 command
// Followed by an arbitary number of these:
@@ -62,9 +65,9 @@ enum ToClientCommand
[N] char[20] name
*/
- TOCLIENT_OPT_BLOCK_NOT_FOUND = 0x25, // Not used
+ TOCLIENT_OPT_BLOCK_NOT_FOUND = 0x25, // Obsolete
- TOCLIENT_SECTORMETA = 0x26, // Not used
+ TOCLIENT_SECTORMETA = 0x26, // Obsolete
/*
[0] u16 command
[2] u8 sector count
@@ -134,6 +137,19 @@ enum ToClientCommand
}
*/
+ TOCLIENT_HP = 0x33,
+ /*
+ u16 command
+ u8 hp
+ */
+
+ TOCLIENT_MOVE_PLAYER = 0x34,
+ /*
+ u16 command
+ v3f1000 player position
+ f1000 player pitch
+ f1000 player yaw
+ */
};
enum ToServerCommand
@@ -155,9 +171,9 @@ enum ToServerCommand
[0] u16 TOSERVER_INIT2
*/
- TOSERVER_GETBLOCK=0x20, // Not used
- TOSERVER_ADDNODE = 0x21, // Not used
- TOSERVER_REMOVENODE = 0x22, // deprecated
+ TOSERVER_GETBLOCK=0x20, // Obsolete
+ TOSERVER_ADDNODE = 0x21, // Obsolete
+ TOSERVER_REMOVENODE = 0x22, // Obsolete
TOSERVER_PLAYERPOS = 0x23,
/*
@@ -186,7 +202,7 @@ enum ToServerCommand
...
*/
- TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // deprecated
+ TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // Obsolete
/*
[0] u16 command
[2] v3s16 pos
@@ -218,9 +234,9 @@ enum ToServerCommand
3: digging completed
*/
- TOSERVER_RELEASE = 0x29, // Not used
+ TOSERVER_RELEASE = 0x29, // Obsolete
- TOSERVER_SIGNTEXT = 0x30,
+ TOSERVER_SIGNTEXT = 0x30, // Old signs
/*
u16 command
v3s16 blockpos
@@ -257,7 +273,12 @@ enum ToServerCommand
[3] u16 id
[5] u16 item
*/
-
+
+ TOSERVER_DAMAGE = 0x35,
+ /*
+ u16 command
+ u8 amount
+ */
};
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)
diff --git a/src/collision.cpp b/src/collision.cpp
index 83cefe4d1..63186a84a 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -70,6 +70,7 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
/*
Go through every node around the object
+ TODO: Calculate the range of nodes that need to be checked
*/
for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
diff --git a/src/collision.h b/src/collision.h
index 172431401..9c913c6a9 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -38,6 +38,16 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
f32 dtime, v3f &pos_f, v3f &speed_f);
//{return collisionMoveResult();}
+enum CollisionType
+{
+ COLLISION_FALL
+};
+
+struct CollisionInfo
+{
+ CollisionType t;
+ f32 speed;
+};
#endif
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 2a548d406..b5d863914 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -55,6 +55,7 @@ void set_default_settings()
g_settings.setDefault("enable_experimental", "false");
g_settings.setDefault("creative_mode", "false");
+ g_settings.setDefault("enable_damage", "false"); //TODO: Set to true
g_settings.setDefault("objectdata_interval", "0.2");
g_settings.setDefault("active_object_range", "2");
diff --git a/src/environment.cpp b/src/environment.cpp
index 3f95ed9f9..b3055ca6f 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h"
#include "filesys.h"
#include "porting.h"
+#include "collision.h"
Environment::Environment()
{
@@ -377,6 +378,55 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
}
}
+#if 0
+void spawnRandomObjects(MapBlock *block)
+{
+ for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+ for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ {
+ bool last_node_walkable = false;
+ for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+ {
+ v3s16 p(x0,y0,z0);
+ MapNode n = block->getNodeNoEx(p);
+ if(n.d == CONTENT_IGNORE)
+ continue;
+ if(content_features(n.d).liquid_type != LIQUID_NONE)
+ continue;
+ if(content_features(n.d).walkable)
+ {
+ last_node_walkable = true;
+ continue;
+ }
+ if(last_node_walkable)
+ {
+ // If block contains light information
+ if(content_features(n.d).param_type == CPT_LIGHT)
+ {
+ if(n.getLight(LIGHTBANK_DAY) <= 5)
+ {
+ if(myrand() % 1000 == 0)
+ {
+ v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
+ pos_f.Y -= BS*0.4;
+ ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
+ std::string data = obj->getStaticData();
+ StaticObject s_obj(obj->getType(),
+ obj->getBasePosition(), data);
+ // Add one
+ block->m_static_objects.insert(0, s_obj);
+ delete obj;
+ block->setChangedFlag();
+ }
+ }
+ }
+ }
+ last_node_walkable = false;
+ }
+ }
+}
+#endif
+
void ServerEnvironment::step(float dtime)
{
DSTACK(__FUNCTION_NAME);
@@ -429,26 +479,29 @@ void ServerEnvironment::step(float dtime)
}
}
}
-
+
/*
Step active objects
*/
-
- bool send_recommended = false;
- m_send_recommended_timer += dtime;
- if(m_send_recommended_timer > 0.15)
{
- m_send_recommended_timer = 0;
- send_recommended = true;
- }
+ //TimeTaker timer("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, send_recommended);
+ bool send_recommended = false;
+ m_send_recommended_timer += dtime;
+ if(m_send_recommended_timer > 0.15)
+ {
+ m_send_recommended_timer = 0;
+ send_recommended = true;
+ }
+
+ 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, send_recommended);
+ }
}
if(m_object_management_interval.step(dtime, 0.5))
@@ -506,7 +559,7 @@ void ServerEnvironment::step(float dtime)
const s16 to_active_max_blocks = 3;
- const f32 to_static_max_f = (to_active_max_blocks+1)*MAP_BLOCKSIZE*BS;
+ const f32 to_static_max_f = (to_active_max_blocks+2)*MAP_BLOCKSIZE*BS;
/*
Convert stored objects from blocks near the players to active.
@@ -719,7 +772,8 @@ void ServerEnvironment::step(float dtime)
//TestSAO *obj = new TestSAO(this, 0, pos);
//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
- ServerActiveObject *obj = new RatSAO(this, 0, pos);
+ //ServerActiveObject *obj = new RatSAO(this, 0, pos);
+ ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
addActiveObject(obj);
}
#endif
@@ -976,14 +1030,18 @@ void ClientEnvironment::step(float dtime)
//TimeTaker timer("Client m_map->timerUpdate()", g_device);
m_map->timerUpdate(dtime);
}
-
+
+ // Get local player
+ LocalPlayer *lplayer = getLocalPlayer();
+ assert(lplayer);
+ // collision info queue
+ core::list<CollisionInfo> player_collisions;
+
/*
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();
+ player_speed = lplayer->getSpeed().getLength();
/*
Maximum position increment
@@ -1036,20 +1094,18 @@ void ClientEnvironment::step(float dtime)
*/
{
- Player *player = getLocalPlayer();
-
- v3f playerpos = player->getPosition();
+ v3f lplayerpos = lplayer->getPosition();
// Apply physics
if(free_move == false)
{
// Gravity
- v3f speed = player->getSpeed();
- if(player->swimming_up == false)
+ v3f speed = lplayer->getSpeed();
+ if(lplayer->swimming_up == false)
speed.Y -= 9.81 * BS * dtime_part * 2;
// Water resistance
- if(player->in_water_stable || player->in_water)
+ if(lplayer->in_water_stable || lplayer->in_water)
{
f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down;
@@ -1061,19 +1117,47 @@ void ClientEnvironment::step(float dtime)
}
}
- player->setSpeed(speed);
+ lplayer->setSpeed(speed);
}
/*
- Move the player.
+ Move the lplayer.
This also does collision detection.
*/
- player->move(dtime_part, *m_map, position_max_increment);
+ lplayer->move(dtime_part, *m_map, position_max_increment,
+ &player_collisions);
}
}
while(dtime_downcount > 0.001);
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
+
+ for(core::list<CollisionInfo>::Iterator
+ i = player_collisions.begin();
+ i != player_collisions.end(); i++)
+ {
+ CollisionInfo &info = *i;
+ if(info.t == COLLISION_FALL)
+ {
+ //f32 tolerance = BS*10; // 2 without damage
+ f32 tolerance = BS*12; // 3 without damage
+ f32 factor = 1;
+ if(info.speed > tolerance)
+ {
+ f32 damage_f = (info.speed - tolerance)/BS*factor;
+ u16 damage = (u16)(damage_f+0.5);
+ if(lplayer->hp > damage)
+ lplayer->hp -= damage;
+ else
+ lplayer->hp = 0;
+
+ ClientEnvEvent event;
+ event.type = CEE_PLAYER_DAMAGE;
+ event.player_damage.amount = damage;
+ m_client_event_queue.push_back(event);
+ }
+ }
+ }
/*
Stuff that can be done in an arbitarily large dtime
@@ -1287,6 +1371,30 @@ void ClientEnvironment::processActiveObjectMessage(u16 id,
obj->processMessage(data);
}
+/*
+ Callbacks for activeobjects
+*/
+
+void ClientEnvironment::damageLocalPlayer(u8 damage)
+{
+ LocalPlayer *lplayer = getLocalPlayer();
+ assert(lplayer);
+
+ if(lplayer->hp > damage)
+ lplayer->hp -= damage;
+ else
+ lplayer->hp = 0;
+
+ ClientEnvEvent event;
+ event.type = CEE_PLAYER_DAMAGE;
+ event.player_damage.amount = damage;
+ m_client_event_queue.push_back(event);
+}
+
+/*
+ Client likes to call these
+*/
+
void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
core::array<DistanceSortedActiveObject> &dest)
{
@@ -1307,6 +1415,16 @@ void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
}
}
+ClientEnvEvent ClientEnvironment::getClientEvent()
+{
+ if(m_client_event_queue.size() == 0)
+ {
+ ClientEnvEvent event;
+ event.type = CEE_NONE;
+ return event;
+ }
+ return m_client_event_queue.pop_front();
+}
#endif // #ifndef SERVER
diff --git a/src/environment.h b/src/environment.h
index e82cea6ae..00192d262 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -170,6 +170,24 @@ private:
Client uses an environment mutex.
*/
+enum ClientEnvEventType
+{
+ CEE_NONE,
+ CEE_PLAYER_DAMAGE
+};
+
+struct ClientEnvEvent
+{
+ ClientEnvEventType type;
+ union {
+ struct{
+ } none;
+ struct{
+ u8 amount;
+ } player_damage;
+ };
+};
+
class ClientEnvironment : public Environment
{
public:
@@ -214,15 +232,29 @@ public:
void removeActiveObject(u16 id);
void processActiveObjectMessage(u16 id, const std::string &data);
+
+ /*
+ Callbacks for activeobjects
+ */
+
+ void damageLocalPlayer(u8 damage);
+
+ /*
+ Client likes to call these
+ */
// Get all nearby objects
void getActiveObjects(v3f origin, f32 max_d,
core::array<DistanceSortedActiveObject> &dest);
+ // Get event from queue. CEE_NONE is returned if queue is empty.
+ ClientEnvEvent getClientEvent();
+
private:
ClientMap *m_map;
scene::ISceneManager *m_smgr;
core::map<u16, ClientActiveObject*> m_active_objects;
+ Queue<ClientEnvEvent> m_client_event_queue;
};
#endif
diff --git a/src/inventory.h b/src/inventory.h
index d2d23542e..f162952d3 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -369,6 +369,12 @@ public:
basename = "tool_stoneaxe.png";
else if(m_toolname == "SteelAxe")
basename = "tool_steelaxe.png";
+ else if(m_toolname == "WSword")
+ basename = "tool_woodsword.png";
+ else if(m_toolname == "STSword")
+ basename = "tool_stonesword.png";
+ else if(m_toolname == "SteelSword")
+ basename = "tool_steelsword.png";
else
basename = "cloud.png";
diff --git a/src/main.cpp b/src/main.cpp
index bf5f3182b..436e5babc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -93,6 +93,10 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
SUGG: Calculate lighting per vertex to get a lighting effect like in
bartwe's game
+SUGG: Background music based on cellular automata?
+ http://www.earslap.com/projectslab/otomata
+
+
Gaming ideas:
-------------
@@ -126,6 +130,12 @@ Game content:
- You can drop on top of it, and have some time to attack there
before he shakes you off
+- Maybe the difficulty could come from monsters getting tougher in
+ far-away places, and the player starting to need something from
+ there when time goes by.
+ - The player would have some of that stuff at the beginning, and
+ would need new supplies of it when it runs out
+
Documentation:
--------------
@@ -1210,7 +1220,7 @@ void updateViewingRange(f32 frametime_in, Client *client)
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
- Inventory *inventory)
+ Inventory *inventory, s32 halfheartcount)
{
InventoryList *mainlist = inventory->getList("main");
if(mainlist == NULL)
@@ -1259,6 +1269,40 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
drawInventoryItem(driver, font, item, rect, NULL);
}
}
+
+ /*
+ Draw hearts
+ */
+ {
+ video::ITexture *heart_texture =
+ driver->getTexture(porting::getDataPath("heart.png").c_str());
+ v2s32 p = pos + v2s32(0, -20);
+ for(s32 i=0; i<halfheartcount/2; i++)
+ {
+ const video::SColor color(255,255,255,255);
+ const video::SColor colors[] = {color,color,color,color};
+ core::rect<s32> rect(0,0,16,16);
+ rect += p;
+ driver->draw2DImage(heart_texture, rect,
+ core::rect<s32>(core::position2d<s32>(0,0),
+ core::dimension2di(heart_texture->getOriginalSize())),
+ NULL, colors, true);
+ p += v2s32(20,0);
+ }
+ if(halfheartcount % 2 == 1)
+ {
+ const video::SColor color(255,255,255,255);
+ const video::SColor colors[] = {color,color,color,color};
+ core::rect<s32> rect(0,0,16/2,16);
+ rect += p;
+ core::dimension2di srcd(heart_texture->getOriginalSize());
+ srcd.Width /= 2;
+ driver->draw2DImage(heart_texture, rect,
+ core::rect<s32>(core::position2d<s32>(0,0), srcd),
+ NULL, colors, true);
+ p += v2s32(20,0);
+ }
+ }
}
#if 0
@@ -1519,6 +1563,215 @@ void SpeedTests()
}
}
+void getPointedNode(v3f player_position,
+ v3f camera_direction, v3f camera_position,
+ bool &nodefound, core::line3d<f32> shootline,
+ v3s16 &nodepos, v3s16 &neighbourpos,
+ core::aabbox3d<f32> &nodehilightbox,
+ f32 d)
+{
+ assert(g_client);
+
+ f32 mindistance = BS * 1001;
+
+ v3s16 pos_i = floatToInt(player_position, BS);
+
+ /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
+ <<std::endl;*/
+
+ s16 a = d;
+ s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
+ s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
+ s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
+ s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
+ s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
+ s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
+
+ for(s16 y = ystart; y <= yend; y++)
+ for(s16 z = zstart; z <= zend; z++)
+ for(s16 x = xstart; x <= xend; x++)
+ {
+ MapNode n;
+ try
+ {
+ n = g_client->getNode(v3s16(x,y,z));
+ if(content_pointable(n.d) == false)
+ continue;
+ }
+ catch(InvalidPositionException &e)
+ {
+ continue;
+ }
+
+ v3s16 np(x,y,z);
+ v3f npf = intToFloat(np, BS);
+
+ f32 d = 0.01;
+
+ v3s16 dirs[6] = {
+ v3s16(0,0,1), // back
+ v3s16(0,1,0), // top
+ v3s16(1,0,0), // right
+ v3s16(0,0,-1), // front
+ v3s16(0,-1,0), // bottom
+ v3s16(-1,0,0), // left
+ };
+
+ /*
+ Meta-objects
+ */
+ if(n.d == CONTENT_TORCH)
+ {
+ v3s16 dir = unpackDir(n.dir);
+ v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
+ dir_f *= BS/2 - BS/6 - BS/20;
+ v3f cpf = npf + dir_f;
+ f32 distance = (cpf - camera_position).getLength();
+
+ core::aabbox3d<f32> box;
+
+ // bottom
+ if(dir == v3s16(0,-1,0))
+ {
+ box = core::aabbox3d<f32>(
+ npf - v3f(BS/6, BS/2, BS/6),
+ npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
+ );
+ }
+ // top
+ else if(dir == v3s16(0,1,0))
+ {
+ box = core::aabbox3d<f32>(
+ npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
+ npf + v3f(BS/6, BS/2, BS/6)
+ );
+ }
+ // side
+ else
+ {
+ box = core::aabbox3d<f32>(
+ cpf - v3f(BS/6, BS/3, BS/6),
+ cpf + v3f(BS/6, BS/3, BS/6)
+ );
+ }
+
+ if(distance < mindistance)
+ {
+ if(box.intersectsWithLine(shootline))
+ {
+ nodefound = true;
+ nodepos = np;
+ neighbourpos = np;
+ mindistance = distance;
+ nodehilightbox = box;
+ }
+ }
+ }
+ else if(n.d == CONTENT_SIGN_WALL)
+ {
+ v3s16 dir = unpackDir(n.dir);
+ v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
+ dir_f *= BS/2 - BS/6 - BS/20;
+ v3f cpf = npf + dir_f;
+ f32 distance = (cpf - camera_position).getLength();
+
+ v3f vertices[4] =
+ {
+ v3f(BS*0.42,-BS*0.35,-BS*0.4),
+ v3f(BS*0.49, BS*0.35, BS*0.4),
+ };
+
+ for(s32 i=0; i<2; i++)
+ {
+ if(dir == v3s16(1,0,0))
+ vertices[i].rotateXZBy(0);
+ if(dir == v3s16(-1,0,0))
+ vertices[i].rotateXZBy(180);
+ if(dir == v3s16(0,0,1))
+ vertices[i].rotateXZBy(90);
+ if(dir == v3s16(0,0,-1))
+ vertices[i].rotateXZBy(-90);
+ if(dir == v3s16(0,-1,0))
+ vertices[i].rotateXYBy(-90);
+ if(dir == v3s16(0,1,0))
+ vertices[i].rotateXYBy(90);
+
+ vertices[i] += npf;
+ }
+
+ core::aabbox3d<f32> box;
+
+ box = core::aabbox3d<f32>(vertices[0]);
+ box.addInternalPoint(vertices[1]);
+
+ if(distance < mindistance)
+ {
+ if(box.intersectsWithLine(shootline))
+ {
+ nodefound = true;
+ nodepos = np;
+ neighbourpos = np;
+ mindistance = distance;
+ nodehilightbox = box;
+ }
+ }
+ }
+ /*
+ Regular blocks
+ */
+ else
+ {
+ for(u16 i=0; i<6; i++)
+ {
+ v3f dir_f = v3f(dirs[i].X,
+ dirs[i].Y, dirs[i].Z);
+ v3f centerpoint = npf + dir_f * BS/2;
+ f32 distance =
+ (centerpoint - camera_position).getLength();
+
+ if(distance < mindistance)
+ {
+ core::CMatrix4<f32> m;
+ m.buildRotateFromTo(v3f(0,0,1), dir_f);
+
+ // This is the back face
+ v3f corners[2] = {
+ v3f(BS/2, BS/2, BS/2),
+ v3f(-BS/2, -BS/2, BS/2+d)
+ };
+
+ for(u16 j=0; j<2; j++)
+ {
+ m.rotateVect(corners[j]);
+ corners[j] += npf;
+ }
+
+ core::aabbox3d<f32> facebox(corners[0]);
+ facebox.addInternalPoint(corners[1]);
+
+ if(facebox.intersectsWithLine(shootline))
+ {
+ nodefound = true;
+ nodepos = np;
+ neighbourpos = np + dirs[i];
+ mindistance = distance;
+
+ //nodehilightbox = facebox;
+
+ 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, BS);
+ nodebox.MinEdge += nodepos_f;
+ nodebox.MaxEdge += nodepos_f;
+ nodehilightbox = nodebox;
+ }
+ } // if distance < mindistance
+ } // for dirs
+ } // regular block
+ } // for coords
+}
+
int main(int argc, char *argv[])
{
/*
@@ -2148,30 +2401,14 @@ int main(int argc, char *argv[])
//video::SColor skycolor = video::SColor(255,90,140,200);
//video::SColor skycolor = video::SColor(255,166,202,244);
- video::SColor skycolor = video::SColor(255,120,185,244);
+ //video::SColor skycolor = video::SColor(255,120,185,244);
+ video::SColor skycolor = video::SColor(255,140,186,250);
camera->setFOV(FOV_ANGLE);
// Just so big a value that everything rendered is visible
camera->setFarValue(100000*BS);
- /*
- Lighting test code. Doesn't quite work this way.
- The CPU-computed lighting is good.
- */
-
- /*
- smgr->addLightSceneNode(NULL,
- v3f(0, BS*1000000, 0),
- video::SColorf(0.3,0.3,0.3),
- BS*10000000);
-
- smgr->setAmbientLight(video::SColorf(0.0, 0.0, 0.0));
-
- scene::ILightSceneNode *light = smgr->addLightSceneNode(camera,
- v3f(0, 0, 0), video::SColorf(0.5,0.5,0.5), BS*4);
- */
-
f32 camera_yaw = 0; // "right/left"
f32 camera_pitch = 0; // "up/down"
@@ -2226,6 +2463,8 @@ int main(int argc, char *argv[])
core::list<float> frametime_log;
+ float damage_flash_timer = 0;
+
/*
Main loop
*/
@@ -2453,6 +2692,16 @@ int main(int argc, char *argv[])
);
client.setPlayerControl(control);
}
+
+ /*
+ Run server
+ */
+
+ if(server != NULL)
+ {
+ //TimeTaker timer("server->step(dtime)");
+ server->step(dtime);
+ }
/*
Process environment
@@ -2464,12 +2713,28 @@ int main(int argc, char *argv[])
//client.step(dtime_avg1);
}
- if(server != NULL)
+ // Read client events
+ for(;;)
{
- //TimeTaker timer("server->step(dtime)");
- server->step(dtime);
+ ClientEvent event = client.getClientEvent();
+ if(event.type == CE_NONE)
+ {
+ break;
+ }
+ else if(event.type == CE_PLAYER_DAMAGE)
+ {
+ //u16 damage = event.player_damage.amount;
+ //dstream<<"Player damage: "<<damage<<std::endl;
+ damage_flash_timer = 0.05;
+ }
+ else if(event.type == CE_PLAYER_FORCE_MOVE)
+ {
+ camera_yaw = event.player_force_move.yaw;
+ camera_pitch = event.player_force_move.pitch;
+ }
}
-
+
+ // Get player position
v3f player_position = client.getPlayerPosition();
//TimeTaker //timer2("//timer2");
@@ -2637,22 +2902,6 @@ int main(int argc, char *argv[])
else if(g_input->getRightClicked())
{
std::cout<<DTIME<<"Right-clicked object"<<std::endl;
-#if 0
- /*
- Check if we want to modify the object ourselves
- */
- if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)
- {
- }
- /*
- Otherwise pass the event to the server as-is
- */
- else
- {
- client.clickObject(1, selected_object->getBlock()->getPos(),
- selected_object->getId(), g_selected_item);
- }
-#endif
}
}
else // selected_object == NULL
@@ -2666,205 +2915,13 @@ int main(int argc, char *argv[])
v3s16 nodepos;
v3s16 neighbourpos;
core::aabbox3d<f32> nodehilightbox;
- f32 mindistance = BS * 1001;
-
- v3s16 pos_i = floatToInt(player_position, BS);
-
- /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
- <<std::endl;*/
-
- s16 a = d;
- s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
- s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
- s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
- s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
- s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
- s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
-
- for(s16 y = ystart; y <= yend; y++)
- for(s16 z = zstart; z <= zend; z++)
- for(s16 x = xstart; x <= xend; x++)
- {
- MapNode n;
- try
- {
- n = client.getNode(v3s16(x,y,z));
- if(content_pointable(n.d) == false)
- continue;
- }
- catch(InvalidPositionException &e)
- {
- continue;
- }
-
- v3s16 np(x,y,z);
- v3f npf = intToFloat(np, BS);
-
- f32 d = 0.01;
-
- v3s16 dirs[6] = {
- v3s16(0,0,1), // back
- v3s16(0,1,0), // top
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(0,-1,0), // bottom
- v3s16(-1,0,0), // left
- };
-
- /*
- Meta-objects
- */
- if(n.d == CONTENT_TORCH)
- {
- v3s16 dir = unpackDir(n.dir);
- v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
- dir_f *= BS/2 - BS/6 - BS/20;
- v3f cpf = npf + dir_f;
- f32 distance = (cpf - camera_position).getLength();
-
- core::aabbox3d<f32> box;
-
- // bottom
- if(dir == v3s16(0,-1,0))
- {
- box = core::aabbox3d<f32>(
- npf - v3f(BS/6, BS/2, BS/6),
- npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
- );
- }
- // top
- else if(dir == v3s16(0,1,0))
- {
- box = core::aabbox3d<f32>(
- npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
- npf + v3f(BS/6, BS/2, BS/6)
- );
- }
- // side
- else
- {
- box = core::aabbox3d<f32>(
- cpf - v3f(BS/6, BS/3, BS/6),
- cpf + v3f(BS/6, BS/3, BS/6)
- );
- }
-
- if(distance < mindistance)
- {
- if(box.intersectsWithLine(shootline))
- {
- nodefound = true;
- nodepos = np;
- neighbourpos = np;
- mindistance = distance;
- nodehilightbox = box;
- }
- }
- }
- else if(n.d == CONTENT_SIGN_WALL)
- {
- v3s16 dir = unpackDir(n.dir);
- v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
- dir_f *= BS/2 - BS/6 - BS/20;
- v3f cpf = npf + dir_f;
- f32 distance = (cpf - camera_position).getLength();
-
- v3f vertices[4] =
- {
- v3f(BS*0.42,-BS*0.35,-BS*0.4),
- v3f(BS*0.49, BS*0.35, BS*0.4),
- };
-
- for(s32 i=0; i<2; i++)
- {
- if(dir == v3s16(1,0,0))
- vertices[i].rotateXZBy(0);
- if(dir == v3s16(-1,0,0))
- vertices[i].rotateXZBy(180);
- if(dir == v3s16(0,0,1))
- vertices[i].rotateXZBy(90);
- if(dir == v3s16(0,0,-1))
- vertices[i].rotateXZBy(-90);
- if(dir == v3s16(0,-1,0))
- vertices[i].rotateXYBy(-90);
- if(dir == v3s16(0,1,0))
- vertices[i].rotateXYBy(90);
-
- vertices[i] += npf;
- }
-
- core::aabbox3d<f32> box;
-
- box = core::aabbox3d<f32>(vertices[0]);
- box.addInternalPoint(vertices[1]);
-
- if(distance < mindistance)
- {
- if(box.intersectsWithLine(shootline))
- {
- nodefound = true;
- nodepos = np;
- neighbourpos = np;
- mindistance = distance;
- nodehilightbox = box;
- }
- }
- }
- /*
- Regular blocks
- */
- else
- {
- for(u16 i=0; i<6; i++)
- {
- v3f dir_f = v3f(dirs[i].X,
- dirs[i].Y, dirs[i].Z);
- v3f centerpoint = npf + dir_f * BS/2;
- f32 distance =
- (centerpoint - camera_position).getLength();
-
- if(distance < mindistance)
- {
- core::CMatrix4<f32> m;
- m.buildRotateFromTo(v3f(0,0,1), dir_f);
-
- // This is the back face
- v3f corners[2] = {
- v3f(BS/2, BS/2, BS/2),
- v3f(-BS/2, -BS/2, BS/2+d)
- };
-
- for(u16 j=0; j<2; j++)
- {
- m.rotateVect(corners[j]);
- corners[j] += npf;
- }
-
- core::aabbox3d<f32> facebox(corners[0]);
- facebox.addInternalPoint(corners[1]);
-
- if(facebox.intersectsWithLine(shootline))
- {
- nodefound = true;
- nodepos = np;
- neighbourpos = np + dirs[i];
- mindistance = distance;
-
- //nodehilightbox = facebox;
-
- 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, BS);
- nodebox.MinEdge += nodepos_f;
- nodebox.MaxEdge += nodepos_f;
- nodehilightbox = nodebox;
- }
- } // if distance < mindistance
- } // for dirs
- } // regular block
- } // for coords
+ getPointedNode(player_position,
+ camera_direction, camera_position,
+ nodefound, shootline,
+ nodepos, neighbourpos,
+ nodehilightbox, d);
+
static float nodig_delay_counter = 0.0;
if(nodefound)
@@ -3430,10 +3487,26 @@ int main(int argc, char *argv[])
*/
{
draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),
- hotbar_imagesize, hotbar_itemcount, &local_inventory);
+ hotbar_imagesize, hotbar_itemcount, &local_inventory,
+ client.getHP());
+ }
+
+ /*
+ Damage flash
+ */
+ if(damage_flash_timer > 0.0)
+ {
+ damage_flash_timer -= dtime;
+
+ video::SColor color(128,255,0,0);
+ driver->draw2DRectangle(color,
+ core::rect<s32>(0,0,screensize.X,screensize.Y),
+ NULL);
}
- // End drawing
+ /*
+ End scene
+ */
{
TimeTaker timer("endScene");
driver->endScene();
diff --git a/src/map.cpp b/src/map.cpp
index 2a92f6733..7e4fc4f47 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -37,8 +37,8 @@ Map::Map(std::ostream &dout):
m_dout(dout),
m_sector_cache(NULL)
{
- m_sector_mutex.Init();
- assert(m_sector_mutex.IsInitialized());
+ /*m_sector_mutex.Init();
+ assert(m_sector_mutex.IsInitialized());*/
}
Map::~Map()
@@ -104,7 +104,7 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
return getSectorNoGenerateNoExNoLock(p);
}
@@ -1347,7 +1347,7 @@ bool Map::dayNightDiffed(v3s16 blockpos)
*/
void Map::timerUpdate(float dtime)
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Iterator si;
@@ -1397,7 +1397,7 @@ void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
core::list<v3s16> *deleted_blocks)
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::list<v2s16> sector_deletion_queue;
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
@@ -2163,6 +2163,18 @@ void addRandomObjects(MapBlock *block)
block->m_static_objects.insert(0, s_obj);
delete obj;
}
+ if(myrand() % 300 == 0)
+ {
+ v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
+ pos_f.Y -= BS*0.4;
+ ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
+ std::string data = obj->getStaticData();
+ StaticObject s_obj(obj->getType(),
+ obj->getBasePosition(), data);
+ // Add one
+ block->m_static_objects.insert(0, s_obj);
+ delete obj;
+ }
}
}
}
@@ -4714,7 +4726,7 @@ plan_b:
// This won't work if proper generation is disabled
if(m_chunksize == 0)
return WATER_LEVEL+2;
- double level = base_rock_level_2d(m_seed, p2d);
+ double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
return (s16)level;
}
@@ -4794,7 +4806,7 @@ void ServerMap::save(bool only_changed)
u32 block_count = 0;
{ //sectorlock
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
for(; i.atEnd() == false; i++)
@@ -4856,7 +4868,7 @@ void ServerMap::loadAll()
dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
s32 counter = 0;
s32 printed_counter = -100000;
@@ -5163,7 +5175,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
MapSector *sector = NULL;
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
try{
sector = loadSectorMeta(sectorsubdir);
@@ -5410,7 +5422,7 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
ClientMapSector *sector = new ClientMapSector(this, p2d);
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector);
}
@@ -5422,7 +5434,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
DSTACK(__FUNCTION_NAME);
ClientMapSector *sector = NULL;
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
@@ -5435,7 +5447,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
{
sector = new ClientMapSector(this, p2d);
{
- JMutexAutoLock lock(m_sector_mutex);
+ //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector);
}
}
diff --git a/src/map.h b/src/map.h
index 206dc7d7b..1cd021f52 100644
--- a/src/map.h
+++ b/src/map.h
@@ -287,6 +287,11 @@ public:
void removeNodeMetadata(v3s16 p);
void nodeMetadataStep(float dtime,
core::map<v3s16, MapBlock*> &changed_blocks);
+
+ /*
+ Misc.
+ */
+ core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
/*
Variables
@@ -298,16 +303,13 @@ protected:
core::map<MapEventReceiver*, bool> m_event_receivers;
- // Mutex is important because on client map is accessed asynchronously
core::map<v2s16, MapSector*> m_sectors;
- JMutex m_sector_mutex;
+ //JMutex m_sector_mutex;
// Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache;
v2s16 m_sector_cache_p;
- //WrapperHeightmap m_hwrapper;
-
// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;
};
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 38c081eec..5b8bc7b9f 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -1924,9 +1924,19 @@ void MapBlock::serialize(std::ostream &os, u8 version)
*/
if(version >= 14)
{
- std::ostringstream oss(std::ios_base::binary);
- m_node_metadata.serialize(oss);
- os<<serializeString(oss.str());
+ if(version <= 15)
+ {
+ std::ostringstream oss(std::ios_base::binary);
+ m_node_metadata.serialize(oss);
+ os<<serializeString(oss.str());
+ }
+ else
+ {
+ std::ostringstream oss(std::ios_base::binary);
+ m_node_metadata.serialize(oss);
+ compressZlib(oss.str(), os);
+ //os<<serializeLongString(oss.str());
+ }
}
}
}
@@ -2055,9 +2065,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
{
// Ignore errors
try{
- std::string data = deSerializeString(is);
- std::istringstream iss(data, std::ios_base::binary);
- m_node_metadata.deSerialize(iss);
+ if(version <= 15)
+ {
+ std::string data = deSerializeString(is);
+ std::istringstream iss(data, std::ios_base::binary);
+ m_node_metadata.deSerialize(iss);
+ }
+ else
+ {
+ //std::string data = deSerializeLongString(is);
+ std::ostringstream oss(std::ios_base::binary);
+ decompressZlib(is, oss);
+ std::istringstream iss(oss.str(), std::ios_base::binary);
+ m_node_metadata.deSerialize(iss);
+ }
}
catch(SerializationError &e)
{
diff --git a/src/player.cpp b/src/player.cpp
index 8f594eee6..31415b6b2 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -33,6 +33,7 @@ Player::Player():
in_water_stable(false),
swimming_up(false),
craftresult_is_preview(true),
+ hp(20),
peer_id(PEER_ID_INEXISTENT),
m_pitch(0),
m_yaw(0),
@@ -102,6 +103,7 @@ void Player::serialize(std::ostream &os)
args.setFloat("yaw", m_yaw);
args.setV3F("position", m_position);
args.setBool("craftresult_is_preview", craftresult_is_preview);
+ args.setS32("hp", hp);
args.writeLines(os);
@@ -138,6 +140,11 @@ void Player::deSerialize(std::istream &is)
}catch(SettingNotFoundException &e){
craftresult_is_preview = true;
}
+ try{
+ hp = args.getS32("hp");
+ }catch(SettingNotFoundException &e){
+ hp = 20;
+ }
inventory.deSerialize(is);
}
@@ -276,7 +283,8 @@ LocalPlayer::~LocalPlayer()
{
}
-void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
+void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
+ core::list<CollisionInfo> *collision_info)
{
v3f position = getPosition();
v3f oldpos = position;
@@ -530,9 +538,23 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
*/
if(other_axes_overlap && main_axis_collides)
{
+ v3f old_speed = m_speed;
+
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
position -= position.dotProduct(dirs[i]) * dirs[i];
position += oldpos.dotProduct(dirs[i]) * dirs[i];
+
+ if(collision_info)
+ {
+ // Report fall collision
+ if(old_speed.Y < m_speed.Y - 0.1)
+ {
+ CollisionInfo info;
+ info.t = COLLISION_FALL;
+ info.speed = m_speed.Y - old_speed.Y;
+ collision_info->push_back(info);
+ }
+ }
}
}
@@ -617,6 +639,11 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
setPosition(position);
}
+void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
+{
+ move(dtime, map, pos_max_d, NULL);
+}
+
void LocalPlayer::applyControl(float dtime)
{
// Clear stuff
diff --git a/src/player.h b/src/player.h
index 2eaeaae9a..03fba1e2c 100644
--- a/src/player.h
+++ b/src/player.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "inventory.h"
+#include "collision.h"
#define PLAYERNAME_SIZE 20
@@ -124,6 +125,8 @@ public:
bool craftresult_is_preview;
+ u16 hp;
+
u16 peer_id;
protected:
@@ -325,6 +328,8 @@ public:
return true;
}
+ void move(f32 dtime, Map &map, f32 pos_max_d,
+ core::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d);
void applyControl(float dtime);
diff --git a/src/serialization.cpp b/src/serialization.cpp
index c324ca0fd..6a43d9190 100644
--- a/src/serialization.cpp
+++ b/src/serialization.cpp
@@ -105,6 +105,12 @@ void compressZlib(SharedBuffer<u8> data, std::ostream &os)
}
+void compressZlib(const std::string &data, std::ostream &os)
+{
+ SharedBuffer<u8> databuf((u8*)data.c_str(), data.size());
+ compressZlib(databuf, os);
+}
+
void decompressZlib(std::istream &is, std::ostream &os)
{
z_stream z;
diff --git a/src/serialization.h b/src/serialization.h
index c87162e69..c7cafc5d1 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -48,17 +48,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
13: (dev) Mapgen v2
14: (dev) NodeMetadata
15: (dev) StaticObjects
+ 16: (dev) larger maximum size of node metadata, and compression
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 15
+#define SER_FMT_VER_HIGHEST 16
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0
#define ser_ver_supported(v) (v >= SER_FMT_VER_LOWEST && v <= SER_FMT_VER_HIGHEST)
+void compressZlib(SharedBuffer<u8> data, std::ostream &os);
+void compressZlib(const std::string &data, std::ostream &os);
+void decompressZlib(std::istream &is, std::ostream &os);
+
void compress(SharedBuffer<u8> data, std::ostream &os, u8 version);
+//void compress(const std::string &data, std::ostream &os, u8 version);
void decompress(std::istream &is, std::ostream &os, u8 version);
/*class Serializable
diff --git a/src/server.cpp b/src/server.cpp
index 154603a47..ee7a035e6 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -959,6 +959,8 @@ Server::Server(
Server::~Server()
{
+ dstream<<"Server::~Server()"<<std::endl;
+
/*
Send shutdown message
*/
@@ -980,13 +982,18 @@ Server::~Server()
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
- SendChatMessage(client->peer_id, line);
+ try{
+ SendChatMessage(client->peer_id, line);
+ }
+ catch(con::PeerNotFoundException &e)
+ {}
}
}
/*
Save players
*/
+ dstream<<"Server: Saving players"<<std::endl;
m_env.serializePlayers(m_mapsavedir);
/*
@@ -1046,11 +1053,6 @@ void Server::stop()
m_emergethread.stop();
dout_server<<"Server: Threads stopped"<<std::endl;
-
- dout_server<<"Server: Saving players"<<std::endl;
- // Save players
- // FIXME: Apparently this does not do anything here
- //m_env.serializePlayers(m_mapsavedir);
}
void Server::step(float dtime)
@@ -1550,6 +1552,8 @@ void Server::AsyncRunStep()
Step node metadata
*/
{
+ //TimeTaker timer("Step node metadata");
+
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
@@ -1781,20 +1785,30 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
data[20+3-1] = 0;
player->updateName((const char*)&data[3]);
}*/
-
- // Now answer with a TOCLIENT_INIT
- SharedBuffer<u8> reply(2+1+6+8);
- writeU16(&reply[0], TOCLIENT_INIT);
- writeU8(&reply[2], deployed);
- writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
- //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
-
- // Send as reliable
- m_con.Send(peer_id, 0, reply, true);
+ /*
+ Answer with a TOCLIENT_INIT
+ */
+ {
+ SharedBuffer<u8> reply(2+1+6+8);
+ writeU16(&reply[0], TOCLIENT_INIT);
+ writeU8(&reply[2], deployed);
+ writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+ //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
+ writeU64(&reply[2+1+6], 0); // no seed
+
+ // Send as reliable
+ m_con.Send(peer_id, 0, reply, true);
+ }
+
+ /*
+ Send complete position information
+ */
+ SendMovePlayer(player);
return;
}
+
if(command == TOSERVER_INIT2)
{
derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
@@ -1812,7 +1826,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendPlayerInfos();
// Send inventory to player
+ UpdateCrafting(peer->id);
SendInventory(peer->id);
+
+ // Send HP
+ {
+ Player *player = m_env.getPlayer(peer_id);
+ SendPlayerHP(player);
+ }
// Send time of day
{
@@ -2005,6 +2026,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Add to inventory and send inventory
ilist->addItem(item);
+ UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
}
@@ -2026,7 +2048,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
u8 button = readU8(&data[2]);
u16 id = readS16(&data[3]);
- //u16 item_i = readU16(&data[11]);
+ u16 item_i = readU16(&data[11]);
ServerActiveObject *obj = m_env.getActiveObject(id);
@@ -2066,11 +2088,42 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
// Add to inventory and send inventory
ilist->addItem(item);
+ UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
// Remove object from environment
obj->m_removed = true;
}
+ else
+ {
+ /*
+ Item cannot be picked up. Punch it instead.
+ */
+
+ ToolItem *titem = NULL;
+ std::string toolname = "";
+
+ InventoryList *mlist = player->inventory.getList("main");
+ if(mlist != NULL)
+ {
+ InventoryItem *item = mlist->getItem(item_i);
+ if(item && (std::string)item->getName() == "ToolItem")
+ {
+ titem = (ToolItem*)item;
+ toolname = titem->getToolName();
+ }
+ }
+
+ u16 wear = obj->punch(toolname);
+
+ if(titem)
+ {
+ bool weared_out = titem->addWear(wear);
+ if(weared_out)
+ mlist->deleteItem(item_i);
+ SendInventory(player->peer_id);
+ }
+ }
}
}
}
@@ -2276,6 +2329,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
player->inventory.addItem("main", item);
// Send inventory
+ UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
}
}
@@ -2380,6 +2434,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else
mitem->remove(1);
// Send inventory
+ UpdateCrafting(peer_id);
SendInventory(peer_id);
}
@@ -2492,6 +2547,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
item->remove(dropcount);
// Send inventory
+ UpdateCrafting(peer_id);
SendInventory(peer_id);
}
}
@@ -2711,6 +2767,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else
{
// Send inventory
+ UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
}
}
@@ -2856,6 +2913,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
}
}
+ else if(command == TOSERVER_DAMAGE)
+ {
+ if(g_settings.getBool("enable_damage"))
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+ u8 damage = readU8(is);
+ if(player->hp > damage)
+ {
+ player->hp -= damage;
+ }
+ else
+ {
+ player->hp = 0;
+
+ dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
+ <<std::endl;
+
+ v3f pos = findSpawnPos(m_env.getServerMap());
+ player->setPosition(pos);
+ player->hp = 20;
+ SendMovePlayer(player);
+ SendPlayerHP(player);
+
+ //TODO: Throw items around
+ }
+ }
+
+ SendPlayerHP(player);
+ }
else
{
derr_server<<"WARNING: Server::ProcessData(): Ignoring "
@@ -2914,6 +3001,7 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
{
assert(c->current_player);
// Send inventory
+ UpdateCrafting(c->current_player->peer_id);
SendInventory(c->current_player->peer_id);
return;
}
@@ -3016,6 +3104,29 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
m_peer_change_queue.push_back(c);
}
+/*
+ Static send methods
+*/
+
+void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_HP);
+ writeU8(os, hp);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ con.Send(peer_id, 0, data, true);
+}
+
+/*
+ Non-static send methods
+*/
+
void Server::SendObjectData(float dtime)
{
DSTACK(__FUNCTION_NAME);
@@ -3082,6 +3193,306 @@ void Server::SendInventory(u16 peer_id)
assert(player);
/*
+ Serialize it
+ */
+
+ std::ostringstream os;
+ //os.imbue(std::locale("C"));
+
+ player->inventory.serialize(os);
+
+ std::string s = os.str();
+
+ SharedBuffer<u8> data(s.size()+2);
+ writeU16(&data[0], TOCLIENT_INVENTORY);
+ memcpy(&data[2], s.c_str(), s.size());
+
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ std::ostringstream os(std::ios_base::binary);
+ u8 buf[12];
+
+ // Write command
+ writeU16(buf, TOCLIENT_CHAT_MESSAGE);
+ os.write((char*)buf, 2);
+
+ // Write length
+ writeU16(buf, message.size());
+ os.write((char*)buf, 2);
+
+ // Write string
+ for(u32 i=0; i<message.size(); i++)
+ {
+ u16 w = message[i];
+ writeU16(buf, w);
+ os.write((char*)buf, 2);
+ }
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::BroadcastChatMessage(const std::wstring &message)
+{
+ for(core::map<u16, RemoteClient*>::Iterator
+ i = m_clients.getIterator();
+ i.atEnd() == false; i++)
+ {
+ // Get client and check that it is valid
+ RemoteClient *client = i.getNode()->getValue();
+ assert(client->peer_id == i.getNode()->getKey());
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ SendChatMessage(client->peer_id, message);
+ }
+}
+
+void Server::SendPlayerHP(Player *player)
+{
+ SendHP(m_con, player->peer_id, player->hp);
+}
+
+void Server::SendMovePlayer(Player *player)
+{
+ DSTACK(__FUNCTION_NAME);
+ std::ostringstream os(std::ios_base::binary);
+
+ writeU16(os, TOCLIENT_MOVE_PLAYER);
+ writeV3F1000(os, player->getPosition());
+ writeF1000(os, player->getPitch());
+ writeF1000(os, player->getYaw());
+
+ {
+ v3f pos = player->getPosition();
+ f32 pitch = player->getPitch();
+ f32 yaw = player->getYaw();
+ dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
+ <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
+ <<" pitch="<<pitch
+ <<" yaw="<<yaw
+ <<std::endl;
+ }
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(player->peer_id, 0, data, true);
+}
+
+void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
+ core::list<u16> *far_players, float far_d_nodes)
+{
+ float maxd = far_d_nodes*BS;
+ v3f p_f = intToFloat(p, BS);
+
+ // Create packet
+ u32 replysize = 8;
+ SharedBuffer<u8> reply(replysize);
+ writeU16(&reply[0], TOCLIENT_REMOVENODE);
+ writeS16(&reply[2], p.X);
+ writeS16(&reply[4], p.Y);
+ writeS16(&reply[6], p.Z);
+
+ for(core::map<u16, RemoteClient*>::Iterator
+ i = m_clients.getIterator();
+ i.atEnd() == false; i++)
+ {
+ // Get client and check that it is valid
+ RemoteClient *client = i.getNode()->getValue();
+ assert(client->peer_id == i.getNode()->getKey());
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ // Don't send if it's the same one
+ if(client->peer_id == ignore_id)
+ continue;
+
+ if(far_players)
+ {
+ // Get player
+ Player *player = m_env.getPlayer(client->peer_id);
+ if(player)
+ {
+ // If player is far away, only set modified blocks not sent
+ v3f player_pos = player->getPosition();
+ if(player_pos.getDistanceFrom(p_f) > maxd)
+ {
+ far_players->push_back(client->peer_id);
+ continue;
+ }
+ }
+ }
+
+ // Send as reliable
+ m_con.Send(client->peer_id, 0, reply, true);
+ }
+}
+
+void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
+ core::list<u16> *far_players, float far_d_nodes)
+{
+ float maxd = far_d_nodes*BS;
+ v3f p_f = intToFloat(p, BS);
+
+ for(core::map<u16, RemoteClient*>::Iterator
+ i = m_clients.getIterator();
+ i.atEnd() == false; i++)
+ {
+ // Get client and check that it is valid
+ RemoteClient *client = i.getNode()->getValue();
+ assert(client->peer_id == i.getNode()->getKey());
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ // Don't send if it's the same one
+ if(client->peer_id == ignore_id)
+ continue;
+
+ if(far_players)
+ {
+ // Get player
+ Player *player = m_env.getPlayer(client->peer_id);
+ if(player)
+ {
+ // If player is far away, only set modified blocks not sent
+ v3f player_pos = player->getPosition();
+ if(player_pos.getDistanceFrom(p_f) > maxd)
+ {
+ far_players->push_back(client->peer_id);
+ continue;
+ }
+ }
+ }
+
+ // Create packet
+ u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
+ SharedBuffer<u8> reply(replysize);
+ writeU16(&reply[0], TOCLIENT_ADDNODE);
+ writeS16(&reply[2], p.X);
+ writeS16(&reply[4], p.Y);
+ writeS16(&reply[6], p.Z);
+ n.serialize(&reply[8], client->serialization_version);
+
+ // Send as reliable
+ m_con.Send(client->peer_id, 0, reply, true);
+ }
+}
+
+void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
+{
+ DSTACK(__FUNCTION_NAME);
+ /*
+ Create a packet with the block in the right format
+ */
+
+ std::ostringstream os(std::ios_base::binary);
+ block->serialize(os, ver);
+ std::string s = os.str();
+ SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
+
+ u32 replysize = 8 + blockdata.getSize();
+ SharedBuffer<u8> reply(replysize);
+ v3s16 p = block->getPos();
+ writeU16(&reply[0], TOCLIENT_BLOCKDATA);
+ writeS16(&reply[2], p.X);
+ writeS16(&reply[4], p.Y);
+ writeS16(&reply[6], p.Z);
+ memcpy(&reply[8], *blockdata, blockdata.getSize());
+
+ /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
+ <<": \tpacket size: "<<replysize<<std::endl;*/
+
+ /*
+ Send packet
+ */
+ m_con.Send(peer_id, 1, reply, true);
+}
+
+void Server::SendBlocks(float dtime)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ JMutexAutoLock envlock(m_env_mutex);
+ JMutexAutoLock conlock(m_con_mutex);
+
+ //TimeTaker timer("Server::SendBlocks");
+
+ core::array<PrioritySortedBlockTransfer> queue;
+
+ s32 total_sending = 0;
+
+ for(core::map<u16, RemoteClient*>::Iterator
+ i = m_clients.getIterator();
+ i.atEnd() == false; i++)
+ {
+ RemoteClient *client = i.getNode()->getValue();
+ assert(client->peer_id == i.getNode()->getKey());
+
+ total_sending += client->SendingCount();
+
+ if(client->serialization_version == SER_FMT_VER_INVALID)
+ continue;
+
+ client->GetNextBlocks(this, dtime, queue);
+ }
+
+ // Sort.
+ // Lowest priority number comes first.
+ // Lowest is most important.
+ queue.sort();
+
+ for(u32 i=0; i<queue.size(); i++)
+ {
+ //TODO: Calculate limit dynamically
+ if(total_sending >= g_settings.getS32
+ ("max_simultaneous_block_sends_server_total"))
+ break;
+
+ PrioritySortedBlockTransfer q = queue[i];
+
+ MapBlock *block = NULL;
+ try
+ {
+ block = m_env.getMap().getBlockNoCreate(q.pos);
+ }
+ catch(InvalidPositionException &e)
+ {
+ continue;
+ }
+
+ RemoteClient *client = getClient(q.peer_id);
+
+ SendBlockNoLock(q.peer_id, block, client->serialization_version);
+
+ client->SentBlock(q.pos);
+
+ total_sending++;
+ }
+}
+
+/*
+ Something random
+*/
+
+void Server::UpdateCrafting(u16 peer_id)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ Player* player = m_env.getPlayer(peer_id);
+ assert(player);
+
+ /*
Calculate crafting stuff
*/
if(g_settings.getBool("creative_mode") == false)
@@ -3226,7 +3637,7 @@ void Server::SendInventory(u16 peer_id)
}
}
- // Wooden showel
+ // Wooden shovel
if(!found)
{
ItemSpec specs[9];
@@ -3240,7 +3651,7 @@ void Server::SendInventory(u16 peer_id)
}
}
- // Stone showel
+ // Stone shovel
if(!found)
{
ItemSpec specs[9];
@@ -3254,7 +3665,7 @@ void Server::SendInventory(u16 peer_id)
}
}
- // Steel showel
+ // Steel shovel
if(!found)
{
ItemSpec specs[9];
@@ -3316,6 +3727,48 @@ void Server::SendInventory(u16 peer_id)
}
}
+ // Wooden sword
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new ToolItem("WSword", 0));
+ found = true;
+ }
+ }
+
+ // Stone sword
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+ specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
+ specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new ToolItem("STSword", 0));
+ found = true;
+ }
+ }
+
+ // Steel sword
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
+ specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new ToolItem("SteelSword", 0));
+ found = true;
+ }
+ }
+
// Chest
if(!found)
{
@@ -3376,264 +3829,8 @@ void Server::SendInventory(u16 peer_id)
}
} // if creative_mode == false
-
- /*
- Serialize it
- */
-
- std::ostringstream os;
- //os.imbue(std::locale("C"));
-
- player->inventory.serialize(os);
-
- std::string s = os.str();
-
- SharedBuffer<u8> data(s.size()+2);
- writeU16(&data[0], TOCLIENT_INVENTORY);
- memcpy(&data[2], s.c_str(), s.size());
-
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
}
-void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
-{
- DSTACK(__FUNCTION_NAME);
-
- std::ostringstream os(std::ios_base::binary);
- u8 buf[12];
-
- // Write command
- writeU16(buf, TOCLIENT_CHAT_MESSAGE);
- os.write((char*)buf, 2);
-
- // Write length
- writeU16(buf, message.size());
- os.write((char*)buf, 2);
-
- // Write string
- for(u32 i=0; i<message.size(); i++)
- {
- u16 w = message[i];
- writeU16(buf, w);
- os.write((char*)buf, 2);
- }
-
- // Make data buffer
- std::string s = os.str();
- SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
-}
-
-void Server::BroadcastChatMessage(const std::wstring &message)
-{
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
- {
- // Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- SendChatMessage(client->peer_id, message);
- }
-}
-
-void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
- core::list<u16> *far_players, float far_d_nodes)
-{
- float maxd = far_d_nodes*BS;
- v3f p_f = intToFloat(p, BS);
-
- // Create packet
- u32 replysize = 8;
- SharedBuffer<u8> reply(replysize);
- writeU16(&reply[0], TOCLIENT_REMOVENODE);
- writeS16(&reply[2], p.X);
- writeS16(&reply[4], p.Y);
- writeS16(&reply[6], p.Z);
-
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
- {
- // Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- // Don't send if it's the same one
- if(client->peer_id == ignore_id)
- continue;
-
- if(far_players)
- {
- // Get player
- Player *player = m_env.getPlayer(client->peer_id);
- if(player)
- {
- // If player is far away, only set modified blocks not sent
- v3f player_pos = player->getPosition();
- if(player_pos.getDistanceFrom(p_f) > maxd)
- {
- far_players->push_back(client->peer_id);
- continue;
- }
- }
- }
-
- // Send as reliable
- m_con.Send(client->peer_id, 0, reply, true);
- }
-}
-
-void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
- core::list<u16> *far_players, float far_d_nodes)
-{
- float maxd = far_d_nodes*BS;
- v3f p_f = intToFloat(p, BS);
-
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
- {
- // Get client and check that it is valid
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- // Don't send if it's the same one
- if(client->peer_id == ignore_id)
- continue;
-
- if(far_players)
- {
- // Get player
- Player *player = m_env.getPlayer(client->peer_id);
- if(player)
- {
- // If player is far away, only set modified blocks not sent
- v3f player_pos = player->getPosition();
- if(player_pos.getDistanceFrom(p_f) > maxd)
- {
- far_players->push_back(client->peer_id);
- continue;
- }
- }
- }
-
- // Create packet
- u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
- SharedBuffer<u8> reply(replysize);
- writeU16(&reply[0], TOCLIENT_ADDNODE);
- writeS16(&reply[2], p.X);
- writeS16(&reply[4], p.Y);
- writeS16(&reply[6], p.Z);
- n.serialize(&reply[8], client->serialization_version);
-
- // Send as reliable
- m_con.Send(client->peer_id, 0, reply, true);
- }
-}
-
-void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
-{
- DSTACK(__FUNCTION_NAME);
- /*
- Create a packet with the block in the right format
- */
-
- std::ostringstream os(std::ios_base::binary);
- block->serialize(os, ver);
- std::string s = os.str();
- SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
-
- u32 replysize = 8 + blockdata.getSize();
- SharedBuffer<u8> reply(replysize);
- v3s16 p = block->getPos();
- writeU16(&reply[0], TOCLIENT_BLOCKDATA);
- writeS16(&reply[2], p.X);
- writeS16(&reply[4], p.Y);
- writeS16(&reply[6], p.Z);
- memcpy(&reply[8], *blockdata, blockdata.getSize());
-
- /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
- <<": \tpacket size: "<<replysize<<std::endl;*/
-
- /*
- Send packet
- */
- m_con.Send(peer_id, 1, reply, true);
-}
-
-void Server::SendBlocks(float dtime)
-{
- DSTACK(__FUNCTION_NAME);
-
- JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
- //TimeTaker timer("Server::SendBlocks");
-
- core::array<PrioritySortedBlockTransfer> queue;
-
- s32 total_sending = 0;
-
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
- {
- RemoteClient *client = i.getNode()->getValue();
- assert(client->peer_id == i.getNode()->getKey());
-
- total_sending += client->SendingCount();
-
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- client->GetNextBlocks(this, dtime, queue);
- }
-
- // Sort.
- // Lowest priority number comes first.
- // Lowest is most important.
- queue.sort();
-
- for(u32 i=0; i<queue.size(); i++)
- {
- //TODO: Calculate limit dynamically
- if(total_sending >= g_settings.getS32
- ("max_simultaneous_block_sends_server_total"))
- break;
-
- PrioritySortedBlockTransfer q = queue[i];
-
- MapBlock *block = NULL;
- try
- {
- block = m_env.getMap().getBlockNoCreate(q.pos);
- }
- catch(InvalidPositionException &e)
- {
- continue;
- }
-
- RemoteClient *client = getClient(q.peer_id);
-
- SendBlockNoLock(q.peer_id, block, client->serialization_version);
-
- client->SentBlock(q.pos);
-
- total_sending++;
- }
-}
-
-
RemoteClient* Server::getClient(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
@@ -3682,14 +3879,24 @@ void setCreativeInventory(Player *player)
{
player->resetInventory();
- // Give some good picks
+ // Give some good tools
{
- InventoryItem *item = new ToolItem("STPick", 0);
+ InventoryItem *item = new ToolItem("MesePick", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
- InventoryItem *item = new ToolItem("MesePick", 0);
+ InventoryItem *item = new ToolItem("SteelPick", 0);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new ToolItem("SteelAxe", 0);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new ToolItem("SteelShovel", 0);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
@@ -3756,6 +3963,52 @@ void setCreativeInventory(Player *player)
}*/
}
+v3f findSpawnPos(ServerMap &map)
+{
+ v2s16 nodepos;
+ s16 groundheight = 0;
+
+ // Try to find a good place a few times
+ for(s32 i=0; i<1000; i++)
+ {
+ s32 range = 1 + i;
+ // We're going to try to throw the player to this position
+ nodepos = v2s16(-range + (myrand()%(range*2)),
+ -range + (myrand()%(range*2)));
+ v2s16 sectorpos = getNodeSectorPos(nodepos);
+ // Get sector (NOTE: Don't get because it's slow)
+ //m_env.getMap().emergeSector(sectorpos);
+ // Get ground height at point (fallbacks to heightmap function)
+ groundheight = map.findGroundLevel(nodepos);
+ // Don't go underwater
+ if(groundheight < WATER_LEVEL)
+ {
+ //dstream<<"-> Underwater"<<std::endl;
+ continue;
+ }
+ // Don't go to high places
+ if(groundheight > WATER_LEVEL + 4)
+ {
+ //dstream<<"-> Underwater"<<std::endl;
+ continue;
+ }
+
+ // Found a good place
+ //dstream<<"Searched through "<<i<<" places."<<std::endl;
+ break;
+ }
+
+ // If no suitable place was not found, go above water at least.
+ if(groundheight < WATER_LEVEL)
+ groundheight = WATER_LEVEL;
+
+ return intToFloat(v3s16(
+ nodepos.X,
+ groundheight + 2,
+ nodepos.Y
+ ), BS);
+}
+
Player *Server::emergePlayer(const char *name, const char *password,
u16 peer_id)
{
@@ -3811,58 +4064,9 @@ Player *Server::emergePlayer(const char *name, const char *password,
dstream<<"Server: Finding spawn place for player \""
<<player->getName()<<"\""<<std::endl;
- v2s16 nodepos;
-#if 0
- player->setPosition(intToFloat(v3s16(
- 0,
- 45, //64,
- 0
- ), BS));
-#endif
-#if 1
- s16 groundheight = 0;
-#if 1
- // Try to find a good place a few times
- for(s32 i=0; i<1000; i++)
- {
- s32 range = 1 + i;
- // We're going to try to throw the player to this position
- nodepos = v2s16(-range + (myrand()%(range*2)),
- -range + (myrand()%(range*2)));
- v2s16 sectorpos = getNodeSectorPos(nodepos);
- // Get sector (NOTE: Don't get because it's slow)
- //m_env.getMap().emergeSector(sectorpos);
- // Get ground height at point (fallbacks to heightmap function)
- groundheight = m_env.getServerMap().findGroundLevel(nodepos);
- // Don't go underwater
- if(groundheight < WATER_LEVEL)
- {
- //dstream<<"-> Underwater"<<std::endl;
- continue;
- }
- // Don't go to high places
- if(groundheight > WATER_LEVEL + 4)
- {
- //dstream<<"-> Underwater"<<std::endl;
- continue;
- }
-
- // Found a good place
- dstream<<"Searched through "<<i<<" places."<<std::endl;
- break;
- }
-#endif
-
- // If no suitable place was not found, go above water at least.
- if(groundheight < WATER_LEVEL)
- groundheight = WATER_LEVEL;
+ v3f pos = findSpawnPos(m_env.getServerMap());
- player->setPosition(intToFloat(v3s16(
- nodepos.X,
- groundheight + 5, // Accomodate mud
- nodepos.Y
- ), BS));
-#endif
+ player->setPosition(pos);
/*
Add player to environment
diff --git a/src/server.h b/src/server.h
index 9059e91b8..cba5fc2ce 100644
--- a/src/server.h
+++ b/src/server.h
@@ -33,6 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "inventory.h"
+/*
+ Some random functions
+*/
+v3f findSpawnPos(ServerMap &map);
+
+/*
+ A structure containing the data needed for queueing the fetching
+ of blocks.
+*/
struct QueuedBlockEmerge
{
v3s16 pos;
@@ -397,12 +406,24 @@ private:
void peerAdded(con::Peer *peer);
void deletingPeer(con::Peer *peer, bool timeout);
+ /*
+ Static send methods
+ */
+
+ static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
+
+ /*
+ Non-static send methods
+ */
+
// Envlock and conlock should be locked when calling these
void SendObjectData(float dtime);
void SendPlayerInfos();
void SendInventory(u16 peer_id);
void SendChatMessage(u16 peer_id, const std::wstring &message);
void BroadcastChatMessage(const std::wstring &message);
+ void SendPlayerHP(Player *player);
+ void SendMovePlayer(Player *player);
/*
Send a node removal/addition event to all clients except ignore_id.
Additionally, if far_players!=NULL, players further away than
@@ -418,6 +439,12 @@ private:
// Sends blocks to clients
void SendBlocks(float dtime);
+
+ /*
+ Something random
+ */
+
+ void UpdateCrafting(u16 peer_id);
// When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id);
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index 5d391dbcf..30234f7e9 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -451,4 +451,219 @@ InventoryItem* RatSAO::createPickedUpItem()
return item;
}
+/*
+ Oerkki1SAO
+*/
+
+// Prototype
+Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
+
+Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
+ ServerActiveObject(env, id, pos),
+ m_is_active(false),
+ m_speed_f(0,0,0)
+{
+ ServerActiveObject::registerType(getType(), create);
+
+ m_oldpos = v3f(0,0,0);
+ m_last_sent_position = v3f(0,0,0);
+ m_yaw = 0;
+ m_counter1 = 0;
+ m_counter2 = 0;
+ m_age = 0;
+ m_touching_ground = false;
+ m_hp = 20;
+}
+
+ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ std::istringstream is(data, std::ios::binary);
+ // read version
+ u8 version = readU8(is);
+ // read hp
+ u8 hp = readU8(is);
+ // check if version is supported
+ if(version != 0)
+ return NULL;
+ Oerkki1SAO *o = new Oerkki1SAO(env, id, pos);
+ o->m_hp = hp;
+ return o;
+}
+
+void Oerkki1SAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
+ bool send_recommended)
+{
+ assert(m_env);
+
+ if(m_is_active == false)
+ {
+ if(m_inactive_interval.step(dtime, 0.5)==false)
+ return;
+ }
+
+ /*
+ The AI
+ */
+
+ m_age += dtime;
+ if(m_age > 60)
+ {
+ // Die
+ m_removed = true;
+ return;
+ }
+
+ // Apply gravity
+ m_speed_f.Y -= dtime*9.81*BS;
+
+ /*
+ Move around if some player is close
+ */
+ bool player_is_close = false;
+ v3f near_player_pos;
+ // Check connected players
+ core::list<Player*> players = m_env->getPlayers(true);
+ core::list<Player*>::Iterator i;
+ for(i = players.begin();
+ i != players.end(); i++)
+ {
+ Player *player = *i;
+ v3f playerpos = player->getPosition();
+ if(m_base_position.getDistanceFrom(playerpos) < BS*15.0)
+ {
+ player_is_close = true;
+ near_player_pos = playerpos;
+ break;
+ }
+ }
+
+ m_is_active = player_is_close;
+
+ if(player_is_close == false)
+ {
+ m_speed_f.X = 0;
+ m_speed_f.Z = 0;
+ }
+ else
+ {
+ // Move around
+
+ v3f ndir = near_player_pos - m_base_position;
+ ndir.Y = 0;
+ ndir /= ndir.getLength();
+ f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
+ if(nyaw < m_yaw - 180)
+ nyaw += 360;
+ else if(nyaw > m_yaw + 180)
+ nyaw -= 360;
+ m_yaw = 0.95*m_yaw + 0.05*nyaw;
+ m_yaw = wrapDegrees(m_yaw);
+
+ v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
+ f32 speed = 2*BS;
+ m_speed_f.X = speed * dir.X;
+ m_speed_f.Z = speed * dir.Z;
+
+ if(m_touching_ground && (m_oldpos - m_base_position).getLength()
+ < dtime*speed/2)
+ {
+ m_counter1 -= dtime;
+ if(m_counter1 < 0.0)
+ {
+ m_counter1 += 1.0;
+ // Jump
+ m_speed_f.Y = 5.0*BS;
+ }
+ }
+
+ {
+ m_counter2 -= dtime;
+ if(m_counter2 < 0.0)
+ {
+ m_counter2 += (float)(myrand()%100)/100*3.0;
+ //m_yaw += ((float)(myrand()%200)-100)/100*180;
+ m_yaw += ((float)(myrand()%200)-100)/100*90;
+ m_yaw = wrapDegrees(m_yaw);
+ }
+ }
+ }
+
+ m_oldpos = m_base_position;
+
+ /*
+ Move it, with collision detection
+ */
+
+ core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
+ collisionMoveResult moveresult;
+ // Maximum movement without glitches
+ f32 pos_max_d = BS*0.25;
+ // Limit speed
+ if(m_speed_f.getLength()*dtime > pos_max_d)
+ m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
+ v3f pos_f = getBasePosition();
+ v3f pos_f_old = pos_f;
+ moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
+ box, dtime, pos_f, m_speed_f);
+ m_touching_ground = moveresult.touching_ground;
+
+ setBasePosition(pos_f);
+
+ if(send_recommended == false)
+ return;
+
+ if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+ {
+ m_last_sent_position = pos_f;
+
+ std::ostringstream os(std::ios::binary);
+ // command (0 = update position)
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_base_position);
+ // yaw
+ writeF1000(os, m_yaw);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ messages.push_back(aom);
+ }
+}
+
+std::string Oerkki1SAO::getClientInitializationData()
+{
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_base_position);
+ return os.str();
+}
+
+std::string Oerkki1SAO::getStaticData()
+{
+ //dstream<<__FUNCTION_NAME<<std::endl;
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ // hp
+ writeU8(os, m_hp);
+ return os.str();
+}
+
+u16 Oerkki1SAO::punch(const std::string &toolname)
+{
+ u16 amount = 5;
+ if(amount < m_hp)
+ {
+ m_hp -= amount;
+ }
+ else
+ {
+ // Die
+ m_removed = true;
+ }
+ return 65536/100;
+}
+
diff --git a/src/serverobject.h b/src/serverobject.h
index 2889d0c39..71199475e 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -100,6 +100,12 @@ public:
*/
virtual InventoryItem* createPickedUpItem(){return NULL;}
+ /*
+ If the object doesn't return an item, this will be called.
+ Return value is tool wear.
+ */
+ virtual u16 punch(const std::string &toolname){return 0;}
+
// Number of players which know about this object
u16 m_known_by_count;
/*
@@ -201,5 +207,33 @@ private:
bool m_touching_ground;
};
+class Oerkki1SAO : public ServerActiveObject
+{
+public:
+ Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos);
+ u8 getType() const
+ {return ACTIVEOBJECT_TYPE_OERKKI1;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ void step(float dtime, Queue<ActiveObjectMessage> &messages,
+ bool send_recommended);
+ std::string getClientInitializationData();
+ std::string getStaticData();
+ InventoryItem* createPickedUpItem(){return NULL;}
+ u16 punch(const std::string &toolname);
+private:
+ bool m_is_active;
+ IntervalLimiter m_inactive_interval;
+ v3f m_speed_f;
+ v3f m_oldpos;
+ v3f m_last_sent_position;
+ float m_yaw;
+ float m_counter1;
+ float m_counter2;
+ float m_age;
+ bool m_touching_ground;
+ u8 m_hp;
+};
+
#endif
diff --git a/src/test.cpp b/src/test.cpp
index c7bffcdf3..07ef772ef 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -951,18 +951,18 @@ struct TestConnection
assert(got_exception);
}
{
- //u8 data1[1100];
- SharedBuffer<u8> data1(1100);
- for(u16 i=0; i<1100; i++){
+ const int datasize = 30000;
+ SharedBuffer<u8> data1(datasize);
+ for(u16 i=0; i<datasize; i++){
data1[i] = i/4;
}
- dstream<<"Sending data (size="<<1100<<"):";
- for(int i=0; i<1100 && i<20; i++){
+ dstream<<"Sending data (size="<<datasize<<"):";
+ for(int i=0; i<datasize && i<20; i++){
if(i%2==0) DEBUGPRINT(" ");
DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff);
}
- if(1100>20)
+ if(datasize>20)
dstream<<"...";
dstream<<std::endl;
@@ -970,10 +970,10 @@ struct TestConnection
sleep_ms(50);
- u8 recvdata[2000];
+ u8 recvdata[datasize + 1000];
dstream<<"** running client.Receive()"<<std::endl;
u16 peer_id = 132;
- u16 size = client.Receive(peer_id, recvdata, 2000);
+ u16 size = client.Receive(peer_id, recvdata, datasize + 1000);
dstream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<std::endl;
diff --git a/src/utility.h b/src/utility.h
index 0b59ce6fd..c6bb3f879 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -215,8 +215,8 @@ inline void writeU16(std::ostream &os, u16 p)
}
inline u16 readU16(std::istream &is)
{
- char buf[12];
- is.read(buf, 12);
+ char buf[2];
+ is.read(buf, 2);
return readU16((u8*)buf);
}
@@ -228,8 +228,8 @@ inline void writeF1000(std::ostream &os, f32 p)
}
inline f32 readF1000(std::istream &is)
{
- char buf[12];
- is.read(buf, 12);
+ char buf[2];
+ is.read(buf, 2);
return readF1000((u8*)buf);
}