This commit is contained in:
Perttu Ahola 2011-10-15 02:28:57 +03:00
parent 080002f8ed
commit 43a28f04fa
29 changed files with 1720 additions and 2889 deletions

BIN
data/dungeon_master.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
data/fireball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

@ -107,7 +107,6 @@ set(common_SRCS
defaultsettings.cpp
mapnode.cpp
voxel.cpp
mapblockobject.cpp
inventory.cpp
debug.cpp
serialization.cpp
@ -137,6 +136,7 @@ endif()
# Client sources
set(minetest_SRCS
${common_SRCS}
MyBillboardSceneNode.cpp
content_mapblock.cpp
content_cao.cpp
mapblock_mesh.cpp

@ -0,0 +1,202 @@
// Copyright (C) 2002-2010 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "MyBillboardSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
namespace irr
{
namespace scene
{
//! constructor
MyBillboardSceneNode::MyBillboardSceneNode(ISceneNode* parent,
ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size)
: IBillboardSceneNode(parent, mgr, id, position)
{
#ifdef _DEBUG
setDebugName("MyBillboardSceneNode");
#endif
setSize(size);
indices[0] = 0;
indices[1] = 2;
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
video::SColor colorTop = video::SColor(0xFFFFFFFF);
video::SColor colorBottom = video::SColor(0xFFFFFFFF);
vertices[0].TCoords.set(1.0f, 1.0f);
vertices[0].Color = colorBottom;
vertices[1].TCoords.set(1.0f, 0.0f);
vertices[1].Color = colorTop;
vertices[2].TCoords.set(0.0f, 0.0f);
vertices[2].Color = colorTop;
vertices[3].TCoords.set(0.0f, 1.0f);
vertices[3].Color = colorBottom;
}
//! pre render event
void MyBillboardSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! render
void MyBillboardSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
// make billboard look to camera
core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition();
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();
core::vector3df horizontal = up.crossProduct(view);
if ( horizontal.getLength() == 0 )
{
horizontal.set(up.Y,up.X,up.Z);
}
horizontal.normalize();
horizontal *= 0.5f * Size.Width;
core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();
vertical *= 0.5f * Size.Height;
view *= -1.0f;
for (s32 i=0; i<4; ++i)
vertices[i].Normal = view;
vertices[0].Pos = pos + horizontal + vertical;
vertices[1].Pos = pos + horizontal - vertical;
vertices[2].Pos = pos - horizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical;
// draw
if ( DebugDataVisible & scene::EDS_BBOX )
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(BBox, video::SColor(0,208,195,152));
}
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(vertices, 4, indices, 2);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& MyBillboardSceneNode::getBoundingBox() const
{
return BBox;
}
//! sets the size of the billboard
void MyBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{
Size = size;
if (Size.Width == 0.0f)
Size.Width = 1.0f;
if (Size.Height == 0.0f )
Size.Height = 1.0f;
f32 avg = (size.Width + size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg);
}
video::SMaterial& MyBillboardSceneNode::getMaterial(u32 i)
{
return Material;
}
//! returns amount of materials used by this scene node.
u32 MyBillboardSceneNode::getMaterialCount() const
{
return 1;
}
//! gets the size of the billboard
const core::dimension2d<f32>& MyBillboardSceneNode::getSize() const
{
return Size;
}
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
void MyBillboardSceneNode::setColor(const video::SColor & overallColor)
{
for(u32 vertex = 0; vertex < 4; ++vertex)
vertices[vertex].Color = overallColor;
}
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
void MyBillboardSceneNode::setColor(const video::SColor & topColor, const video::SColor & bottomColor)
{
vertices[0].Color = bottomColor;
vertices[1].Color = topColor;
vertices[2].Color = topColor;
vertices[3].Color = bottomColor;
}
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
void MyBillboardSceneNode::getColor(video::SColor & topColor, video::SColor & bottomColor) const
{
bottomColor = vertices[0].Color;
topColor = vertices[1].Color;
}
void MyBillboardSceneNode::setTCoords(u32 i, core::vector2d<f32> c)
{
vertices[i].TCoords = c;
}
} // end namespace scene
} // end namespace irr

@ -0,0 +1,77 @@
// Copyright (C) 2002-2010 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#include "IBillboardSceneNode.h"
#include "S3DVertex.h"
namespace irr
{
namespace scene
{
//! Scene node which is a billboard. A billboard is like a 3d sprite: A 2d element,
//! which always looks to the camera.
class MyBillboardSceneNode : virtual public IBillboardSceneNode
{
public:
//! constructor
MyBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size);
//! pre render event
virtual void OnRegisterSceneNode();
//! render
virtual void render();
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! sets the size of the billboard
virtual void setSize(const core::dimension2d<f32>& size);
//! gets the size of the billboard
virtual const core::dimension2d<f32>& getSize() const;
virtual video::SMaterial& getMaterial(u32 i);
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const;
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
virtual void setColor(const video::SColor & overallColor);
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
virtual void setColor(const video::SColor & topColor, const video::SColor & bottomColor);
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
virtual void getColor(video::SColor& topColor, video::SColor& bottomColor) const;
virtual void setTCoords(u32 i, core::vector2d<f32> c);
private:
core::dimension2d<f32> Size;
core::aabbox3d<f32> BBox;
video::SMaterial Material;
video::S3DVertex vertices[4];
u16 indices[6];
};
} // end namespace scene
} // end namespace irr
#endif

@ -522,24 +522,6 @@ void Client::step(float dtime)
// Step environment
m_env.step(dtime);
/*
Handle active blocks
NOTE: These old objects are DEPRECATED. TODO: Remove
*/
for(core::map<v3s16, bool>::Iterator
i = m_active_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(p);
if(block == NULL)
continue;
// Step MapBlockObjects
block->stepObjects(dtime, false, m_env.getDayNightRatio());
}
/*
Get events
*/
@ -1191,16 +1173,11 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
//DEBUG
else if(command == TOCLIENT_OBJECTDATA)
//else if(0)
{
// Strip command word and create a stringstream
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
{ //envlock
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
u8 buf[12];
/*
@ -1250,106 +1227,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
/*
Read block objects
NOTE: Deprecated stuff here, TODO: Remove
NOTE: Deprecated stuff
*/
// Read active block count
is.read((char*)buf, 2);
u16 blockcount = readU16(buf);
// Initialize delete queue with all active blocks
core::map<v3s16, bool> abs_to_delete;
for(core::map<v3s16, bool>::Iterator
i = m_active_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
/*dstream<<"adding "
<<"("<<p.x<<","<<p.y<<","<<p.z<<") "
<<" to abs_to_delete"
<<std::endl;*/
abs_to_delete.insert(p, true);
}
/*dstream<<"Initial delete queue size: "<<abs_to_delete.size()
<<std::endl;*/
for(u16 i=0; i<blockcount; i++)
{
// Read blockpos
is.read((char*)buf, 6);
v3s16 p = readV3S16(buf);
// Get block from somewhere
MapBlock *block = NULL;
try{
block = m_env.getMap().getBlockNoCreate(p);
}
catch(InvalidPositionException &e)
{
//TODO: Create a dummy block?
}
if(block == NULL)
{
dstream<<"WARNING: "
<<"Could not get block at blockpos "
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
<<"in TOCLIENT_OBJECTDATA. Ignoring "
<<"following block object data."
<<std::endl;
u16 blockcount = readU16(is);
if(blockcount != 0){
dstream<<"WARNING: TOCLIENT_OBJECTDATA: blockcount != 0 "
"not supported"<<std::endl;
return;
}
/*dstream<<"Client updating objects for block "
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<std::endl;*/
// Insert to active block list
m_active_blocks.insert(p, true);
// Remove from deletion queue
if(abs_to_delete.find(p) != NULL)
abs_to_delete.remove(p);
/*
Update objects of block
NOTE: Be sure this is done in the main thread.
*/
block->updateObjects(is, m_server_ser_ver,
m_device->getSceneManager(), m_env.getDayNightRatio());
}
/*dstream<<"Final delete queue size: "<<abs_to_delete.size()
<<std::endl;*/
// Delete objects of blocks in delete queue
for(core::map<v3s16, bool>::Iterator
i = abs_to_delete.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
try
{
MapBlock *block = m_env.getMap().getBlockNoCreate(p);
// Clear objects
block->clearObjects();
// Remove from active blocks list
m_active_blocks.remove(p);
}
catch(InvalidPositionException &e)
{
dstream<<"WARNAING: Client: "
<<"Couldn't clear objects of active->inactive"
<<" block "
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<" because block was not found"
<<std::endl;
// Ignore
}
}
} //envlock
}
else if(command == TOCLIENT_TIME_OF_DAY)
{
@ -1636,32 +1523,6 @@ void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
Send(0, data, true);
}
void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
{
if(connectedAndInitialized() == false){
dout_client<<DTIME<<"Client::clickObject() "
"cancelled (not connected)"
<<std::endl;
return;
}
/*
[0] u16 command=TOSERVER_CLICK_OBJECT
[2] u8 button (0=left, 1=right)
[3] v3s16 block
[9] s16 id
[11] u16 item
*/
u8 datasize = 2 + 1 + 6 + 2 + 2;
SharedBuffer<u8> data(datasize);
writeU16(&data[0], TOSERVER_CLICK_OBJECT);
writeU8(&data[2], button);
writeV3S16(&data[3], blockpos);
writeS16(&data[9], id);
writeU16(&data[11], item);
Send(0, data, true);
}
void Client::clickActiveObject(u8 button, u16 id, u16 item)
{
if(connectedAndInitialized() == false){
@ -1687,45 +1548,6 @@ void Client::clickActiveObject(u8 button, u16 id, u16 item)
Send(0, data, true);
}
void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
{
/*
u16 command
v3s16 blockpos
s16 id
u16 textlen
textdata
*/
std::ostringstream os(std::ios_base::binary);
u8 buf[12];
// Write command
writeU16(buf, TOSERVER_SIGNTEXT);
os.write((char*)buf, 2);
// Write blockpos
writeV3S16(buf, blockpos);
os.write((char*)buf, 6);
// Write id
writeS16(buf, id);
os.write((char*)buf, 2);
u16 textlen = text.size();
// Write text length
writeS16(buf, textlen);
os.write((char*)buf, 2);
// Write text
os.write((char*)text.c_str(), textlen);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
Send(0, data, true);
}
void Client::sendSignNodeText(v3s16 p, std::string text)
{
/*
@ -2083,71 +1905,6 @@ void Client::inventoryAction(InventoryAction *a)
sendInventoryAction(a);
}
MapBlockObject * Client::getSelectedObject(
f32 max_d,
v3f from_pos_f_on_map,
core::line3d<f32> shootline_on_map
)
{
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
core::array<DistanceSortedObject> objects;
for(core::map<v3s16, bool>::Iterator
i = m_active_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
MapBlock *block = NULL;
try
{
block = m_env.getMap().getBlockNoCreate(p);
}
catch(InvalidPositionException &e)
{
continue;
}
// Calculate from_pos relative to block
v3s16 block_pos_i_on_map = block->getPosRelative();
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
block->getObjects(from_pos_f_on_block, max_d, objects);
//block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
}
//dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
// Sort them.
// After this, the closest object is the first in the array.
objects.sort();
for(u32 i=0; i<objects.size(); i++)
{
MapBlockObject *obj = objects[i].obj;
MapBlock *block = obj->getBlock();
// Calculate shootline relative to block
v3s16 block_pos_i_on_map = block->getPosRelative();
v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
core::line3d<f32> shootline_on_block(
shootline_on_map.start - block_pos_f_on_map,
shootline_on_map.end - block_pos_f_on_map
);
if(obj->isSelected(shootline_on_block))
{
//dstream<<"Returning selected object"<<std::endl;
return obj;
}
}
//dstream<<"No object selected; returning NULL."<<std::endl;
return NULL;
}
ClientActiveObject * Client::getSelectedActiveObject(
f32 max_d,
v3f from_pos_f_on_map,

@ -183,10 +183,8 @@ 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);
void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message);
@ -225,14 +223,6 @@ public:
Inventory* getInventory(InventoryContext *c, std::string id);
void inventoryAction(InventoryAction *a);
// Gets closest object pointed by the shootline
// Returns NULL if not found
MapBlockObject * getSelectedObject(
f32 max_d,
v3f from_pos_f_on_map,
core::line3d<f32> shootline_on_map
);
// Gets closest object pointed by the shootline
// Returns NULL if not found
ClientActiveObject * getSelectedActiveObject(

@ -45,7 +45,7 @@ ClientActiveObject* ClientActiveObject::create(u8 type)
{
// If factory is not found, just return.
dstream<<"WARNING: ClientActiveObject: No factory for type="
<<type<<std::endl;
<<(int)type<<std::endl;
return NULL;
}

@ -51,6 +51,7 @@ public:
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
virtual v3f getPosition(){return v3f(0,0,0);}
virtual bool doShowSelectionBox(){return true;}
// Step object in time
virtual void step(float dtime, ClientEnvironment *env){}

@ -20,6 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cao.h"
#include "tile.h"
#include "environment.h"
#include "settings.h"
#include <ICameraSceneNode.h>
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
@ -683,7 +685,7 @@ void Oerkki1CAO::processMessage(const std::string &data)
}
else if(cmd == 1)
{
u16 damage = readU8(is);
//u16 damage = readU8(is);
m_damage_visual_timer = 1.0;
}
}
@ -850,3 +852,377 @@ void FireflyCAO::initialize(const std::string &data)
updateNodePos();
}
/*
MobV2CAO
*/
// Prototype
MobV2CAO proto_MobV2CAO;
MobV2CAO::MobV2CAO():
ClientActiveObject(0),
m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0),
m_walking(false),
m_walking_unset_timer(0),
m_walk_timer(0),
m_walk_frame(0),
m_damage_visual_timer(0),
m_last_light(0),
m_shooting(0),
m_shooting_unset_timer(0),
m_bright_shooting(false),
m_player_hit_timer(0)
{
ClientActiveObject::registerType(getType(), create);
m_properties = new Settings;
}
MobV2CAO::~MobV2CAO()
{
delete m_properties;
}
ClientActiveObject* MobV2CAO::create()
{
return new MobV2CAO();
}
void MobV2CAO::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
std::string texture_name = m_properties->get("texture_name");
//dstream<<"MobV2CAO::addToScene using texture_name="<<texture_name<<std::endl;
std::string texture_string = "[makealpha2:128,0,0;128,128,0:";
texture_string += texture_name;
scene::MyBillboardSceneNode *bill = new scene::MyBillboardSceneNode(
smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
bill->setMaterialTexture(0, g_texturesource->getTextureRaw(texture_string));
bill->setMaterialFlag(video::EMF_LIGHTING, false);
bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
bill->setColor(video::SColor(255,0,0,0));
bill->setVisible(false); /* Set visible when brightness is known */
bill->setSize(m_sprite_size);
if(m_sprite_type == "humanoid_1"){
const float txp = 1./192;
const float txs = txp*32;
const float typ = 1./240;
const float tys = typ*48;
bill->setTCoords(0, v2f(txs*1, tys*1));
bill->setTCoords(1, v2f(txs*1, tys*0));
bill->setTCoords(2, v2f(txs*0, tys*0));
bill->setTCoords(3, v2f(txs*0, tys*1));
} else if(m_sprite_type == "simple"){
const float txs = 1.0;
const float tys = 1.0 / m_simple_anim_frames;
bill->setTCoords(0, v2f(txs*1, tys*1));
bill->setTCoords(1, v2f(txs*1, tys*0));
bill->setTCoords(2, v2f(txs*0, tys*0));
bill->setTCoords(3, v2f(txs*0, tys*1));
} else {
dstream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
<<std::endl;
}
m_node = bill;
updateNodePos();
}
void MobV2CAO::removeFromScene()
{
if(m_node == NULL)
return;
m_node->drop();
m_node->remove();
m_node = NULL;
}
void MobV2CAO::updateLight(u8 light_at_pos)
{
if(m_lock_full_brightness)
light_at_pos = 15;
m_last_light = light_at_pos;
if(m_node == NULL)
return;
if(m_damage_visual_timer > 0)
return;
if(m_shooting && m_bright_shooting)
return;
/*if(light_at_pos <= 2){
m_node->setVisible(false);
return;
}*/
m_node->setVisible(true);
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
m_node->setColor(color);
}
v3s16 MobV2CAO::getLightPosition()
{
return floatToInt(m_position+v3f(0,0,0), BS);
}
void MobV2CAO::updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(pos_translator.vect_show + m_sprite_pos);
}
void MobV2CAO::step(float dtime, ClientEnvironment *env)
{
scene::MyBillboardSceneNode *bill = m_node;
pos_translator.translate(dtime);
if(m_sprite_type == "humanoid_1"){
scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
cam_to_mob.normalize();
int col = 0;
if(cam_to_mob.Y > 0.7)
col = 5;
else if(cam_to_mob.Y < -0.7)
col = 4;
else{
float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / M_PI * 180.;
float dir = mob_dir - m_yaw;
dir = wrapDegrees_180(dir);
//dstream<<"id="<<m_id<<" dir="<<dir<<std::endl;
if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
col = 2;
else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
col = 3;
else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
col = 0;
else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
col = 1;
else
col = 4;
}
int row = 0;
if(m_shooting){
row = 3;
} else if(m_walking){
m_walk_timer += dtime;
if(m_walk_timer >= 0.5){
m_walk_frame = (m_walk_frame + 1) % 2;
m_walk_timer = 0;
}
if(m_walk_frame == 0)
row = 1;
else
row = 2;
}
const float txp = 1./192;
const float txs = txp*32;
const float typ = 1./240;
const float tys = typ*48;
bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
} else if(m_sprite_type == "simple"){
m_walk_timer += dtime;
if(m_walk_timer >= m_simple_anim_frametime){
m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
m_walk_timer = 0;
}
int col = 0;
int row = m_walk_frame;
const float txs = 1.0;
const float tys = 1.0 / m_simple_anim_frames;
bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
} else {
dstream<<"MobV2CAO::step(): Unknown sprite type \""
<<m_sprite_type<<"\""<<std::endl;
}
updateNodePos();
/* Damage local player */
if(m_player_hit_damage && m_player_hit_timer <= 0.0){
LocalPlayer *player = env->getLocalPlayer();
assert(player);
v3f playerpos = player->getPosition();
v2f playerpos_2d(playerpos.X,playerpos.Z);
v2f objectpos_2d(m_position.X,m_position.Z);
if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
{
env->damageLocalPlayer(m_player_hit_damage);
m_player_hit_timer = m_player_hit_interval;
}
}
/* Run timers */
m_player_hit_timer -= dtime;
if(m_damage_visual_timer >= 0){
m_damage_visual_timer -= dtime;
if(m_damage_visual_timer <= 0){
dstream<<"id="<<m_id<<" damage visual ended"<<std::endl;
}
}
m_walking_unset_timer += dtime;
if(m_walking_unset_timer >= 1.0){
m_walking = false;
}
m_shooting_unset_timer -= dtime;
if(m_shooting_unset_timer <= 0.0){
if(m_bright_shooting){
u8 li = decode_light(m_last_light);
video::SColor color(255,li,li,li);
bill->setColor(color);
m_bright_shooting = false;
}
m_shooting = false;
}
}
void MobV2CAO::processMessage(const std::string &data)
{
//dstream<<"MobV2CAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
// Move
if(cmd == 0)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
m_walking = true;
m_walking_unset_timer = 0;
updateNodePos();
}
// Damage
else if(cmd == 1)
{
//u16 damage = readU16(is);
u8 li = decode_light(m_last_light);
if(li >= 100)
li = 30;
else
li = 255;
video::SColor color(255,li,li,li);
m_node->setColor(color);
m_damage_visual_timer = 0.2;
}
// Trigger shooting
else if(cmd == 2)
{
// length
m_shooting_unset_timer = readF1000(is);
// bright?
m_bright_shooting = readU8(is);
if(m_bright_shooting){
u8 li = 255;
video::SColor color(255,li,li,li);
m_node->setColor(color);
}
m_shooting = true;
}
}
void MobV2CAO::initialize(const std::string &data)
{
//dstream<<"MobV2CAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0){
dstream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
return;
}
std::ostringstream tmp_os(std::ios::binary);
decompressZlib(is, tmp_os);
std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
/*dstream<<"INFO: MobV2CAO::initialize(): got properties:"<<std::endl;
m_properties->writeLines(dstream);*/
m_properties->setDefault("texture_name", "stone.png");
m_properties->setDefault("yaw", "0");
m_properties->setDefault("pos", "(0,0,0)");
m_properties->setDefault("sprite_size", "(1,1)");
m_properties->setDefault("sprite_pos", "(0,0,0)");
m_properties->setDefault("selection_size", "(0.4,0.4)");
m_properties->setDefault("selection_y", "-0.4");
m_properties->setDefault("sprite_type", "humanoid_1");
m_properties->setDefault("simple_anim_frames", "1");
m_properties->setDefault("simple_anim_frametime", "0.5");
m_properties->setDefault("lock_full_brightness", "false");
m_properties->setDefault("player_hit_damage", "0");
m_properties->setDefault("player_hit_distance", "1.5");
m_properties->setDefault("player_hit_interval", "1.5");
m_yaw = m_properties->getFloat("yaw");
m_position = m_properties->getV3F("pos");
m_sprite_size = m_properties->getV2F("sprite_size") * BS;
m_sprite_pos = m_properties->getV3F("sprite_pos") * BS;
v2f selection_size = m_properties->getV2F("selection_size") * BS;
float selection_y = m_properties->getFloat("selection_y") * BS;
m_selection_box = core::aabbox3d<f32>(
-selection_size.X, selection_y, -selection_size.X,
selection_size.X, selection_y+selection_size.Y,
selection_size.X);
m_sprite_type = m_properties->get("sprite_type");
m_simple_anim_frames = m_properties->getS32("simple_anim_frames");
m_simple_anim_frametime = m_properties->getFloat("simple_anim_frametime");
m_lock_full_brightness = m_properties->getBool("lock_full_brightness");
m_player_hit_damage = m_properties->getS32("player_hit_damage");
m_player_hit_distance = m_properties->getFloat("player_hit_distance");
m_player_hit_interval = m_properties->getFloat("player_hit_interval");
pos_translator.init(m_position);
}
updateNodePos();
}

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientobject.h"
#include "content_object.h"
#include "utility.h" // For IntervalLimiter
class Settings;
#include "MyBillboardSceneNode.h"
/*
SmoothTranslator
@ -74,11 +76,16 @@ struct SmoothTranslator
if(anim_time > 0.001)
moveratio = anim_time_counter / anim_time;
// Move a bit less than should, to avoid oscillation
moveratio = moveratio * 0.8;
moveratio = moveratio * 0.5;
if(moveratio > 1.5)
moveratio = 1.5;
vect_show = vect_old + vect_move * moveratio;
}
bool is_moving()
{
return ((anim_time_counter / anim_time) < 1.4);
}
};
@ -286,6 +293,72 @@ private:
SmoothTranslator pos_translator;
};
/*
MobV2CAO
*/
class MobV2CAO : public ClientActiveObject
{
public:
MobV2CAO();
virtual ~MobV2CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_MOBV2;
}
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;}
//{return m_position;}
bool doShowSelectionBox(){return false;}
private:
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::MyBillboardSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
bool m_walking;
float m_walking_unset_timer;
float m_walk_timer;
int m_walk_frame;
float m_damage_visual_timer;
u8 m_last_light;
bool m_shooting;
float m_shooting_unset_timer;
v2f m_sprite_size;
v3f m_sprite_pos;
bool m_bright_shooting;
std::string m_sprite_type;
int m_simple_anim_frames;
float m_simple_anim_frametime;
bool m_lock_full_brightness;
int m_player_hit_damage;
float m_player_hit_distance;
float m_player_hit_interval;
float m_player_hit_timer;
Settings *m_properties;
};
#endif

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define ACTIVEOBJECT_TYPE_RAT 3
#define ACTIVEOBJECT_TYPE_OERKKI1 4
#define ACTIVEOBJECT_TYPE_FIREFLY 5
#define ACTIVEOBJECT_TYPE_MOBV2 6
#endif

@ -20,9 +20,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "collision.h"
#include "environment.h"
#include "settings.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
/* Some helper functions */
// Y is copied, X and Z change is limited
void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase)
{
v3f d_wanted = target_speed - speed;
d_wanted.Y = 0;
f32 dl_wanted = d_wanted.getLength();
f32 dl = dl_wanted;
if(dl > max_increase)
dl = max_increase;
v3f d = d_wanted.normalize() * dl;
speed.X += d.X;
speed.Z += d.Z;
speed.Y = target_speed.Y;
}
/*
TestSAO
*/
@ -422,23 +442,6 @@ InventoryItem* RatSAO::createPickedUpItem()
Oerkki1SAO
*/
// Y is copied, X and Z change is limited
void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase)
{
v3f d_wanted = target_speed - speed;
d_wanted.Y = 0;
f32 dl_wanted = d_wanted.getLength();
f32 dl = dl_wanted;
if(dl > max_increase)
dl = max_increase;
v3f d = d_wanted.normalize() * dl;
speed.X += d.X;
speed.Z += d.Z;
speed.Y = target_speed.Y;
}
// Prototype
Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
@ -617,7 +620,7 @@ void Oerkki1SAO::step(float dtime, bool send_recommended)
m_touching_ground = moveresult.touching_ground;
// Do collision damage
float tolerance = BS*12;
float tolerance = BS*30;
float factor = BS*0.5;
v3f speed_diff = old_speed - m_speed_f;
// Increase effect in X and Z
@ -886,3 +889,477 @@ InventoryItem* FireflySAO::createPickedUpItem()
InventoryItem *item = InventoryItem::deSerialize(is);
return item;
}
/*
MobV2SAO
*/
// Prototype
MobV2SAO proto_MobV2SAO(NULL, 0, v3f(0,0,0), NULL);
MobV2SAO::MobV2SAO(ServerEnvironment *env, u16 id, v3f pos,
Settings *init_properties):
ServerActiveObject(env, id, pos),
m_move_type("ground_nodes"),
m_speed(0,0,0),
m_last_sent_position(0,0,0),
m_oldpos(0,0,0),
m_yaw(0),
m_counter1(0),
m_counter2(0),
m_age(0),
m_touching_ground(false),
m_hp(10),
m_walk_around(false),
m_walk_around_timer(0),
m_next_pos_exists(false),
m_shoot_reload_timer(0),
m_shooting(false),
m_shooting_timer(0),
m_falling(false)
{
ServerActiveObject::registerType(getType(), create);
m_properties = new Settings();
if(init_properties)
m_properties->update(*init_properties);
m_properties->setV3F("pos", pos);
setPropertyDefaults();
readProperties();
}
MobV2SAO::~MobV2SAO()
{
delete m_properties;
}
ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
Settings properties;
properties.parseConfigLines(is, "MobArgsEnd");
MobV2SAO *o = new MobV2SAO(env, id, pos, &properties);
return o;
}
std::string MobV2SAO::getStaticData()
{
updateProperties();
std::ostringstream os(std::ios::binary);
m_properties->writeLines(os);
return os.str();
}
std::string MobV2SAO::getClientInitializationData()
{
//dstream<<__FUNCTION_NAME<<std::endl;
updateProperties();
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
Settings client_properties;
/*client_properties.set("version", "0");
client_properties.updateValue(*m_properties, "pos");
client_properties.updateValue(*m_properties, "yaw");
client_properties.updateValue(*m_properties, "hp");*/
// Just send everything for simplicity
client_properties.update(*m_properties);
std::ostringstream os2(std::ios::binary);
client_properties.writeLines(os2);
compressZlib(os2.str(), os);
return os.str();
}
bool checkFreePosition(Map *map, v3s16 p0, v3s16 size)
{
for(int dx=0; dx<size.X; dx++)
for(int dy=0; dy<size.Y; dy++)
for(int dz=0; dz<size.Z; dz++){
v3s16 dp(dx, dy, dz);
v3s16 p = p0 + dp;
MapNode n = map->getNodeNoEx(p);
if(n.getContent() != CONTENT_AIR)
return false;
}
return true;
}
bool checkWalkablePosition(Map *map, v3s16 p0)
{
v3s16 p = p0 + v3s16(0,-1,0);
MapNode n = map->getNodeNoEx(p);
if(n.getContent() != CONTENT_AIR)
return true;
return false;
}
bool checkFreeAndWalkablePosition(Map *map, v3s16 p0, v3s16 size)
{
if(!checkFreePosition(map, p0, size))
return false;
if(!checkWalkablePosition(map, p0))
return false;
return true;
}
static void get_random_u32_array(u32 a[], u32 len)
{
u32 i, n;
for(i=0; i<len; i++)
a[i] = i;
n = len;
while(n > 1){
u32 k = myrand() % n;
n--;
u32 temp = a[n];
a[n] = a[k];
a[k] = temp;
}
}
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
static void explodeSquare(Map *map, v3s16 p0, v3s16 size)
{
core::map<v3s16, MapBlock*> modified_blocks;
for(int dx=0; dx<size.X; dx++)
for(int dy=0; dy<size.Y; dy++)
for(int dz=0; dz<size.Z; dz++){
v3s16 dp(dx - size.X/2, dy - size.Y/2, dz - size.Z/2);
v3s16 p = p0 + dp;
MapNode n = map->getNodeNoEx(p);
if(n.getContent() == CONTENT_IGNORE)
continue;
//map->removeNodeWithEvent(p);
map->removeNodeAndUpdate(p, modified_blocks);
}
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
for(core::map<v3s16, MapBlock*>::Iterator
i = modified_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
event.modified_blocks.insert(p, true);
}
map->dispatchEvent(&event);
}
void MobV2SAO::step(float dtime, bool send_recommended)
{
assert(m_env);
Map *map = &m_env->getMap();
m_age += dtime;
if(m_die_age >= 0.0 && m_age >= m_die_age){
m_removed = true;
return;
}
if(!m_falling)
{
m_shooting_timer -= dtime;
if(m_shooting_timer <= 0.0 && m_shooting){
m_shooting = false;
std::string shoot_type = m_properties->get("shoot_type");
v3f shoot_pos(0,0,0);
shoot_pos.Y += m_properties->getFloat("shoot_y") * BS;
if(shoot_type == "fireball"){
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
v3f speed = dir * BS * 10.0;
v3f pos = m_base_position + shoot_pos;
dstream<<__FUNCTION_NAME<<": Shooting fireball from "<<PP(pos)
<<" at speed "<<PP(speed)<<std::endl;
Settings properties;
properties.setV3F("speed", speed);
properties.setFloat("die_age", 5.0);
properties.set("move_type", "constant_speed");
properties.set("texture_name", "fireball.png");
properties.setV3F("sprite_pos", v3f(0.0, 0.0, 0.0));
properties.setV2F("sprite_size", v2f(1.0, 1.0));
properties.set("sprite_type", "simple");
properties.set("simple_anim_frames", "3");
properties.set("simple_anim_frametime", "0.1");
properties.setFloat("hp", 1000);
properties.set("lock_full_brightness", "true");
properties.set("player_hit_damage", "9");
properties.set("player_hit_distance", "2");
properties.set("player_hit_interval", "1");
ServerActiveObject *obj = new MobV2SAO(m_env, 0,
pos, &properties);
//m_env->addActiveObjectAsStatic(obj);
m_env->addActiveObject(obj);
} else {
dstream<<__FUNCTION_NAME<<": Unknown shoot_type="<<shoot_type
<<std::endl;
}
}
m_shoot_reload_timer += dtime;
if(m_shoot_reload_timer >= 5.0 && !m_next_pos_exists)
{
m_shoot_reload_timer = 0.0;
m_shooting = true;
m_shooting_timer = 1.5;
{
std::ostringstream os(std::ios::binary);
// command (2 = shooting)
writeU8(os, 2);
// time
writeF1000(os, m_shooting_timer + 0.1);
// bright?
writeU8(os, true);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
}
if(m_move_type == "ground_nodes")
{
if(!m_shooting){
m_walk_around_timer -= dtime;
if(m_walk_around_timer <= 0.0){
m_walk_around = !m_walk_around;
if(m_walk_around)
m_walk_around_timer = 0.1*myrand_range(10,50);
else
m_walk_around_timer = 0.1*myrand_range(30,70);
}
}
/* Move */
if(m_next_pos_exists){
v3f pos_f = m_base_position;
v3f next_pos_f = intToFloat(m_next_pos_i, BS);
v3f v = next_pos_f - pos_f;
m_yaw = atan2(v.Z, v.X) / M_PI * 180;
v3f diff = next_pos_f - pos_f;
v3f dir = diff;
dir.normalize();
float speed = BS * 0.5;
if(m_falling)
speed = BS * 3.0;
dir *= dtime * speed;
bool arrived = false;
if(dir.getLength() > diff.getLength()){
dir = diff;
arrived = true;
}
pos_f += dir;
m_base_position = pos_f;
if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
//dstream<<"id="<<m_id<<": arrived to "<<PP(m_next_pos_i)<<std::endl;
m_next_pos_exists = false;
}
}
v3s16 pos_i = floatToInt(m_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
if(!m_next_pos_exists){
/* Check whether to drop down */
if(checkFreePosition(map,
pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){
m_next_pos_i = pos_i + v3s16(0,-1,0);
m_next_pos_exists = true;
m_falling = true;
} else {
m_falling = false;
}
}
if(m_walk_around)
{
if(!m_next_pos_exists){
/* Find some position where to go next */
v3s16 dps[3*3*3];
int num_dps = 0;
for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++)
for(int dz=-1; dz<=1; dz++){
if(dx == 0 && dy == 0)
continue;
if(dx != 0 && dz != 0 && dy != 0)
continue;
dps[num_dps++] = v3s16(dx,dy,dz);
}
u32 order[3*3*3];
get_random_u32_array(order, num_dps);
/*dstream<<"At pos "<<PP(pos_i)<<"; Random array: ";
for(int i=0; i<num_dps; i++){
dstream<<order[i]<<" ";
}
dstream<<std::endl;*/
for(int i=0; i<num_dps; i++){
v3s16 p = dps[order[i]] + pos_i;
bool is_free = checkFreeAndWalkablePosition(map,
p + pos_size_off, size_blocks);
//dstream<<PP(p)<<" is_free="<<is_free<<std::endl;
if(!is_free)
continue;
m_next_pos_i = p;
m_next_pos_exists = true;
break;
}
}
}
}
else if(m_move_type == "constant_speed")
{
m_base_position += m_speed * dtime;
v3s16 pos_i = floatToInt(m_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
if(!free){
explodeSquare(map, pos_i, v3s16(3,3,3));
m_removed = true;
return;
}
}
else
{
dstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\""
<<m_move_type<<"\""<<std::endl;
}
if(send_recommended == false)
return;
if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
m_last_sent_position = m_base_position;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
u16 MobV2SAO::punch(const std::string &toolname, v3f dir)
{
u16 amount = 2;
dstream<<"id="<<m_id<<": punch with \""<<toolname<<"\""<<std::endl;
/* See tool names in inventory.h */
if(toolname == "WSword")
amount = 4;
if(toolname == "STSword")
amount = 7;
if(toolname == "SteelSword")
amount = 10;
if(toolname == "STAxe")
amount = 3;
if(toolname == "SteelAxe")
amount = 4;
if(toolname == "SteelPick")
amount = 3;
doDamage(amount);
return 65536/100;
}
void MobV2SAO::setPropertyDefaults()
{
m_properties->setDefault("move_type", "ground_nodes");
m_properties->setDefault("speed", "(0,0,0)");
m_properties->setDefault("age", "0");
m_properties->setDefault("yaw", "0");
m_properties->setDefault("pos", "(0,0,0)");
m_properties->setDefault("hp", "0");
m_properties->setDefault("die_age", "-1");
m_properties->setDefault("size", "(1,2)");
m_properties->setDefault("shoot_type", "fireball");
m_properties->setDefault("shoot_y", "0");
}
void MobV2SAO::readProperties()
{
m_move_type = m_properties->get("move_type");
m_speed = m_properties->getV3F("speed");
m_age = m_properties->getFloat("age");
m_yaw = m_properties->getFloat("yaw");
m_base_position = m_properties->getV3F("pos");
m_hp = m_properties->getS32("hp");
m_die_age = m_properties->getFloat("die_age");
m_size = m_properties->getV2F("size");
}
void MobV2SAO::updateProperties()
{
m_properties->set("move_type", m_move_type);
m_properties->setV3F("speed", m_speed);
m_properties->setFloat("age", m_age);
m_properties->setFloat("yaw", m_yaw);
m_properties->setV3F("pos", m_base_position);
m_properties->setS32("hp", m_hp);
m_properties->setFloat("die_age", m_die_age);
m_properties->setV2F("size", m_size);
m_properties->setS32("version", 0);
}
void MobV2SAO::doDamage(u16 d)
{
dstream<<"MobV2 hp="<<m_hp<<" damage="<<d<<std::endl;
if(d < m_hp)
{
m_hp -= d;
}
else
{
// Die
m_hp = 0;
m_removed = true;
}
{
std::ostringstream os(std::ios::binary);
// command (1 = damage)
writeU8(os, 1);
// amount
writeU16(os, d);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}

@ -139,5 +139,52 @@ private:
bool m_touching_ground;
};
class Settings;
class MobV2SAO : public ServerActiveObject
{
public:
MobV2SAO(ServerEnvironment *env, u16 id, v3f pos,
Settings *init_properties);
virtual ~MobV2SAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_MOBV2;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data);
std::string getStaticData();
std::string getClientInitializationData();
void step(float dtime, bool send_recommended);
InventoryItem* createPickedUpItem(){return NULL;}
u16 punch(const std::string &toolname, v3f dir);
private:
void setPropertyDefaults();
void readProperties();
void updateProperties();
void doDamage(u16 d);
std::string m_move_type;
v3f m_speed;
v3f m_last_sent_position;
v3f m_oldpos;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
int m_hp;
bool m_walk_around;
float m_walk_around_timer;
bool m_next_pos_exists;
v3s16 m_next_pos_i;
float m_shoot_reload_timer;
bool m_shooting;
float m_shooting_timer;
float m_die_age;
v2f m_size;
bool m_falling;
Settings *m_properties;
};
#endif

@ -89,7 +89,8 @@ void set_default_settings(Settings *settings)
settings->setDefault("fixed_map_seed", "");
settings->setDefault("objectdata_interval", "0.2");
settings->setDefault("active_object_range", "2");
settings->setDefault("active_object_send_range_blocks", "3");
settings->setDefault("active_block_range", "5");
//settings->setDefault("max_simultaneous_block_sends_per_client", "1");
// This causes frametime jitter on client side, or does it?
settings->setDefault("max_simultaneous_block_sends_per_client", "2");

@ -643,6 +643,24 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
}
}
static void getMob_dungeon_master(Settings &properties)
{
properties.set("texture_name", "dungeon_master.png");
properties.setV3F("sprite_pos", v3f(0.0, 0.85, 0.0));
properties.setV2F("sprite_size", v2f(2.0, 3.0));
properties.setFloat("selection_y", -0.4);
properties.setV2F("selection_size", v2f(0.4, 2.6));
properties.setFloat("yaw", 1.57);
properties.setFloat("hp", 20);
properties.setBool("bright_shooting", true);
properties.set("shoot_type", "fireball");
properties.set("shoot_y", "0.7");
properties.set("sprite_type", "humanoid_1");
properties.set("player_hit_damage", "1");
properties.set("player_hit_distance", "1.0");
properties.set("player_hit_interval", "0.5");
}
void ServerEnvironment::step(float dtime)
{
DSTACK(__FUNCTION_NAME);
@ -725,7 +743,7 @@ void ServerEnvironment::step(float dtime)
/*
Update list of active blocks, collecting changes
*/
const s16 active_block_range = 5;
const s16 active_block_range = g_settings->getS16("active_block_range");
core::map<v3s16, bool> blocks_removed;
core::map<v3s16, bool> blocks_added;
m_active_blocks.update(players_blockpos, active_block_range,
@ -925,6 +943,44 @@ void ServerEnvironment::step(float dtime)
}
}
}
/*
Fun things spawn in caves and dungeons
*/
if(n.getContent() == CONTENT_STONE ||
n.getContent() == CONTENT_MOSSYCOBBLE)
{
if(myrand()%200 == 0 && active_object_count_wider == 0)
{
v3s16 p1 = p + v3s16(0,1,0);
MapNode n1a = m_map->getNodeNoEx(p1+v3s16(0,0,0));
if(n1a.getLightBlend(getDayNightRatio()) <= 3){
MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,1,0));
if(n1a.getContent() == CONTENT_AIR &&
n1b.getContent() == CONTENT_AIR)
{
v3f pos = intToFloat(p1, BS);
int i = myrand()%5;
if(i == 0 || i == 1){
Settings properties;
getMob_dungeon_master(properties);
ServerActiveObject *obj = new MobV2SAO(
this, 0, pos, &properties);
addActiveObject(obj);
} else if(i == 2 || i == 3){
for(int j=0; j<3; j++){
ServerActiveObject *obj = new RatSAO(
this, 0, pos);
addActiveObject(obj);
}
} else {
ServerActiveObject *obj = new Oerkki1SAO(
this, 0, pos);
addActiveObject(obj);
}
}
}
}
}
/*
Make trees from saplings!
*/
@ -964,7 +1020,6 @@ void ServerEnvironment::step(float dtime)
m_map->dispatchEvent(&event);
}
}
}
}
}
@ -978,7 +1033,7 @@ void ServerEnvironment::step(float dtime)
// This helps the objects to send data at the same time
bool send_recommended = false;
m_send_recommended_timer += dtime;
if(m_send_recommended_timer > 0.15)
if(m_send_recommended_timer > 0.10)
{
m_send_recommended_timer = 0;
send_recommended = true;
@ -1020,7 +1075,7 @@ void ServerEnvironment::step(float dtime)
/*
TEST CODE
*/
#if 1
#if 0
m_random_spawn_timer -= dtime;
if(m_random_spawn_timer < 0)
{
@ -1042,7 +1097,7 @@ void ServerEnvironment::step(float dtime)
pos = player->getPosition();
pos += v3f(
myrand_range(-3,3)*BS,
0,
5,
myrand_range(-3,3)*BS
);
@ -1054,7 +1109,14 @@ void ServerEnvironment::step(float dtime)
//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
//ServerActiveObject *obj = new RatSAO(this, 0, pos);
//ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
ServerActiveObject *obj = new FireflySAO(this, 0, pos);
//ServerActiveObject *obj = new FireflySAO(this, 0, pos);
dstream<<DTIME<<"INFO: Server: Spawning MobV2SAO at "
<<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
Settings properties;
getMob_dungeon_master(properties);
ServerActiveObject *obj = new MobV2SAO(this, 0, pos, &properties);
addActiveObject(obj);
}
#endif
@ -1110,6 +1172,47 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
return id;
}
bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
{
assert(obj);
v3f objectpos = obj->getBasePosition();
// The block in which the object resides in
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
/*
Update the static data
*/
// Create 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));
// Get or generate the block
MapBlock *block = m_map->emergeBlock(blockpos);
bool succeeded = false;
if(block)
{
block->m_static_objects.insert(0, s_obj);
block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
succeeded = true;
}
else{
dstream<<"WARNING: ServerEnvironment::addActiveObjectAsStatic: "
<<"Could not find or generate "
<<"a block for storing static object"<<std::endl;
succeeded = false;
}
delete obj;
return succeeded;
}
/*
Finds out what new objects have been added to
inside a radius around a position
@ -1894,9 +1997,9 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
obj->setId(id);
addActiveObject(obj);
obj->initialize(init_data);
addActiveObject(obj);
}
void ClientEnvironment::removeActiveObject(u16 id)

@ -175,6 +175,14 @@ public:
*/
u16 addActiveObject(ServerActiveObject *object);
/*
Add an active object as a static object to the corresponding
MapBlock.
Caller allocates memory, ServerEnvironment frees memory.
Return value: true if succeeded, false if failed.
*/
bool addActiveObjectAsStatic(ServerActiveObject *object);
/*
Find out what new objects have been added to
inside a radius around a position

@ -89,27 +89,6 @@ u16 g_selected_item = 0;
Text input system
*/
struct TextDestSign : public TextDest
{
TextDestSign(v3s16 blockpos, s16 id, Client *client)
{
m_blockpos = blockpos;
m_id = id;
m_client = client;
}
void gotText(std::wstring text)
{
std::string ntext = wide_to_narrow(text);
dstream<<"Changing text of a sign object: "
<<ntext<<std::endl;
m_client->sendSignText(m_blockpos, m_id, ntext);
}
v3s16 m_blockpos;
s16 m_id;
Client *m_client;
};
struct TextDestChat : public TextDest
{
TextDestChat(Client *client)
@ -298,7 +277,7 @@ void getPointedNode(Client *client, v3f player_position,
v3s16 pos_i = floatToInt(player_position, BS);
/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
/*dstream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
<<std::endl;*/
s16 a = d;
@ -705,7 +684,7 @@ void the_game(
SharedPtr<Server> server;
if(address == ""){
draw_load_screen(L"Creating server...", driver, font);
std::cout<<DTIME<<"Creating server"<<std::endl;
dstream<<DTIME<<"Creating server"<<std::endl;
server = new Server(map_dir, configpath);
server->start(port);
}
@ -715,7 +694,7 @@ void the_game(
*/
draw_load_screen(L"Creating client...", driver, font);
std::cout<<DTIME<<"Creating client"<<std::endl;
dstream<<DTIME<<"Creating client"<<std::endl;
MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control);
@ -730,7 +709,7 @@ void the_game(
}
catch(ResolveError &e)
{
std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;
dstream<<DTIME<<"Couldn't resolve address"<<std::endl;
//return 0;
error_message = L"Couldn't resolve address";
//gui_loadingtext->remove();
@ -799,12 +778,12 @@ void the_game(
{
error_message = L"Access denied. Reason: "
+client.accessDeniedReason();
std::cout<<DTIME<<wide_to_narrow(error_message)<<std::endl;
dstream<<DTIME<<wide_to_narrow(error_message)<<std::endl;
}
else
{
error_message = L"Connection timed out.";
std::cout<<DTIME<<"Timed out."<<std::endl;
dstream<<DTIME<<"Timed out."<<std::endl;
}
//gui_loadingtext->remove();
return;
@ -924,9 +903,17 @@ void the_game(
core::list<float> frametime_log;
float nodig_delay_counter = 0.0;
float dig_time = 0.0;
u16 dig_index = 0;
v3s16 nodepos_old(-32768,-32768,-32768);
float damage_flash_timer = 0;
s16 farmesh_range = 20*MAP_BLOCKSIZE;
const float object_hit_delay = 0.5;
float object_hit_delay_timer = 0.0;
bool invert_mouse = g_settings->getBool("invert_mouse");
/*
@ -952,7 +939,7 @@ void the_game(
{
error_message = L"Access denied. Reason: "
+client.accessDeniedReason();
std::cout<<DTIME<<wide_to_narrow(error_message)<<std::endl;
dstream<<DTIME<<wide_to_narrow(error_message)<<std::endl;
break;
}
@ -1018,7 +1005,7 @@ void the_game(
busytime = busytime_u32 / 1000.0;
}
//std::cout<<"busytime_u32="<<busytime_u32<<std::endl;
//dstream<<"busytime_u32="<<busytime_u32<<std::endl;
// Necessary for device->getTimer()->getTime()
device->run();
@ -1053,6 +1040,10 @@ void the_game(
dtime = 0;
lasttime = time;
/* Run timers */
object_hit_delay_timer -= dtime;
/*
Log frametime for visualization
*/
@ -1067,8 +1058,8 @@ void the_game(
Visualize frametime in terminal
*/
/*for(u32 i=0; i<dtime*400; i++)
std::cout<<"X";
std::cout<<std::endl;*/
dstream<<"X";
dstream<<std::endl;*/
/*
Time average and jitter calculation
@ -1133,7 +1124,7 @@ void the_game(
if(counter < 0)
{
counter = 30.0;
client.printDebugInfo(std::cout);
client.printDebugInfo(dstream);
}
}
@ -1359,7 +1350,7 @@ void the_game(
}
if(first_loop_after_window_activation){
//std::cout<<"window active, first loop"<<std::endl;
//dstream<<"window active, first loop"<<std::endl;
first_loop_after_window_activation = false;
}
else{
@ -1367,7 +1358,7 @@ void the_game(
s32 dy = input->getMousePos().Y - displaycenter.Y;
if(invert_mouse)
dy = -dy;
//std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
//dstream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
/*const float keyspeed = 500;
if(input->isKeyDown(irr::KEY_UP))
@ -1391,7 +1382,7 @@ void the_game(
if(device->getCursorControl()->isVisible() == false)
device->getCursorControl()->setVisible(true);
//std::cout<<"window inactive"<<std::endl;
//dstream<<"window inactive"<<std::endl;
first_loop_after_window_activation = true;
}
@ -1500,71 +1491,23 @@ void the_game(
core::line3d<f32> shootline(camera_position,
camera_position + camera_direction * BS * (d+1));
MapBlockObject *selected_object = client.getSelectedObject
(d*BS, camera_position, shootline);
ClientActiveObject *selected_active_object
= client.getSelectedActiveObject
(d*BS, camera_position, shootline);
if(selected_object != NULL)
bool left_punch = false;
bool left_punch_muted = false;
if(selected_active_object != NULL)
{
//dstream<<"Client returned selected_object != NULL"<<std::endl;
core::aabbox3d<f32> box_on_map
= selected_object->getSelectionBoxOnMap();
hilightboxes.push_back(box_on_map);
infotext = narrow_to_wide(selected_object->infoText());
if(input->getLeftClicked())
/* Clear possible cracking animation */
if(nodepos_old != v3s16(-32768,-32768,-32768))
{
std::cout<<DTIME<<"Left-clicked object"<<std::endl;
client.clickObject(0, selected_object->getBlock()->getPos(),
selected_object->getId(), g_selected_item);
client.clearTempMod(nodepos_old);
dig_time = 0.0;
nodepos_old = v3s16(-32768,-32768,-32768);
}
else if(input->getRightClicked())
{
std::cout<<DTIME<<"Right-clicked object"<<std::endl;
/*
Check if we want to modify the object ourselves
*/
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
*/
else
{
client.clickObject(1, selected_object->getBlock()->getPos(),
selected_object->getId(), g_selected_item);
}
}
}
else if(selected_active_object != NULL)
{
//dstream<<"Client returned selected_active_object != NULL"<<std::endl;
core::aabbox3d<f32> *selection_box
@ -1580,20 +1523,30 @@ void the_game(
selection_box->MaxEdge + pos
);
if(selected_active_object->doShowSelectionBox())
hilightboxes.push_back(box_on_map);
//infotext = narrow_to_wide("A ClientActiveObject");
infotext = narrow_to_wide(selected_active_object->infoText());
if(input->getLeftClicked())
//if(input->getLeftClicked())
if(input->getLeftState())
{
std::cout<<DTIME<<"Left-clicked object"<<std::endl;
if(object_hit_delay_timer <= 0.0){
dstream<<DTIME<<"Left-clicked object"<<std::endl;
client.clickActiveObject(0,
selected_active_object->getId(), g_selected_item);
object_hit_delay_timer = object_hit_delay;
left_punch = true;
} else {
dstream<<DTIME<<"Left-clicked object faster than allowed"
<<std::endl;
left_punch_muted = true;
}
}
else if(input->getRightClicked())
{
std::cout<<DTIME<<"Right-clicked object"<<std::endl;
dstream<<DTIME<<"Right-clicked object"<<std::endl;
client.clickActiveObject(1,
selected_active_object->getId(), g_selected_item);
}
@ -1616,15 +1569,14 @@ void the_game(
nodepos, neighbourpos,
nodehilightbox, d);
static float nodig_delay_counter = 0.0;
if(nodefound)
if(!nodefound){
if(nodepos_old != v3s16(-32768,-32768,-32768))
{
static v3s16 nodepos_old(-32768,-32768,-32768);
static float dig_time = 0.0;
static u16 dig_index = 0;
client.clearTempMod(nodepos_old);
dig_time = 0.0;
nodepos_old = v3s16(-32768,-32768,-32768);
}
} else {
/*
Visualize selection
*/
@ -1661,13 +1613,14 @@ void the_game(
{
if(nodepos != nodepos_old)
{
std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","
dstream<<DTIME<<"Pointing at ("<<nodepos.X<<","
<<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;
if(nodepos_old != v3s16(-32768,-32768,-32768))
{
client.clearTempMod(nodepos_old);
dig_time = 0.0;
nodepos_old = v3s16(-32768,-32768,-32768);
}
}
@ -1771,7 +1724,7 @@ void the_game(
if(input->getRightClicked())
{
std::cout<<DTIME<<"Ground right-clicked"<<std::endl;
dstream<<DTIME<<"Ground right-clicked"<<std::endl;
// If metadata provides an inventory view, activate it
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
@ -1836,7 +1789,7 @@ void the_game(
} // selected_object == NULL
if(input->getLeftClicked())
if(left_punch || (input->getLeftClicked() && !left_punch_muted))
{
camera.setDigging(0); // left click animation
}
@ -1846,13 +1799,13 @@ void the_game(
if(input->getLeftReleased())
{
std::cout<<DTIME<<"Left button released (stopped digging)"
dstream<<DTIME<<"Left button released (stopped digging)"
<<std::endl;
client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);
}
if(input->getRightReleased())
{
//std::cout<<DTIME<<"Right released"<<std::endl;
//dstream<<DTIME<<"Right released"<<std::endl;
// Nothing here
}
@ -2097,7 +2050,7 @@ void the_game(
{
client.selectPlayerItem(g_selected_item);
old_selected_item = g_selected_item;
//std::cout<<"Updating local inventory"<<std::endl;
//dstream<<"Updating local inventory"<<std::endl;
client.getLocalInventory(local_inventory);
// Update wielded tool
@ -2136,7 +2089,7 @@ void the_game(
//timer3.stop();
//std::cout<<DTIME<<"smgr->drawAll()"<<std::endl;
//dstream<<DTIME<<"smgr->drawAll()"<<std::endl;
{
TimeTaker timer("smgr");
@ -2162,7 +2115,7 @@ void the_game(
for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();
i != hilightboxes.end(); i++)
{
/*std::cout<<"hilightbox min="
/*dstream<<"hilightbox min="
<<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
<<" max="
<<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"

@ -97,7 +97,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
{
std::string inventorystring;
std::getline(is, inventorystring, '|');
return new MapBlockObjectItem(inventorystring);
throw SerializationError("MBOItem not supported anymore");
}
else if(name == "CraftItem")
{
@ -219,77 +219,6 @@ bool CraftItem::use(ServerEnvironment *env, Player *player)
return false;
}
/*
MapBlockObjectItem DEPRECATED
TODO: Remove
*/
#ifndef SERVER
video::ITexture * MapBlockObjectItem::getImage() const
{
if(m_inventorystring.substr(0,3) == "Rat")
return g_texturesource->getTextureRaw("rat.png");
if(m_inventorystring.substr(0,4) == "Sign")
return g_texturesource->getTextureRaw("sign.png");
return NULL;
}
#endif
std::string MapBlockObjectItem::getText()
{
if(m_inventorystring.substr(0,3) == "Rat")
return "";
if(m_inventorystring.substr(0,4) == "Sign")
return "";
return "obj";
}
MapBlockObject * MapBlockObjectItem::createObject
(v3f pos, f32 player_yaw, f32 player_pitch)
{
std::istringstream is(m_inventorystring);
std::string name;
std::getline(is, name, ' ');
if(name == "None")
{
return NULL;
}
else if(name == "Sign")
{
std::string text;
std::getline(is, text, '|');
SignObject *obj = new SignObject(NULL, -1, pos);
obj->setText(text);
obj->setYaw(-player_yaw);
return obj;
}
else if(name == "Rat")
{
RatObject *obj = new RatObject(NULL, -1, pos);
return obj;
}
else if(name == "ItemObj")
{
/*
Now we are an inventory item containing the serialization
string of an object that contains the serialization
string of an inventory item. Fuck this.
*/
//assert(0);
dstream<<__FUNCTION_NAME<<": WARNING: Ignoring ItemObj "
<<"because an item-object should never be inside "
<<"an object-item."<<std::endl;
return NULL;
}
else
{
return NULL;
}
}
/*
Inventory
*/

@ -29,7 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include "common_irrlicht.h"
#include "debug.h"
#include "mapblockobject.h"
#include "main.h" // For g_materials
#include "mapnode.h" // For content_t
@ -196,56 +195,6 @@ private:
content_t m_content;
};
//TODO: Remove
class MapBlockObjectItem : public InventoryItem
{
public:
MapBlockObjectItem(std::string inventorystring):
InventoryItem(1)
{
m_inventorystring = inventorystring;
}
/*
Implementation interface
*/
virtual const char* getName() const
{
return "MBOItem";
}
virtual void serialize(std::ostream &os) const
{
std::string sane_string(m_inventorystring);
str_replace_char(sane_string, '|', '?');
os<<getName();
os<<" ";
os<<sane_string;
os<<"|";
}
virtual InventoryItem* clone()
{
return new MapBlockObjectItem(m_inventorystring);
}
#ifndef SERVER
video::ITexture * getImage() const;
#endif
std::string getText();
/*
Special methods
*/
std::string getInventoryString()
{
return m_inventorystring;
}
MapBlockObject * createObject(v3f pos, f32 player_yaw, f32 player_pitch);
private:
std::string m_inventorystring;
};
/*
An item that is used as a mid-product when crafting.
Subnames:

@ -36,7 +36,6 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, bool dummy):
m_lighting_expired(true),
m_day_night_differs(false),
m_generated(false),
m_objects(this),
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
m_usage_timer(0)
{
@ -434,18 +433,6 @@ void MapBlock::copyFrom(VoxelManipulator &dst)
getPosRelative(), data_size);
}
void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
{
/*
Step objects
*/
m_objects.step(dtime, server, daynight_ratio);
//setChangedFlag();
raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
}
void MapBlock::updateDayNightDiff()
{
if(data == NULL)
@ -818,10 +805,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
{
// Versions up from 9 have block objects.
// Versions up from 9 have block objects. (DEPRECATED)
if(version >= 9)
{
//serializeObjects(os, version); // DEPRECATED
// count=0
writeU16(os, 0);
}
@ -842,11 +828,17 @@ void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
{
/*
Versions up from 9 have block objects.
Versions up from 9 have block objects. (DEPRECATED)
*/
if(version >= 9)
{
updateObjects(is, version, NULL, 0);
u16 count = readU16(is);
// Not supported and length not known if count is not 0
if(count != 0){
dstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
<<"Ignoring stuff coming at and after MBOs"<<std::endl;
return;
}
}
/*

@ -29,7 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "exceptions.h"
#include "serialization.h"
#include "constants.h"
#include "mapblockobject.h"
#include "voxel.h"
#include "nodemetadata.h"
#include "staticobject.h"
@ -423,68 +422,6 @@ public:
// Copies data from VoxelManipulator getPosRelative()
void copyFrom(VoxelManipulator &dst);
/*
MapBlockObject stuff
DEPRECATED
*/
/*void serializeObjects(std::ostream &os, u8 version)
{
m_objects.serialize(os, version);
}*/
// If smgr!=NULL, new objects are added to the scene
void updateObjects(std::istream &is, u8 version,
scene::ISceneManager *smgr, u32 daynight_ratio)
{
m_objects.update(is, version, smgr, daynight_ratio);
raiseModified(MOD_STATE_WRITE_NEEDED);
}
void clearObjects()
{
m_objects.clear();
raiseModified(MOD_STATE_WRITE_NEEDED);
}
void addObject(MapBlockObject *object)
throw(ContainerFullException, AlreadyExistsException)
{
m_objects.add(object);
raiseModified(MOD_STATE_WRITE_NEEDED);
}
void removeObject(s16 id)
{
m_objects.remove(id);
raiseModified(MOD_STATE_WRITE_NEEDED);
}
MapBlockObject * getObject(s16 id)
{
return m_objects.get(id);
}
JMutexAutoLock * getObjectLock()
{
return m_objects.getLock();
}
/*
Moves objects, deletes objects and spawns new objects
*/
void stepObjects(float dtime, bool server, u32 daynight_ratio);
// origin is relative to block
void getObjects(v3f origin, f32 max_d,
core::array<DistanceSortedObject> &dest)
{
m_objects.getObjects(origin, max_d, dest);
}
s32 getObjectCount()
{
return m_objects.getCount();
}
#ifndef SERVER // Only on client
/*
Methods for setting temporary modifications to nodes for
@ -688,9 +625,6 @@ private:
bool m_generated;
// DEPRECATED
MapBlockObjectList m_objects;
#ifndef SERVER // Only on client
/*
Set to true if the mesh has been ordered to be updated

@ -1,939 +0,0 @@
/*
Minetest-c55
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// This file contains the DEPRECATED MapBlockObject system
#include "mapblockobject.h"
#include "mapblock.h"
// For object wrapping
#include "map.h"
#include "inventory.h"
#include "utility.h"
#include "mapblock.h"
/*
MapBlockObject
*/
// This is here because it uses the MapBlock
v3f MapBlockObject::getAbsolutePos()
{
if(m_block == NULL)
return m_pos;
// getPosRelative gets nodepos relative to map origin
v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
return blockpos + m_pos;
}
void MapBlockObject::setBlockChanged()
{
if(m_block)
m_block->setChangedFlag();
}
/*
MovingObject
*/
v3f MovingObject::getAbsoluteShowPos()
{
if(m_block == NULL)
return m_pos;
// getPosRelative gets nodepos relative to map origin
v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
return blockpos + m_showpos;
}
void MovingObject::move(float dtime, v3f acceleration)
{
DSTACKF("%s: typeid=%i, pos=(%f,%f,%f), speed=(%f,%f,%f)"
", dtime=%f, acc=(%f,%f,%f)",
__FUNCTION_NAME,
getTypeId(),
m_pos.X, m_pos.Y, m_pos.Z,
m_speed.X, m_speed.Y, m_speed.Z,
dtime,
acceleration.X, acceleration.Y, acceleration.Z
);
v3s16 oldpos_i = floatToInt(m_pos, BS);
if(m_block->isValidPosition(oldpos_i) == false)
{
// Should have wrapped, cancelling further movement.
return;
}
// No collisions if there is no collision box
if(m_collision_box == NULL)
{
m_speed += dtime * acceleration;
m_pos += m_speed * dtime;
return;
}
// Set insane speed to zero
// Otherwise there will be divides by zero and other silly stuff
if(m_speed.getLength() > 1000.0*BS)
m_speed = v3f(0,0,0);
// Limit speed to a reasonable value
float speed_limit = 20.0*BS;
if(m_speed.getLength() > speed_limit)
m_speed = m_speed * (speed_limit / m_speed.getLength());
v3f position = m_pos;
v3f oldpos = position;
/*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
<<oldpos_i.Z<<")"<<std::endl;*/
// Maximum time increment (for collision detection etc)
// Allow 0.1 blocks per increment
// time = distance / speed
// NOTE: In the loop below collisions are detected at 0.15*BS radius
float speedlength = m_speed.getLength();
f32 dtime_max_increment;
if(fabs(speedlength) > 0.001)
dtime_max_increment = 0.05*BS / speedlength;
else
dtime_max_increment = 0.5;
m_touching_ground = false;
u32 loopcount = 0;
do
{
loopcount++;
f32 dtime_part;
if(dtime > dtime_max_increment)
dtime_part = dtime_max_increment;
else
dtime_part = dtime;
dtime -= dtime_part;
// Begin of dtime limited code
m_speed += acceleration * dtime_part;
position += m_speed * dtime_part;
/*
Collision detection
*/
v3s16 pos_i = floatToInt(position, BS);
// The loop length is limited to the object moving a distance
f32 d = (float)BS * 0.15;
core::aabbox3d<f32> objectbox(
m_collision_box->MinEdge + position,
m_collision_box->MaxEdge + position
);
core::aabbox3d<f32> objectbox_old(
m_collision_box->MinEdge + oldpos,
m_collision_box->MaxEdge + oldpos
);
//TODO: Get these ranges from somewhere
for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
{
try{
MapNode n = m_block->getNodeParent(v3s16(x,y,z));
if(content_features(n).walkable == false)
continue;
}
catch(InvalidPositionException &e)
{
// Doing nothing here will block the object from
// walking over map borders
}
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
// See if the object is touching ground
if(
fabs(nodebox.MaxEdge.Y-objectbox.MinEdge.Y) < d
&& nodebox.MaxEdge.X-d > objectbox.MinEdge.X
&& nodebox.MinEdge.X+d < objectbox.MaxEdge.X
&& nodebox.MaxEdge.Z-d > objectbox.MinEdge.Z
&& nodebox.MinEdge.Z+d < objectbox.MaxEdge.Z
){
m_touching_ground = true;
}
if(objectbox.intersectsWithBox(nodebox))
{
v3f dirs[3] = {
v3f(0,0,1), // back
v3f(0,1,0), // top
v3f(1,0,0), // right
};
for(u16 i=0; i<3; i++)
{
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
f32 playermax = objectbox.MaxEdge.dotProduct(dirs[i]);
f32 playermin = objectbox.MinEdge.dotProduct(dirs[i]);
f32 playermax_old = objectbox_old.MaxEdge.dotProduct(dirs[i]);
f32 playermin_old = objectbox_old.MinEdge.dotProduct(dirs[i]);
bool main_edge_collides =
((nodemax > playermin && nodemax <= playermin_old + d
&& m_speed.dotProduct(dirs[i]) < 0)
||
(nodemin < playermax && nodemin >= playermax_old - d
&& m_speed.dotProduct(dirs[i]) > 0));
bool other_edges_collide = true;
for(u16 j=0; j<3; j++)
{
if(j == i)
continue;
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
f32 playermax = objectbox.MaxEdge.dotProduct(dirs[j]);
f32 playermin = objectbox.MinEdge.dotProduct(dirs[j]);
if(!(nodemax - d > playermin && nodemin + d < playermax))
{
other_edges_collide = false;
break;
}
}
if(main_edge_collides && other_edges_collide)
{
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
position -= position.dotProduct(dirs[i]) * dirs[i];
position += oldpos.dotProduct(dirs[i]) * dirs[i];
}
}
} // if(objectbox.intersectsWithBox(nodebox))
} // for y
} // End of dtime limited loop
while(dtime > 0.001);
m_pos = position;
}
void MovingObject::simpleMove(float dtime)
{
m_pos_animation_time_counter += dtime;
m_pos_animation_counter += dtime;
v3f movevector = m_pos - m_oldpos;
f32 moveratio;
if(m_pos_animation_time < 0.001)
moveratio = 1.0;
else
moveratio = m_pos_animation_counter / m_pos_animation_time;
if(moveratio > 1.5)
moveratio = 1.5;
m_showpos = m_oldpos + movevector * moveratio;
}
#ifndef SERVER
/*
RatObject
*/
void RatObject::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
video::IVideoDriver* driver = smgr->getVideoDriver();
scene::SMesh *mesh = new scene::SMesh();
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
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),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture
(0, driver->getTexture(getTexturePath("rat.png").c_str()));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
updateNodePos();
}
#endif
/*
ItemObject
*/
#ifndef SERVER
void ItemObject::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
// Get image of item for showing
video::ITexture *texture = getItemImage();
/*
Create a mesh
*/
scene::SMesh *mesh = new scene::SMesh();
{
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 1,0),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 0,0),*/
video::S3DVertex(BS/3,-BS/2,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/3,-BS/2,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/3,-BS/2+BS*2/3,0, 0,0,0, c, 1,0),
video::S3DVertex(BS/3,-BS/2+BS*2/3,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, texture);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = smgr->addMeshSceneNode(mesh, NULL);
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
((scene::IMeshSceneNode*)m_node)->setReadOnlyMaterials(true);
mesh->drop();
updateSceneNode();
}
video::ITexture * ItemObject::getItemImage()
{
/*
Create an inventory item to see what is its image
*/
video::ITexture *texture = NULL;
InventoryItem *item = createInventoryItem();
if(item)
texture = item->getImage();
if(item)
delete item;
return texture;
}
#endif
InventoryItem * ItemObject::createInventoryItem()
{
try{
std::istringstream is(m_itemstring, std::ios_base::binary);
InventoryItem *item = InventoryItem::deSerialize(is);
dstream<<__FUNCTION_NAME<<": m_itemstring=\""
<<m_itemstring<<"\" -> item="<<item
<<std::endl;
return item;
}
catch(SerializationError &e)
{
dstream<<__FUNCTION_NAME<<": serialization error: "
<<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
return NULL;
}
}
/*
PlayerObject
*/
#ifndef SERVER
void PlayerObject::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
video::IVideoDriver* driver = smgr->getVideoDriver();
// Attach a simple mesh to the player for showing an image
scene::SMesh *mesh = new scene::SMesh();
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player.png").c_str()));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
//buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
};
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player_back.png").c_str()));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
updateNodePos();
}
#endif
/*
MapBlockObjectList
*/
MapBlockObjectList::MapBlockObjectList(MapBlock *block):
m_block(block)
{
m_mutex.Init();
}
MapBlockObjectList::~MapBlockObjectList()
{
clear();
}
/*
The serialization format:
[0] u16 number of entries
[2] entries (id, typeId, parameters)
*/
void MapBlockObjectList::serialize(std::ostream &os, u8 version)
{
JMutexAutoLock lock(m_mutex);
u8 buf[2];
writeU16(buf, m_objects.size());
os.write((char*)buf, 2);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
i.getNode()->getValue()->serialize(os, version);
}
}
void MapBlockObjectList::update(std::istream &is, u8 version,
scene::ISceneManager *smgr, u32 daynight_ratio)
{
JMutexAutoLock lock(m_mutex);
/*
Collect all existing ids to a set.
As things are updated, they are removed from this.
All remaining ones are deleted.
*/
core::map<s16, bool> ids_to_delete;
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
ids_to_delete.insert(i.getNode()->getKey(), true);
}
u8 buf[6];
is.read((char*)buf, 2);
u16 count = readU16(buf);
for(u16 i=0; i<count; i++)
{
// Read id
is.read((char*)buf, 2);
s16 id = readS16(buf);
// Read position
// stored as x1000/BS v3s16
is.read((char*)buf, 6);
v3s16 pos_i = readV3S16(buf);
v3f pos((f32)pos_i.X/1000*BS,
(f32)pos_i.Y/1000*BS,
(f32)pos_i.Z/1000*BS);
// Read typeId
is.read((char*)buf, 2);
u16 type_id = readU16(buf);
bool create_new = false;
// Find an object with the id
core::map<s16, MapBlockObject*>::Node *n;
n = m_objects.find(id);
// If no entry is found for id
if(n == NULL)
{
// Insert dummy pointer node
m_objects.insert(id, NULL);
// Get node
n = m_objects.find(id);
// A new object will be created at this node
create_new = true;
}
// If type_id differs
else if(n->getValue()->getTypeId() != type_id)
{
// Delete old object
delete n->getValue();
// A new object will be created at this node
create_new = true;
}
MapBlockObject *obj = NULL;
if(create_new)
{
/*dstream<<"MapBlockObjectList adding new object"
" id="<<id
<<std::endl;*/
if(type_id == MAPBLOCKOBJECT_TYPE_SIGN)
{
obj = new SignObject(m_block, id, pos);
}
else if(type_id == MAPBLOCKOBJECT_TYPE_RAT)
{
obj = new RatObject(m_block, id, pos);
}
else if(type_id == MAPBLOCKOBJECT_TYPE_ITEM)
{
obj = new ItemObject(m_block, id, pos);
}
else
{
// This is fatal because we cannot know the length
// of the object's data
throw SerializationError
("MapBlockObjectList::update(): Unknown MapBlockObject type");
}
if(smgr != NULL)
//obj->addToScene(smgr, daynight_ratio);
obj->addToScene(smgr);
n->setValue(obj);
}
else
{
obj = n->getValue();
obj->updatePos(pos);
/*if(daynight_ratio != m_last_update_daynight_ratio)
{
obj->removeFromScene();
obj->addToScene(smgr, daynight_ratio);
}*/
}
// Now there is an object in obj.
// Update it.
obj->update(is, version);
/*
Update light on client
*/
if(smgr != NULL)
{
u8 light = LIGHT_MAX;
try{
v3s16 relpos_i = floatToInt(obj->m_pos, BS);
MapNode n = m_block->getNodeParent(relpos_i);
light = n.getLightBlend(daynight_ratio);
}
catch(InvalidPositionException &e) {}
obj->updateLight(light);
}
// Remove from deletion list
if(ids_to_delete.find(id) != NULL)
ids_to_delete.remove(id);
}
// Delete all objects whose ids_to_delete remain in ids_to_delete
for(core::map<s16, bool>::Iterator
i = ids_to_delete.getIterator();
i.atEnd() == false; i++)
{
s16 id = i.getNode()->getKey();
/*dstream<<"MapBlockObjectList deleting object"
" id="<<id
<<std::endl;*/
MapBlockObject *obj = m_objects[id];
obj->removeFromScene();
delete obj;
m_objects.remove(id);
}
m_last_update_daynight_ratio = daynight_ratio;
}
s16 MapBlockObjectList::getFreeId() throw(ContainerFullException)
{
s16 id = 0;
for(;;)
{
if(m_objects.find(id) == NULL)
return id;
if(id == 32767)
throw ContainerFullException
("MapBlockObjectList doesn't fit more objects");
id++;
}
}
void MapBlockObjectList::add(MapBlockObject *object)
throw(ContainerFullException, AlreadyExistsException)
{
if(object == NULL)
{
dstream<<"MapBlockObjectList::add(): NULL object"<<std::endl;
return;
}
JMutexAutoLock lock(m_mutex);
// Create unique id if id==-1
if(object->m_id == -1)
{
object->m_id = getFreeId();
}
if(m_objects.find(object->m_id) != NULL)
{
dstream<<"MapBlockObjectList::add(): "
"object with same id already exists"<<std::endl;
throw AlreadyExistsException
("MapBlockObjectList already has given id");
}
object->m_block = m_block;
/*v3f p = object->m_pos;
dstream<<"MapBlockObjectList::add(): "
<<"m_block->getPos()=("
<<m_block->getPos().X<<","
<<m_block->getPos().Y<<","
<<m_block->getPos().Z<<")"
<<" inserting object with id="<<object->m_id
<<" pos="
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<std::endl;*/
m_objects.insert(object->m_id, object);
}
void MapBlockObjectList::clear()
{
JMutexAutoLock lock(m_mutex);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
//FIXME: This really shouldn't be NULL at any time,
// but this condition was added because it was.
if(obj != NULL)
{
obj->removeFromScene();
delete obj;
}
}
m_objects.clear();
}
void MapBlockObjectList::remove(s16 id)
{
JMutexAutoLock lock(m_mutex);
core::map<s16, MapBlockObject*>::Node *n;
n = m_objects.find(id);
if(n == NULL)
return;
n->getValue()->removeFromScene();
delete n->getValue();
m_objects.remove(id);
}
MapBlockObject * MapBlockObjectList::get(s16 id)
{
core::map<s16, MapBlockObject*>::Node *n;
n = m_objects.find(id);
if(n == NULL)
return NULL;
else
return n->getValue();
}
void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
{
DSTACK(__FUNCTION_NAME);
JMutexAutoLock lock(m_mutex);
core::map<s16, bool> ids_to_delete;
{
DSTACKF("%s: stepping objects", __FUNCTION_NAME);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
DSTACKF("%s: stepping object type %i", __FUNCTION_NAME,
obj->getTypeId());
if(server)
{
// Update light
u8 light = LIGHT_MAX;
try{
v3s16 relpos_i = floatToInt(obj->m_pos, BS);
MapNode n = m_block->getNodeParent(relpos_i);
light = n.getLightBlend(daynight_ratio);
}
catch(InvalidPositionException &e) {}
obj->updateLight(light);
bool to_delete = obj->serverStep(dtime, daynight_ratio);
if(to_delete)
ids_to_delete.insert(obj->m_id, true);
}
else
{
obj->clientStep(dtime);
}
}
}
{
DSTACKF("%s: deleting objects", __FUNCTION_NAME);
// Delete objects in delete queue
for(core::map<s16, bool>::Iterator
i = ids_to_delete.getIterator();
i.atEnd() == false; i++)
{
s16 id = i.getNode()->getKey();
MapBlockObject *obj = m_objects[id];
obj->removeFromScene();
delete obj;
m_objects.remove(id);
}
}
/*
Wrap objects on server
*/
if(server == false)
return;
{
DSTACKF("%s: object wrap loop", __FUNCTION_NAME);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
v3s16 pos_i = floatToInt(obj->m_pos, BS);
if(m_block->isValidPosition(pos_i))
{
// No wrap
continue;
}
bool impossible = wrapObject(obj);
if(impossible)
{
// No wrap
continue;
}
// Restart find
i = m_objects.getIterator();
}
}
}
bool MapBlockObjectList::wrapObject(MapBlockObject *object)
{
DSTACK(__FUNCTION_NAME);
// No lock here; this is called so that the lock is already locked.
//JMutexAutoLock lock(m_mutex);
assert(object->m_block == m_block);
assert(m_objects.find(object->m_id) != NULL);
assert(m_objects[object->m_id] == object);
Map *map = m_block->getParent();
// Calculate blockpos on map
v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
v3f pos_f_on_oldblock = object->m_pos;
v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock, BS);
v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
// Get new block
MapBlock *newblock;
try{
newblock = map->getBlockNoCreate(pos_blocks_on_map);
}
catch(InvalidPositionException &e)
{
// Couldn't find block -> not wrapping
/*dstream<<"WARNING: Wrapping object not possible: "
<<"could not find new block"
<<"("<<pos_blocks_on_map.X
<<","<<pos_blocks_on_map.Y
<<","<<pos_blocks_on_map.Z
<<")"<<std::endl;*/
/*dstream<<"pos_f_on_oldblock=("
<<pos_f_on_oldblock.X<<","
<<pos_f_on_oldblock.Y<<","
<<pos_f_on_oldblock.Z<<")"
<<std::endl;*/
return true;
}
if(newblock == m_block)
{
dstream<<"WARNING: Wrapping object not possible: "
"newblock == oldblock"<<std::endl;
return true;
}
// Calculate position on new block
v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map, BS);
v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map, BS);
v3f pos_f_on_newblock = pos_f_on_oldblock
- newblock_pos_f_on_map + oldblock_pos_f_on_map;
// Remove object from this block
m_objects.remove(object->m_id);
// Add object to new block
object->m_pos = pos_f_on_newblock;
object->m_id = -1;
object->m_block = NULL;
newblock->addObject(object);
//dstream<<"NOTE: Wrapped object"<<std::endl;
return false;
}
void MapBlockObjectList::getObjects(v3f origin, f32 max_d,
core::array<DistanceSortedObject> &dest)
{
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
f32 d = (obj->getRelativeShowPos() - origin).getLength();
if(d > max_d)
continue;
DistanceSortedObject dso(obj, d);
dest.push_back(dso);
}
}
//END

File diff suppressed because it is too large Load Diff

@ -1405,6 +1405,7 @@ bool get_have_sand(u64 seed, v2s16 p2d)
*/
void add_random_objects(MapBlock *block)
{
#if 0
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
@ -1465,6 +1466,7 @@ void add_random_objects(MapBlock *block)
}
}
block->setChangedFlag();
#endif
}
void make_block(BlockMakeData *data)

@ -860,107 +860,10 @@ void RemoteClient::SendObjectData(
v3s16 center_nodepos = floatToInt(playerpos, BS);
v3s16 center = getNodeBlockPos(center_nodepos);
s16 d_max = g_settings->getS16("active_object_range");
// Number of blocks whose objects were written to bos
u16 blockcount = 0;
std::ostringstream bos(std::ios_base::binary);
for(s16 d = 0; d <= d_max; d++)
{
core::list<v3s16> list;
getFacePositions(list, d);
core::list<v3s16>::Iterator li;
for(li=list.begin(); li!=list.end(); li++)
{
v3s16 p = *li + center;
/*
Ignore blocks that haven't been sent to the client
*/
{
if(m_blocks_sent.find(p) == NULL)
continue;
}
// Try stepping block and add it to a send queue
try
{
// Get block
MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
/*
Step block if not in stepped_blocks and add to stepped_blocks.
*/
if(stepped_blocks.find(p) == NULL)
{
block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
stepped_blocks.insert(p, true);
//block->setChangedFlag();
}
// Skip block if there are no objects
if(block->getObjectCount() == 0)
continue;
/*
Write objects
*/
// Write blockpos
writeV3S16(buf, p);
bos.write((char*)buf, 6);
// Write objects
//block->serializeObjects(bos, serialization_version); // DEPRECATED
// count=0
writeU16(bos, 0);
blockcount++;
/*
Stop collecting objects if data is already too big
*/
// Sum of player and object data sizes
s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
// break out if data too big
if(sum > MAX_OBJECTDATA_SIZE)
{
goto skip_subsequent;
}
} //try
catch(InvalidPositionException &e)
{
// Not in memory
// Add it to the emerge queue and trigger the thread.
// Fetch the block only if it is on disk.
// Grab and increment counter
/*SharedPtr<JMutexAutoLock> lock
(m_num_blocks_in_emerge_queue.getLock());
m_num_blocks_in_emerge_queue.m_value++;*/
// Add to queue as an anonymous fetch from disk
u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
server->m_emerge_queue.addBlock(0, p, flags);
server->m_emergethread.trigger();
}
}
}
skip_subsequent:
// Write block count
writeU16(buf, blockcount);
writeU16(buf, 0);
os.write((char*)buf, 2);
// Write block objects
os<<bos.str();
/*
Send data
*/
@ -1431,7 +1334,8 @@ void Server::AsyncRunStep()
ScopeProfiler sp(g_profiler, "Server: checking added and deleted objects");
// Radius inside which objects are active
s16 radius = 32;
s16 radius = g_settings->getS16("active_object_send_range_blocks");
radius *= MAP_BLOCKSIZE;
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
@ -2343,87 +2247,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_CLICK_OBJECT)
{
if(datasize < 13)
derr_server<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
return;
if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
return;
/*
[0] u16 command
[2] u8 button (0=left, 1=right)
[3] v3s16 block
[9] s16 id
[11] u16 item
*/
u8 button = readU8(&data[2]);
v3s16 p;
p.X = readS16(&data[3]);
p.Y = readS16(&data[5]);
p.Z = readS16(&data[7]);
s16 id = readS16(&data[9]);
//u16 item_i = readU16(&data[11]);
MapBlock *block = NULL;
try
{
block = m_env.getMap().getBlockNoCreate(p);
}
catch(InvalidPositionException &e)
{
derr_server<<"CLICK_OBJECT block not found"<<std::endl;
return;
}
MapBlockObject *obj = block->getObject(id);
if(obj == NULL)
{
derr_server<<"CLICK_OBJECT object not found"<<std::endl;
return;
}
//TODO: Check that object is reasonably close
// Left click
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->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
{
item = ((ItemObject*)obj)->createInventoryItem();
}
// Else create an item of the object
else
{
item = new MapBlockObjectItem
(obj->getInventoryString());
}
// Add to inventory and send inventory
ilist->addItem(item);
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
}
// Remove from block
block->removeObject(id);
}
}
else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
{
@ -2442,7 +2267,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
u8 button = readU8(&data[2]);
u16 id = readS16(&data[3]);
u16 item_i = readU16(&data[11]);
u16 item_i = readU16(&data[5]);
ServerActiveObject *obj = m_env.getActiveObject(id);
@ -3076,62 +2901,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
#endif
else if(command == TOSERVER_SIGNTEXT)
{
if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
derr_server<<"Server: TOSERVER_SIGNTEXT not supported anymore"
<<std::endl;
return;
/*
u16 command
v3s16 blockpos
s16 id
u16 textlen
textdata
*/
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u8 buf[6];
// Read stuff
is.read((char*)buf, 6);
v3s16 blockpos = readV3S16(buf);
is.read((char*)buf, 2);
s16 id = readS16(buf);
is.read((char*)buf, 2);
u16 textlen = readU16(buf);
std::string text;
for(u16 i=0; i<textlen; i++)
{
is.read((char*)buf, 1);
text += (char)buf[0];
}
MapBlock *block = NULL;
try
{
block = m_env.getMap().getBlockNoCreate(blockpos);
}
catch(InvalidPositionException &e)
{
derr_server<<"Error while setting sign text: "
"block not found"<<std::endl;
return;
}
MapBlockObject *obj = block->getObject(id);
if(obj == NULL)
{
derr_server<<"Error while setting sign text: "
"object not found"<<std::endl;
return;
}
if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
{
derr_server<<"Error while setting sign text: "
"object is not a sign"<<std::endl;
return;
}
((SignObject*)obj)->setText(text);
obj->getBlock()->setChangedFlag();
}
else if(command == TOSERVER_SIGNNODETEXT)
{

@ -102,6 +102,22 @@ public:
return true;
}
void parseConfigLines(std::istream &is, const std::string &endstring)
{
for(;;){
if(is.eof())
break;
std::string line;
std::getline(is, line);
std::string trimmedline = trim(line);
if(endstring != ""){
if(trimmedline == endstring)
break;
}
parseConfigLine(line);
}
}
// Returns false on EOF
bool parseConfigObject(std::istream &is)
{
@ -481,6 +497,16 @@ public:
return value;
}
v2f getV2F(std::string name)
{
v2f value;
Strfnd f(get(name));
f.next("(");
value.X = stof(f.next(","));
value.Y = stof(f.next(")"));
return value;
}
u64 getU64(std::string name)
{
u64 value = 0;
@ -515,6 +541,13 @@ public:
set(name, os.str());
}
void setV2F(std::string name, v2f value)
{
std::ostringstream os;
os<<"("<<value.X<<","<<value.Y<<")";
set(name, os.str());
}
void setU64(std::string name, u64 value)
{
std::ostringstream os;
@ -530,6 +563,47 @@ public:
m_defaults.clear();
}
void updateValue(Settings &other, const std::string &name)
{
JMutexAutoLock lock(m_mutex);
if(&other == this)
return;
try{
std::string val = other.get(name);
m_settings[name] = val;
} catch(SettingNotFoundException &e){
}
return;
}
void update(Settings &other)
{
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this)
return;
for(core::map<std::string, std::string>::Iterator
i = other.m_settings.getIterator();
i.atEnd() == false; i++)
{
m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
}
for(core::map<std::string, std::string>::Iterator
i = other.m_defaults.getIterator();
i.atEnd() == false; i++)
{
m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
}
return;
}
Settings & operator+=(Settings &other)
{
JMutexAutoLock lock(m_mutex);

@ -1054,6 +1054,120 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
image->drop();
}
}
/*
"[makealpha:R,G,B:filename.png"
Use an image with converting one color to transparent.
*/
else if(part_of_name.substr(0,11) == "[makealpha:")
{
if(baseimg != NULL)
{
dstream<<"WARNING: generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
Strfnd sf(part_of_name.substr(11));
u32 r1 = stoi(sf.next(","));
u32 g1 = stoi(sf.next(","));
u32 b1 = stoi(sf.next(":"));
std::string filename = sf.next("");
std::string path = getTexturePath(filename.c_str());
dstream<<"INFO: generate_image(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
dstream<<"WARNING: generate_image(): Loading path \""
<<path<<"\" failed"<<std::endl;
}
else
{
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
for(u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++)
{
video::SColor c = image->getPixel(x,y);
u32 r = c.getRed();
u32 g = c.getGreen();
u32 b = c.getBlue();
if(!(r == r1 && g == g1 && b == b1))
continue;
c.setAlpha(0);
image->setPixel(x,y,c);
}
// Blit
image->copyTo(baseimg);
image->drop();
}
}
/*
"[makealpha2:R,G,B;R2,G2,B2:filename.png"
Use an image with converting two colors to transparent.
*/
else if(part_of_name.substr(0,12) == "[makealpha2:")
{
if(baseimg != NULL)
{
dstream<<"WARNING: generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
Strfnd sf(part_of_name.substr(12));
u32 r1 = stoi(sf.next(","));
u32 g1 = stoi(sf.next(","));
u32 b1 = stoi(sf.next(";"));
u32 r2 = stoi(sf.next(","));
u32 g2 = stoi(sf.next(","));
u32 b2 = stoi(sf.next(":"));
std::string filename = sf.next("");
std::string path = getTexturePath(filename.c_str());
dstream<<"INFO: generate_image(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
dstream<<"WARNING: generate_image(): Loading path \""
<<path<<"\" failed"<<std::endl;
}
else
{
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
for(u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++)
{
video::SColor c = image->getPixel(x,y);
u32 r = c.getRed();
u32 g = c.getGreen();
u32 b = c.getBlue();
if(!(r == r1 && g == g1 && b == b1) &&
!(r == r2 && g == g2 && b == b2))
continue;
c.setAlpha(0);
image->setPixel(x,y,c);
}
// Blit
image->copyTo(baseimg);
image->drop();
}
}
/*
[inventorycube{topimage{leftimage{rightimage
In every subimage, replace ^ with &.

@ -810,6 +810,35 @@ inline float wrapDegrees(float f)
return f;
}
/* Wrap to 0...360 */
inline float wrapDegrees_0_360(float f)
{
// Take examples of f=10, f=720.5, f=-0.5, f=-360.5
// This results in
// 10, 720, -1, -361
int i = floor(f);
// 0, 2, 0, -1
int l = i / 360;
// Wrap to 0...360
// 0, 2, -1, -2
if(i < 0)
l -= 1;
// 0, 720, 0, -360
int k = l * 360;
// 10, 0.5, -0.5, -0.5
f -= float(k);
return f;
}
/* Wrap to -180...180 */
inline float wrapDegrees_180(float f)
{
f += 180;
f = wrapDegrees_0_360(f);
f -= 180;
return f;
}
inline std::string lowercase(const std::string &s)
{
std::string s2;