summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client.cpp29
-rw-r--r--src/client.h1
-rw-r--r--src/clientobject.cpp22
-rw-r--r--src/clientobject.h12
-rw-r--r--src/clientserver.h9
-rw-r--r--src/environment.cpp208
-rw-r--r--src/main.cpp26
-rw-r--r--src/map.cpp16
-rw-r--r--src/mapblock.h2
-rw-r--r--src/nodemetadata.h2
-rw-r--r--src/serialization.h3
-rw-r--r--src/server.cpp190
-rw-r--r--src/serverobject.cpp91
-rw-r--r--src/serverobject.h70
-rw-r--r--src/utility.h14
15 files changed, 535 insertions, 160 deletions
diff --git a/src/client.cpp b/src/client.cpp
index 1f2f7e1e8..fca7b1b02 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -1193,7 +1193,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
{
- if(g_settings.getBool("enable_experimental"))
+ //if(g_settings.getBool("enable_experimental"))
{
/*
u16 command
@@ -1252,7 +1252,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
{
- if(g_settings.getBool("enable_experimental"))
+ //if(g_settings.getBool("enable_experimental"))
{
/*
u16 command
@@ -1594,6 +1594,31 @@ void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
Send(0, data, true);
}
+void Client::clickActiveObject(u8 button, u16 id, u16 item)
+{
+ if(connectedAndInitialized() == false){
+ dout_client<<DTIME<<"Client::clickActiveObject() "
+ "cancelled (not connected)"
+ <<std::endl;
+ return;
+ }
+
+ /*
+ length: 7
+ [0] u16 command
+ [2] u8 button (0=left, 1=right)
+ [3] u16 id
+ [5] u16 item
+ */
+ u8 datasize = 2 + 1 + 6 + 2 + 2;
+ SharedBuffer<u8> data(datasize);
+ writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
+ writeU8(&data[2], button);
+ writeU16(&data[3], id);
+ writeU16(&data[5], item);
+ Send(0, data, true);
+}
+
void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
{
/*
diff --git a/src/client.h b/src/client.h
index 0616cc914..ef3dd435a 100644
--- a/src/client.h
+++ b/src/client.h
@@ -275,6 +275,7 @@ public:
void groundAction(u8 action, v3s16 nodepos_undersurface,
v3s16 nodepos_oversurface, u16 item);
void clickObject(u8 button, v3s16 blockpos, s16 id, u16 item);
+ void clickActiveObject(u8 button, u16 id, u16 item);
void sendSignText(v3s16 blockpos, s16 id, std::string text);
void sendSignNodeText(v3s16 p, std::string text);
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index d95862d1d..a6aa033ef 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "constants.h"
#include "utility.h"
+#include "environment.h"
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
@@ -148,7 +149,7 @@ void TestCAO::updateNodePos()
//m_node->setRotation(v3f(0, 45, 0));
}
-void TestCAO::step(float dtime)
+void TestCAO::step(float dtime, ClientEnvironment *env)
{
if(m_node)
{
@@ -187,7 +188,7 @@ ItemCAO proto_ItemCAO;
ItemCAO::ItemCAO():
ClientActiveObject(0),
- m_selection_box(-BS*0.4,0.0,-BS*0.4, BS*0.4,BS*0.8,BS*0.4),
+ m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0))
{
@@ -219,10 +220,10 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr)
video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
- video::S3DVertex(BS/3,0,0, 0,0,0, c, 0,1),
- video::S3DVertex(-BS/3,0,0, 0,0,0, c, 1,1),
- video::S3DVertex(-BS/3,0+BS*2/3,0, 0,0,0, c, 1,0),
- video::S3DVertex(BS/3,0+BS*2/3,0, 0,0,0, c, 0,0),
+ video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
+ video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
+ video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
+ video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
@@ -272,12 +273,17 @@ void ItemCAO::updateNodePos()
m_node->setPosition(m_position);
}
-void ItemCAO::step(float dtime)
+void ItemCAO::step(float dtime, ClientEnvironment *env)
{
if(m_node)
{
- v3f rot = m_node->getRotation();
+ /*v3f rot = m_node->getRotation();
rot.Y += dtime * 120;
+ m_node->setRotation(rot);*/
+ LocalPlayer *player = env->getLocalPlayer();
+ assert(player);
+ v3f rot = m_node->getRotation();
+ rot.Y = 180.0 - (player->getYaw());
m_node->setRotation(rot);
}
}
diff --git a/src/clientobject.h b/src/clientobject.h
index ebdcb948e..50fae67c2 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -35,6 +35,8 @@ Some planning
*/
+class ClientEnvironment;
+
class ClientActiveObject : public ActiveObject
{
public:
@@ -51,11 +53,13 @@ public:
virtual v3f getPosition(){return v3f(0,0,0);}
// Step object in time
- virtual void step(float dtime){}
+ virtual void step(float dtime, ClientEnvironment *env){}
// Process a message sent by the server side object
virtual void processMessage(const std::string &data){}
+ virtual std::string infoText() {return "";}
+
/*
This takes the return value of
ServerActiveObject::getClientInitializationData
@@ -66,9 +70,11 @@ public:
static ClientActiveObject* create(u8 type);
protected:
+ // Used for creating objects based on type
typedef ClientActiveObject* (*Factory)();
static void registerType(u16 type, Factory f);
private:
+ // Used for creating objects based on type
static core::map<u16, Factory> m_types;
};
@@ -112,7 +118,7 @@ public:
v3s16 getLightPosition();
void updateNodePos();
- void step(float dtime);
+ void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
@@ -144,7 +150,7 @@ public:
v3s16 getLightPosition();
void updateNodePos();
- void step(float dtime);
+ void step(float dtime, ClientEnvironment *env);
void processMessage(const std::string &data);
diff --git a/src/clientserver.h b/src/clientserver.h
index 7baa79fa6..fadafed5f 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -249,6 +249,15 @@ enum ToServerCommand
textdata
*/
+ TOSERVER_CLICK_ACTIVEOBJECT = 0x34,
+ /*
+ length: 7
+ [0] u16 command
+ [2] u8 button (0=left, 1=right)
+ [3] u16 id
+ [5] u16 item
+ */
+
};
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)
diff --git a/src/environment.cpp b/src/environment.cpp
index f4afb28bf..7e1d268df 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -189,7 +189,7 @@ u32 Environment::getDayNightRatio()
ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
m_map(map),
m_server(server),
- m_random_spawn_timer(0)
+ m_random_spawn_timer(3)
{
}
@@ -422,7 +422,7 @@ void ServerEnvironment::step(float dtime)
}
}
- if(g_settings.getBool("enable_experimental"))
+ //if(g_settings.getBool("enable_experimental"))
{
/*
@@ -438,7 +438,7 @@ void ServerEnvironment::step(float dtime)
}
/*
- Remove (m_removed && m_known_by_count==0) objects
+ Remove objects that satisfy (m_removed && m_known_by_count==0)
*/
{
core::list<u16> objects_to_remove;
@@ -457,16 +457,173 @@ void ServerEnvironment::step(float dtime)
objects_to_remove.push_back(id);
continue;
}
- else
+ // If not m_removed, don't remove.
+ if(obj->m_removed == false)
+ continue;
+ // Delete
+ delete obj;
+ // Id to be removed from m_active_objects
+ objects_to_remove.push_back(id);
+ }
+ // Remove references from m_active_objects
+ for(core::list<u16>::Iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); i++)
+ {
+ m_active_objects.remove(*i);
+ }
+ }
+
+
+ const s16 to_active_max_blocks = 3;
+ const f32 to_static_max_f = (to_active_max_blocks+1)*MAP_BLOCKSIZE*BS;
+
+ /*
+ Convert stored objects from blocks near the players to active.
+ */
+ for(core::list<Player*>::Iterator i = m_players.begin();
+ i != m_players.end(); i++)
+ {
+ Player *player = *i;
+ v3f playerpos = player->getPosition();
+
+ v3s16 blockpos0 = getNodeBlockPos(floatToInt(playerpos, BS));
+ v3s16 bpmin = blockpos0 - v3s16(1,1,1)*to_active_max_blocks;
+ v3s16 bpmax = blockpos0 + v3s16(1,1,1)*to_active_max_blocks;
+ // Loop through all nearby blocks
+ for(s16 x=bpmin.X; x<=bpmax.X; x++)
+ for(s16 y=bpmin.Y; y<=bpmax.Y; y++)
+ for(s16 z=bpmin.Z; z<=bpmax.Z; z++)
+ {
+ v3s16 blockpos(x,y,z);
+ MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+ if(block==NULL)
+ continue;
+ // Ignore if no stored objects (to not set changed flag)
+ if(block->m_static_objects.m_stored.size() == 0)
+ continue;
+ // This will contain the leftovers of the stored list
+ core::list<StaticObject> new_stored;
+ // Loop through stored static objects
+ for(core::list<StaticObject>::Iterator
+ i = block->m_static_objects.m_stored.begin();
+ i != block->m_static_objects.m_stored.end(); i++)
{
- // If not m_removed, don't remove.
- if(obj->m_removed == false)
+ dstream<<"INFO: Server: Creating an active object from "
+ <<"static data"<<std::endl;
+ StaticObject &s_obj = *i;
+ // Create an active object from the data
+ ServerActiveObject *obj = ServerActiveObject::create
+ (s_obj.type, this, 0, s_obj.pos, s_obj.data);
+ if(obj==NULL)
+ {
+ // This is necessary to preserve stuff during bugs
+ // and errors
+ new_stored.push_back(s_obj);
continue;
- // Delete
- delete obj;
- // Id to be removed from m_active_objects
- objects_to_remove.push_back(id);
+ }
+ // This will also add the object to the active static list
+ addActiveObject(obj);
+ //u16 id = addActiveObject(obj);
+ }
+ // Clear stored list
+ block->m_static_objects.m_stored.clear();
+ // Add leftover stuff to stored list
+ for(core::list<StaticObject>::Iterator
+ i = new_stored.begin();
+ i != new_stored.end(); i++)
+ {
+ StaticObject &s_obj = *i;
+ block->m_static_objects.m_stored.push_back(s_obj);
+ }
+ block->setChangedFlag();
+ }
+ }
+
+ /*
+ Convert objects that are far away from all the players to static.
+ */
+ {
+ core::list<u16> objects_to_remove;
+ for(core::map<u16, ServerActiveObject*>::Iterator
+ i = m_active_objects.getIterator();
+ i.atEnd()==false; i++)
+ {
+ ServerActiveObject* obj = i.getNode()->getValue();
+ u16 id = i.getNode()->getKey();
+ v3f objectpos = obj->getBasePosition();
+
+ // This shouldn't happen but check it
+ if(obj == NULL)
+ {
+ dstream<<"WARNING: NULL object found in ServerEnvironment"
+ <<std::endl;
+ continue;
}
+ // If known by some client, don't convert to static.
+ if(obj->m_known_by_count > 0)
+ continue;
+
+ // If close to some player, don't convert to static.
+ bool close_to_player = false;
+ for(core::list<Player*>::Iterator i = m_players.begin();
+ i != m_players.end(); i++)
+ {
+ Player *player = *i;
+ v3f playerpos = player->getPosition();
+ f32 d = playerpos.getDistanceFrom(objectpos);
+ if(d < to_static_max_f)
+ {
+ close_to_player = true;
+ break;
+ }
+ }
+
+ if(close_to_player)
+ continue;
+
+ /*
+ Update the static data and remove the active object.
+ */
+
+ // Delete old static object
+ MapBlock *oldblock = NULL;
+ if(obj->m_static_exists)
+ {
+ MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
+ if(block)
+ {
+ block->m_static_objects.remove(id);
+ oldblock = block;
+ }
+ }
+ // Add new static object
+ std::string staticdata = obj->getStaticData();
+ StaticObject s_obj(obj->getType(), objectpos, staticdata);
+ // Add to the block where the object is located in
+ v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
+ MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+ if(block)
+ {
+ block->m_static_objects.insert(0, s_obj);
+ block->setChangedFlag();
+ }
+ // If not possible, add back to previous block
+ else if(oldblock)
+ {
+ oldblock->m_static_objects.insert(0, s_obj);
+ oldblock->setChangedFlag();
+ }
+ else{
+ dstream<<"WARNING: Server: Could not find a block for "
+ <<"storing static object"<<std::endl;
+ continue;
+ }
+ // Delete active object
+ dstream<<"INFO: Server: Stored static data. Deleting object."
+ <<std::endl;
+ delete obj;
+ // Id to be removed from m_active_objects
+ objects_to_remove.push_back(id);
}
// Remove references from m_active_objects
for(core::list<u16>::Iterator i = objects_to_remove.begin();
@@ -479,11 +636,13 @@ void ServerEnvironment::step(float dtime)
/*
TEST CODE
*/
+#if 1
m_random_spawn_timer -= dtime;
if(m_random_spawn_timer < 0)
{
//m_random_spawn_timer += myrand_range(2.0, 20.0);
- m_random_spawn_timer += 2.0;
+ //m_random_spawn_timer += 2.0;
+ m_random_spawn_timer += 200.0;
/*
Find some position
@@ -508,11 +667,10 @@ void ServerEnvironment::step(float dtime)
*/
//TestSAO *obj = new TestSAO(this, 0, pos);
- ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
-
- // Add the object to the environment
- addActiveObject(obj);
+ //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
+ //addActiveObject(obj);
}
+#endif
} // enable_experimental
}
@@ -582,7 +740,25 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
}
dstream<<"INGO: ServerEnvironment::addActiveObject(): "
<<"added (id="<<object->getId()<<")"<<std::endl;
+
m_active_objects.insert(object->getId(), object);
+
+ // Add static object to active static list of the block
+ v3f objectpos = object->getBasePosition();
+ std::string staticdata = object->getStaticData();
+ StaticObject s_obj(object->getType(), objectpos, staticdata);
+ // Add to the block where the object is located in
+ v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
+ MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+ if(block)
+ {
+ block->m_static_objects.m_active.insert(object->getId(), s_obj);
+ }
+ else{
+ dstream<<"WARNING: Server: Could not find a block for "
+ <<"storing newly added static active object"<<std::endl;
+ }
+
return object->getId();
}
@@ -912,7 +1088,7 @@ void ClientEnvironment::step(float dtime)
{
ClientActiveObject* obj = i.getNode()->getValue();
// Step object
- obj->step(dtime);
+ obj->step(dtime, this);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index d3f979cac..7749266d9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2620,10 +2620,8 @@ int main(int argc, char *argv[])
if(g_input->getLeftClicked())
{
std::cout<<DTIME<<"Left-clicked object"<<std::endl;
-#if 0
- client.clickObject(0, selected_object->getBlock()->getPos(),
- selected_object->getId(), g_selected_item);
-#endif
+ client.clickActiveObject(0,
+ selected_active_object->getId(), g_selected_item);
}
else if(g_input->getRightClicked())
{
@@ -2634,26 +2632,6 @@ int main(int argc, char *argv[])
*/
if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)
{
- dstream<<"Sign object right-clicked"<<std::endl;
-
- if(random_input == false)
- {
- // Get a new text for it
-
- TextDest *dest = new TextDestSign(
- selected_object->getBlock()->getPos(),
- selected_object->getId(),
- &client);
-
- SignObject *sign_object = (SignObject*)selected_object;
-
- std::wstring wtext =
- narrow_to_wide(sign_object->getText());
-
- (new GUITextInputMenu(guienv, guiroot, -1,
- &g_menumgr, dest,
- wtext))->drop();
- }
}
/*
Otherwise pass the event to the server as-is
diff --git a/src/map.cpp b/src/map.cpp
index 49ed2f5fe..59cf937c0 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -5239,6 +5239,14 @@ void ServerMap::saveBlock(MapBlock *block)
block->serializeObjects(o, version);
}
+ /*
+ Versions up from 15 have static objects.
+ */
+ if(version >= 15)
+ {
+ block->m_static_objects.serialize(o);
+ }
+
// We just wrote it to the disk
block->resetChangedFlag();
}
@@ -5296,6 +5304,14 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
block->updateObjects(is, version, NULL, 0);
}
+ /*
+ Versions up from 15 have static objects.
+ */
+ if(version >= 15)
+ {
+ block->m_static_objects.deSerialize(is);
+ }
+
if(created_new)
sector->insertBlock(block);
diff --git a/src/mapblock.h b/src/mapblock.h
index a77bf40c0..ce5682568 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblockobject.h"
#include "voxel.h"
#include "nodemetadata.h"
+#include "staticobject.h"
// Named by looking towards z+
@@ -681,6 +682,7 @@ public:
#endif
NodeMetadataList m_node_metadata;
+ StaticObjectList m_static_objects;
private:
/*
diff --git a/src/nodemetadata.h b/src/nodemetadata.h
index e56bff17f..ae02cfc3c 100644
--- a/src/nodemetadata.h
+++ b/src/nodemetadata.h
@@ -54,7 +54,7 @@ public:
virtual u16 typeId() const = 0;
virtual NodeMetadata* clone() = 0;
virtual void serializeBody(std::ostream &os) = 0;
- virtual std::string infoText() {return "<todo: remove this text>";}
+ virtual std::string infoText() {return "";}
virtual Inventory* getInventory() {return NULL;}
// This is called always after the inventory is modified, before
// the changes are copied elsewhere
diff --git a/src/serialization.h b/src/serialization.h
index fed5bb522..7b5c7d418 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -47,11 +47,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
12: (dev) UnlimitedHeightmap now uses interpolated areas
13: (dev) Mapgen v2
14: (dev) NodeMetadata
+ 15: (dev) StaticObjects
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 14
+#define SER_FMT_VER_HIGHEST 15
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 2
diff --git a/src/server.cpp b/src/server.cpp
index 20a6a21c3..ab4032743 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1228,7 +1228,7 @@ void Server::AsyncRunStep()
}
}
- if(g_settings.getBool("enable_experimental"))
+ //if(g_settings.getBool("enable_experimental"))
{
/*
@@ -1345,6 +1345,33 @@ void Server::AsyncRunStep()
<<added_objects.size()<<" added, "
<<"packet size is "<<reply.getSize()<<std::endl;
}
+
+#if 0
+ /*
+ Collect a list of all the objects known by the clients
+ and report it back to the environment.
+ */
+
+ core::map<u16, bool> all_known_objects;
+
+ for(core::map<u16, RemoteClient*>::Iterator
+ i = m_clients.getIterator();
+ i.atEnd() == false; i++)
+ {
+ RemoteClient *client = i.getNode()->getValue();
+ // Go through all known objects of client
+ for(core::map<u16, bool>::Iterator
+ i = client->m_known_objects.getIterator();
+ i.atEnd()==false; i++)
+ {
+ u16 id = i.getNode()->getKey();
+ all_known_objects[id] = true;
+ }
+ }
+
+ m_env.setKnownActiveObjects(whatever);
+#endif
+
}
/*
@@ -1978,6 +2005,70 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
block->removeObject(id);
}
}
+ else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
+ {
+ if(datasize < 7)
+ return;
+
+ /*
+ length: 7
+ [0] u16 command
+ [2] u8 button (0=left, 1=right)
+ [3] u16 id
+ [5] u16 item
+ */
+ u8 button = readU8(&data[2]);
+ u16 id = readS16(&data[3]);
+ //u16 item_i = readU16(&data[11]);
+
+ ServerActiveObject *obj = m_env.getActiveObject(id);
+
+ if(obj == NULL)
+ {
+ derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
+ <<std::endl;
+ return;
+ }
+
+ //TODO: Check that object is reasonably close
+
+ // Left click, pick object up (usually)
+ if(button == 0)
+ {
+ InventoryList *ilist = player->inventory.getList("main");
+ if(g_settings.getBool("creative_mode") == false && ilist != NULL)
+ {
+
+ // Skip if inventory has no free space
+ if(ilist->getUsedSlots() == ilist->getSize())
+ {
+ dout_server<<"Player inventory has no free space"<<std::endl;
+ 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();
+ }
+
+ if(item)
+ {
+ // Add to inventory and send inventory
+ ilist->addItem(item);
+ SendInventory(player->peer_id);
+ }
+ }
+
+ // Remove object from environment
+ obj->m_removed = true;
+ }
+ }
else if(command == TOSERVER_GROUND_ACTION)
{
if(datasize < 17)
@@ -2327,68 +2418,40 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}*/
}
/*
- Handle other items
+ Place other item (not a block)
*/
else
{
v3s16 blockpos = getNodeBlockPos(p_over);
-
- MapBlock *block = NULL;
- try
- {
- block = m_env.getMap().getBlockNoCreate(blockpos);
- }
- catch(InvalidPositionException &e)
+
+ /*
+ Check that the block is loaded so that the item
+ can properly be added to the static list too
+ */
+ MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
+ if(block==NULL)
{
derr_server<<"Error while placing object: "
"block not found"<<std::endl;
return;
}
- v3s16 block_pos_i_on_map = block->getPosRelative();
- v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
-
v3f pos = intToFloat(p_over, BS);
- pos -= block_pos_f_on_map;
-
- /*dout_server<<"pos="
- <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
- <<std::endl;*/
+ pos.Y -= BS*0.45;
- MapBlockObject *obj = NULL;
-
- /*
- Handle block object items
- */
- if(std::string("MBOItem") == item->getName())
- {
- MapBlockObjectItem *oitem = (MapBlockObjectItem*)item;
-
- /*dout_server<<"Trying to place a MapBlockObjectItem: "
- "inventorystring=\""
- <<oitem->getInventoryString()
- <<"\""<<std::endl;*/
-
- obj = oitem->createObject
- (pos, player->getYaw(), player->getPitch());
- }
+ dout_server<<"Placing a miscellaneous item on map"
+ <<std::endl;
+
/*
- Handle other items
+ Create an ItemSAO
*/
- else
- {
- dout_server<<"Placing a miscellaneous item on map"
- <<std::endl;
- /*
- Create an ItemObject that contains the item.
- */
- ItemObject *iobj = new ItemObject(NULL, -1, pos);
- std::ostringstream os(std::ios_base::binary);
- item->serialize(os);
- dout_server<<"Item string is \""<<os.str()<<"\""<<std::endl;
- iobj->setItemString(os.str());
- obj = iobj;
- }
+ // 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());
if(obj == NULL)
{
@@ -2398,8 +2461,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else
{
- block->addObject(obj);
-
+ // Add the object to the environment
+ m_env.addActiveObject(obj);
+
dout_server<<"Placed object"<<std::endl;
InventoryList *ilist = player->inventory.getList("main");
@@ -3874,30 +3938,6 @@ Player *Server::emergePlayer(const char *name, const char *password,
} // create new player
}
-#if 0
-void Server::UpdateBlockWaterPressure(MapBlock *block,
- core::map<v3s16, MapBlock*> &modified_blocks)
-{
- MapVoxelManipulator v(&m_env.getMap());
- v.m_disable_water_climb =
- g_settings.getBool("disable_water_climb");
-
- VoxelArea area(block->getPosRelative(),
- block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
-
- try
- {
- v.updateAreaWaterPressure(area, m_flow_active_nodes);
- }
- catch(ProcessingLimitException &e)
- {
- dstream<<"Processing limit reached (1)"<<std::endl;
- }
-
- v.blitBack(modified_blocks);
-}
-#endif
-
void Server::handlePeerChange(PeerChange &c)
{
JMutexAutoLock envlock(m_env_mutex);
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index 3645f7666..f0ef7d8d6 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -20,11 +20,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include <fstream>
#include "environment.h"
+#include "inventory.h"
+
+core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos):
ActiveObject(id),
m_known_by_count(0),
m_removed(false),
+ m_static_exists(false),
+ m_static_block(1337,1337,1337),
m_env(env),
m_base_position(pos)
{
@@ -34,15 +39,55 @@ ServerActiveObject::~ServerActiveObject()
{
}
+ServerActiveObject* ServerActiveObject::create(u8 type,
+ ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ // Find factory function
+ core::map<u16, Factory>::Node *n;
+ n = m_types.find(type);
+ if(n == NULL)
+ {
+ // If factory is not found, just return.
+ dstream<<"WARNING: ServerActiveObject: No factory for type="
+ <<type<<std::endl;
+ return NULL;
+ }
+
+ Factory f = n->getValue();
+ ServerActiveObject *object = (*f)(env, id, pos, data);
+ return object;
+}
+
+void ServerActiveObject::registerType(u16 type, Factory f)
+{
+ core::map<u16, Factory>::Node *n;
+ n = m_types.find(type);
+ if(n)
+ return;
+ m_types.insert(type, f);
+}
+
+
/*
TestSAO
*/
+// Prototype
+TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
+
TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
ServerActiveObject(env, id, pos),
m_timer1(0),
m_age(0)
{
+ ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ return new TestSAO(env, id, pos);
}
void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
@@ -84,6 +129,9 @@ void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
ItemSAO
*/
+// Prototype
+ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
+
ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
const std::string inventorystring):
ServerActiveObject(env, id, pos),
@@ -91,6 +139,19 @@ ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
{
dstream<<"Server: ItemSAO created with inventorystring=\""
<<m_inventorystring<<"\""<<std::endl;
+ ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ std::istringstream is(data, std::ios::binary);
+ char buf[1];
+ is.read(buf, 1); // read version
+ std::string inventorystring = deSerializeString(is);
+ dstream<<"ItemSAO::create(): Creating item \""
+ <<inventorystring<<"\""<<std::endl;
+ return new ItemSAO(env, id, pos, inventorystring);
}
void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
@@ -111,4 +172,34 @@ std::string ItemSAO::getClientInitializationData()
return data;
}
+std::string ItemSAO::getStaticData()
+{
+ dstream<<__FUNCTION_NAME<<std::endl;
+ std::ostringstream os(std::ios::binary);
+ char buf[1];
+ buf[0] = 0; //version
+ os.write(buf, 1);
+ os<<serializeString(m_inventorystring);
+ return os.str();
+}
+
+InventoryItem * ItemSAO::createInventoryItem()
+{
+ try{
+ std::istringstream is(m_inventorystring, std::ios_base::binary);
+ InventoryItem *item = InventoryItem::deSerialize(is);
+ dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
+ <<m_inventorystring<<"\" -> item="<<item
+ <<std::endl;
+ return item;
+ }
+ catch(SerializationError &e)
+ {
+ dstream<<__FUNCTION_NAME<<": serialization error: "
+ <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
+ return NULL;
+ }
+}
+
+
diff --git a/src/serverobject.h b/src/serverobject.h
index 241458193..a307c421f 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -39,27 +39,28 @@ Some planning
*/
class ServerEnvironment;
+class InventoryItem;
class ServerActiveObject : public ActiveObject
{
public:
- ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos=v3f(0,0,0));
+ ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos);
virtual ~ServerActiveObject();
- v3f getBasePosition()
- {
- return m_base_position;
- }
+ // Create a certain type of ServerActiveObject
+ static ServerActiveObject* create(u8 type,
+ ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ /*
+ Some simple getters/setters
+ */
+ v3f getBasePosition()
+ {return m_base_position;}
void setBasePosition(v3f pos)
- {
- m_base_position = pos;
- }
-
+ {m_base_position = pos;}
ServerEnvironment* getEnv()
- {
- return m_env;
- }
+ {return m_env;}
/*
Step object in time.
@@ -75,14 +76,10 @@ public:
/*
The return value of this is passed to the server-side object
- when it is loaded from disk or from a static object
- */
- virtual std::string getServerInitializationData(){return "";}
-
- /*
- This takes the return value of getServerInitializationData
+ when it is created (converted from static to active - actually
+ the data is the static form)
*/
- virtual void initialize(const std::string &data){}
+ virtual std::string getStaticData(){return "";}
// Number of players which know about this object
u16 m_known_by_count;
@@ -93,12 +90,33 @@ public:
it could be confused to some other object by some client.
- This is set to true by the step() method when the object wants
to be deleted.
+ - This can be set to true by anything else too.
*/
bool m_removed;
+ /*
+ Whether the object's static data has been stored to a block
+ */
+ bool m_static_exists;
+ /*
+ The block from which the object was loaded from, and in which
+ a copy of the static data resides.
+ */
+ v3s16 m_static_block;
+
protected:
+ // Used for creating objects based on type
+ typedef ServerActiveObject* (*Factory)
+ (ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ static void registerType(u16 type, Factory f);
+
ServerEnvironment *m_env;
v3f m_base_position;
+
+private:
+ // Used for creating objects based on type
+ static core::map<u16, Factory> m_types;
};
class TestSAO : public ServerActiveObject
@@ -106,9 +124,9 @@ class TestSAO : public ServerActiveObject
public:
TestSAO(ServerEnvironment *env, u16 id, v3f pos);
u8 getType() const
- {
- return ACTIVEOBJECT_TYPE_TEST;
- }
+ {return ACTIVEOBJECT_TYPE_TEST;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
void step(float dtime, Queue<ActiveObjectMessage> &messages);
private:
float m_timer1;
@@ -121,11 +139,13 @@ public:
ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
const std::string inventorystring);
u8 getType() const
- {
- return ACTIVEOBJECT_TYPE_ITEM;
- }
+ {return ACTIVEOBJECT_TYPE_ITEM;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
void step(float dtime, Queue<ActiveObjectMessage> &messages);
std::string getClientInitializationData();
+ std::string getStaticData();
+ InventoryItem* createInventoryItem();
private:
std::string m_inventorystring;
};
diff --git a/src/utility.h b/src/utility.h
index 3640b4b51..2b143f0ba 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -1839,15 +1839,17 @@ inline std::string serializeString(const std::string plain)
return s;
}
-// Reads a string with the length as the first two bytes
+/*// Reads a string with the length as the first two bytes
inline std::string deSerializeString(const std::string encoded)
{
u16 s_size = readU16((u8*)&encoded.c_str()[0]);
+ if(s_size > encoded.length() - 2)
+ return "";
std::string s;
s.reserve(s_size);
s.append(&encoded.c_str()[2], s_size);
return s;
-}
+}*/
// Reads a string with the length as the first two bytes
inline std::string deSerializeString(std::istream &is)
@@ -1878,15 +1880,17 @@ inline std::string serializeLongString(const std::string plain)
return s;
}
-// Reads a string with the length as the first four bytes
+/*// Reads a string with the length as the first four bytes
inline std::string deSerializeLongString(const std::string encoded)
{
u32 s_size = readU32((u8*)&encoded.c_str()[0]);
+ if(s_size > encoded.length() - 4)
+ return "";
std::string s;
s.reserve(s_size);
- s.append(&encoded.c_str()[2], s_size);
+ s.append(&encoded.c_str()[4], s_size);
return s;
-}
+}*/
// Reads a string with the length as the first four bytes
inline std::string deSerializeLongString(std::istream &is)