From 5a4d8ffad3b172eae67844deda6b65273b7c9757 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 10 Apr 2011 15:16:27 +0300 Subject: [PATCH] implemented rats in new system to verify that it works --- src/clientobject.cpp | 189 ++++++++++++++++++++++++++++++++++++----- src/clientobject.h | 99 ++++++++++++++++++++++ src/collision.cpp | 184 ++++++++++++++++++++++++++++++++++++++++ src/collision.h | 43 ++++++++++ src/environment.cpp | 37 +++++++-- src/environment.h | 1 + src/inventory.cpp | 57 +++++++++++++ src/inventory.h | 39 ++++----- src/mapblock.cpp | 6 +- src/mapblock.h | 3 +- src/server.cpp | 47 ++++++----- src/serverobject.cpp | 194 ++++++++++++++++++++++++++++++++++++++++++- src/serverobject.h | 79 +++++++++++++++++- src/utility.h | 81 +++++++++++++++++- 14 files changed, 974 insertions(+), 85 deletions(-) create mode 100644 src/collision.cpp create mode 100644 src/collision.h diff --git a/src/clientobject.cpp b/src/clientobject.cpp index 901b3d072..1d9dd215b 100644 --- a/src/clientobject.cpp +++ b/src/clientobject.cpp @@ -24,6 +24,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "utility.h" #include "environment.h" +/* + ClientActiveObject +*/ + core::map ClientActiveObject::m_types; ClientActiveObject::ClientActiveObject(u16 id): @@ -231,8 +235,9 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr) buf->getMaterial().setFlag(video::EMF_LIGHTING, false); buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false); //buf->getMaterial().setTexture(0, NULL); + // Initialize with the stick texture buf->getMaterial().setTexture - (0, driver->getTexture(porting::getDataPath("rat.png").c_str())); + (0, driver->getTexture(porting::getDataPath("stick.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; @@ -313,19 +318,12 @@ void ItemCAO::processMessage(const std::string &data) { dstream<<"ItemCAO: Got message"<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("rat.png").c_str())); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + // Add to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + m_node = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + // 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 RatCAO::removeFromScene() +{ + if(m_node == NULL) + return; + + m_node->remove(); + m_node = NULL; +} + +void RatCAO::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; jgetMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; isetPosition(m_position); + m_node->setPosition(pos_translator.vect_show); + + v3f rot = m_node->getRotation(); + rot.Y = 180.0 - m_yaw; + m_node->setRotation(rot); +} + +void RatCAO::step(float dtime, ClientEnvironment *env) +{ + pos_translator.translate(dtime); + updateNodePos(); +} + +void RatCAO::processMessage(const std::string &data) +{ + //dstream<<"RatCAO: Got message"< 1.0) + anim_time = anim_time_counter; + else + anim_time = anim_time * 0.9 + anim_time_counter * 0.1; + anim_time_counter = 0; + anim_counter = 0; + } + + void translate(f32 dtime) + { + anim_time_counter = anim_time_counter + dtime; + anim_counter = anim_counter + dtime; + v3f vect_move = vect_aim - vect_old; + f32 moveratio = 1.0; + if(anim_time > 0.001) + moveratio = anim_time_counter / anim_time; + // Move a bit less than should, to avoid oscillation + moveratio = moveratio * 0.8; + if(moveratio > 1.5) + moveratio = 1.5; + vect_show = vect_old + vect_move * moveratio; + } +}; + class ClientEnvironment; class ClientActiveObject : public ActiveObject @@ -168,5 +225,47 @@ private: std::string m_inventorystring; }; +/* + RatCAO +*/ + +class RatCAO : public ClientActiveObject +{ +public: + RatCAO(); + virtual ~RatCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_RAT; + } + + 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* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return m_position;} + +private: + core::aabbox3d m_selection_box; + scene::IMeshSceneNode *m_node; + v3f m_position; + float m_yaw; + SmoothTranslator pos_translator; +}; + #endif diff --git a/src/collision.cpp b/src/collision.cpp new file mode 100644 index 000000000..83cefe4d1 --- /dev/null +++ b/src/collision.cpp @@ -0,0 +1,184 @@ +/* +Minetest-c55 +Copyright (C) 2010 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "collision.h" +#include "mapblock.h" +#include "map.h" + +collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d, + const core::aabbox3d &box_0, + f32 dtime, v3f &pos_f, v3f &speed_f) +{ + collisionMoveResult result; + + v3f oldpos_f = pos_f; + v3s16 oldpos_i = floatToInt(oldpos_f, BS); + + /* + Calculate new position + */ + pos_f += speed_f * dtime; + + /* + Collision detection + */ + + // position in nodes + v3s16 pos_i = floatToInt(pos_f, BS); + + /* + Collision uncertainty radius + Make it a bit larger than the maximum distance of movement + */ + f32 d = pos_max_d * 1.1; + // A fairly large value in here makes moving smoother + //f32 d = 0.15*BS; + + // This should always apply, otherwise there are glitches + assert(d > pos_max_d); + + /* + Calculate collision box + */ + core::aabbox3d box = box_0; + box.MaxEdge += pos_f; + box.MinEdge += pos_f; + core::aabbox3d oldbox = box_0; + oldbox.MaxEdge += oldpos_f; + oldbox.MinEdge += oldpos_f; + + /* + If the object lies on a walkable node, this is set to true. + */ + result.touching_ground = false; + + /* + Go through every node around the object + */ + 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++) + for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++) + { + try{ + // Object collides into walkable nodes + if(content_walkable(map->getNode(v3s16(x,y,z)).d) == false) + continue; + } + catch(InvalidPositionException &e) + { + // Doing nothing here will block the object from + // walking over map borders + } + + core::aabbox3d nodebox = getNodeBox(v3s16(x,y,z), BS); + + /* + See if the object is touching ground. + + Object touches ground if object's minimum Y is near node's + maximum Y and object's X-Z-area overlaps with the node's + X-Z-area. + + Use 0.15*BS so that it is easier to get on a node. + */ + if( + //fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < d + fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS + && nodebox.MaxEdge.X-d > box.MinEdge.X + && nodebox.MinEdge.X+d < box.MaxEdge.X + && nodebox.MaxEdge.Z-d > box.MinEdge.Z + && nodebox.MinEdge.Z+d < box.MaxEdge.Z + ){ + result.touching_ground = true; + } + + // If object doesn't intersect with node, ignore node. + if(box.intersectsWithBox(nodebox) == false) + continue; + + /* + Go through every axis + */ + v3f dirs[3] = { + v3f(0,0,1), // back-front + v3f(0,1,0), // top-bottom + v3f(1,0,0), // right-left + }; + for(u16 i=0; i<3; i++) + { + /* + Calculate values along the axis + */ + f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]); + f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]); + f32 objectmax = box.MaxEdge.dotProduct(dirs[i]); + f32 objectmin = box.MinEdge.dotProduct(dirs[i]); + f32 objectmax_old = oldbox.MaxEdge.dotProduct(dirs[i]); + f32 objectmin_old = oldbox.MinEdge.dotProduct(dirs[i]); + + /* + Check collision for the axis. + Collision happens when object is going through a surface. + */ + bool negative_axis_collides = + (nodemax > objectmin && nodemax <= objectmin_old + d + && speed_f.dotProduct(dirs[i]) < 0); + bool positive_axis_collides = + (nodemin < objectmax && nodemin >= objectmax_old - d + && speed_f.dotProduct(dirs[i]) > 0); + bool main_axis_collides = + negative_axis_collides || positive_axis_collides; + + /* + Check overlap of object and node in other axes + */ + bool other_axes_overlap = true; + for(u16 j=0; j<3; j++) + { + if(j == i) + continue; + f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]); + f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]); + f32 objectmax = box.MaxEdge.dotProduct(dirs[j]); + f32 objectmin = box.MinEdge.dotProduct(dirs[j]); + if(!(nodemax - d > objectmin && nodemin + d < objectmax)) + { + other_axes_overlap = false; + break; + } + } + + /* + If this is a collision, revert the pos_f in the main + direction. + */ + if(other_axes_overlap && main_axis_collides) + { + speed_f -= speed_f.dotProduct(dirs[i]) * dirs[i]; + pos_f -= pos_f.dotProduct(dirs[i]) * dirs[i]; + pos_f += oldpos_f.dotProduct(dirs[i]) * dirs[i]; + } + + } + } // xyz + + return result; +} + + diff --git a/src/collision.h b/src/collision.h new file mode 100644 index 000000000..172431401 --- /dev/null +++ b/src/collision.h @@ -0,0 +1,43 @@ +/* +Minetest-c55 +Copyright (C) 2010 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef COLLISION_HEADER +#define COLLISION_HEADER + +#include "common_irrlicht.h" + +class Map; + +struct collisionMoveResult +{ + bool touching_ground; + + collisionMoveResult(): + touching_ground(false) + {} +}; + +collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d, + const core::aabbox3d &box_0, + f32 dtime, v3f &pos_f, v3f &speed_f); +//{return collisionMoveResult();} + + +#endif + diff --git a/src/environment.cpp b/src/environment.cpp index 7e1d268df..edccad1ce 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -189,7 +189,8 @@ u32 Environment::getDayNightRatio() ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server): m_map(map), m_server(server), - m_random_spawn_timer(3) + m_random_spawn_timer(3), + m_send_recommended_timer(0) { } @@ -422,19 +423,25 @@ void ServerEnvironment::step(float dtime) } } - //if(g_settings.getBool("enable_experimental")) - { - /* Step active objects */ + + bool send_recommended = false; + m_send_recommended_timer += dtime; + if(m_send_recommended_timer > 0.2) + { + m_send_recommended_timer = 0; + send_recommended = true; + } + for(core::map::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); + obj->step(dtime, m_active_object_messages, send_recommended); } /* @@ -460,6 +467,19 @@ void ServerEnvironment::step(float dtime) // If not m_removed, don't remove. if(obj->m_removed == false) continue; + // Delete static data from block + if(obj->m_static_exists) + { + MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block); + if(block) + { + block->m_static_objects.remove(id); + block->setChangedFlag(); + } + } + // If m_known_by_count > 0, don't actually remove. + if(obj->m_known_by_count > 0) + continue; // Delete delete obj; // Id to be removed from m_active_objects @@ -633,6 +653,9 @@ void ServerEnvironment::step(float dtime) } } + if(g_settings.getBool("enable_experimental")) + { + /* TEST CODE */ @@ -668,7 +691,8 @@ void ServerEnvironment::step(float dtime) //TestSAO *obj = new TestSAO(this, 0, pos); //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1"); - //addActiveObject(obj); + ServerActiveObject *obj = new RatSAO(this, 0, pos); + addActiveObject(obj); } #endif @@ -1082,6 +1106,7 @@ void ClientEnvironment::step(float dtime) /* Step active objects */ + for(core::map::Iterator i = m_active_objects.getIterator(); i.atEnd()==false; i++) diff --git a/src/environment.h b/src/environment.h index 9532271bb..85d2f668f 100644 --- a/src/environment.h +++ b/src/environment.h @@ -153,6 +153,7 @@ private: core::map m_active_objects; Queue m_active_object_messages; float m_random_spawn_timer; + float m_send_recommended_timer; }; #ifndef SERVER diff --git a/src/inventory.cpp b/src/inventory.cpp index f9b9107a0..b14828ae2 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "debug.h" #include #include "main.h" +#include "serverobject.h" /* InventoryItem @@ -90,6 +91,19 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is) } } +ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) +{ + /* + Create an ItemSAO + */ + // Get item string + std::ostringstream os(std::ios_base::binary); + serialize(os); + // Create object + ServerActiveObject *obj = new ItemSAO(env, 0, pos, os.str()); + return obj; +} + /* MaterialItem */ @@ -124,6 +138,48 @@ InventoryItem *MaterialItem::createCookResult() CraftItem */ +#ifndef SERVER +video::ITexture * CraftItem::getImage() +{ + if(g_texturesource == NULL) + return NULL; + + std::string name; + + if(m_subname == "Stick") + name = "stick.png"; + else if(m_subname == "lump_of_coal") + name = "lump_of_coal.png"; + else if(m_subname == "lump_of_iron") + name = "lump_of_iron.png"; + else if(m_subname == "steel_ingot") + name = "steel_ingot.png"; + else if(m_subname == "rat") + name = "rat.png"; + else + name = "cloud.png"; + + // Get such a texture + //return g_irrlicht->getTexture(name); + return g_texturesource->getTextureRaw(name); +} +#endif + +ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) +{ + // Special cases + if(m_subname == "rat") + { + ServerActiveObject *obj = new RatSAO(env, id, pos); + return obj; + } + // Default + else + { + return InventoryItem::createSAO(env, id, pos); + } +} + bool CraftItem::isCookable() { if(m_subname == "lump_of_iron") @@ -144,6 +200,7 @@ InventoryItem *CraftItem::createCookResult() /* MapBlockObjectItem + TODO: Remove */ #ifndef SERVER video::ITexture * MapBlockObjectItem::getImage() diff --git a/src/inventory.h b/src/inventory.h index 761e664a9..3ba655880 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -35,6 +35,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define QUANTITY_ITEM_MAX_COUNT 99 +class ServerActiveObject; +class ServerEnvironment; + class InventoryItem { public: @@ -54,6 +57,12 @@ public: #endif // Shall return a text to show in the GUI virtual std::string getText() { return ""; } + // Creates an object from the item, to be placed in the world. + virtual ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos); + + /* + Quantity methods + */ // Shall return true if the item can be add()ed to the other virtual bool addableTo(InventoryItem *other) @@ -61,9 +70,6 @@ public: return false; } - /* - Quantity methods - */ u16 getCount() { return m_count; @@ -175,6 +181,7 @@ private: u8 m_content; }; +//TODO: Remove class MapBlockObjectItem : public InventoryItem { public: @@ -262,28 +269,7 @@ public: return new CraftItem(m_subname, m_count); } #ifndef SERVER - video::ITexture * getImage() - { - if(g_texturesource == NULL) - return NULL; - - std::string name; - - if(m_subname == "Stick") - name = "stick.png"; - else if(m_subname == "lump_of_coal") - name = "lump_of_coal.png"; - else if(m_subname == "lump_of_iron") - name = "lump_of_iron.png"; - else if(m_subname == "steel_ingot") - name = "steel_ingot.png"; - else - name = "cloud.png"; - - // Get such a texture - //return g_irrlicht->getTexture(name); - return g_texturesource->getTextureRaw(name); - } + video::ITexture * getImage(); #endif std::string getText() { @@ -291,6 +277,9 @@ public: os<getName()) != "CraftItem") diff --git a/src/mapblock.cpp b/src/mapblock.cpp index a4e13320e..377e28435 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -1295,7 +1295,7 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy): if(dummy == false) reallocate(); - m_spawn_timer = -10000; + //m_spawn_timer = -10000; #ifndef SERVER m_mesh_expired = false; @@ -1687,7 +1687,8 @@ void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio) Step objects */ m_objects.step(dtime, server, daynight_ratio); - + +#if 0 /* Spawn some objects at random. @@ -1724,6 +1725,7 @@ void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio) } } } +#endif setChangedFlag(); } diff --git a/src/mapblock.h b/src/mapblock.h index ce5682568..30e9e38f8 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -729,10 +729,11 @@ private: // Whether day and night lighting differs bool m_day_night_differs; + // TODO: Remove this MapBlockObjectList m_objects; // Object spawning stuff - float m_spawn_timer; + //float m_spawn_timer; #ifndef SERVER // Only on client /* diff --git a/src/server.cpp b/src/server.cpp index 4334d77c7..04d204a2a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2045,28 +2045,26 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) dout_server<<"Player inventory has no free space"<m_removed) + return; /* Create the inventory item */ - InventoryItem *item = NULL; - // If it is an item-object, take the item from it - if(obj->getType() == ACTIVEOBJECT_TYPE_ITEM - && obj->m_removed == false) - { - item = ((ItemSAO*)obj)->createInventoryItem(); - } + InventoryItem *item = obj->createPickedUpItem(); if(item) { // Add to inventory and send inventory ilist->addItem(item); SendInventory(player->peer_id); + + // Remove object from environment + obj->m_removed = true; } } - - // Remove object from environment - obj->m_removed = true; } } else if(command == TOSERVER_GROUND_ACTION) @@ -2448,15 +2446,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0; /* - Create an ItemSAO + Create the object */ - // Get item string - std::ostringstream os(std::ios_base::binary); - item->serialize(os); - dout_server<<"Item string is \""<createSAO(&m_env, 0, pos); if(obj == NULL) { @@ -2471,11 +2463,22 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) dout_server<<"Placed object"<inventory.getList("main"); - if(g_settings.getBool("creative_mode") == false && ilist) + // If item has count<=1, delete it + if(item->getCount() <= 1) { - // Remove from inventory and send inventory - ilist->deleteItem(item_i); + InventoryList *ilist = player->inventory.getList("main"); + if(g_settings.getBool("creative_mode") == false && ilist) + { + // Remove from inventory and send inventory + ilist->deleteItem(item_i); + // Send inventory + SendInventory(peer_id); + } + } + // Else decrement it + else + { + item->remove(1); // Send inventory SendInventory(peer_id); } diff --git a/src/serverobject.cpp b/src/serverobject.cpp index 92a0b83f4..ce7259d67 100644 --- a/src/serverobject.cpp +++ b/src/serverobject.cpp @@ -91,7 +91,8 @@ ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos, return new TestSAO(env, id, pos); } -void TestSAO::step(float dtime, Queue &messages) +void TestSAO::step(float dtime, Queue &messages, + bool send_recommended) { m_age += dtime; if(m_age > 10) @@ -104,6 +105,9 @@ void TestSAO::step(float dtime, Queue &messages) if(m_base_position.Y > 8*BS) m_base_position.Y = 2*BS; + if(send_recommended == false) + return; + m_timer1 -= dtime; if(m_timer1 < 0.0) { @@ -137,7 +141,8 @@ ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos, const std::string inventorystring): ServerActiveObject(env, id, pos), m_inventorystring(inventorystring), - m_speed_f(0,0,0) + m_speed_f(0,0,0), + m_last_sent_position(0,0,0) { dstream<<"Server: ItemSAO created with inventorystring=\"" < &messages) +void ItemSAO::step(float dtime, Queue &messages, + bool send_recommended) { core::aabbox3d box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.); collisionMoveResult moveresult; @@ -177,9 +183,13 @@ void ItemSAO::step(float dtime, Queue &messages) moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d, box, dtime, pos_f, m_speed_f); - if(pos_f.getDistanceFrom(pos_f_old) > 0.01*BS) + if(send_recommended == false) + return; + + if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS) { setBasePosition(pos_f); + m_last_sent_position = pos_f; std::ostringstream os(std::ios::binary); char buf[6]; @@ -250,4 +260,180 @@ InventoryItem * ItemSAO::createInventoryItem() } +/* + RatSAO +*/ + +// Prototype +RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0)); + +RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos): + ServerActiveObject(env, id, pos), + m_speed_f(0,0,0) +{ + dstream<<"Server: RatSAO created"< &messages, + bool send_recommended) +{ + /* + 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; + // Check connected players + core::list players = m_env->getPlayers(true); + core::list::Iterator i; + for(i = players.begin(); + i != players.end(); i++) + { + Player *player = *i; + v3f playerpos = player->getPosition(); + if(m_base_position.getDistanceFrom(playerpos) < BS*10.0) + { + player_is_close = true; + break; + } + } + + if(player_is_close == false) + { + m_speed_f.X = 0; + m_speed_f.Z = 0; + } + else + { + // Move around + 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; + 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 = wrapDegrees(m_yaw); + } + } + } + + m_oldpos = m_base_position; + + /* + Move it, with collision detection + */ + + core::aabbox3d box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./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 RatSAO::getClientInitializationData() +{ + std::ostringstream os(std::ios::binary); + // version + writeU8(os, 0); + // pos + writeV3F1000(os, m_base_position); + return os.str(); +} + +std::string RatSAO::getStaticData() +{ + dstream<<__FUNCTION_NAME< &messages){} + virtual void step(float dtime, Queue &messages, + bool send_recommended){} /* The return value of this is passed to the client-side object @@ -83,6 +122,12 @@ public: */ virtual std::string getStaticData(){return "";} + /* + Item that the player gets when this object is picked up. + If NULL, object cannot be picked up. + */ + virtual InventoryItem* createPickedUpItem(){return NULL;} + // Number of players which know about this object u16 m_known_by_count; /* @@ -129,7 +174,8 @@ public: {return ACTIVEOBJECT_TYPE_TEST;} static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, const std::string &data); - void step(float dtime, Queue &messages); + void step(float dtime, Queue &messages, + bool send_recommended); private: float m_timer1; float m_age; @@ -144,13 +190,40 @@ public: {return ACTIVEOBJECT_TYPE_ITEM;} static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, const std::string &data); - void step(float dtime, Queue &messages); + void step(float dtime, Queue &messages, + bool send_recommended); std::string getClientInitializationData(); std::string getStaticData(); InventoryItem* createInventoryItem(); + InventoryItem* createPickedUpItem(){return createInventoryItem();} private: std::string m_inventorystring; v3f m_speed_f; + v3f m_last_sent_position; +}; + +class RatSAO : public ServerActiveObject +{ +public: + RatSAO(ServerEnvironment *env, u16 id, v3f pos); + u8 getType() const + {return ACTIVEOBJECT_TYPE_RAT;} + static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + const std::string &data); + void step(float dtime, Queue &messages, + bool send_recommended); + std::string getClientInitializationData(); + std::string getStaticData(); + InventoryItem* createPickedUpItem(); +private: + 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; }; #endif diff --git a/src/utility.h b/src/utility.h index 2b143f0ba..f2f3018df 100644 --- a/src/utility.h +++ b/src/utility.h @@ -95,8 +95,6 @@ inline u8 readU8(u8 *data) return (data[0]<<0); } -// Signed variants of the above - inline void writeS32(u8 *data, s32 i){ writeU32(data, (u32)i); } @@ -104,6 +102,13 @@ inline s32 readS32(u8 *data){ return (s32)readU32(data); } +inline void writeF1000(u8 *data, f32 i){ + writeS32(data, i*1000); +} +inline f32 readF1000(u8 *data){ + return (f32)readS32(data)/1000.; +} + inline void writeS16(u8 *data, s16 i){ writeU16(data, (u16)i); } @@ -117,7 +122,6 @@ inline void writeV3S32(u8 *data, v3s32 p) writeS32(&data[4], p.Y); writeS32(&data[8], p.Z); } - inline v3s32 readV3S32(u8 *data) { v3s32 p; @@ -127,6 +131,21 @@ inline v3s32 readV3S32(u8 *data) return p; } +inline void writeV3F1000(u8 *data, v3f p) +{ + writeF1000(&data[0], p.X); + writeF1000(&data[4], p.Y); + writeF1000(&data[8], p.Z); +} +inline v3f readV3F1000(u8 *data) +{ + v3f p; + p.X = (float)readF1000(&data[0]); + p.Y = (float)readF1000(&data[4]); + p.Z = (float)readF1000(&data[8]); + return p; +} + inline void writeV2S16(u8 *data, v2s16 p) { writeS16(&data[0], p.X); @@ -171,6 +190,62 @@ inline v3s16 readV3S16(u8 *data) return p; } +/* + The above stuff directly interfaced to iostream +*/ + +inline void writeU8(std::ostream &os, u8 p) +{ + char buf[1]; + writeU8((u8*)buf, p); + os.write(buf, 1); +} +inline u8 readU8(std::istream &is) +{ + char buf[1]; + is.read(buf, 1); + return readU8((u8*)buf); +} + +inline void writeU16(std::ostream &os, u16 p) +{ + char buf[2]; + writeU16((u8*)buf, p); + os.write(buf, 2); +} +inline u16 readU16(std::istream &is) +{ + char buf[12]; + is.read(buf, 12); + return readU16((u8*)buf); +} + +inline void writeF1000(std::ostream &os, f32 p) +{ + char buf[2]; + writeF1000((u8*)buf, p); + os.write(buf, 2); +} +inline f32 readF1000(std::istream &is) +{ + char buf[12]; + is.read(buf, 12); + return readF1000((u8*)buf); +} + +inline void writeV3F1000(std::ostream &os, v3f p) +{ + char buf[12]; + writeV3F1000((u8*)buf, p); + os.write(buf, 12); +} +inline v3f readV3F1000(std::istream &is) +{ + char buf[12]; + is.read(buf, 12); + return readV3F1000((u8*)buf); +} + /* None of these are used at the moment */