remove Item{S,C}ao, drop items directly to parcels

master
darkrose 2016-01-28 02:02:42 +10:00
parent 9cf5666177
commit 02fd4ceb8c
14 changed files with 372 additions and 769 deletions

View File

@ -34,192 +34,6 @@
core::map<u16, ClientActiveObject::Factory> 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"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if (cmd == 0) {
// pos
m_position = readV3F1000(is);
m_position += v3f(0,BS*0.4,0);
pos_translator.update(m_position,m_rot);
updateNodePos();
}
}
void ItemCAO::initialize(const std::string &data)
{
infostream<<"ItemCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if (version == 1) {
readF1000(is);
}else if (version != 0) {
return;
}
// pos
m_position = readV3F1000(is);
m_position += v3f(0,BS*0.4,0);
// inventorystring
m_inventorystring = deSerializeString(is);
pos_translator.init(m_position,m_rot);
}
updateVisual();
updateNodePos();
}
void ItemCAO::updateVisual()
{
if (m_node == NULL)
return;
InventoryItem *item = NULL;
// Create an inventory item to see what is its image
std::istringstream is(m_inventorystring, std::ios_base::binary);
try{
item = InventoryItem::deSerialize(is);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
}
catch(SerializationError &e)
{
infostream<<"WARNING: "<<__FUNCTION_NAME
<<": error deSerializing inventorystring \""
<<m_inventorystring<<"\""<<std::endl;
}
if (item == NULL)
return;
bool haveWield = false;
// Try to make a MaterialItem cube.
if (std::string(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
*/

View File

@ -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<f32>* 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<f32> 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
*/

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 \""<<inventorystring<<"\""<<std::endl;
return new ItemSAO(env, id, pos, age, inventorystring);
}
void ItemSAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG);
assert(m_env);
// craftitems, and materialitems should die after a while
if (
(m_content&CONTENT_TOOLITEM_MASK) == 0
&& (m_content&CONTENT_CLOTHESITEM_MASK) == 0
) {
m_age -= dtime;
if (m_age < 0.0) {
m_removed = true;
return;
}
}
const float interval = 0.2;
if (m_move_interval.step(dtime, interval) == false)
return;
dtime = interval;
core::aabbox3d<f32> 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<content_t> 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<<serializeString(m_inventorystring);
return os.str();
}
std::string ItemSAO::getStaticData()
{
infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
char buf[1];
// version
buf[0] = 1;
os.write(buf, 1);
// age
writeF1000(os,m_age);
// inventorystring
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);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
return item;
}
catch(SerializationError &e)
{
infostream<<__FUNCTION_NAME<<": serialization error: "
<<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
return NULL;
}
}
bool ItemSAO::rightClick(Player *player)
{
infostream<<__FUNCTION_NAME<<std::endl;
InventoryItem *item = createInventoryItem();
if (item == NULL)
return false;
bool to_be_deleted = 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)

View File

@ -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:

View File

@ -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;
}

View File

@ -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:
/*

View File

@ -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;
}
/*

View File

@ -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(); }

View File

@ -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 = "";

View File

@ -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"
<<std::endl;
InventoryItem *nitem;
if (g_settings->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<<player->getName()<<" places "<<item->getName()
<<" at "<<PP(p_over)<<std::endl;
@ -4090,9 +4099,18 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
if (obj == NULL) {
infostream<<"WARNING: item resulted in NULL object, "
<<"not placing onto map"
<<std::endl;
InventoryItem *nitem;
if (g_settings->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<<player->getName()<<" places "<<item->getName()
<<" at "<<PP(p_over)<<std::endl;
@ -4378,19 +4396,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
) {
InventoryList *list = player->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<u16> 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<v3s16, MapBlock*> 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<u16>::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);
}
}
}

View File

@ -53,21 +53,6 @@ ServerActiveObject* ServerActiveObject::create(u8 type,
core::map<u16, Factory>::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="
<<type<<std::endl;