mirror of
https://github.com/minetest/minetest.git
synced 2024-12-23 14:42:24 +01:00
mobv2
This commit is contained in:
parent
080002f8ed
commit
43a28f04fa
BIN
data/dungeon_master.png
Normal file
BIN
data/dungeon_master.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
BIN
data/fireball.png
Normal file
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
|
||||
|
202
src/MyBillboardSceneNode.cpp
Normal file
202
src/MyBillboardSceneNode.cpp
Normal file
@ -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
|
||||
|
77
src/MyBillboardSceneNode.h
Normal file
77
src/MyBillboardSceneNode.h
Normal file
@ -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
|
||||
|
255
src/client.cpp
255
src/client.cpp
@ -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);
|
||||
u16 blockcount = readU16(is);
|
||||
if(blockcount != 0){
|
||||
dstream<<"WARNING: TOCLIENT_OBJECTDATA: blockcount != 0 "
|
||||
"not supported"<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/*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;
|
||||
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,
|
||||
|
10
src/client.h
10
src/client.h
@ -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,
|
||||
@ -926,14 +944,52 @@ void ServerEnvironment::step(float dtime)
|
||||
}
|
||||
}
|
||||
/*
|
||||
Make trees from saplings!
|
||||
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!
|
||||
*/
|
||||
if(n.getContent() == CONTENT_SAPLING)
|
||||
{
|
||||
if(myrand()%50 == 0)
|
||||
if(myrand()%50 == 0)
|
||||
{
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
v3s16 tree_p = p;
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
v3s16 tree_p = p;
|
||||
ManualMapVoxelManipulator vmanip(m_map);
|
||||
v3s16 tree_blockp = getNodeBlockPos(tree_p);
|
||||
vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
|
||||
@ -944,8 +1000,8 @@ void ServerEnvironment::step(float dtime)
|
||||
// update lighting
|
||||
core::map<v3s16, MapBlock*> lighting_modified_blocks;
|
||||
for(core::map<v3s16, MapBlock*>::Iterator
|
||||
i = modified_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
i = modified_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
|
||||
}
|
||||
@ -955,16 +1011,15 @@ void ServerEnvironment::step(float dtime)
|
||||
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();
|
||||
i = modified_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
event.modified_blocks.insert(p, true);
|
||||
}
|
||||
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
|
||||
|
185
src/game.cpp
185
src/game.cpp
@ -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,8 +903,16 @@ 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);
|
||||
|
||||
bool left_punch = false;
|
||||
bool left_punch_muted = false;
|
||||
|
||||
if(selected_object != NULL)
|
||||
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
|
||||
@ -1579,21 +1522,31 @@ void the_game(
|
||||
selection_box->MinEdge + pos,
|
||||
selection_box->MaxEdge + pos
|
||||
);
|
||||
|
||||
hilightboxes.push_back(box_on_map);
|
||||
|
||||
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;
|
||||
client.clickActiveObject(0,
|
||||
selected_active_object->getId(), g_selected_item);
|
||||
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)
|
||||
{
|
||||
static v3s16 nodepos_old(-32768,-32768,-32768);
|
||||
|
||||
static float dig_time = 0.0;
|
||||
static u16 dig_index = 0;
|
||||
|
||||
if(!nodefound){
|
||||
if(nodepos_old != v3s16(-32768,-32768,-32768))
|
||||
{
|
||||
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
|
1091
src/mapblockobject.h
1091
src/mapblockobject.h
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)
|
||||
|
246
src/server.cpp
246
src/server.cpp
@ -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)
|
||||
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);
|
||||
}
|
||||
derr_server<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
|
||||
return;
|
||||
}
|
||||
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)
|
||||
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();
|
||||
derr_server<<"Server: TOSERVER_SIGNTEXT not supported anymore"
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
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);
|
||||
|
114
src/tile.cpp
114
src/tile.cpp
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user