mirror of
https://github.com/minetest/minetest.git
synced 2024-09-27 06:50:29 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
6c43e29c54
|
@ -215,8 +215,8 @@ minetest.register_chatcommand("clearpassword", {
|
|||
privs = {password=true},
|
||||
func = function(name, param)
|
||||
toname = param
|
||||
if not toname then
|
||||
minetest.chat_send_player(toname, "Name field required")
|
||||
if toname == "" then
|
||||
minetest.chat_send_player(name, "Name field required")
|
||||
return
|
||||
end
|
||||
minetest.set_player_password(toname, '')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Minetest Lua Modding API Reference 0.4.0
|
||||
Minetest Lua Modding API Reference 0.4.3
|
||||
==========================================
|
||||
More information at http://c55.me/minetest/
|
||||
|
||||
|
@ -694,6 +694,11 @@ image[<X>,<Y>;<W>,<H>;<texture name>]
|
|||
^ Show an image
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
background[<X>,<Y>;<W>,<H>;<texture name>]
|
||||
^ Use a background. Inventory rectangles are not drawn then.
|
||||
^ Position and size units are inventory slots
|
||||
^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
|
||||
|
||||
field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
|
||||
^ Textual field; will be sent to server when a button is clicked
|
||||
^ x and y position the field relative to the top left of the menu
|
||||
|
@ -1098,6 +1103,10 @@ methods:
|
|||
- get_wielded_item() -> ItemStack
|
||||
- set_wielded_item(item): replaces the wielded item, returns true if successful
|
||||
- set_armor_groups({group1=rating, group2=rating, ...})
|
||||
- set_animation({x=1,y=1}, frame_speed=15, frame_blend=0)
|
||||
- set_attach(parent, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
|
||||
- set_detach()
|
||||
- set_bone_position("", {x=0,y=0,z=0}, {x=0,y=0,z=0})
|
||||
- set_properties(object property table)
|
||||
LuaEntitySAO-only: (no-op for other objects)
|
||||
- setvelocity({x=num, y=num, z=num})
|
||||
|
@ -1123,6 +1132,10 @@ Player-only: (no-op for other objects)
|
|||
^ Redefine player's inventory form
|
||||
^ Should usually be called in on_joinplayer
|
||||
- get_inventory_formspec() -> formspec string
|
||||
- get_player_control(): returns table with player pressed keys
|
||||
{jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
|
||||
- get_player_control_bits(): returns integer with bit packed player pressed keys
|
||||
bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
|
||||
|
||||
InvRef: Reference to an inventory
|
||||
methods:
|
||||
|
@ -1222,9 +1235,11 @@ Object Properties
|
|||
physical = true,
|
||||
weight = 5,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "cube"/"sprite"/"upright_sprite",
|
||||
visual = "cube"/"sprite"/"upright_sprite"/"mesh",
|
||||
visual_size = {x=1, y=1},
|
||||
mesh = "model",
|
||||
textures = {}, -- number of required textures depends on visual
|
||||
colors = {}, -- number of required colors depends on visual
|
||||
spritediv = {x=1, y=1},
|
||||
initial_sprite_basepos = {x=0, y=0},
|
||||
is_visible = true,
|
||||
|
|
|
@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "sound.h"
|
||||
#include "util/string.h"
|
||||
#include "hex.h"
|
||||
#include "IMeshCache.h"
|
||||
|
||||
static std::string getMediaCacheDir()
|
||||
{
|
||||
|
@ -860,6 +861,28 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
const char *model_ext[] = {
|
||||
".x", ".b3d", ".md2", ".obj",
|
||||
NULL
|
||||
};
|
||||
name = removeStringEnd(filename, model_ext);
|
||||
if(name != "")
|
||||
{
|
||||
verbosestream<<"Client: Storing model into Irrlicht: "
|
||||
<<"\""<<filename<<"\""<<std::endl;
|
||||
|
||||
io::IFileSystem *irrfs = m_device->getFileSystem();
|
||||
io::IReadFile *rfile = irrfs->createMemoryReadFile(
|
||||
*data_rw, data_rw.getSize(), filename.c_str());
|
||||
assert(rfile);
|
||||
|
||||
scene::ISceneManager *smgr = m_device->getSceneManager();
|
||||
scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
|
||||
smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
errorstream<<"Client: Don't know how to load file \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
return false;
|
||||
|
@ -1961,7 +1984,7 @@ void Client::sendPlayerPos()
|
|||
v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
|
||||
s32 pitch = myplayer->getPitch() * 100;
|
||||
s32 yaw = myplayer->getYaw() * 100;
|
||||
|
||||
u32 keyPressed=myplayer->keyPressed;
|
||||
/*
|
||||
Format:
|
||||
[0] u16 command
|
||||
|
@ -1969,15 +1992,15 @@ void Client::sendPlayerPos()
|
|||
[2+12] v3s32 speed*100
|
||||
[2+12+12] s32 pitch*100
|
||||
[2+12+12+4] s32 yaw*100
|
||||
[2+12+12+4+4] u32 keyPressed
|
||||
*/
|
||||
|
||||
SharedBuffer<u8> data(2+12+12+4+4);
|
||||
SharedBuffer<u8> data(2+12+12+4+4+4);
|
||||
writeU16(&data[0], TOSERVER_PLAYERPOS);
|
||||
writeV3S32(&data[2], position);
|
||||
writeV3S32(&data[2+12], speed);
|
||||
writeS32(&data[2+12+12], pitch);
|
||||
writeS32(&data[2+12+12+4], yaw);
|
||||
|
||||
writeU32(&data[2+12+12+4+4], keyPressed);
|
||||
// Send as unreliable
|
||||
Send(0, data, false);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef,
|
|||
|
||||
ClientActiveObject::~ClientActiveObject()
|
||||
{
|
||||
removeFromScene();
|
||||
removeFromScene(true);
|
||||
}
|
||||
|
||||
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
|
||||
|
|
|
@ -49,13 +49,19 @@ public:
|
|||
|
||||
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
|
||||
IrrlichtDevice *irr){}
|
||||
virtual void removeFromScene(){}
|
||||
virtual void removeFromScene(bool permanent){}
|
||||
// 0 <= light_at_pos <= LIGHT_SUN
|
||||
virtual void updateLight(u8 light_at_pos){}
|
||||
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
||||
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
|
||||
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
|
||||
virtual v3f getPosition(){return v3f(0,0,0);}
|
||||
virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;}
|
||||
virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode(){return NULL;}
|
||||
virtual scene::IBillboardSceneNode *getSpriteSceneNode(){return NULL;}
|
||||
virtual bool isPlayer(){return false;}
|
||||
virtual bool isLocalPlayer(){return false;}
|
||||
virtual void setAttachments(){}
|
||||
virtual bool doShowSelectionBox(){return true;}
|
||||
|
||||
// Step object in time
|
||||
|
|
|
@ -67,9 +67,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
TOCLIENT_DETACHED_INVENTORY
|
||||
PROTOCOL_VERSION 13:
|
||||
InventoryList field "Width" (deserialization fails with old versions)
|
||||
PROTOCOL_VERSION 14:
|
||||
Added transfer of player pressed keys to the server
|
||||
Added new messages for mesh and bone animation, as well as attachments
|
||||
GENERIC_CMD_SET_ANIMATION
|
||||
GENERIC_CMD_SET_BONE_POSITION
|
||||
GENERIC_CMD_SET_ATTACHMENT
|
||||
*/
|
||||
|
||||
#define PROTOCOL_VERSION 13
|
||||
#define PROTOCOL_VERSION 14
|
||||
|
||||
#define PROTOCOL_ID 0x4f457403
|
||||
|
||||
|
@ -366,6 +372,7 @@ enum ToServerCommand
|
|||
[2+12] v3s32 speed*100
|
||||
[2+12+12] s32 pitch*100
|
||||
[2+12+12+4] s32 yaw*100
|
||||
[2+12+12+4+4] u32 keyPressed
|
||||
*/
|
||||
|
||||
TOSERVER_GOTBLOCKS = 0x24,
|
||||
|
|
|
@ -40,7 +40,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "util/serialize.h"
|
||||
#include "util/mathconstants.h"
|
||||
#include "map.h"
|
||||
#include "main.h" // g_settings
|
||||
#include <IMeshManipulator.h>
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
#include <IBoneSceneNode.h>
|
||||
|
||||
class Settings;
|
||||
struct ToolCapabilities;
|
||||
|
@ -552,7 +555,8 @@ private:
|
|||
// Only set at initialization
|
||||
std::string m_name;
|
||||
bool m_is_player;
|
||||
bool m_is_local_player; // determined locally
|
||||
bool m_is_local_player;
|
||||
int m_id;
|
||||
// Property-ish things
|
||||
ObjectProperties m_prop;
|
||||
//
|
||||
|
@ -560,6 +564,7 @@ private:
|
|||
IrrlichtDevice *m_irr;
|
||||
core::aabbox3d<f32> m_selection_box;
|
||||
scene::IMeshSceneNode *m_meshnode;
|
||||
scene::IAnimatedMeshSceneNode *m_animated_meshnode;
|
||||
scene::IBillboardSceneNode *m_spritenode;
|
||||
scene::ITextSceneNode* m_textnode;
|
||||
v3f m_position;
|
||||
|
@ -573,6 +578,14 @@ private:
|
|||
v2s16 m_tx_basepos;
|
||||
bool m_initial_tx_basepos_set;
|
||||
bool m_tx_select_horiz_by_yawpitch;
|
||||
v2f m_animation_range;
|
||||
int m_animation_speed;
|
||||
int m_animation_blend;
|
||||
std::map<std::string, core::vector2d<v3f> > m_bone_position; // stores position and rotation for each bone name
|
||||
std::string m_attachment_bone;
|
||||
v3f m_attachment_position;
|
||||
v3f m_attachment_rotation;
|
||||
bool m_attached_to_local;
|
||||
int m_anim_frame;
|
||||
int m_anim_num_frames;
|
||||
float m_anim_framelength;
|
||||
|
@ -582,6 +595,7 @@ private:
|
|||
bool m_visuals_expired;
|
||||
float m_step_distance_counter;
|
||||
u8 m_last_light;
|
||||
bool m_is_visible;
|
||||
|
||||
public:
|
||||
GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
|
||||
|
@ -589,11 +603,13 @@ public:
|
|||
//
|
||||
m_is_player(false),
|
||||
m_is_local_player(false),
|
||||
m_id(0),
|
||||
//
|
||||
m_smgr(NULL),
|
||||
m_irr(NULL),
|
||||
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
|
||||
m_meshnode(NULL),
|
||||
m_animated_meshnode(NULL),
|
||||
m_spritenode(NULL),
|
||||
m_textnode(NULL),
|
||||
m_position(v3f(0,10*BS,0)),
|
||||
|
@ -605,6 +621,14 @@ public:
|
|||
m_tx_basepos(0,0),
|
||||
m_initial_tx_basepos_set(false),
|
||||
m_tx_select_horiz_by_yawpitch(false),
|
||||
m_animation_range(v2f(0,0)),
|
||||
m_animation_speed(15),
|
||||
m_animation_blend(0),
|
||||
m_bone_position(std::map<std::string, core::vector2d<v3f> >()),
|
||||
m_attachment_bone(""),
|
||||
m_attachment_position(v3f(0,0,0)),
|
||||
m_attachment_rotation(v3f(0,0,0)),
|
||||
m_attached_to_local(false),
|
||||
m_anim_frame(0),
|
||||
m_anim_num_frames(1),
|
||||
m_anim_framelength(0.2),
|
||||
|
@ -612,7 +636,8 @@ public:
|
|||
m_reset_textures_timer(-1),
|
||||
m_visuals_expired(false),
|
||||
m_step_distance_counter(0),
|
||||
m_last_light(255)
|
||||
m_last_light(255),
|
||||
m_is_visible(false)
|
||||
{
|
||||
if(gamedef == NULL)
|
||||
ClientActiveObject::registerType(getType(), create);
|
||||
|
@ -632,6 +657,7 @@ public:
|
|||
}
|
||||
m_name = deSerializeString(is);
|
||||
m_is_player = readU8(is);
|
||||
m_id = readS16(is);
|
||||
m_position = readV3F1000(is);
|
||||
m_yaw = readF1000(is);
|
||||
m_hp = readS16(is);
|
||||
|
@ -668,21 +694,113 @@ public:
|
|||
}
|
||||
core::aabbox3d<f32>* getSelectionBox()
|
||||
{
|
||||
if(!m_prop.is_visible || m_is_local_player)
|
||||
if(!m_prop.is_visible || !m_is_visible || m_is_local_player || getParent() != NULL)
|
||||
return NULL;
|
||||
return &m_selection_box;
|
||||
}
|
||||
v3f getPosition()
|
||||
{
|
||||
if(getParent() != NULL){
|
||||
if(m_meshnode)
|
||||
return m_meshnode->getAbsolutePosition();
|
||||
if(m_animated_meshnode)
|
||||
return m_animated_meshnode->getAbsolutePosition();
|
||||
if(m_spritenode)
|
||||
return m_spritenode->getAbsolutePosition();
|
||||
return m_position;
|
||||
}
|
||||
return pos_translator.vect_show;
|
||||
}
|
||||
|
||||
void removeFromScene()
|
||||
scene::IMeshSceneNode *getMeshSceneNode()
|
||||
{
|
||||
if(m_meshnode)
|
||||
return m_meshnode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode()
|
||||
{
|
||||
if(m_animated_meshnode)
|
||||
return m_animated_meshnode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene::IBillboardSceneNode *getSpriteSceneNode()
|
||||
{
|
||||
if(m_spritenode)
|
||||
return m_spritenode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool isPlayer()
|
||||
{
|
||||
return m_is_player;
|
||||
}
|
||||
|
||||
bool isLocalPlayer()
|
||||
{
|
||||
return m_is_local_player;
|
||||
}
|
||||
|
||||
void setAttachments()
|
||||
{
|
||||
updateAttachments();
|
||||
}
|
||||
|
||||
ClientActiveObject *getParent()
|
||||
{
|
||||
ClientActiveObject *obj = NULL;
|
||||
for(std::vector<core::vector2d<int> >::const_iterator cii = m_env->attachment_list.begin(); cii != m_env->attachment_list.end(); cii++)
|
||||
{
|
||||
if(cii->X == getId()){ // This ID is our child
|
||||
if(cii->Y > 0){ // A parent ID exists for our child
|
||||
if(cii->X != cii->Y){ // The parent and child ID are not the same
|
||||
obj = m_env->getActiveObject(cii->Y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(obj)
|
||||
return obj;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void removeFromScene(bool permanent)
|
||||
{
|
||||
if(permanent) // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
|
||||
{
|
||||
// Detach this object's children
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->Y == getId()) // Is a child of our object
|
||||
{
|
||||
ii->Y = 0;
|
||||
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
|
||||
if(obj)
|
||||
obj->setAttachments();
|
||||
}
|
||||
}
|
||||
// Delete this object from the attachments list
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->X == getId()) // Is our object
|
||||
{
|
||||
m_env->attachment_list.erase(ii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_meshnode){
|
||||
m_meshnode->remove();
|
||||
m_meshnode = NULL;
|
||||
}
|
||||
if(m_animated_meshnode){
|
||||
m_animated_meshnode->remove();
|
||||
m_animated_meshnode = NULL;
|
||||
}
|
||||
if(m_spritenode){
|
||||
m_spritenode->remove();
|
||||
m_spritenode = NULL;
|
||||
|
@ -695,7 +813,7 @@ public:
|
|||
m_smgr = smgr;
|
||||
m_irr = irr;
|
||||
|
||||
if(m_meshnode != NULL || m_spritenode != NULL)
|
||||
if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL)
|
||||
return;
|
||||
|
||||
m_visuals_expired = false;
|
||||
|
@ -791,7 +909,24 @@ public:
|
|||
m_prop.visual_size.X));
|
||||
u8 li = m_last_light;
|
||||
setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
|
||||
} else if(m_prop.visual == "wielditem"){
|
||||
}
|
||||
else if(m_prop.visual == "mesh"){
|
||||
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
|
||||
scene::IAnimatedMesh *mesh = smgr->getMesh(m_prop.mesh.c_str());
|
||||
if(mesh)
|
||||
{
|
||||
m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
|
||||
m_animated_meshnode->animateJoints(); // Needed for some animations
|
||||
m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
|
||||
m_prop.visual_size.Y,
|
||||
m_prop.visual_size.X));
|
||||
u8 li = m_last_light;
|
||||
setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
|
||||
}
|
||||
else
|
||||
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
|
||||
}
|
||||
else if(m_prop.visual == "wielditem"){
|
||||
infostream<<"GenericCAO::addToScene(): node"<<std::endl;
|
||||
infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
|
||||
if(m_prop.textures.size() >= 1){
|
||||
|
@ -823,6 +958,8 @@ public:
|
|||
scene::ISceneNode *node = NULL;
|
||||
if(m_spritenode)
|
||||
node = m_spritenode;
|
||||
else if(m_animated_meshnode)
|
||||
node = m_animated_meshnode;
|
||||
else if(m_meshnode)
|
||||
node = m_meshnode;
|
||||
if(node && m_is_player && !m_is_local_player){
|
||||
|
@ -835,6 +972,9 @@ public:
|
|||
}
|
||||
|
||||
updateNodePos();
|
||||
updateAnimation();
|
||||
updateBonePosition();
|
||||
updateAttachments();
|
||||
}
|
||||
|
||||
void expireVisuals()
|
||||
|
@ -844,19 +984,16 @@ public:
|
|||
|
||||
void updateLight(u8 light_at_pos)
|
||||
{
|
||||
bool is_visible = (m_hp != 0);
|
||||
u8 li = decode_light(light_at_pos);
|
||||
if(li != m_last_light){
|
||||
m_last_light = li;
|
||||
video::SColor color(255,li,li,li);
|
||||
if(m_meshnode){
|
||||
if(m_meshnode)
|
||||
setMeshColor(m_meshnode->getMesh(), color);
|
||||
m_meshnode->setVisible(is_visible);
|
||||
}
|
||||
if(m_spritenode){
|
||||
if(m_animated_meshnode)
|
||||
setMeshColor(m_animated_meshnode->getMesh(), color);
|
||||
if(m_spritenode)
|
||||
m_spritenode->setColor(color);
|
||||
m_spritenode->setVisible(is_visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -867,12 +1004,21 @@ public:
|
|||
|
||||
void updateNodePos()
|
||||
{
|
||||
if(getParent() != NULL)
|
||||
return;
|
||||
|
||||
if(m_meshnode){
|
||||
m_meshnode->setPosition(pos_translator.vect_show);
|
||||
v3f rot = m_meshnode->getRotation();
|
||||
rot.Y = -m_yaw;
|
||||
m_meshnode->setRotation(rot);
|
||||
}
|
||||
if(m_animated_meshnode){
|
||||
m_animated_meshnode->setPosition(pos_translator.vect_show);
|
||||
v3f rot = m_animated_meshnode->getRotation();
|
||||
rot.Y = -m_yaw;
|
||||
m_animated_meshnode->setRotation(rot);
|
||||
}
|
||||
if(m_spritenode){
|
||||
m_spritenode->setPosition(pos_translator.vect_show);
|
||||
}
|
||||
|
@ -880,13 +1026,72 @@ public:
|
|||
|
||||
void step(float dtime, ClientEnvironment *env)
|
||||
{
|
||||
v3f lastpos = pos_translator.vect_show;
|
||||
|
||||
if(m_visuals_expired && m_smgr && m_irr){
|
||||
m_visuals_expired = false;
|
||||
removeFromScene();
|
||||
addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
|
||||
|
||||
// Attachments, part 1: All attached objects must be unparented first, or Irrlicht causes a segmentation fault
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->Y == getId()) // This is a child of our parent
|
||||
{
|
||||
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
|
||||
if(obj)
|
||||
{
|
||||
scene::IMeshSceneNode *m_child_meshnode = obj->getMeshSceneNode();
|
||||
scene::IAnimatedMeshSceneNode *m_child_animated_meshnode = obj->getAnimatedMeshSceneNode();
|
||||
scene::IBillboardSceneNode *m_child_spritenode = obj->getSpriteSceneNode();
|
||||
if(m_child_meshnode)
|
||||
m_child_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
if(m_child_animated_meshnode)
|
||||
m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
if(m_child_spritenode)
|
||||
m_child_spritenode->setParent(m_smgr->getRootSceneNode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeFromScene(false);
|
||||
addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
|
||||
|
||||
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->Y == getId()) // This is a child of our parent
|
||||
{
|
||||
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
|
||||
if(obj)
|
||||
obj->setAttachments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure m_is_visible is always applied
|
||||
if(m_meshnode)
|
||||
m_meshnode->setVisible(m_is_visible);
|
||||
if(m_animated_meshnode)
|
||||
m_animated_meshnode->setVisible(m_is_visible);
|
||||
if(m_spritenode)
|
||||
m_spritenode->setVisible(m_is_visible);
|
||||
if(m_textnode)
|
||||
m_textnode->setVisible(m_is_visible);
|
||||
|
||||
if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
|
||||
{
|
||||
// Set these for later
|
||||
m_position = getPosition();
|
||||
m_velocity = v3f(0,0,0);
|
||||
m_acceleration = v3f(0,0,0);
|
||||
pos_translator.vect_show = m_position;
|
||||
|
||||
if(m_is_local_player) // Update local player attachment position
|
||||
{
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->overridePosition = getParent()->getPosition();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
v3f lastpos = pos_translator.vect_show;
|
||||
|
||||
if(m_prop.physical){
|
||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||
|
@ -932,6 +1137,7 @@ public:
|
|||
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_anim_timer += dtime;
|
||||
if(m_anim_timer >= m_anim_framelength){
|
||||
|
@ -950,7 +1156,7 @@ public:
|
|||
updateTextures("");
|
||||
}
|
||||
}
|
||||
if(fabs(m_prop.automatic_rotate) > 0.001){
|
||||
if(getParent() == NULL && fabs(m_prop.automatic_rotate) > 0.001){
|
||||
m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
|
||||
updateNodePos();
|
||||
}
|
||||
|
@ -1008,6 +1214,10 @@ public:
|
|||
{
|
||||
ITextureSource *tsrc = m_gamedef->tsrc();
|
||||
|
||||
bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
|
||||
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
|
||||
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
|
||||
|
||||
if(m_spritenode)
|
||||
{
|
||||
if(m_prop.visual == "sprite")
|
||||
|
@ -1018,6 +1228,58 @@ public:
|
|||
texturestring += mod;
|
||||
m_spritenode->setMaterialTexture(0,
|
||||
tsrc->getTextureRaw(texturestring));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() >= 1)
|
||||
{
|
||||
m_spritenode->getMaterial(0).AmbientColor = m_prop.colors[0];
|
||||
m_spritenode->getMaterial(0).DiffuseColor = m_prop.colors[0];
|
||||
m_spritenode->getMaterial(0).SpecularColor = m_prop.colors[0];
|
||||
}
|
||||
|
||||
m_spritenode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_spritenode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
m_spritenode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
}
|
||||
if(m_animated_meshnode)
|
||||
{
|
||||
if(m_prop.visual == "mesh")
|
||||
{
|
||||
for (u32 i = 0; i < m_prop.textures.size() && i < m_animated_meshnode->getMaterialCount(); ++i)
|
||||
{
|
||||
std::string texturestring = m_prop.textures[i];
|
||||
if(texturestring == "")
|
||||
continue; // Empty texture string means don't modify that material
|
||||
texturestring += mod;
|
||||
video::ITexture* texture = tsrc->getTextureRaw(texturestring);
|
||||
if(!texture)
|
||||
{
|
||||
errorstream<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set material flags and texture
|
||||
m_animated_meshnode->setMaterialTexture(i, texture);
|
||||
video::SMaterial& material = m_animated_meshnode->getMaterial(i);
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
|
||||
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
for (u32 i = 0; i < m_prop.colors.size() && i < m_animated_meshnode->getMaterialCount(); ++i)
|
||||
{
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
m_animated_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
|
||||
m_animated_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
|
||||
m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_meshnode)
|
||||
|
@ -1044,6 +1306,20 @@ public:
|
|||
material.setTexture(0, atlas);
|
||||
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
|
||||
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() > i)
|
||||
{
|
||||
m_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
|
||||
m_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
|
||||
m_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
|
||||
}
|
||||
|
||||
m_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
m_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
}
|
||||
else if(m_prop.visual == "upright_sprite")
|
||||
|
@ -1057,6 +1333,20 @@ public:
|
|||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
|
||||
buf->getMaterial().setTexture(0,
|
||||
tsrc->getTextureRaw(tname));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() >= 1)
|
||||
{
|
||||
buf->getMaterial().AmbientColor = m_prop.colors[0];
|
||||
buf->getMaterial().DiffuseColor = m_prop.colors[0];
|
||||
buf->getMaterial().SpecularColor = m_prop.colors[0];
|
||||
}
|
||||
|
||||
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
{
|
||||
std::string tname = "unknown_object.png";
|
||||
|
@ -1068,7 +1358,209 @@ public:
|
|||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
|
||||
buf->getMaterial().setTexture(0,
|
||||
tsrc->getTextureRaw(tname));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() >= 2)
|
||||
{
|
||||
buf->getMaterial().AmbientColor = m_prop.colors[1];
|
||||
buf->getMaterial().DiffuseColor = m_prop.colors[1];
|
||||
buf->getMaterial().SpecularColor = m_prop.colors[1];
|
||||
}
|
||||
else if(m_prop.colors.size() >= 1)
|
||||
{
|
||||
buf->getMaterial().AmbientColor = m_prop.colors[0];
|
||||
buf->getMaterial().DiffuseColor = m_prop.colors[0];
|
||||
buf->getMaterial().SpecularColor = m_prop.colors[0];
|
||||
}
|
||||
|
||||
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateAnimation()
|
||||
{
|
||||
if(m_animated_meshnode == NULL)
|
||||
return;
|
||||
|
||||
m_animated_meshnode->setFrameLoop((int)m_animation_range.X, (int)m_animation_range.Y);
|
||||
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
|
||||
m_animated_meshnode->setTransitionTime(m_animation_blend);
|
||||
}
|
||||
|
||||
void updateBonePosition()
|
||||
{
|
||||
if(!m_bone_position.size() || m_animated_meshnode == NULL)
|
||||
return;
|
||||
|
||||
m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
std::string bone_name = (*ii).first;
|
||||
v3f bone_pos = (*ii).second.X;
|
||||
v3f bone_rot = (*ii).second.Y;
|
||||
irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
|
||||
if(bone)
|
||||
{
|
||||
bone->setPosition(bone_pos);
|
||||
bone->setRotation(bone_rot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateAttachments()
|
||||
{
|
||||
m_attached_to_local = getParent() != NULL && getParent()->isLocalPlayer();
|
||||
m_is_visible = !m_attached_to_local; // Objects attached to the local player should always be hidden
|
||||
|
||||
if(getParent() == NULL || m_attached_to_local) // Detach or don't attach
|
||||
{
|
||||
if(m_meshnode)
|
||||
{
|
||||
v3f old_position = m_meshnode->getAbsolutePosition();
|
||||
v3f old_rotation = m_meshnode->getRotation();
|
||||
m_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
m_meshnode->setPosition(old_position);
|
||||
m_meshnode->setRotation(old_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
if(m_animated_meshnode)
|
||||
{
|
||||
v3f old_position = m_animated_meshnode->getAbsolutePosition();
|
||||
v3f old_rotation = m_animated_meshnode->getRotation();
|
||||
m_animated_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
m_animated_meshnode->setPosition(old_position);
|
||||
m_animated_meshnode->setRotation(old_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
if(m_spritenode)
|
||||
{
|
||||
v3f old_position = m_spritenode->getAbsolutePosition();
|
||||
v3f old_rotation = m_spritenode->getRotation();
|
||||
m_spritenode->setParent(m_smgr->getRootSceneNode());
|
||||
m_spritenode->setPosition(old_position);
|
||||
m_spritenode->setRotation(old_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
if(m_is_local_player)
|
||||
{
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->isAttached = false;
|
||||
}
|
||||
}
|
||||
else // Attach
|
||||
{
|
||||
scene::IMeshSceneNode *parent_mesh = NULL;
|
||||
if(getParent()->getMeshSceneNode())
|
||||
parent_mesh = getParent()->getMeshSceneNode();
|
||||
scene::IAnimatedMeshSceneNode *parent_animated_mesh = NULL;
|
||||
if(getParent()->getAnimatedMeshSceneNode())
|
||||
parent_animated_mesh = getParent()->getAnimatedMeshSceneNode();
|
||||
scene::IBillboardSceneNode *parent_sprite = NULL;
|
||||
if(getParent()->getSpriteSceneNode())
|
||||
parent_sprite = getParent()->getSpriteSceneNode();
|
||||
|
||||
scene::IBoneSceneNode *parent_bone = NULL;
|
||||
if(parent_animated_mesh && m_attachment_bone != "")
|
||||
parent_bone = parent_animated_mesh->getJointNode(m_attachment_bone.c_str());
|
||||
|
||||
// The spaghetti code below makes sure attaching works if either the parent or child is a spritenode, meshnode, or animatedmeshnode
|
||||
// TODO: Perhaps use polymorphism here to save code duplication
|
||||
if(m_meshnode){
|
||||
if(parent_bone){
|
||||
m_meshnode->setParent(parent_bone);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parent_mesh){
|
||||
m_meshnode->setParent(parent_mesh);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_animated_mesh){
|
||||
m_meshnode->setParent(parent_animated_mesh);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_sprite){
|
||||
m_meshnode->setParent(parent_sprite);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_animated_meshnode){
|
||||
if(parent_bone){
|
||||
m_animated_meshnode->setParent(parent_bone);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parent_mesh){
|
||||
m_animated_meshnode->setParent(parent_mesh);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_animated_mesh){
|
||||
m_animated_meshnode->setParent(parent_animated_mesh);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_sprite){
|
||||
m_animated_meshnode->setParent(parent_sprite);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_spritenode){
|
||||
if(parent_bone){
|
||||
m_spritenode->setParent(parent_bone);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parent_mesh){
|
||||
m_spritenode->setParent(parent_mesh);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_animated_mesh){
|
||||
m_spritenode->setParent(parent_animated_mesh);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_sprite){
|
||||
m_spritenode->setParent(parent_sprite);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_is_local_player)
|
||||
{
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->isAttached = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1099,6 +1591,8 @@ public:
|
|||
}
|
||||
else if(cmd == GENERIC_CMD_UPDATE_POSITION)
|
||||
{
|
||||
// Not sent by the server if this object is an attachment.
|
||||
// We might however get here if the server notices the object being detached before the client.
|
||||
m_position = readV3F1000(is);
|
||||
m_velocity = readV3F1000(is);
|
||||
m_acceleration = readV3F1000(is);
|
||||
|
@ -1113,6 +1607,9 @@ public:
|
|||
if(m_prop.physical)
|
||||
m_position += v3f(0,0.002,0);
|
||||
|
||||
if(getParent() != NULL) // Just in case
|
||||
return;
|
||||
|
||||
if(do_interpolate){
|
||||
if(!m_prop.physical)
|
||||
pos_translator.update(m_position, is_end_position, update_interval);
|
||||
|
@ -1140,6 +1637,41 @@ public:
|
|||
|
||||
updateTexturePos();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_SET_ANIMATION)
|
||||
{
|
||||
m_animation_range = readV2F1000(is);
|
||||
m_animation_speed = readF1000(is);
|
||||
m_animation_blend = readF1000(is);
|
||||
|
||||
updateAnimation();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_SET_BONE_POSITION)
|
||||
{
|
||||
std::string bone = deSerializeString(is);
|
||||
v3f position = readV3F1000(is);
|
||||
v3f rotation = readV3F1000(is);
|
||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
||||
|
||||
updateBonePosition();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_SET_ATTACHMENT)
|
||||
{
|
||||
// If an entry already exists for this object, delete it first to avoid duplicates
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->X == getId()) // This is the ID of our object
|
||||
{
|
||||
m_env->attachment_list.erase(ii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_env->attachment_list.push_back(core::vector2d<int>(getId(), readS16(is)));
|
||||
m_attachment_bone = deSerializeString(is);
|
||||
m_attachment_position = readV3F1000(is);
|
||||
m_attachment_rotation = readV3F1000(is);
|
||||
|
||||
updateAttachments();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_PUNCHED)
|
||||
{
|
||||
/*s16 damage =*/ readS16(is);
|
||||
|
|
|
@ -355,7 +355,10 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
|
|||
m_last_sent_velocity(0,0,0),
|
||||
m_last_sent_position_timer(0),
|
||||
m_last_sent_move_precision(0),
|
||||
m_armor_groups_sent(false)
|
||||
m_armor_groups_sent(false),
|
||||
m_animation_sent(false),
|
||||
m_bone_position_sent(false),
|
||||
m_attachment_sent(false)
|
||||
{
|
||||
// Only register type if no environment supplied
|
||||
if(env == NULL){
|
||||
|
@ -429,6 +432,17 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
|
|||
return sao;
|
||||
}
|
||||
|
||||
bool LuaEntitySAO::isAttached()
|
||||
{
|
||||
if(!m_attachment_parent_id)
|
||||
return false;
|
||||
// Check if the parent still exists
|
||||
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
|
||||
if(obj)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
if(!m_properties_sent)
|
||||
|
@ -440,8 +454,29 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
|||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
// If attached, check that our parent is still there. If it isn't, detach.
|
||||
if(m_attachment_parent_id && !isAttached())
|
||||
{
|
||||
m_attachment_parent_id = 0;
|
||||
m_attachment_bone = "";
|
||||
m_attachment_position = v3f(0,0,0);
|
||||
m_attachment_rotation = v3f(0,0,0);
|
||||
sendPosition(false, true);
|
||||
}
|
||||
|
||||
m_last_sent_position_timer += dtime;
|
||||
|
||||
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
|
||||
// If the object gets detached this comes into effect automatically from the last known origin
|
||||
if(isAttached())
|
||||
{
|
||||
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||
m_base_position = pos;
|
||||
m_velocity = v3f(0,0,0);
|
||||
m_acceleration = v3f(0,0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_prop.physical){
|
||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||
box.MinEdge *= BS;
|
||||
|
@ -465,6 +500,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
|||
* dtime * m_acceleration;
|
||||
m_velocity += dtime * m_acceleration;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_registered){
|
||||
lua_State *L = m_env->getLua();
|
||||
|
@ -474,6 +510,8 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
|||
if(send_recommended == false)
|
||||
return;
|
||||
|
||||
if(!isAttached())
|
||||
{
|
||||
// TODO: force send when acceleration changes enough?
|
||||
float minchange = 0.2*BS;
|
||||
if(m_last_sent_position_timer > 1.0){
|
||||
|
@ -488,6 +526,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
|||
fabs(m_yaw - m_last_sent_yaw) > 1.0){
|
||||
sendPosition(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_armor_groups_sent == false){
|
||||
m_armor_groups_sent = true;
|
||||
|
@ -497,6 +536,32 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
|||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_animation_sent == false){
|
||||
m_animation_sent = true;
|
||||
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_bone_position_sent == false){
|
||||
m_bone_position_sent = true;
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_attachment_sent == false){
|
||||
m_attachment_sent = true;
|
||||
std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LuaEntitySAO::getClientInitializationData()
|
||||
|
@ -504,13 +569,21 @@ std::string LuaEntitySAO::getClientInitializationData()
|
|||
std::ostringstream os(std::ios::binary);
|
||||
writeU8(os, 0); // version
|
||||
os<<serializeString(""); // name
|
||||
writeS16(os, getId()); //id
|
||||
writeU8(os, 0); // is_player
|
||||
writeV3F1000(os, m_base_position);
|
||||
writeF1000(os, m_yaw);
|
||||
writeS16(os, m_hp);
|
||||
writeU8(os, 2); // number of messages stuffed in here
|
||||
|
||||
writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
|
||||
}
|
||||
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
|
||||
|
||||
// return result
|
||||
return os.str();
|
||||
}
|
||||
|
@ -551,6 +624,10 @@ int LuaEntitySAO::punch(v3f dir,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// It's best that attachments cannot be punched
|
||||
if(isAttached())
|
||||
return 0;
|
||||
|
||||
ItemStack *punchitem = NULL;
|
||||
ItemStack punchitem_static;
|
||||
if(puncher){
|
||||
|
@ -594,18 +671,25 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
|
|||
{
|
||||
if(!m_registered)
|
||||
return;
|
||||
// It's best that attachments cannot be clicked
|
||||
if(isAttached())
|
||||
return;
|
||||
lua_State *L = m_env->getLua();
|
||||
scriptapi_luaentity_rightclick(L, m_id, clicker);
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setPos(v3f pos)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_base_position = pos;
|
||||
sendPosition(false, true);
|
||||
}
|
||||
|
||||
void LuaEntitySAO::moveTo(v3f pos, bool continuous)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_base_position = pos;
|
||||
if(!continuous)
|
||||
sendPosition(true, true);
|
||||
|
@ -644,6 +728,37 @@ void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
|
|||
m_armor_groups_sent = false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
|
||||
{
|
||||
m_animation_range = frame_range;
|
||||
m_animation_speed = frame_speed;
|
||||
m_animation_blend = frame_blend;
|
||||
m_animation_sent = false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setBonePosition(std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
||||
m_bone_position_sent = false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
// Attachments need to be handled on both the server and client.
|
||||
// If we just attach on the server, we can only copy the position of the parent. Attachments
|
||||
// are still sent to clients at an interval so players might see them lagging, plus we can't
|
||||
// read and attach to skeletal bones.
|
||||
// If we just attach on the client, the server still sees the child at its original location.
|
||||
// This breaks some things so we also give the server the most accurate representation
|
||||
// even if players only see the client changes.
|
||||
|
||||
m_attachment_parent_id = parent_id;
|
||||
m_attachment_bone = bone;
|
||||
m_attachment_position = position;
|
||||
m_attachment_rotation = rotation;
|
||||
m_attachment_sent = false;
|
||||
}
|
||||
|
||||
ObjectProperties* LuaEntitySAO::accessObjectProperties()
|
||||
{
|
||||
return &m_prop;
|
||||
|
@ -718,6 +833,10 @@ std::string LuaEntitySAO::getPropertyPacket()
|
|||
|
||||
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
|
||||
{
|
||||
// If the object is attached client-side, don't waste bandwidth sending its position to clients
|
||||
if(isAttached())
|
||||
return;
|
||||
|
||||
m_last_sent_move_precision = m_base_position.getDistanceFrom(
|
||||
m_last_sent_position);
|
||||
m_last_sent_position_timer = 0;
|
||||
|
@ -765,8 +884,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
|
|||
m_properties_sent(true),
|
||||
m_privs(privs),
|
||||
m_is_singleplayer(is_singleplayer),
|
||||
m_animation_sent(false),
|
||||
m_bone_position_sent(false),
|
||||
m_attachment_sent(false),
|
||||
// public
|
||||
m_teleported(false),
|
||||
m_moved(false),
|
||||
m_inventory_not_sent(false),
|
||||
m_hp_not_sent(false),
|
||||
m_wielded_item_not_sent(false)
|
||||
|
@ -782,13 +904,17 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
|
|||
m_prop.physical = false;
|
||||
m_prop.weight = 75;
|
||||
m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
|
||||
// start of default appearance, this should be overwritten by LUA
|
||||
m_prop.visual = "upright_sprite";
|
||||
m_prop.visual_size = v2f(1, 2);
|
||||
m_prop.textures.clear();
|
||||
m_prop.textures.push_back("player.png");
|
||||
m_prop.textures.push_back("player_back.png");
|
||||
m_prop.colors.clear();
|
||||
m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
|
||||
m_prop.spritediv = v2s16(1,1);
|
||||
m_prop.is_visible = (getHP() != 0);
|
||||
// end of default appearance
|
||||
m_prop.is_visible = true;
|
||||
m_prop.makes_footstep_sound = true;
|
||||
}
|
||||
|
||||
|
@ -842,12 +968,21 @@ std::string PlayerSAO::getClientInitializationData()
|
|||
writeU8(os, 0); // version
|
||||
os<<serializeString(m_player->getName()); // name
|
||||
writeU8(os, 1); // is_player
|
||||
writeS16(os, getId()); //id
|
||||
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
|
||||
writeF1000(os, m_player->getYaw());
|
||||
writeS16(os, getHP());
|
||||
writeU8(os, 2); // number of messages stuffed in here
|
||||
|
||||
writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
|
||||
}
|
||||
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
|
||||
|
||||
// return result
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
@ -857,6 +992,17 @@ std::string PlayerSAO::getStaticData()
|
|||
return "";
|
||||
}
|
||||
|
||||
bool PlayerSAO::isAttached()
|
||||
{
|
||||
if(!m_attachment_parent_id)
|
||||
return false;
|
||||
// Check if the parent still exists
|
||||
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
|
||||
if(obj)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PlayerSAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
if(!m_properties_sent)
|
||||
|
@ -868,9 +1014,31 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
|||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
// If attached, check that our parent is still there. If it isn't, detach.
|
||||
if(m_attachment_parent_id && !isAttached())
|
||||
{
|
||||
m_attachment_parent_id = 0;
|
||||
m_attachment_bone = "";
|
||||
m_attachment_position = v3f(0,0,0);
|
||||
m_attachment_rotation = v3f(0,0,0);
|
||||
m_player->setPosition(m_last_good_position);
|
||||
m_moved = true;
|
||||
}
|
||||
|
||||
m_time_from_last_punch += dtime;
|
||||
m_nocheat_dig_time += dtime;
|
||||
|
||||
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
|
||||
// If the object gets detached this comes into effect automatically from the last known origin
|
||||
if(isAttached())
|
||||
{
|
||||
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||
m_last_good_position = pos;
|
||||
m_last_good_position_age = 0;
|
||||
m_player->setPosition(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
|
||||
{
|
||||
m_last_good_position = m_player->getPosition();
|
||||
|
@ -920,21 +1088,28 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
|||
<<" moved too fast; resetting position"
|
||||
<<std::endl;
|
||||
m_player->setPosition(m_last_good_position);
|
||||
m_teleported = true;
|
||||
m_moved = true;
|
||||
}
|
||||
m_last_good_position_age = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(send_recommended == false)
|
||||
return;
|
||||
|
||||
if(m_position_not_sent)
|
||||
// If the object is attached client-side, don't waste bandwidth sending its position to clients
|
||||
if(m_position_not_sent && !isAttached())
|
||||
{
|
||||
m_position_not_sent = false;
|
||||
float update_interval = m_env->getSendRecommendedInterval();
|
||||
v3f pos;
|
||||
if(isAttached()) // Just in case we ever do send attachment position too
|
||||
pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||
else
|
||||
pos = m_player->getPosition() + v3f(0,BS*1,0);
|
||||
std::string str = gob_cmd_update_position(
|
||||
m_player->getPosition() + v3f(0,BS*1,0),
|
||||
pos,
|
||||
v3f(0,0,0),
|
||||
v3f(0,0,0),
|
||||
m_player->getYaw(),
|
||||
|
@ -961,32 +1136,63 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
|||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_animation_sent == false){
|
||||
m_animation_sent = true;
|
||||
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_bone_position_sent == false){
|
||||
m_bone_position_sent = true;
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_attachment_sent == false){
|
||||
m_attachment_sent = true;
|
||||
std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerSAO::setBasePosition(const v3f &position)
|
||||
{
|
||||
// This needs to be ran for attachments too
|
||||
ServerActiveObject::setBasePosition(position);
|
||||
m_position_not_sent = true;
|
||||
}
|
||||
|
||||
void PlayerSAO::setPos(v3f pos)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_player->setPosition(pos);
|
||||
// Movement caused by this command is always valid
|
||||
m_last_good_position = pos;
|
||||
m_last_good_position_age = 0;
|
||||
// Force position change on client
|
||||
m_teleported = true;
|
||||
m_moved = true;
|
||||
}
|
||||
|
||||
void PlayerSAO::moveTo(v3f pos, bool continuous)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_player->setPosition(pos);
|
||||
// Movement caused by this command is always valid
|
||||
m_last_good_position = pos;
|
||||
m_last_good_position_age = 0;
|
||||
// Force position change on client
|
||||
m_teleported = true;
|
||||
m_moved = true;
|
||||
}
|
||||
|
||||
int PlayerSAO::punch(v3f dir,
|
||||
|
@ -994,6 +1200,10 @@ int PlayerSAO::punch(v3f dir,
|
|||
ServerActiveObject *puncher,
|
||||
float time_from_last_punch)
|
||||
{
|
||||
// It's best that attachments cannot be punched
|
||||
if(isAttached())
|
||||
return 0;
|
||||
|
||||
if(!toolcap)
|
||||
return 0;
|
||||
|
||||
|
@ -1075,6 +1285,39 @@ void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
|
|||
m_armor_groups_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
|
||||
{
|
||||
// store these so they can be updated to clients
|
||||
m_animation_range = frame_range;
|
||||
m_animation_speed = frame_speed;
|
||||
m_animation_blend = frame_blend;
|
||||
m_animation_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
// store these so they can be updated to clients
|
||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
||||
m_bone_position_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
// Attachments need to be handled on both the server and client.
|
||||
// If we just attach on the server, we can only copy the position of the parent. Attachments
|
||||
// are still sent to clients at an interval so players might see them lagging, plus we can't
|
||||
// read and attach to skeletal bones.
|
||||
// If we just attach on the client, the server still sees the child at its original location.
|
||||
// This breaks some things so we also give the server the most accurate representation
|
||||
// even if players only see the client changes.
|
||||
|
||||
m_attachment_parent_id = parent_id;
|
||||
m_attachment_bone = bone;
|
||||
m_attachment_position = position;
|
||||
m_attachment_rotation = rotation;
|
||||
m_attachment_sent = false;
|
||||
}
|
||||
|
||||
ObjectProperties* PlayerSAO::accessObjectProperties()
|
||||
{
|
||||
return &m_prop;
|
||||
|
@ -1138,7 +1381,7 @@ void PlayerSAO::disconnected()
|
|||
|
||||
std::string PlayerSAO::getPropertyPacket()
|
||||
{
|
||||
m_prop.is_visible = (getHP() != 0);
|
||||
m_prop.is_visible = (true);
|
||||
return gob_cmd_set_properties(m_prop);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
virtual void addedToEnvironment(u32 dtime_s);
|
||||
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
|
||||
const std::string &data);
|
||||
bool isAttached();
|
||||
void step(float dtime, bool send_recommended);
|
||||
std::string getClientInitializationData();
|
||||
std::string getStaticData();
|
||||
|
@ -61,6 +62,9 @@ public:
|
|||
void setHP(s16 hp);
|
||||
s16 getHP() const;
|
||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
||||
void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
|
||||
void setBonePosition(std::string bone, v3f position, v3f rotation);
|
||||
void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
|
||||
ObjectProperties* accessObjectProperties();
|
||||
void notifyObjectPropertiesModified();
|
||||
/* LuaEntitySAO-specific */
|
||||
|
@ -96,6 +100,20 @@ private:
|
|||
float m_last_sent_position_timer;
|
||||
float m_last_sent_move_precision;
|
||||
bool m_armor_groups_sent;
|
||||
|
||||
v2f m_animation_range;
|
||||
float m_animation_speed;
|
||||
float m_animation_blend;
|
||||
bool m_animation_sent;
|
||||
|
||||
std::map<std::string, core::vector2d<v3f> > m_bone_position;
|
||||
bool m_bone_position_sent;
|
||||
|
||||
int m_attachment_parent_id;
|
||||
std::string m_attachment_bone;
|
||||
v3f m_attachment_position;
|
||||
v3f m_attachment_rotation;
|
||||
bool m_attachment_sent;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -124,6 +142,7 @@ public:
|
|||
bool unlimitedTransferDistance() const;
|
||||
std::string getClientInitializationData();
|
||||
std::string getStaticData();
|
||||
bool isAttached();
|
||||
void step(float dtime, bool send_recommended);
|
||||
void setBasePosition(const v3f &position);
|
||||
void setPos(v3f pos);
|
||||
|
@ -142,6 +161,9 @@ public:
|
|||
void setHP(s16 hp);
|
||||
|
||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
||||
void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
|
||||
void setBonePosition(std::string bone, v3f position, v3f rotation);
|
||||
void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
|
||||
ObjectProperties* accessObjectProperties();
|
||||
void notifyObjectPropertiesModified();
|
||||
|
||||
|
@ -229,15 +251,32 @@ private:
|
|||
bool m_position_not_sent;
|
||||
ItemGroupList m_armor_groups;
|
||||
bool m_armor_groups_sent;
|
||||
|
||||
|
||||
|
||||
bool m_properties_sent;
|
||||
struct ObjectProperties m_prop;
|
||||
// Cached privileges for enforcement
|
||||
std::set<std::string> m_privs;
|
||||
bool m_is_singleplayer;
|
||||
|
||||
v2f m_animation_range;
|
||||
float m_animation_speed;
|
||||
float m_animation_blend;
|
||||
bool m_animation_sent;
|
||||
|
||||
std::map<std::string, core::vector2d<v3f> > m_bone_position; // Stores position and rotation for each bone name
|
||||
bool m_bone_position_sent;
|
||||
|
||||
int m_attachment_parent_id;
|
||||
std::string m_attachment_bone;
|
||||
v3f m_attachment_position;
|
||||
v3f m_attachment_rotation;
|
||||
bool m_attachment_sent;
|
||||
|
||||
public:
|
||||
// Some flags used by Server
|
||||
bool m_teleported;
|
||||
bool m_moved;
|
||||
bool m_inventory_not_sent;
|
||||
bool m_hp_not_sent;
|
||||
bool m_wielded_item_not_sent;
|
||||
|
|
|
@ -2315,7 +2315,7 @@ void ClientEnvironment::removeActiveObject(u16 id)
|
|||
<<"id="<<id<<" not found"<<std::endl;
|
||||
return;
|
||||
}
|
||||
obj->removeFromScene();
|
||||
obj->removeFromScene(true);
|
||||
delete obj;
|
||||
m_active_objects.remove(id);
|
||||
}
|
||||
|
|
|
@ -464,6 +464,8 @@ public:
|
|||
// Get event from queue. CEE_NONE is returned if queue is empty.
|
||||
ClientEnvEvent getClientEvent();
|
||||
|
||||
std::vector<core::vector2d<int> > attachment_list; // X is child ID, Y is parent ID
|
||||
|
||||
private:
|
||||
ClientMap *m_map;
|
||||
scene::ISceneManager *m_smgr;
|
||||
|
|
16
src/game.cpp
16
src/game.cpp
|
@ -1881,6 +1881,8 @@ void the_game(
|
|||
bool a_jump,
|
||||
bool a_superspeed,
|
||||
bool a_sneak,
|
||||
bool a_LMB,
|
||||
bool a_RMB,
|
||||
float a_pitch,
|
||||
float a_yaw*/
|
||||
PlayerControl control(
|
||||
|
@ -1891,10 +1893,24 @@ void the_game(
|
|||
input->isKeyDown(getKeySetting("keymap_jump")),
|
||||
input->isKeyDown(getKeySetting("keymap_special1")),
|
||||
input->isKeyDown(getKeySetting("keymap_sneak")),
|
||||
input->getLeftState(),
|
||||
input->getRightState(),
|
||||
camera_pitch,
|
||||
camera_yaw
|
||||
);
|
||||
client.setPlayerControl(control);
|
||||
u32 keyPressed=
|
||||
1*(int)input->isKeyDown(getKeySetting("keymap_forward"))+
|
||||
2*(int)input->isKeyDown(getKeySetting("keymap_backward"))+
|
||||
4*(int)input->isKeyDown(getKeySetting("keymap_left"))+
|
||||
8*(int)input->isKeyDown(getKeySetting("keymap_right"))+
|
||||
16*(int)input->isKeyDown(getKeySetting("keymap_jump"))+
|
||||
32*(int)input->isKeyDown(getKeySetting("keymap_special1"))+
|
||||
64*(int)input->isKeyDown(getKeySetting("keymap_sneak"))+
|
||||
128*(int)input->getLeftState()+
|
||||
256*(int)input->getRightState();
|
||||
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
||||
player->keyPressed=keyPressed;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -92,6 +92,43 @@ std::string gob_cmd_set_sprite(
|
|||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command
|
||||
writeU8(os, GENERIC_CMD_SET_ANIMATION);
|
||||
// parameters
|
||||
writeV2F1000(os, frames);
|
||||
writeF1000(os, frame_speed);
|
||||
writeF1000(os, frame_blend);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command
|
||||
writeU8(os, GENERIC_CMD_SET_BONE_POSITION);
|
||||
// parameters
|
||||
os<<serializeString(bone);
|
||||
writeV3F1000(os, position);
|
||||
writeV3F1000(os, rotation);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command
|
||||
writeU8(os, GENERIC_CMD_SET_ATTACHMENT);
|
||||
// parameters
|
||||
writeS16(os, parent_id);
|
||||
os<<serializeString(bone);
|
||||
writeV3F1000(os, position);
|
||||
writeV3F1000(os, rotation);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_punched(s16 damage, s16 result_hp)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
|
|
|
@ -28,8 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define GENERIC_CMD_UPDATE_POSITION 1
|
||||
#define GENERIC_CMD_SET_TEXTURE_MOD 2
|
||||
#define GENERIC_CMD_SET_SPRITE 3
|
||||
#define GENERIC_CMD_PUNCHED 4
|
||||
#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 5
|
||||
#define GENERIC_CMD_SET_ANIMATION 4
|
||||
#define GENERIC_CMD_SET_BONE_POSITION 5
|
||||
#define GENERIC_CMD_SET_ATTACHMENT 6
|
||||
#define GENERIC_CMD_PUNCHED 7
|
||||
#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 8
|
||||
|
||||
#include "object_properties.h"
|
||||
std::string gob_cmd_set_properties(const ObjectProperties &prop);
|
||||
|
@ -54,6 +57,12 @@ std::string gob_cmd_set_sprite(
|
|||
bool select_horiz_by_yawpitch
|
||||
);
|
||||
|
||||
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend);
|
||||
|
||||
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation);
|
||||
|
||||
std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation);
|
||||
|
||||
std::string gob_cmd_punched(s16 damage, s16 result_hp);
|
||||
|
||||
#include "itemgroup.h"
|
||||
|
|
|
@ -199,6 +199,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||
|
||||
m_inventorylists.clear();
|
||||
m_images.clear();
|
||||
m_backgrounds.clear();
|
||||
m_fields.clear();
|
||||
|
||||
Strfnd f(m_formspec_string);
|
||||
|
@ -278,9 +279,26 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||
<<std::endl;
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
|
||||
errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
|
||||
m_images.push_back(ImageDrawSpec(name, pos, geom));
|
||||
}
|
||||
else if(type == "background")
|
||||
{
|
||||
v2s32 pos = basepos;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
|
||||
v2s32 geom;
|
||||
geom.X = stof(f.next(",")) * (float)spacing.X;
|
||||
geom.Y = stof(f.next(";")) * (float)spacing.Y;
|
||||
std::string name = f.next("]");
|
||||
infostream<<"image name="<<name
|
||||
<<", pos=("<<pos.X<<","<<pos.Y<<")"
|
||||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||
<<std::endl;
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
|
||||
m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
|
||||
}
|
||||
else if(type == "field")
|
||||
{
|
||||
std::string fname = f.next(";");
|
||||
|
@ -458,6 +476,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||
|
||||
video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
|
||||
gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
|
||||
e->setUseAlphaChannel(true);
|
||||
e->setImage(texture);
|
||||
e->setPressedImage(texture);
|
||||
e->setScaleImage(true);
|
||||
|
@ -691,6 +710,26 @@ void GUIFormSpecMenu::drawMenu()
|
|||
|
||||
m_tooltip_element->setVisible(false);
|
||||
|
||||
/*
|
||||
Draw backgrounds
|
||||
*/
|
||||
for(u32 i=0; i<m_backgrounds.size(); i++)
|
||||
{
|
||||
const ImageDrawSpec &spec = m_backgrounds[i];
|
||||
video::ITexture *texture =
|
||||
m_gamedef->tsrc()->getTextureRaw(spec.name);
|
||||
// Image size on screen
|
||||
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
|
||||
// Image rectangle on screen
|
||||
core::rect<s32> rect = imgrect + spec.pos;
|
||||
const video::SColor color(255,255,255,255);
|
||||
const video::SColor colors[] = {color,color,color,color};
|
||||
driver->draw2DImage(texture, rect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getOriginalSize())),
|
||||
NULL/*&AbsoluteClippingRect*/, colors, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Draw images
|
||||
*/
|
||||
|
@ -715,8 +754,11 @@ void GUIFormSpecMenu::drawMenu()
|
|||
Draw items
|
||||
Phase 0: Item slot rectangles
|
||||
Phase 1: Item images; prepare tooltip
|
||||
If backgrounds used, do not draw Item slot rectangles
|
||||
*/
|
||||
for(int phase=0; phase<=1; phase++)
|
||||
int start_phase=0;
|
||||
if (m_backgrounds.size() > 0) start_phase=1;
|
||||
for(int phase=start_phase; phase<=1; phase++)
|
||||
for(u32 i=0; i<m_inventorylists.size(); i++)
|
||||
{
|
||||
drawList(m_inventorylists[i], phase);
|
||||
|
|
|
@ -206,6 +206,7 @@ protected:
|
|||
TextDest *m_text_dst;
|
||||
|
||||
core::array<ListDrawSpec> m_inventorylists;
|
||||
core::array<ImageDrawSpec> m_backgrounds;
|
||||
core::array<ImageDrawSpec> m_images;
|
||||
core::array<FieldSpec> m_fields;
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
LocalPlayer::LocalPlayer(IGameDef *gamedef):
|
||||
Player(gamedef),
|
||||
isAttached(false),
|
||||
overridePosition(v3f(0,0,0)),
|
||||
m_sneak_node(32767,32767,32767),
|
||||
m_sneak_node_exists(false),
|
||||
m_old_node_below(32767,32767,32767),
|
||||
|
@ -59,6 +61,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
|||
|
||||
v3f old_speed = m_speed;
|
||||
|
||||
// Copy parent position if local player is attached
|
||||
if(isAttached)
|
||||
{
|
||||
setPosition(overridePosition);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip collision detection if a special movement mode is used
|
||||
bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
|
||||
bool free_move = fly_allowed && g_settings->getBool("free_move");
|
||||
|
@ -353,6 +362,13 @@ void LocalPlayer::applyControl(float dtime)
|
|||
setPitch(control.pitch);
|
||||
setYaw(control.yaw);
|
||||
|
||||
// Nullify speed and don't run positioning code if the player is attached
|
||||
if(isAttached)
|
||||
{
|
||||
setSpeed(v3f(0,0,0));
|
||||
return;
|
||||
}
|
||||
|
||||
v3f move_direction = v3f(0,0,1);
|
||||
move_direction.rotateXZBy(getYaw());
|
||||
|
||||
|
|
|
@ -22,53 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#include "player.h"
|
||||
|
||||
struct PlayerControl
|
||||
{
|
||||
PlayerControl()
|
||||
{
|
||||
up = false;
|
||||
down = false;
|
||||
left = false;
|
||||
right = false;
|
||||
jump = false;
|
||||
aux1 = false;
|
||||
sneak = false;
|
||||
pitch = 0;
|
||||
yaw = 0;
|
||||
}
|
||||
PlayerControl(
|
||||
bool a_up,
|
||||
bool a_down,
|
||||
bool a_left,
|
||||
bool a_right,
|
||||
bool a_jump,
|
||||
bool a_aux1,
|
||||
bool a_sneak,
|
||||
float a_pitch,
|
||||
float a_yaw
|
||||
)
|
||||
{
|
||||
up = a_up;
|
||||
down = a_down;
|
||||
left = a_left;
|
||||
right = a_right;
|
||||
jump = a_jump;
|
||||
aux1 = a_aux1;
|
||||
sneak = a_sneak;
|
||||
pitch = a_pitch;
|
||||
yaw = a_yaw;
|
||||
}
|
||||
bool up;
|
||||
bool down;
|
||||
bool left;
|
||||
bool right;
|
||||
bool jump;
|
||||
bool aux1;
|
||||
bool sneak;
|
||||
float pitch;
|
||||
float yaw;
|
||||
};
|
||||
|
||||
class LocalPlayer : public Player
|
||||
{
|
||||
public:
|
||||
|
@ -80,6 +33,10 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool isAttached;
|
||||
|
||||
v3f overridePosition;
|
||||
|
||||
void move(f32 dtime, Map &map, f32 pos_max_d,
|
||||
core::list<CollisionInfo> *collision_info);
|
||||
void move(f32 dtime, Map &map, f32 pos_max_d);
|
||||
|
@ -87,9 +44,6 @@ public:
|
|||
void applyControl(float dtime);
|
||||
|
||||
v3s16 getStandingNodePos();
|
||||
|
||||
PlayerControl control;
|
||||
|
||||
private:
|
||||
// This is used for determining the sneaking range
|
||||
v3s16 m_sneak_node;
|
||||
|
|
|
@ -132,6 +132,7 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
|
|||
for(s16 ii=0; ii<trunk_h; ii++)
|
||||
{
|
||||
if(vmanip.m_area.contains(p1))
|
||||
if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
|
||||
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
|
||||
p1.Y++;
|
||||
}
|
||||
|
|
|
@ -433,9 +433,6 @@ video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
|
|||
}
|
||||
|
||||
// Create render target texture
|
||||
video::ITexture *oldtexture = driver->findTexture(texture_name.c_str());
|
||||
if(oldtexture)
|
||||
driver->removeTexture(oldtexture);
|
||||
video::ITexture *rtt = driver->addRenderTargetTexture(
|
||||
dim, texture_name.c_str(), video::ECF_A8R8G8B8);
|
||||
if(rtt == NULL)
|
||||
|
|
|
@ -217,7 +217,7 @@ void ContentFeatures::reset()
|
|||
|
||||
void ContentFeatures::serialize(std::ostream &os)
|
||||
{
|
||||
writeU8(os, 5); // version
|
||||
writeU8(os, 6); // version
|
||||
os<<serializeString(name);
|
||||
writeU16(os, groups.size());
|
||||
for(ItemGroupList::const_iterator
|
||||
|
@ -254,6 +254,7 @@ void ContentFeatures::serialize(std::ostream &os)
|
|||
os<<serializeString(liquid_alternative_flowing);
|
||||
os<<serializeString(liquid_alternative_source);
|
||||
writeU8(os, liquid_viscosity);
|
||||
writeU8(os, liquid_renewable);
|
||||
writeU8(os, light_source);
|
||||
writeU32(os, damage_per_second);
|
||||
node_box.serialize(os);
|
||||
|
@ -265,13 +266,12 @@ void ContentFeatures::serialize(std::ostream &os)
|
|||
serializeSimpleSoundSpec(sound_dug, os);
|
||||
// Stuff below should be moved to correct place in a version that otherwise changes
|
||||
// the protocol version
|
||||
writeU8(os, liquid_renewable);
|
||||
}
|
||||
|
||||
void ContentFeatures::deSerialize(std::istream &is)
|
||||
{
|
||||
int version = readU8(is);
|
||||
if(version != 5)
|
||||
if(version != 6)
|
||||
throw SerializationError("unsupported ContentFeatures version");
|
||||
name = deSerializeString(is);
|
||||
groups.clear();
|
||||
|
@ -311,6 +311,7 @@ void ContentFeatures::deSerialize(std::istream &is)
|
|||
liquid_alternative_flowing = deSerializeString(is);
|
||||
liquid_alternative_source = deSerializeString(is);
|
||||
liquid_viscosity = readU8(is);
|
||||
liquid_renewable = readU8(is);
|
||||
light_source = readU8(is);
|
||||
damage_per_second = readU32(is);
|
||||
node_box.deSerialize(is);
|
||||
|
@ -325,7 +326,6 @@ void ContentFeatures::deSerialize(std::istream &is)
|
|||
try{
|
||||
// Stuff below should be moved to correct place in a version that
|
||||
// otherwise changes the protocol version
|
||||
liquid_renewable = readU8(is);
|
||||
}catch(SerializationError &e) {};
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
*/
|
||||
|
||||
#include "object_properties.h"
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "util/serialize.h"
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
|
||||
|
@ -30,6 +32,7 @@ ObjectProperties::ObjectProperties():
|
|||
weight(5),
|
||||
collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
|
||||
visual("sprite"),
|
||||
mesh(""),
|
||||
visual_size(1,1),
|
||||
spritediv(1,1),
|
||||
initial_sprite_basepos(0,0),
|
||||
|
@ -38,6 +41,7 @@ ObjectProperties::ObjectProperties():
|
|||
automatic_rotate(0)
|
||||
{
|
||||
textures.push_back("unknown_object.png");
|
||||
colors.push_back(video::SColor(255,255,255,255));
|
||||
}
|
||||
|
||||
std::string ObjectProperties::dump()
|
||||
|
@ -48,12 +52,18 @@ std::string ObjectProperties::dump()
|
|||
os<<", weight="<<weight;
|
||||
os<<", collisionbox="<<PP(collisionbox.MinEdge)<<","<<PP(collisionbox.MaxEdge);
|
||||
os<<", visual="<<visual;
|
||||
os<<", mesh="<<mesh;
|
||||
os<<", visual_size="<<PP2(visual_size);
|
||||
os<<", textures=[";
|
||||
for(u32 i=0; i<textures.size(); i++){
|
||||
os<<"\""<<textures[i]<<"\" ";
|
||||
}
|
||||
os<<"]";
|
||||
os<<", colors=[";
|
||||
for(u32 i=0; i<colors.size(); i++){
|
||||
os<<"\""<<colors[i].getAlpha()<<","<<colors[i].getRed()<<","<<colors[i].getGreen()<<","<<colors[i].getBlue()<<"\" ";
|
||||
}
|
||||
os<<"]";
|
||||
os<<", spritediv="<<PP2(spritediv);
|
||||
os<<", initial_sprite_basepos="<<PP2(initial_sprite_basepos);
|
||||
os<<", is_visible="<<is_visible;
|
||||
|
@ -71,11 +81,16 @@ void ObjectProperties::serialize(std::ostream &os) const
|
|||
writeV3F1000(os, collisionbox.MinEdge);
|
||||
writeV3F1000(os, collisionbox.MaxEdge);
|
||||
os<<serializeString(visual);
|
||||
os<<serializeString(mesh);
|
||||
writeV2F1000(os, visual_size);
|
||||
writeU16(os, textures.size());
|
||||
for(u32 i=0; i<textures.size(); i++){
|
||||
os<<serializeString(textures[i]);
|
||||
}
|
||||
writeU16(os, colors.size());
|
||||
for(u32 i=0; i<colors.size(); i++){
|
||||
writeARGB8(os, colors[i]);
|
||||
}
|
||||
writeV2S16(os, spritediv);
|
||||
writeV2S16(os, initial_sprite_basepos);
|
||||
writeU8(os, is_visible);
|
||||
|
@ -94,12 +109,17 @@ void ObjectProperties::deSerialize(std::istream &is)
|
|||
collisionbox.MinEdge = readV3F1000(is);
|
||||
collisionbox.MaxEdge = readV3F1000(is);
|
||||
visual = deSerializeString(is);
|
||||
mesh = deSerializeString(is);
|
||||
visual_size = readV2F1000(is);
|
||||
textures.clear();
|
||||
u32 texture_count = readU16(is);
|
||||
for(u32 i=0; i<texture_count; i++){
|
||||
textures.push_back(deSerializeString(is));
|
||||
}
|
||||
u32 color_count = readU16(is);
|
||||
for(u32 i=0; i<color_count; i++){
|
||||
colors.push_back(readARGB8(is));
|
||||
}
|
||||
spritediv = readV2S16(is);
|
||||
initial_sprite_basepos = readV2S16(is);
|
||||
is_visible = readU8(is);
|
||||
|
|
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <string>
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
struct ObjectProperties
|
||||
{
|
||||
|
@ -32,14 +33,17 @@ struct ObjectProperties
|
|||
float weight;
|
||||
core::aabbox3d<f32> collisionbox;
|
||||
std::string visual;
|
||||
std::string mesh;
|
||||
v2f visual_size;
|
||||
core::array<std::string> textures;
|
||||
core::array<video::SColor> colors;
|
||||
v2s16 spritediv;
|
||||
v2s16 initial_sprite_basepos;
|
||||
bool is_visible;
|
||||
bool makes_footstep_sound;
|
||||
float automatic_rotate;
|
||||
|
||||
|
||||
ObjectProperties();
|
||||
std::string dump();
|
||||
void serialize(std::ostream &os) const;
|
||||
|
|
63
src/player.h
63
src/player.h
|
@ -28,6 +28,61 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
||||
|
||||
struct PlayerControl
|
||||
{
|
||||
PlayerControl()
|
||||
{
|
||||
up = false;
|
||||
down = false;
|
||||
left = false;
|
||||
right = false;
|
||||
jump = false;
|
||||
aux1 = false;
|
||||
sneak = false;
|
||||
LMB = false;
|
||||
RMB = false;
|
||||
pitch = 0;
|
||||
yaw = 0;
|
||||
}
|
||||
PlayerControl(
|
||||
bool a_up,
|
||||
bool a_down,
|
||||
bool a_left,
|
||||
bool a_right,
|
||||
bool a_jump,
|
||||
bool a_aux1,
|
||||
bool a_sneak,
|
||||
bool a_LMB,
|
||||
bool a_RMB,
|
||||
float a_pitch,
|
||||
float a_yaw
|
||||
)
|
||||
{
|
||||
up = a_up;
|
||||
down = a_down;
|
||||
left = a_left;
|
||||
right = a_right;
|
||||
jump = a_jump;
|
||||
aux1 = a_aux1;
|
||||
sneak = a_sneak;
|
||||
LMB = a_LMB;
|
||||
RMB = a_RMB;
|
||||
pitch = a_pitch;
|
||||
yaw = a_yaw;
|
||||
}
|
||||
bool up;
|
||||
bool down;
|
||||
bool left;
|
||||
bool right;
|
||||
bool jump;
|
||||
bool aux1;
|
||||
bool sneak;
|
||||
bool LMB;
|
||||
bool RMB;
|
||||
float pitch;
|
||||
float yaw;
|
||||
};
|
||||
|
||||
class Map;
|
||||
class IGameDef;
|
||||
struct CollisionInfo;
|
||||
|
@ -158,6 +213,14 @@ public:
|
|||
|
||||
std::string inventory_formspec;
|
||||
|
||||
PlayerControl control;
|
||||
PlayerControl getPlayerControl()
|
||||
{
|
||||
return control;
|
||||
}
|
||||
|
||||
u32 keyPressed;
|
||||
|
||||
protected:
|
||||
IGameDef *m_gamedef;
|
||||
|
||||
|
|
|
@ -937,6 +937,8 @@ static void read_object_properties(lua_State *L, int index,
|
|||
|
||||
getstringfield(L, -1, "visual", prop->visual);
|
||||
|
||||
getstringfield(L, -1, "mesh", prop->mesh);
|
||||
|
||||
lua_getfield(L, -1, "visual_size");
|
||||
if(lua_istable(L, -1))
|
||||
prop->visual_size = read_v2f(L, -1);
|
||||
|
@ -959,6 +961,23 @@ static void read_object_properties(lua_State *L, int index,
|
|||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "colors");
|
||||
if(lua_istable(L, -1)){
|
||||
prop->colors.clear();
|
||||
int table = lua_gettop(L);
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
if(lua_isstring(L, -1))
|
||||
prop->colors.push_back(readARGB8(L, -1));
|
||||
else
|
||||
prop->colors.push_back(video::SColor(255, 255, 255, 255));
|
||||
// removes value, keeps key for next iteration
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "spritediv");
|
||||
if(lua_istable(L, -1))
|
||||
prop->spritediv = read_v2s16(L, -1);
|
||||
|
@ -2697,6 +2716,80 @@ private:
|
|||
return 0;
|
||||
}
|
||||
|
||||
// set_animation(self, frame_range, frame_speed, frame_blend)
|
||||
static int l_set_animation(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
if(co == NULL) return 0;
|
||||
// Do it
|
||||
v2f frames = v2f(1, 1);
|
||||
if(!lua_isnil(L, 2))
|
||||
frames = read_v2f(L, 2);
|
||||
float frame_speed = 15;
|
||||
if(!lua_isnil(L, 3))
|
||||
frame_speed = lua_tonumber(L, 3);
|
||||
float frame_blend = 0;
|
||||
if(!lua_isnil(L, 4))
|
||||
frame_blend = lua_tonumber(L, 4);
|
||||
co->setAnimation(frames, frame_speed, frame_blend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
|
||||
static int l_set_bone_position(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
if(co == NULL) return 0;
|
||||
// Do it
|
||||
std::string bone = "";
|
||||
if(!lua_isnil(L, 2))
|
||||
bone = lua_tostring(L, 2);
|
||||
v3f position = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 3))
|
||||
position = read_v3f(L, 3);
|
||||
v3f rotation = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 4))
|
||||
rotation = read_v3f(L, 4);
|
||||
co->setBonePosition(bone, position, rotation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_attach(self, parent, bone, position, rotation)
|
||||
static int l_set_attach(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ObjectRef *parent_ref = checkobject(L, 2);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
ServerActiveObject *parent = getobject(parent_ref);
|
||||
if(co == NULL) return 0;
|
||||
if(parent == NULL) return 0;
|
||||
// Do it
|
||||
std::string bone = "";
|
||||
if(!lua_isnil(L, 3))
|
||||
bone = lua_tostring(L, 3);
|
||||
v3f position = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 4))
|
||||
position = read_v3f(L, 4);
|
||||
v3f rotation = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 5))
|
||||
rotation = read_v3f(L, 5);
|
||||
co->setAttachment(parent->getId(), bone, position, rotation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_detach(self)
|
||||
static int l_set_detach(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
if(co == NULL) return 0;
|
||||
// Do it
|
||||
co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_properties(self, properties)
|
||||
static int l_set_properties(lua_State *L)
|
||||
{
|
||||
|
@ -2933,6 +3026,53 @@ private:
|
|||
return 1;
|
||||
}
|
||||
|
||||
// get_player_control(self)
|
||||
static int l_get_player_control(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
Player *player = getplayer(ref);
|
||||
if(player == NULL){
|
||||
lua_pushlstring(L, "", 0);
|
||||
return 1;
|
||||
}
|
||||
// Do it
|
||||
PlayerControl control = player->getPlayerControl();
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L, control.up);
|
||||
lua_setfield(L, -2, "up");
|
||||
lua_pushboolean(L, control.down);
|
||||
lua_setfield(L, -2, "down");
|
||||
lua_pushboolean(L, control.left);
|
||||
lua_setfield(L, -2, "left");
|
||||
lua_pushboolean(L, control.right);
|
||||
lua_setfield(L, -2, "right");
|
||||
lua_pushboolean(L, control.jump);
|
||||
lua_setfield(L, -2, "jump");
|
||||
lua_pushboolean(L, control.aux1);
|
||||
lua_setfield(L, -2, "aux1");
|
||||
lua_pushboolean(L, control.sneak);
|
||||
lua_setfield(L, -2, "sneak");
|
||||
lua_pushboolean(L, control.LMB);
|
||||
lua_setfield(L, -2, "LMB");
|
||||
lua_pushboolean(L, control.RMB);
|
||||
lua_setfield(L, -2, "RMB");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get_player_control_bits(self)
|
||||
static int l_get_player_control_bits(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
Player *player = getplayer(ref);
|
||||
if(player == NULL){
|
||||
lua_pushlstring(L, "", 0);
|
||||
return 1;
|
||||
}
|
||||
// Do it
|
||||
lua_pushnumber(L, player->keyPressed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
public:
|
||||
ObjectRef(ServerActiveObject *object):
|
||||
m_object(object)
|
||||
|
@ -3011,6 +3151,10 @@ const luaL_reg ObjectRef::methods[] = {
|
|||
method(ObjectRef, get_wielded_item),
|
||||
method(ObjectRef, set_wielded_item),
|
||||
method(ObjectRef, set_armor_groups),
|
||||
method(ObjectRef, set_animation),
|
||||
method(ObjectRef, set_bone_position),
|
||||
method(ObjectRef, set_attach),
|
||||
method(ObjectRef, set_detach),
|
||||
method(ObjectRef, set_properties),
|
||||
// LuaEntitySAO-only
|
||||
method(ObjectRef, setvelocity),
|
||||
|
@ -3031,6 +3175,8 @@ const luaL_reg ObjectRef::methods[] = {
|
|||
method(ObjectRef, get_look_yaw),
|
||||
method(ObjectRef, set_inventory_formspec),
|
||||
method(ObjectRef, get_inventory_formspec),
|
||||
method(ObjectRef, get_player_control),
|
||||
method(ObjectRef, get_player_control_bits),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
|
@ -6589,6 +6735,8 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
|
|||
|
||||
getstringfield(L, -1, "visual", prop->visual);
|
||||
|
||||
getstringfield(L, -1, "mesh", prop->mesh);
|
||||
|
||||
// Deprecated: read object properties directly
|
||||
read_object_properties(L, -1, prop);
|
||||
|
||||
|
|
|
@ -1371,9 +1371,9 @@ void Server::AsyncRunStep()
|
|||
/*
|
||||
Send player inventories and HPs if necessary
|
||||
*/
|
||||
if(playersao->m_teleported){
|
||||
if(playersao->m_moved){
|
||||
SendMovePlayer(client->peer_id);
|
||||
playersao->m_teleported = false;
|
||||
playersao->m_moved = false;
|
||||
}
|
||||
if(playersao->m_inventory_not_sent){
|
||||
UpdateCrafting(client->peer_id);
|
||||
|
@ -2369,7 +2369,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
|
||||
if(command == TOSERVER_PLAYERPOS)
|
||||
{
|
||||
if(datasize < 2+12+12+4+4)
|
||||
if(datasize < 2+12+12+4+4+4)
|
||||
return;
|
||||
|
||||
u32 start = 0;
|
||||
|
@ -2377,6 +2377,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
v3s32 ss = readV3S32(&data[start+2+12]);
|
||||
f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
|
||||
f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
|
||||
u32 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
|
||||
v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
|
||||
v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
|
||||
pitch = wrapDegrees(pitch);
|
||||
|
@ -2386,6 +2387,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
player->setSpeed(speed);
|
||||
player->setPitch(pitch);
|
||||
player->setYaw(yaw);
|
||||
player->keyPressed=keyPressed;
|
||||
player->control.up = (bool)(keyPressed&1);
|
||||
player->control.down = (bool)(keyPressed&2);
|
||||
player->control.left = (bool)(keyPressed&4);
|
||||
player->control.right = (bool)(keyPressed&8);
|
||||
player->control.jump = (bool)(keyPressed&16);
|
||||
player->control.aux1 = (bool)(keyPressed&32);
|
||||
player->control.sneak = (bool)(keyPressed&64);
|
||||
player->control.LMB = (bool)(keyPressed&128);
|
||||
player->control.RMB = (bool)(keyPressed&256);
|
||||
|
||||
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
|
||||
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
|
||||
|
@ -3167,6 +3178,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
|
||||
} // action == 4
|
||||
|
||||
|
||||
/*
|
||||
Catch invalid actions
|
||||
*/
|
||||
|
@ -4029,6 +4041,7 @@ void Server::fillMediaCache()
|
|||
paths.push_back(mod.path + DIR_DELIM + "textures");
|
||||
paths.push_back(mod.path + DIR_DELIM + "sounds");
|
||||
paths.push_back(mod.path + DIR_DELIM + "media");
|
||||
paths.push_back(mod.path + DIR_DELIM + "models");
|
||||
}
|
||||
std::string path_all = "textures";
|
||||
paths.push_back(path_all + DIR_DELIM + "all");
|
||||
|
@ -4054,6 +4067,7 @@ void Server::fillMediaCache()
|
|||
".png", ".jpg", ".bmp", ".tga",
|
||||
".pcx", ".ppm", ".psd", ".wal", ".rgb",
|
||||
".ogg",
|
||||
".x", ".b3d", ".md2", ".obj",
|
||||
NULL
|
||||
};
|
||||
if(removeStringEnd(filename, supported_ext) == ""){
|
||||
|
|
|
@ -152,6 +152,12 @@ public:
|
|||
|
||||
virtual void setArmorGroups(const ItemGroupList &armor_groups)
|
||||
{}
|
||||
virtual void setAnimation(v2f frames, float frame_speed, float frame_blend)
|
||||
{}
|
||||
virtual void setBonePosition(std::string bone, v3f position, v3f rotation)
|
||||
{}
|
||||
virtual void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{}
|
||||
virtual ObjectProperties* accessObjectProperties()
|
||||
{ return NULL; }
|
||||
virtual void notifyObjectPropertiesModified()
|
||||
|
|
40
src/tile.cpp
40
src/tile.cpp
|
@ -518,15 +518,6 @@ core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<
|
|||
// Apply transform to image data
|
||||
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
|
||||
|
||||
/*
|
||||
Adds a new texture to the video driver and returns a pointer to it.
|
||||
This pointer should not be dropped. Any texture that was registered
|
||||
with that name before is removed (this may invalidate some ITexture
|
||||
pointers).
|
||||
*/
|
||||
video::ITexture* register_texture(video::IVideoDriver *driver,
|
||||
std::string name, video::IImage *img);
|
||||
|
||||
/*
|
||||
Generate image based on a string like "stone.png" or "[crack0".
|
||||
if baseimg is NULL, it is created. Otherwise stuff is made on it.
|
||||
|
@ -695,9 +686,11 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
|
|||
" create texture \""<<name<<"\""<<std::endl;
|
||||
}
|
||||
|
||||
// Create texture from resulting image
|
||||
if(baseimg != NULL)
|
||||
t = register_texture(driver, name, baseimg);
|
||||
{
|
||||
// Create texture from resulting image
|
||||
t = driver->addTexture(name.c_str(), baseimg);
|
||||
}
|
||||
|
||||
/*
|
||||
Add texture to caches (add NULL textures too)
|
||||
|
@ -816,7 +809,7 @@ void TextureSource::rebuildImagesAndTextures()
|
|||
// Create texture from resulting image
|
||||
video::ITexture *t = NULL;
|
||||
if(img)
|
||||
t = register_texture(driver, sap->name, img);
|
||||
t = driver->addTexture(sap->name.c_str(), img);
|
||||
|
||||
// Replace texture
|
||||
sap->a.atlas = t;
|
||||
|
@ -1051,7 +1044,7 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
|
|||
/*
|
||||
Make texture
|
||||
*/
|
||||
video::ITexture *t = register_texture(driver, "__main_atlas__", atlas_img);
|
||||
video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
|
||||
assert(t);
|
||||
|
||||
/*
|
||||
|
@ -1142,15 +1135,6 @@ video::IImage* generate_image_from_scratch(std::string name,
|
|||
return baseimg;
|
||||
}
|
||||
|
||||
video::ITexture* register_texture(video::IVideoDriver *driver,
|
||||
std::string name, video::IImage *img)
|
||||
{
|
||||
video::ITexture *old_texture = driver->findTexture(name.c_str());
|
||||
if(old_texture)
|
||||
driver->removeTexture(old_texture);
|
||||
return driver->addTexture(name.c_str(), img);
|
||||
}
|
||||
|
||||
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
IrrlichtDevice *device, SourceImageCache *sourcecache)
|
||||
{
|
||||
|
@ -1557,12 +1541,12 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
|||
assert(img_top && img_left && img_right);
|
||||
|
||||
// Create textures from images
|
||||
video::ITexture *texture_top = register_texture(driver,
|
||||
imagename_top + "__temp1__", img_top);
|
||||
video::ITexture *texture_left = register_texture(driver,
|
||||
imagename_left + "__temp2__", img_left);
|
||||
video::ITexture *texture_right = register_texture(driver,
|
||||
imagename_right + "__temp3__", img_right);
|
||||
video::ITexture *texture_top = driver->addTexture(
|
||||
(imagename_top + "__temp__").c_str(), img_top);
|
||||
video::ITexture *texture_left = driver->addTexture(
|
||||
(imagename_left + "__temp__").c_str(), img_left);
|
||||
video::ITexture *texture_right = driver->addTexture(
|
||||
(imagename_right + "__temp__").c_str(), img_right);
|
||||
assert(texture_top && texture_left && texture_right);
|
||||
|
||||
// Drop images
|
||||
|
|
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define UTIL_SERIALIZE_HEADER
|
||||
|
||||
#include "../irrlichttypes.h"
|
||||
#include "../irrlichttypes_bloated.h"
|
||||
#include "../irr_v2d.h"
|
||||
#include "../irr_v3d.h"
|
||||
#include <iostream>
|
||||
|
@ -197,6 +198,24 @@ inline v3s16 readV3S16(u8 *data)
|
|||
return p;
|
||||
}
|
||||
|
||||
inline void writeARGB8(u8 *data, video::SColor p)
|
||||
{
|
||||
writeU8(&data[0], p.getAlpha());
|
||||
writeU8(&data[1], p.getRed());
|
||||
writeU8(&data[2], p.getGreen());
|
||||
writeU8(&data[3], p.getBlue());
|
||||
}
|
||||
|
||||
inline video::SColor readARGB8(u8 *data)
|
||||
{
|
||||
video::SColor p;
|
||||
p.setAlpha(readU8(&data[0]));
|
||||
p.setRed(readU8(&data[1]));
|
||||
p.setGreen(readU8(&data[2]));
|
||||
p.setBlue(readU8(&data[3]));
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
The above stuff directly interfaced to iostream
|
||||
*/
|
||||
|
@ -344,6 +363,20 @@ inline v3s16 readV3S16(std::istream &is)
|
|||
return readV3S16((u8*)buf);
|
||||
}
|
||||
|
||||
inline void writeARGB8(std::ostream &os, video::SColor p)
|
||||
{
|
||||
char buf[4] = {0};
|
||||
writeARGB8((u8*)buf, p);
|
||||
os.write(buf, 4);
|
||||
}
|
||||
|
||||
inline video::SColor readARGB8(std::istream &is)
|
||||
{
|
||||
char buf[4] = {0};
|
||||
is.read(buf, 4);
|
||||
return readARGB8((u8*)buf);
|
||||
}
|
||||
|
||||
/*
|
||||
More serialization stuff
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user