diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/activeobject.h | 1 | ||||
-rw-r--r-- | src/client.cpp | 340 | ||||
-rw-r--r-- | src/client.h | 79 | ||||
-rw-r--r-- | src/clientobject.cpp | 179 | ||||
-rw-r--r-- | src/clientobject.h | 45 | ||||
-rw-r--r-- | src/clientserver.h | 45 | ||||
-rw-r--r-- | src/collision.cpp | 1 | ||||
-rw-r--r-- | src/collision.h | 10 | ||||
-rw-r--r-- | src/defaultsettings.cpp | 1 | ||||
-rw-r--r-- | src/environment.cpp | 178 | ||||
-rw-r--r-- | src/environment.h | 32 | ||||
-rw-r--r-- | src/inventory.h | 6 | ||||
-rw-r--r-- | src/main.cpp | 551 | ||||
-rw-r--r-- | src/map.cpp | 36 | ||||
-rw-r--r-- | src/map.h | 10 | ||||
-rw-r--r-- | src/mapblock.cpp | 33 | ||||
-rw-r--r-- | src/player.cpp | 29 | ||||
-rw-r--r-- | src/player.h | 5 | ||||
-rw-r--r-- | src/serialization.cpp | 6 | ||||
-rw-r--r-- | src/serialization.h | 8 | ||||
-rw-r--r-- | src/server.cpp | 864 | ||||
-rw-r--r-- | src/server.h | 27 | ||||
-rw-r--r-- | src/serverobject.cpp | 215 | ||||
-rw-r--r-- | src/serverobject.h | 34 | ||||
-rw-r--r-- | src/test.cpp | 16 | ||||
-rw-r--r-- | src/utility.h | 8 |
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); } } @@ -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); } |