#include "utility.h"
#include "environment.h"
+/*
+ ClientActiveObject
+*/
+
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
ClientActiveObject::ClientActiveObject(u16 id):
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;
{
dstream<<"ItemCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
- char buf[4];
// command
- is.read(buf, 1);
- u8 cmd = buf[0];
+ u8 cmd = readU8(is);
if(cmd == 0)
{
// pos
- is.read(buf, 4);
- m_position.X = (float)readS32((u8*)buf)/1000.0;
- is.read(buf, 4);
- m_position.Y = (float)readS32((u8*)buf)/1000.0;
- is.read(buf, 4);
- m_position.Z = (float)readS32((u8*)buf)/1000.0;
+ m_position = readV3F1000(is);
updateNodePos();
}
}
{
std::istringstream is(data, std::ios::binary);
- char buf[4];
// version
- is.read(buf, 1);
- u8 version = buf[0];
+ u8 version = readU8(is);
// check version
if(version != 0)
return;
// pos
- is.read(buf, 4);
- m_position.X = (float)readS32((u8*)buf)/1000.0;
- is.read(buf, 4);
- m_position.Y = (float)readS32((u8*)buf)/1000.0;
- is.read(buf, 4);
- m_position.Z = (float)readS32((u8*)buf)/1000.0;
+ m_position = readV3F1000(is);
// inventorystring
m_inventorystring = deSerializeString(is);
}
}
+/*
+ RatCAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+RatCAO proto_RatCAO;
+
+RatCAO::RatCAO():
+ 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))
+{
+ ClientActiveObject::registerType(getType(), create);
+}
+
+RatCAO::~RatCAO()
+{
+}
+
+ClientActiveObject* RatCAO::create()
+{
+ return new RatCAO();
+}
+
+void RatCAO::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("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; 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 RatCAO::getLightPosition()
+{
+ return floatToInt(m_position, BS);
+}
+
+void RatCAO::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;
+ 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"<<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 RatCAO::initialize(const std::string &data)
+{
+ //dstream<<"RatCAO: 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();
+}
+
*/
+/*
+ SmoothTranslator
+*/
+
+struct SmoothTranslator
+{
+ v3f vect_old;
+ f32 anim_counter;
+ f32 anim_time;
+ f32 anim_time_counter;
+ v3f vect_show;
+ v3f vect_aim;
+
+ SmoothTranslator():
+ vect_old(0,0,0),
+ anim_counter(0),
+ anim_time(0),
+ anim_time_counter(0),
+ vect_show(0,0,0),
+ vect_aim(0,0,0)
+ {}
+
+ void init(v3f vect)
+ {
+ vect_old = vect;
+ vect_show = vect;
+ vect_aim = vect;
+ }
+
+ void update(v3f vect_new)
+ {
+ vect_old = vect_show;
+ vect_aim = vect_new;
+ if(anim_time < 0.001 || anim_time > 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
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<f32>* getSelectionBox()
+ {return &m_selection_box;}
+ v3f getPosition()
+ {return m_position;}
+
+private:
+ core::aabbox3d<f32> m_selection_box;
+ scene::IMeshSceneNode *m_node;
+ v3f m_position;
+ float m_yaw;
+ SmoothTranslator pos_translator;
+};
+
#endif
--- /dev/null
+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "collision.h"
+#include "mapblock.h"
+#include "map.h"
+
+collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
+ const core::aabbox3d<f32> &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<f32> box = box_0;
+ box.MaxEdge += pos_f;
+ box.MinEdge += pos_f;
+ core::aabbox3d<f32> 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<f32> 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;
+}
+
+
--- /dev/null
+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef 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<f32> &box_0,
+ f32 dtime, v3f &pos_f, v3f &speed_f);
+//{return collisionMoveResult();}
+
+
+#endif
+
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)
{
}
}
}
- //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<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);
+ obj->step(dtime, m_active_object_messages, send_recommended);
}
/*
// 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
}
}
+ if(g_settings.getBool("enable_experimental"))
+ {
+
/*
TEST CODE
*/
//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
/*
Step active objects
*/
+
for(core::map<u16, ClientActiveObject*>::Iterator
i = m_active_objects.getIterator();
i.atEnd()==false; i++)
core::map<u16, ServerActiveObject*> m_active_objects;
Queue<ActiveObjectMessage> m_active_object_messages;
float m_random_spawn_timer;
+ float m_send_recommended_timer;
};
#ifndef SERVER
#include "debug.h"
#include <sstream>
#include "main.h"
+#include "serverobject.h"
/*
InventoryItem
}
}
+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
*/
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")
/*
MapBlockObjectItem
+ TODO: Remove
*/
#ifndef SERVER
video::ITexture * MapBlockObjectItem::getImage()
#define QUANTITY_ITEM_MAX_COUNT 99
+class ServerActiveObject;
+class ServerEnvironment;
+
class InventoryItem
{
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)
return false;
}
- /*
- Quantity methods
- */
u16 getCount()
{
return m_count;
u8 m_content;
};
+//TODO: Remove
class MapBlockObjectItem : public InventoryItem
{
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()
{
os<<m_count;
return os.str();
}
+
+ ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos);
+
virtual bool addableTo(InventoryItem *other)
{
if(std::string(other->getName()) != "CraftItem")
if(dummy == false)
reallocate();
- m_spawn_timer = -10000;
+ //m_spawn_timer = -10000;
#ifndef SERVER
m_mesh_expired = false;
Step objects
*/
m_objects.step(dtime, server, daynight_ratio);
-
+
+#if 0
/*
Spawn some objects at random.
}
}
}
+#endif
setChangedFlag();
}
// 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
/*
dout_server<<"Player inventory has no free space"<<std::endl;
return;
}
+
+ // Skip if object has been removed
+ if(obj->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)
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 \""<<os.str()<<"\""<<std::endl;
- // Create object
- ServerActiveObject *obj = new ItemSAO
- (&m_env, 0, pos, os.str());
+ ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
if(obj == NULL)
{
dout_server<<"Placed object"<<std::endl;
- InventoryList *ilist = player->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);
}
return new TestSAO(env, id, pos);
}
-void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
+void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
+ bool send_recommended)
{
m_age += dtime;
if(m_age > 10)
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)
{
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=\""
<<m_inventorystring<<"\""<<std::endl;
return new ItemSAO(env, id, pos, inventorystring);
}
-void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
+void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
+ bool send_recommended)
{
core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
collisionMoveResult moveresult;
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];
}
+/*
+ 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"<<std::endl;
+ 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;
+}
+
+ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ std::istringstream is(data, std::ios::binary);
+ char buf[1];
+ // read version
+ is.read(buf, 1);
+ u8 version = buf[0];
+ // check if version is supported
+ if(version != 0)
+ return NULL;
+ return new RatSAO(env, id, pos);
+}
+
+void RatSAO::step(float dtime, Queue<ActiveObjectMessage> &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<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*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<f32> 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<<std::endl;
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ return os.str();
+}
+
+InventoryItem* RatSAO::createPickedUpItem()
+{
+ std::istringstream is("CraftItem rat 1", std::ios_base::binary);
+ InventoryItem *item = InventoryItem::deSerialize(is);
+ return item;
+}
+
*/
+#if 0
+class IntervalLimiter
+{
+public:
+ IntervalLimiter():
+ m_accumulator(0)
+ {
+ }
+ /*
+ dtime: time from last call to this method
+ wanted_interval: interval wanted
+ return value:
+ true: action should be skipped
+ false: action should be done and dtime has been set
+ */
+ bool step(float &dtime, float wanted_interval)
+ {
+ accumulator += dtime;
+ if(accumulator < wanted_interval)
+ {
+ dtime = 0;
+ return true;
+ }
+ accumulator -= wanted-interval;
+ dtime = wanted_interval;
+ return false;
+ }
+protected:
+ float m_accumulator;
+};
+#endif
+
class ServerEnvironment;
class InventoryItem;
/*
Step object in time.
Messages added to messages are sent to client over network.
+
+ send_recommended:
+ True at around 5 times a second, same for all objects.
+ This is used to let objects send most of the data at the
+ same time so that the data can be combined in a single
+ packet.
*/
- virtual void step(float dtime, Queue<ActiveObjectMessage> &messages){}
+ virtual void step(float dtime, Queue<ActiveObjectMessage> &messages,
+ bool send_recommended){}
/*
The return value of this is passed to the client-side object
*/
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;
/*
{return ACTIVEOBJECT_TYPE_TEST;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data);
- void step(float dtime, Queue<ActiveObjectMessage> &messages);
+ void step(float dtime, Queue<ActiveObjectMessage> &messages,
+ bool send_recommended);
private:
float m_timer1;
float m_age;
{return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data);
- void step(float dtime, Queue<ActiveObjectMessage> &messages);
+ void step(float dtime, Queue<ActiveObjectMessage> &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<ActiveObjectMessage> &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
return (data[0]<<0);
}
-// Signed variants of the above
-
inline void writeS32(u8 *data, s32 i){
writeU32(data, (u32)i);
}
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);
}
writeS32(&data[4], p.Y);
writeS32(&data[8], p.Z);
}
-
inline v3s32 readV3S32(u8 *data)
{
v3s32 p;
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);
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
*/