From 02fd4ceb8c3fdc14215aa2f96f081796882633ef Mon Sep 17 00:00:00 2001 From: darkrose Date: Thu, 28 Jan 2016 02:02:42 +1000 Subject: [PATCH] remove Item{S,C}ao, drop items directly to parcels --- src/content_cao.cpp | 186 ------------------- src/content_cao.h | 52 ------ src/content_mapnode_plants.cpp | 14 ++ src/content_nodemeta.cpp | 34 +--- src/content_object.h | 10 +- src/content_sao.cpp | 310 ------------------------------- src/content_sao.h | 24 --- src/environment.cpp | 325 ++++++++++++++++++++++++++++----- src/environment.h | 3 + src/inventory.cpp | 14 +- src/inventory.h | 2 +- src/mapnode.h | 7 + src/server.cpp | 145 +++++---------- src/serverobject.cpp | 15 -- 14 files changed, 372 insertions(+), 769 deletions(-) diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 78aa1a7..83140d2 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -34,192 +34,6 @@ core::map ClientActiveObject::m_types; -/* - ItemCAO -*/ - -#include "inventory.h" - -// Prototype -ItemCAO proto_ItemCAO; - -ItemCAO::ItemCAO(): - ClientActiveObject(0), - m_selection_box(-0.25*BS,-0.26*BS,-0.26*BS,0.26*BS,0.26*BS,0.26*BS), - m_node(NULL), - m_position(v3f(0,10*BS,0)), - m_camera_offset(v3s16(0,0,0)), - m_content(CONTENT_IGNORE) -{ - ClientActiveObject::registerType(getType(), create); - m_rot = myrand_range(0,360); -} - -ItemCAO::~ItemCAO() -{ -} - -ClientActiveObject* ItemCAO::create() -{ - return new ItemCAO(); -} - -void ItemCAO::addToScene(scene::ISceneManager *smgr) -{ - if (m_node == NULL) { - m_node = new ExtrudedSpriteSceneNode(smgr->getRootSceneNode(),smgr,-1,v3f(0,0,0),v3f(0,0,0),v3f(5,5,5)); - m_node->setVisible(false); - } - - updateVisual(); -} - -void ItemCAO::removeFromScene() -{ - if (m_node == NULL) - return; - - m_node->remove(); - m_node = NULL; -} - -void ItemCAO::updateLight(u8 light_at_pos) -{ - if (m_node == NULL) - return; - - u8 li = decode_light(light_at_pos); - m_node->updateLight(li); -} - -v3s16 ItemCAO::getLightPosition() -{ - return floatToInt(m_position, BS); -} - -void ItemCAO::updateNodePos() -{ - if (m_node == NULL) - return; - - m_node->setPosition(pos_translator.vect_show-intToFloat(m_camera_offset, BS)); -} - -void ItemCAO::step(float dtime, ClientEnvironment *env) -{ - if (m_node == NULL) - return; - - pos_translator.translate(dtime); - updateNodePos(); - - v3f rot = m_node->getRotation(); - rot.Y = m_rot++; - if (m_rot > 360) - m_rot -= 360; - m_node->setRotation(rot); -} - -void ItemCAO::processMessage(const std::string &data) -{ - infostream<<"ItemCAO: Got message"< item="<getName()) == "MaterialItem") { - // A block-type material - MaterialItem* mat_item = (MaterialItem*)item; - content_t content = mat_item->getMaterial(); - if (content_features(content).solidness || content_features(content).visual_solidness) { - m_node->setCube(content_features(content).tiles); - haveWield = true; - }else if ( - ( - content_features(content).draw_type == CDT_NODEBOX - || content_features(content).draw_type == CDT_NODEBOX_META - || content_features(content).draw_type == CDT_FENCELIKE - || content_features(content).draw_type == CDT_WALLLIKE - ) - && content_features(content).wield_nodebox == true - ) { - m_node->setNodeBox(content); - haveWield = true; - } - } - - // If that failed, make an extruded sprite. - if (!haveWield) - m_node->setSprite(item->getImageRaw()); - - m_node->setVisible(true); - updateNodePos(); - m_content = item->getContent(); - delete item; -} - /* MobCAO */ diff --git a/src/content_cao.h b/src/content_cao.h index e8ee03c..8865536 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -124,58 +124,6 @@ struct SmoothTranslator } }; -/* - ItemCAO -*/ - -class ItemCAO : public ClientActiveObject -{ -public: - ItemCAO(); - virtual ~ItemCAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_ITEM; - } - - 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 pos_translator.vect_show;} - - void updateCameraOffset(v3s16 camera_offset) - { - m_camera_offset = camera_offset; - } - - virtual content_t getContent() {return m_content;} - -private: - void updateVisual(); - - core::aabbox3d m_selection_box; - ExtrudedSpriteSceneNode *m_node; - v3f m_position; - v3s16 m_camera_offset; - std::string m_inventorystring; - content_t m_content; - f32 m_rot; - SmoothTranslator pos_translator; -}; - /* MobCAO */ diff --git a/src/content_mapnode_plants.cpp b/src/content_mapnode_plants.cpp index 084d808..1764127 100644 --- a/src/content_mapnode_plants.cpp +++ b/src/content_mapnode_plants.cpp @@ -271,6 +271,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_LEAVES; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_SAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; @@ -302,6 +304,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_LEAVES_AUTUMN; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_SAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; @@ -333,6 +337,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_LEAVES_WINTER; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_SAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; @@ -364,6 +370,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_LEAVES_WINTER; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_SAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; @@ -396,6 +404,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_APPLE_LEAVES; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_APPLE_SAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; @@ -427,6 +437,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_JUNGLE_LEAVES; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_JUNGLESAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; @@ -458,6 +470,8 @@ void content_mapnode_plants(bool repeat) f->ondig_special_drop = CONTENT_TRIMMED_CONIFER_LEAVES; f->ondig_special_drop_count = 1; f->ondig_special_tool = TT_SHEAR; + f->place_on_drop = CONTENT_CONIFER_SAPLING; + f->place_on_drop_alternate = CONTENT_WILDGRASS_SHORT; f->type = CMT_PLANT; f->hardness = 0.15; f->pressure_type = CST_CRUSHABLE; diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp index 1d05e21..2267d48 100644 --- a/src/content_nodemeta.cpp +++ b/src/content_nodemeta.cpp @@ -347,31 +347,15 @@ bool CampBedNodeMetadata::step(float dtime, v3s16 pos, ServerEnvironment *env) if (fp == pos) return false; - MapNode nn = env->getMap().getNodeNoEx(fp); - nn.setContent(CONTENT_PARCEL); - env->getMap().addNodeWithEvent(fp,nn); - NodeMetadata *meta = env->getMap().getNodeMetadata(fp); - if (meta) { - Inventory* inv = meta->getInventory(); - if (inv) { - InventoryList *l = inv->getList("0"); - if (l) { - // add random dead grass/fur to parcel - { - u16 c = myrand_range(1,4); - InventoryItem *item = InventoryItem::create(CONTENT_DEADGRASS,c); - item = l->addItem(item); - if (item) - delete item; - } - if (myrand_range(0,1)) { - InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_FUR,1); - item = l->addItem(item); - if (item) - delete item; - } - } - } + // add random dead grass/fur to parcel + { + u16 c = myrand_range(1,4); + InventoryItem *item = InventoryItem::create(CONTENT_DEADGRASS,c); + env->dropToParcel(pos,item); + } + if (myrand_range(0,1)) { + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_FUR,1); + env->dropToParcel(pos,item); } n.setContent(CONTENT_DEADGRASS); diff --git a/src/content_object.h b/src/content_object.h index 4c4ed72..b8bc435 100644 --- a/src/content_object.h +++ b/src/content_object.h @@ -28,11 +28,11 @@ #define CONTENT_OBJECT_HEADER #define ACTIVEOBJECT_TYPE_TEST 1 -#define ACTIVEOBJECT_TYPE_ITEM 2 -#define ACTIVEOBJECT_TYPE_RAT 3 -#define ACTIVEOBJECT_TYPE_OERKKI1 4 -#define ACTIVEOBJECT_TYPE_FIREFLY 5 -#define ACTIVEOBJECT_TYPE_MOBV2 6 +//#define ACTIVEOBJECT_TYPE_ITEM 2 +//#define ACTIVEOBJECT_TYPE_RAT 3 +//#define ACTIVEOBJECT_TYPE_OERKKI1 4 +//#define ACTIVEOBJECT_TYPE_FIREFLY 5 +//#define ACTIVEOBJECT_TYPE_MOBV2 6 #define ACTIVEOBJECT_TYPE_MOB 7 #endif diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 1c43564..49d9742 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -53,313 +53,6 @@ void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase) speed.Y = target_speed.Y; } - -/* - 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), - m_inventorystring(inventorystring), - m_speed_f(0,0,0), - m_last_sent_position(0,0,0), - m_age(600.0) -{ - ServerActiveObject::registerType(getType(), create); - std::istringstream is(m_inventorystring, std::ios_base::binary); - try{ - InventoryItem *item = NULL; - item = InventoryItem::deSerialize(is); - if (item) { - m_content = item->getContent(); - delete item; - } - }catch(SerializationError &e) {} -} - -ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos, float age, const std::string inventorystring): - ServerActiveObject(env, id, pos), - m_inventorystring(inventorystring), - m_speed_f(0,0,0), - m_last_sent_position(0,0,0), - m_age(age) -{ - ServerActiveObject::registerType(getType(), create); - std::istringstream is(m_inventorystring, std::ios_base::binary); - try{ - InventoryItem *item = NULL; - item = InventoryItem::deSerialize(is); - if (item) { - m_content = item->getContent(); - delete item; - } - }catch(SerializationError &e) {} -} - -ServerActiveObject* ItemSAO::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]; - float age = 600.0; - // check if version is supported - if (version == 1) { - age = readF1000(is); - }else if (version != 0) { - return NULL; - } - - std::string inventorystring = deSerializeString(is); - infostream<<"ItemSAO::create(): Creating item \""< box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.); - collisionMoveResult moveresult; - // Apply gravity - m_speed_f += v3f(0, -dtime*9.81*BS, 0); - // Maximum movement without glitches - f32 pos_max_d = BS*0.5; - // 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 accel_f = v3f(0,0,0); - moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d, - box, 0.0, dtime, pos_f, m_speed_f, accel_f); - - if (moveresult.touching_ground) { - v3s16 pos_i = floatToInt(pos_f,BS); - MapNode n = m_env->getMap().getNodeNoEx(pos_i); - MapNode un = m_env->getMap().getNodeNoEx(pos_i+v3s16(0,-1,0)); - bool parcel = false; - InventoryItem *item = createInventoryItem(); - if (un.getContent() == CONTENT_AIR) { - // item is stuck on the edge of something - setBasePosition(intToFloat(pos_i,BS)); - return; - }else if ( - item - && item->getCount() == 1 - && ( - m_content == CONTENT_LEAVES - || m_content == CONTENT_JUNGLELEAVES - || m_content == CONTENT_APPLE_LEAVES - || m_content == CONTENT_CONIFER_LEAVES - || m_content == CONTENT_LEAVES_AUTUMN - || m_content == CONTENT_LEAVES_WINTER - || m_content == CONTENT_LEAVES_SNOWY - ) - ) { // leaves falling on grass become either saplings or wild grass - if ( - un.getContent() == CONTENT_MUD - || un.getContent() == CONTENT_GRASS - || un.getContent() == CONTENT_GRASS_FOOTSTEPS - || un.getContent() == CONTENT_GRASS_AUTUMN - || un.getContent() == CONTENT_GRASS_FOOTSTEPS_AUTUMN - || un.getContent() == CONTENT_MUDSNOW - ) { - content_t c = CONTENT_SAPLING; - std::vector search; - search.push_back(CONTENT_SAPLING); - search.push_back(CONTENT_JUNGLESAPLING); - search.push_back(CONTENT_APPLE_SAPLING); - search.push_back(CONTENT_CONIFER_SAPLING); - if (m_env->searchNear(pos_i,v3s16(3,3,3),search,NULL)) { - c = CONTENT_WILDGRASS_SHORT; - }else{ - switch (m_content) { - case CONTENT_JUNGLELEAVES: - c = CONTENT_JUNGLESAPLING; - break; - case CONTENT_APPLE_LEAVES: - c = CONTENT_APPLE_SAPLING; - break; - case CONTENT_CONIFER_LEAVES: - c = CONTENT_CONIFER_SAPLING; - break; - default:; - } - } - n.setContent(c); - m_env->getMap().addNodeWithEvent(pos_i,n); - } - delete item; - m_removed = true; - return; - }else if (!content_craftitem_features(m_content).consumable) { - v3s16 pp; - if (n.getContent() == CONTENT_PARCEL) { - parcel = true; - }else if (m_env->searchNear(pos_i,v3s16(3,3,3),CONTENT_PARCEL,&pp)) { - pos_i = pp; - parcel = true; - }else if (n.getContent() == CONTENT_LAVASOURCE) { - m_removed = true; - }else if (content_features(n).buildable_to) { - n.setContent(CONTENT_PARCEL); - m_env->getMap().addNodeWithEvent(pos_i,n); - parcel = true; - } - } - - if (item && parcel) { - NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos_i); - if (!meta) - return; - Inventory *inv = meta->getInventory(); - if (!inv) - return; - InventoryList *l = inv->getList("0"); - if (!l) - return; - l->addItem(item); - m_removed = true; - - { - v3s16 bp = getNodeBlockPos(pos_i); - MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(bp); - if (block) { - MapEditEvent event; - event.type = MEET_BLOCK_NODE_METADATA_CHANGED; - event.p = bp; - m_env->getMap().dispatchEvent(&event); - - block->setChangedFlag(); - } - } - }else if (item) { - delete item; - } - } - - 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]; - // command (0 = update position) - buf[0] = 0; - os.write(buf, 1); - // pos - writeS32((u8*)buf, m_base_position.X*1000); - os.write(buf, 4); - writeS32((u8*)buf, m_base_position.Y*1000); - os.write(buf, 4); - writeS32((u8*)buf, m_base_position.Z*1000); - os.write(buf, 4); - // create message and add to list - ActiveObjectMessage aom(getId(), false, os.str()); - m_messages_out.push_back(aom); - } -} - -std::string ItemSAO::getClientInitializationData() -{ - std::ostringstream os(std::ios::binary); - char buf[6]; - // version - buf[0] = 1; - os.write(buf, 1); - // age - writeF1000(os,m_age); - // pos - writeS32((u8*)buf, m_base_position.X*1000); - os.write(buf, 4); - writeS32((u8*)buf, m_base_position.Y*1000); - os.write(buf, 4); - writeS32((u8*)buf, m_base_position.Z*1000); - os.write(buf, 4); - // inventorystring - os< item="<use(m_env, player); - - if(to_be_deleted) - m_removed = true; - else - // Reflect changes to the item here - m_inventorystring = item->getItemString(); - - delete item; - return false; -} - static void get_random_u32_array(u32 a[], u32 len) { u32 i, n; @@ -713,9 +406,6 @@ void MobSAO::step(float dtime, bool send_recommended) if (obj->getType() == ACTIVEOBJECT_TYPE_MOB) { ((MobSAO*)obj)->doDamage(m.attack_mob_damage); hit = true; - }else if (obj->getType() == ACTIVEOBJECT_TYPE_ITEM) { - ((ItemSAO*)obj)->m_removed = true; - hit = true; } } if (hit) diff --git a/src/content_sao.h b/src/content_sao.h index ea773a0..7989b92 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -31,30 +31,6 @@ #include "content_object.h" #include "content_mob.h" -class ItemSAO : public ServerActiveObject -{ -public: - ItemSAO(ServerEnvironment *env, u16 id, v3f pos, const std::string inventorystring); - ItemSAO(ServerEnvironment *env, u16 id, v3f pos, float age, const std::string inventorystring); - u8 getType() const - {return ACTIVEOBJECT_TYPE_ITEM;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, - const std::string &data); - void step(float dtime, bool send_recommended); - std::string getClientInitializationData(); - std::string getStaticData(); - InventoryItem* createInventoryItem(); - InventoryItem* createPickedUpItem(content_t punch_item){return createInventoryItem();} - bool rightClick(Player *player); -private: - std::string m_inventorystring; - v3f m_speed_f; - v3f m_last_sent_position; - IntervalLimiter m_move_interval; - float m_age; - content_t m_content; -}; - class MobSAO : public ServerActiveObject { public: diff --git a/src/environment.cpp b/src/environment.cpp index 192986b..5d6714c 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -804,6 +804,275 @@ bool ServerEnvironment::searchNearInv(v3s16 pos, v3s16 radius_min, v3s16 radius_ return false; } +/* search from pos in direction dir, until a collidable node is hit + * if pos is a collidable node, then search till not collidable + * return false if CONTENT_IGNORE is found + * return true otherwise + * result is a non-collidable node, which is: + * the first liquid node found + * if searching till not collidable: + * the first walkable node found + * else + * the last walkable node found + */ +bool ServerEnvironment::getCollidedPosition(v3s16 pos, v3s16 dir, v3s16 *result) +{ + ContentFeatures *f; + v3s16 cpos = pos; + MapNode n = m_map->getNodeNoEx(pos); + if (n.getContent() == CONTENT_IGNORE) + return false; + + f = &content_features(n.getContent()); + + // if pos is a collidable node, search till not collidable + if (!f->walkable) { + while (!f->walkable) { + cpos += dir; + n = m_map->getNodeNoEx(cpos); + if (n.getContent() == CONTENT_IGNORE) + return false; + + f = &content_features(n.getContent()); + } + //else search till collidable, then go back one + }else{ + while (f->walkable) { + cpos += dir; + n = m_map->getNodeNoEx(cpos); + if (n.getContent() == CONTENT_IGNORE) + return false; + + f = &content_features(n.getContent()); + } + cpos -= dir; + n = m_map->getNodeNoEx(cpos); + f = &content_features(n.getContent()); + } + + // if node is liquid, or air_equivalent and buildable_to, return true + if (f->liquid_type != LIQUID_NONE || (f->air_equivalent && f->buildable_to)) { + if (result) + *result = cpos; + return true; + } + + // otherwise, reverse direction, but no further than (but including) pos + // search for last air_equivalent and buildable_to + while (cpos != pos) { + cpos -= dir; + n = m_map->getNodeNoEx(cpos); + if (n.getContent() == CONTENT_IGNORE) + return false; + + f = &content_features(n.getContent()); + if (f->liquid_type != LIQUID_NONE || (f->air_equivalent && f->buildable_to)) { + if (result) + *result = cpos; + return true; + } + } + + n = m_map->getNodeNoEx(cpos); + if (n.getContent() == CONTENT_IGNORE) + return false; + + f = &content_features(n.getContent()); + + // if found, return true + if (f->liquid_type != LIQUID_NONE || (f->air_equivalent && f->buildable_to)) { + if (result) + *result = cpos; + return true; + } + + // otherwise, return false + return false; +} + +bool ServerEnvironment::dropToParcel(v3s16 pos, InventoryItem *item) +{ + v3s16 ppos; + NodeMetadata *meta; + Inventory *inv; + InventoryList *list; + + if (!item) + return true; + + // check for single material item and above dirtlike + // if so, and it has a place_on_drop then + if ( + item->getCount() == 1 + && (item->getContent()&0xF000) == 0 + && content_features(item->getContent()).place_on_drop != CONTENT_IGNORE + && getCollidedPosition(pos,v3s16(0,-1,0),&ppos) + && content_features(m_map->getNodeNoEx(ppos+v3s16(0,-1,0)).getContent()).draw_type == CDT_DIRTLIKE + ) { + ContentFeatures *f = &content_features(item->getContent()); + // if it's landing on a place_on_drop, destroy it + if (m_map->getNodeNoEx(ppos).getContent() == f->place_on_drop) { + delete item; + return true; + // it has a place_on_drop_alternate and a place_on_drop is nearby + }else if (f->place_on_drop_alternate && searchNear(ppos,v3s16(3,3,3),f->place_on_drop,NULL)) { + // place place_on_drop_alternate at pos + MapNode n(f->place_on_drop_alternate); + m_map->addNodeWithEvent(ppos,n); + delete item; + return true; + // else place place_on_drop + }else{ + MapNode n(f->place_on_drop); + m_map->addNodeWithEvent(ppos,n); + delete item; + return true; + } + } + + // look for a parcel near pos + if (searchNear(pos,v3s16(3,3,3),CONTENT_PARCEL,&ppos)) { + // add items if found + meta = m_map->getNodeMetadata(ppos); + if (meta) { + inv = meta->getInventory(); + if (inv) { + list = inv->getList("0"); + if (list) + item = list->addItem(item); + } + } + } + + if (!item) { + v3s16 bp = getNodeBlockPos(ppos); + MapBlock *block = m_map->getBlockNoCreateNoEx(bp); + if (block) { + MapEditEvent event; + event.type = MEET_BLOCK_NODE_METADATA_CHANGED; + event.p = bp; + m_map->dispatchEvent(&event); + + block->setChangedFlag(); + } + return true; + } + + // if underground, go up to first air_equivalent and buildable_to + if (!content_features(m_map->getNodeNoEx(pos).getContent()).air_equivalent) { + if (!getCollidedPosition(pos,v3s16(0,1,0),&ppos)) { + delete item; + return false; + } + pos = ppos; + // otherwise go down to first non-air_equivalent and buildable_to + }else{ + if (!getCollidedPosition(pos,v3s16(0,-1,0),&ppos)) { + delete item; + return false; + } + pos = ppos; + } + + // look for a parcel near pos + if (searchNear(pos,v3s16(3,3,3),CONTENT_PARCEL,&ppos)) { + // add items if found + meta = m_map->getNodeMetadata(ppos); + if (meta) { + inv = meta->getInventory(); + if (inv) { + list = inv->getList("0"); + if (list) + item = list->addItem(item); + } + } + } + + if (!item) { + v3s16 bp = getNodeBlockPos(ppos); + MapBlock *block = m_map->getBlockNoCreateNoEx(bp); + if (block) { + MapEditEvent event; + event.type = MEET_BLOCK_NODE_METADATA_CHANGED; + event.p = bp; + m_map->dispatchEvent(&event); + + block->setChangedFlag(); + } + return true; + } + + // if liquid, do a slightly wider search for a parcel on shore + if (content_features(m_map->getNodeNoEx(pos).getContent()).liquid_type != LIQUID_NONE) { + if (content_features(m_map->getNodeNoEx(pos).getContent()).damage_per_second > 0) { + delete item; + return false; + }else if (searchNear(pos,v3s16(5,5,5),CONTENT_PARCEL,&ppos)) { + // add items if found + meta = m_map->getNodeMetadata(ppos); + if (meta) { + inv = meta->getInventory(); + if (inv) { + list = inv->getList("0"); + if (list) + item = list->addItem(item); + } + } + } + } + + if (!item) { + v3s16 bp = getNodeBlockPos(ppos); + MapBlock *block = m_map->getBlockNoCreateNoEx(bp); + if (block) { + MapEditEvent event; + event.type = MEET_BLOCK_NODE_METADATA_CHANGED; + event.p = bp; + m_map->dispatchEvent(&event); + + block->setChangedFlag(); + } + return true; + } + + // check that pos is air_equivalent and buildable_to + { + ContentFeatures *f = &content_features(m_map->getNodeNoEx(pos).getContent()); + if (f->liquid_type != LIQUID_NONE || (f->air_equivalent && f->buildable_to)) { + // create a parcel + MapNode n(CONTENT_PARCEL); + m_map->addNodeWithEvent(pos,n); + // add items + meta = m_map->getNodeMetadata(pos); + if (meta) { + inv = meta->getInventory(); + if (inv) { + list = inv->getList("0"); + if (list) + item = list->addItem(item); + } + } + } + } + + if (!item) { + v3s16 bp = getNodeBlockPos(pos); + MapBlock *block = m_map->getBlockNoCreateNoEx(bp); + if (block) { + MapEditEvent event; + event.type = MEET_BLOCK_NODE_METADATA_CHANGED; + event.p = bp; + m_map->dispatchEvent(&event); + + block->setChangedFlag(); + } + return true; + } + + delete item; + return false; +} + void ServerEnvironment::step(float dtime) { DSTACK(__FUNCTION_NAME); @@ -1101,16 +1370,6 @@ void ServerEnvironment::step(float dtime) Everything should bind to inside this single content searching loop to keep things fast. */ - u32 active_object_count_wider = 0; - for (s16 x=-1; x<=1; x++) - for (s16 y=-1; y<=1; y++) - for (s16 z=-1; z<=1; z++) { - MapBlock *wblock = m_map->getBlockNoCreateNoEx(bp+v3s16(x,y,z)); - if (wblock == NULL) - continue; - active_object_count_wider += wblock->m_static_objects.m_objects.size(); - active_object_count_wider += wblock->m_active_objects.size(); - } if (block->last_spawn < m_time_of_day-6000) { MapNode n1 = block->getNodeNoEx(block->spawn_area+v3s16(0,1,0)); @@ -1713,12 +1972,8 @@ void ServerEnvironment::step(float dtime) m_map->addNodeWithEvent(p, n); }else{ m_map->removeNodeWithEvent(p); - if (active_object_count_wider < 10) { - v3f rot_pos = intToFloat(p, BS); - rot_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, rot_pos, "CraftItem mush 1"); - addActiveObject(obj); - } + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_MUSH,1,0,0); + dropToParcel(p,item); } } break; @@ -1762,10 +2017,8 @@ void ServerEnvironment::step(float dtime) if (!searchNear(p,v3s16(3,3,3),search,NULL)) { m_map->removeNodeWithEvent(leaf_p); if (myrand()%10 == 0) { - v3f sapling_pos = intToFloat(leaf_p, BS); - sapling_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, sapling_pos, "MaterialItem2 " + itos(n.getContent()) + " 1"); - addActiveObject(obj); + InventoryItem *item = InventoryItem::create(n.getContent(),1,0,0); + dropToParcel(p,item); } }else if (n.getContent() == CONTENT_LEAVES) { if (season == ENV_SEASON_AUTUMN) { @@ -1832,10 +2085,8 @@ void ServerEnvironment::step(float dtime) if (myrand()%5 == 0) { n.setContent(CONTENT_APPLE_LEAVES); m_map->addNodeWithEvent(p, n); - v3f blossom_pos = intToFloat(p, BS); - blossom_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, blossom_pos, "CraftItem apple_blossom 1"); - addActiveObject(obj); + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_APPLE_BLOSSOM,1,0,0); + dropToParcel(p,item); } } } @@ -1873,17 +2124,13 @@ void ServerEnvironment::step(float dtime) } if (n.envticks > 10) { m_map->removeNodeWithEvent(p); - v3f ash_pos = intToFloat(p, BS); - ash_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, ash_pos, "CraftItem lump_of_ash 1"); - addActiveObject(obj); + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_ASH,1,0,0); + dropToParcel(p,item); } }else if (n.envticks > 2) { m_map->removeNodeWithEvent(p); - v3f ash_pos = intToFloat(p, BS); - ash_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, ash_pos, "CraftItem lump_of_ash 1"); - addActiveObject(obj); + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_ASH,1,0,0); + dropToParcel(p,item); } break; } @@ -2493,17 +2740,13 @@ void ServerEnvironment::step(float dtime) search.push_back(CONTENT_IGNORE); if (!searchNear(p,v3s16(1,1,1),search,NULL)) { m_map->removeNodeWithEvent(apple_p); - v3f apple_pos = intToFloat(apple_p, BS); - apple_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, apple_pos, "CraftItem apple 1"); - addActiveObject(obj); - }else if ((n.envticks > 600 || (n.envticks > 100 && season == ENV_SEASON_WINTER)) && active_object_count_wider < 10) { + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_APPLE,1,0,0); + dropToParcel(p,item); + }else if (n.envticks > 600 || (n.envticks > 100 && season == ENV_SEASON_WINTER)) { n.setContent(CONTENT_APPLE_LEAVES); m_map->addNodeWithEvent(p,n); - v3f rot_pos = intToFloat(p, BS); - rot_pos += v3f(myrand_range(-1500,1500)*1.0/1000, 0, myrand_range(-1500,1500)*1.0/1000); - ServerActiveObject *obj = new ItemSAO(this, 0, rot_pos, "CraftItem mush 1"); - addActiveObject(obj); + InventoryItem *item = InventoryItem::create(CONTENT_CRAFTITEM_MUSH,1,0,0); + dropToParcel(p,item); } break; } diff --git a/src/environment.h b/src/environment.h index 9cadb66..8a6216e 100644 --- a/src/environment.h +++ b/src/environment.h @@ -387,6 +387,9 @@ public: void setPostStepNodeSwap(v3s16 pos, MapNode n) {m_poststep_nodeswaps[pos] = n;} + bool getCollidedPosition(v3s16 pos, v3s16 dir, v3s16 *result); + bool dropToParcel(v3s16 pos, InventoryItem *item); + private: /* diff --git a/src/inventory.cpp b/src/inventory.cpp index bb2f777..3860a02 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -178,16 +178,6 @@ std::string InventoryItem::getItemString() { return os.str(); } -ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) -{ - /* - Create an ItemSAO - */ - // Create object - ServerActiveObject *obj = new ItemSAO(env, 0, pos, getItemString()); - return obj; -} - /* MaterialItem */ @@ -414,7 +404,7 @@ ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos return obj; } // Default - return InventoryItem::createSAO(env, id, pos); + return NULL; } u16 CraftItem::getDropCount() const @@ -620,7 +610,7 @@ ServerActiveObject* ToolItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) return obj; } // Default - return InventoryItem::createSAO(env, id, pos); + return NULL; } /* diff --git a/src/inventory.h b/src/inventory.h index 4e70712..1c573fb 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -81,7 +81,7 @@ public: // Returns the string used for inventory virtual std::string getItemString(); // Creates an object from the item, to be placed in the world. - virtual ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos); + virtual ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos) {return NULL;} // Gets amount of items that dropping one SAO will decrement virtual u16 getDropCount() const { return getCount(); } diff --git a/src/mapnode.h b/src/mapnode.h index e5fc17c..55bb495 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -424,6 +424,11 @@ struct ContentFeatures // if false then player gets as much as possible, rest stays in undug node bool ondig_gives_inventory_all_or_none; + // if dropped on dirt, place this instead of inserting in a parcel + content_t place_on_drop; + // if a place_on_drop is nearby, place this instead + content_t place_on_drop_alternate; + // when energised, replace with this node content_t powered_node; // when unenergised, replace with this node @@ -569,6 +574,8 @@ struct ContentFeatures onact_also_affects = v3s16(0,0,0); ondig_gives_inventory = false; ondig_gives_inventory_all_or_none = false; + place_on_drop = CONTENT_IGNORE; + place_on_drop_alternate = CONTENT_IGNORE; powered_node = CONTENT_IGNORE; unpowered_node = CONTENT_IGNORE; cook_result = ""; diff --git a/src/server.cpp b/src/server.cpp index ee03794..a65ef83 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3974,9 +3974,18 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) ServerActiveObject *obj = wielditem->createSAO(&m_env, 0, pos); if (obj == NULL) { - infostream<<"WARNING: item resulted in NULL object, " - <<"not placing onto map" - <getBool("infinite_inventory") == false) { + // Delete the right amount of items from the slot + InventoryList *ilist = player->inventory.getList("main"); + nitem = ilist->changeItem(item_i,NULL); + // Send inventory + UpdateCrafting(peer_id); + SendInventory(peer_id); + }else{ + nitem = wielditem->clone(); + } + m_env.dropToParcel(p_over,nitem); }else{ actionstream<getName()<<" places "<getName() <<" at "<getBool("infinite_inventory") == false) { + // Delete the right amount of items from the slot + InventoryList *ilist = player->inventory.getList("main"); + nitem = ilist->changeItem(item_i,NULL); + // Send inventory + UpdateCrafting(peer_id); + SendInventory(peer_id); + }else{ + nitem = wielditem->clone(); + } + m_env.dropToParcel(p_over,nitem); }else{ actionstream<getName()<<" places "<getName() <<" at "<inventory.getList("discard"); InventoryItem *item = list->getItem(0); - if (g_settings->getBool("droppable_inventory")) { - v3f pos = player->getPosition(); - pos.Y += BS; - v3f dir = v3f(0,0,BS); - dir.rotateXZBy(player->getYaw()); - pos += dir; - ServerActiveObject *obj = item->createSAO(&m_env,0,pos); - if (obj) - m_env.addActiveObject(obj); - } - if (g_settings->getBool("infinite_inventory") == false) { - list->deleteItem(0); - SendInventory(player->peer_id); + if (item) { + if (g_settings->getBool("droppable_inventory")) { + v3f pos = player->getPosition(); + pos.Y += BS; + v3f dir = v3f(0,0,BS); + dir.rotateXZBy(player->getYaw()); + pos += dir; + v3s16 pp = floatToInt(pos,BS); + item = item->clone(); + m_env.dropToParcel(pp,item); + } + if (g_settings->getBool("infinite_inventory") == false) { + list->deleteItem(0); + SendInventory(player->peer_id); + } } } } @@ -5530,88 +5550,17 @@ void Server::HandlePlayerHP(Player *player, s16 damage, s16 suffocate, s16 hunge player->wet = 0; player->blood = 0; - //TODO: Throw items around + // Throw items around if (g_settings->getBool("death_drops_inv")) { v3s16 bottompos = floatToInt(player->getPosition() + v3f(0,-BS/4,0), BS); v3s16 p = bottompos + v3s16(0,1,0); - MapNode in_n = m_env.getMap().getNodeNoEx(p); - v3s16 droppos = p; - bool can_drop = false; - // if they're standing in an air-like node, drop inventory to a parcel - // otherwise they just lose it - v3s16 pp; - if (in_n.getContent() == CONTENT_PARCEL) { - can_drop = true; - }else if (m_env.searchNear(p,v3s16(3,3,3),CONTENT_PARCEL,&pp)) { - droppos = pp; - can_drop = true; - }else if (in_n.getContent() != CONTENT_LAVASOURCE && content_features(in_n.getContent()).buildable_to) { - while (!can_drop && p.Y > -30000) { - MapNode nn = m_env.getMap().getNodeNoEx(p+v3s16(0,-1,0)); - if (nn.getContent() == CONTENT_PARCEL) { - droppos = p+v3s16(0,-1,0); - can_drop = true; - }else if (nn.getContent() == CONTENT_LAVASOURCE) { - break; - }else if (!content_features(nn.getContent()).buildable_to) { - droppos = p; - can_drop = true; - break; - } - p.Y--; - } - } - - if (can_drop) { - MapNode nn = m_env.getMap().getNodeNoEx(droppos); - if (nn.getContent() != CONTENT_PARCEL) { - v3s16 pp; - if (m_env.searchNear(droppos,v3s16(3,3,3),CONTENT_PARCEL,&pp)) { - droppos = pp; - nn = m_env.getMap().getNodeNoEx(droppos); - }else{ - nn.setContent(CONTENT_PARCEL); - core::list far_players; - sendAddNode(droppos, nn, 0, &far_players, 30); - - /* - Add node. - - This takes some time so it is done after the quick stuff - */ - core::map modified_blocks; - { - MapEditEventIgnorer ign(&m_ignore_map_edit_events); - - std::string p_name(player->getName()); - m_env.getMap().addNodeAndUpdate(droppos, nn, modified_blocks, p_name); - } - /* - Set blocks not sent to far players - */ - for (core::list::Iterator i = far_players.begin(); i != far_players.end(); i++) { - u16 peer_id = *i; - RemoteClient *client = getClient(peer_id); - if (client==NULL) - continue; - client->SetBlocksNotSent(modified_blocks); - } - } - } - - NodeMetadata *meta = m_env.getMap().getNodeMetadata(droppos); - if (meta) { - Inventory *inv = meta->getInventory(); - if (inv) { - InventoryList *pl = inv->getList("0"); - InventoryList *il = player->inventory.getList("main"); - if (pl && il) { - for (u32 i=0; i<32; i++) { - InventoryItem *item = il->takeItem(i,99); - if (item) - pl->addItem(item); - } - } + { + InventoryList *il = player->inventory.getList("main"); + if (il) { + for (u32 i=0; i<32; i++) { + InventoryItem *item = il->changeItem(i,NULL); + if (item) + m_env.dropToParcel(p,item); } } } diff --git a/src/serverobject.cpp b/src/serverobject.cpp index 4994669..345b877 100644 --- a/src/serverobject.cpp +++ b/src/serverobject.cpp @@ -53,21 +53,6 @@ ServerActiveObject* ServerActiveObject::create(u8 type, core::map::Node *n; n = m_types.find(type); if (n == NULL) { - // convert old creatures to new - switch (type) { - case ACTIVEOBJECT_TYPE_RAT: - return new MobSAO(env,id,pos,CONTENT_MOB_RAT); - break; - case ACTIVEOBJECT_TYPE_OERKKI1: - return new MobSAO(env,id,pos,CONTENT_MOB_OERKKI); - break; - case ACTIVEOBJECT_TYPE_FIREFLY: - return new MobSAO(env,id,pos,CONTENT_MOB_FIREFLY); - break; - case ACTIVEOBJECT_TYPE_MOBV2: - return new MobSAO(env,id,pos,CONTENT_MOB_DUNGEON_MASTER); - break; - } // If factory is not found, just return. dstream<<"WARNING: ServerActiveObject: No factory for type=" <