mirror of https://github.com/minetest/minetest.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
6c43e29c54
|
@ -215,8 +215,8 @@ minetest.register_chatcommand("clearpassword", {
|
||||||
privs = {password=true},
|
privs = {password=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
toname = param
|
toname = param
|
||||||
if not toname then
|
if toname == "" then
|
||||||
minetest.chat_send_player(toname, "Name field required")
|
minetest.chat_send_player(name, "Name field required")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
minetest.set_player_password(toname, '')
|
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/
|
More information at http://c55.me/minetest/
|
||||||
|
|
||||||
|
@ -694,6 +694,11 @@ image[<X>,<Y>;<W>,<H>;<texture name>]
|
||||||
^ Show an image
|
^ Show an image
|
||||||
^ Position and size units are inventory slots
|
^ 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>]
|
field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
|
||||||
^ Textual field; will be sent to server when a button is clicked
|
^ 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
|
^ x and y position the field relative to the top left of the menu
|
||||||
|
@ -1098,6 +1103,10 @@ methods:
|
||||||
- get_wielded_item() -> ItemStack
|
- get_wielded_item() -> ItemStack
|
||||||
- set_wielded_item(item): replaces the wielded item, returns true if successful
|
- set_wielded_item(item): replaces the wielded item, returns true if successful
|
||||||
- set_armor_groups({group1=rating, group2=rating, ...})
|
- 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)
|
- set_properties(object property table)
|
||||||
LuaEntitySAO-only: (no-op for other objects)
|
LuaEntitySAO-only: (no-op for other objects)
|
||||||
- setvelocity({x=num, y=num, z=num})
|
- setvelocity({x=num, y=num, z=num})
|
||||||
|
@ -1123,7 +1132,11 @@ Player-only: (no-op for other objects)
|
||||||
^ Redefine player's inventory form
|
^ Redefine player's inventory form
|
||||||
^ Should usually be called in on_joinplayer
|
^ Should usually be called in on_joinplayer
|
||||||
- get_inventory_formspec() -> formspec string
|
- 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
|
InvRef: Reference to an inventory
|
||||||
methods:
|
methods:
|
||||||
- is_empty(listname): return true if list is empty
|
- is_empty(listname): return true if list is empty
|
||||||
|
@ -1222,9 +1235,11 @@ Object Properties
|
||||||
physical = true,
|
physical = true,
|
||||||
weight = 5,
|
weight = 5,
|
||||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.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},
|
visual_size = {x=1, y=1},
|
||||||
|
mesh = "model",
|
||||||
textures = {}, -- number of required textures depends on visual
|
textures = {}, -- number of required textures depends on visual
|
||||||
|
colors = {}, -- number of required colors depends on visual
|
||||||
spritediv = {x=1, y=1},
|
spritediv = {x=1, y=1},
|
||||||
initial_sprite_basepos = {x=0, y=0},
|
initial_sprite_basepos = {x=0, y=0},
|
||||||
is_visible = true,
|
is_visible = true,
|
||||||
|
|
|
@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "hex.h"
|
#include "hex.h"
|
||||||
|
#include "IMeshCache.h"
|
||||||
|
|
||||||
static std::string getMediaCacheDir()
|
static std::string getMediaCacheDir()
|
||||||
{
|
{
|
||||||
|
@ -821,7 +822,7 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
||||||
if(name != "")
|
if(name != "")
|
||||||
{
|
{
|
||||||
verbosestream<<"Client: Attempting to load image "
|
verbosestream<<"Client: Attempting to load image "
|
||||||
<<"file \""<<filename<<"\""<<std::endl;
|
<<"file \""<<filename<<"\""<<std::endl;
|
||||||
|
|
||||||
io::IFileSystem *irrfs = m_device->getFileSystem();
|
io::IFileSystem *irrfs = m_device->getFileSystem();
|
||||||
video::IVideoDriver *vdrv = m_device->getVideoDriver();
|
video::IVideoDriver *vdrv = m_device->getVideoDriver();
|
||||||
|
@ -855,11 +856,33 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
||||||
if(name != "")
|
if(name != "")
|
||||||
{
|
{
|
||||||
verbosestream<<"Client: Attempting to load sound "
|
verbosestream<<"Client: Attempting to load sound "
|
||||||
<<"file \""<<filename<<"\""<<std::endl;
|
<<"file \""<<filename<<"\""<<std::endl;
|
||||||
m_sound->loadSoundData(name, data);
|
m_sound->loadSoundData(name, data);
|
||||||
return true;
|
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 \""
|
errorstream<<"Client: Don't know how to load file \""
|
||||||
<<filename<<"\""<<std::endl;
|
<<filename<<"\""<<std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
@ -1961,7 +1984,7 @@ void Client::sendPlayerPos()
|
||||||
v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
|
v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
|
||||||
s32 pitch = myplayer->getPitch() * 100;
|
s32 pitch = myplayer->getPitch() * 100;
|
||||||
s32 yaw = myplayer->getYaw() * 100;
|
s32 yaw = myplayer->getYaw() * 100;
|
||||||
|
u32 keyPressed=myplayer->keyPressed;
|
||||||
/*
|
/*
|
||||||
Format:
|
Format:
|
||||||
[0] u16 command
|
[0] u16 command
|
||||||
|
@ -1969,15 +1992,15 @@ void Client::sendPlayerPos()
|
||||||
[2+12] v3s32 speed*100
|
[2+12] v3s32 speed*100
|
||||||
[2+12+12] s32 pitch*100
|
[2+12+12] s32 pitch*100
|
||||||
[2+12+12+4] s32 yaw*100
|
[2+12+12+4] s32 yaw*100
|
||||||
|
[2+12+12+4+4] u32 keyPressed
|
||||||
*/
|
*/
|
||||||
|
SharedBuffer<u8> data(2+12+12+4+4+4);
|
||||||
SharedBuffer<u8> data(2+12+12+4+4);
|
|
||||||
writeU16(&data[0], TOSERVER_PLAYERPOS);
|
writeU16(&data[0], TOSERVER_PLAYERPOS);
|
||||||
writeV3S32(&data[2], position);
|
writeV3S32(&data[2], position);
|
||||||
writeV3S32(&data[2+12], speed);
|
writeV3S32(&data[2+12], speed);
|
||||||
writeS32(&data[2+12+12], pitch);
|
writeS32(&data[2+12+12], pitch);
|
||||||
writeS32(&data[2+12+12+4], yaw);
|
writeS32(&data[2+12+12+4], yaw);
|
||||||
|
writeU32(&data[2+12+12+4+4], keyPressed);
|
||||||
// Send as unreliable
|
// Send as unreliable
|
||||||
Send(0, data, false);
|
Send(0, data, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef,
|
||||||
|
|
||||||
ClientActiveObject::~ClientActiveObject()
|
ClientActiveObject::~ClientActiveObject()
|
||||||
{
|
{
|
||||||
removeFromScene();
|
removeFromScene(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
|
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
|
||||||
|
|
|
@ -49,13 +49,19 @@ public:
|
||||||
|
|
||||||
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
|
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
|
||||||
IrrlichtDevice *irr){}
|
IrrlichtDevice *irr){}
|
||||||
virtual void removeFromScene(){}
|
virtual void removeFromScene(bool permanent){}
|
||||||
// 0 <= light_at_pos <= LIGHT_SUN
|
// 0 <= light_at_pos <= LIGHT_SUN
|
||||||
virtual void updateLight(u8 light_at_pos){}
|
virtual void updateLight(u8 light_at_pos){}
|
||||||
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
||||||
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
|
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
|
||||||
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
|
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
|
||||||
virtual v3f getPosition(){return v3f(0,0,0);}
|
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;}
|
virtual bool doShowSelectionBox(){return true;}
|
||||||
|
|
||||||
// Step object in time
|
// Step object in time
|
||||||
|
|
|
@ -67,9 +67,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
TOCLIENT_DETACHED_INVENTORY
|
TOCLIENT_DETACHED_INVENTORY
|
||||||
PROTOCOL_VERSION 13:
|
PROTOCOL_VERSION 13:
|
||||||
InventoryList field "Width" (deserialization fails with old versions)
|
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
|
#define PROTOCOL_ID 0x4f457403
|
||||||
|
|
||||||
|
@ -366,6 +372,7 @@ enum ToServerCommand
|
||||||
[2+12] v3s32 speed*100
|
[2+12] v3s32 speed*100
|
||||||
[2+12+12] s32 pitch*100
|
[2+12+12] s32 pitch*100
|
||||||
[2+12+12+4] s32 yaw*100
|
[2+12+12+4] s32 yaw*100
|
||||||
|
[2+12+12+4+4] u32 keyPressed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TOSERVER_GOTBLOCKS = 0x24,
|
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/serialize.h"
|
||||||
#include "util/mathconstants.h"
|
#include "util/mathconstants.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
#include "main.h" // g_settings
|
||||||
#include <IMeshManipulator.h>
|
#include <IMeshManipulator.h>
|
||||||
|
#include <IAnimatedMeshSceneNode.h>
|
||||||
|
#include <IBoneSceneNode.h>
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
struct ToolCapabilities;
|
struct ToolCapabilities;
|
||||||
|
@ -552,7 +555,8 @@ private:
|
||||||
// Only set at initialization
|
// Only set at initialization
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
bool m_is_player;
|
bool m_is_player;
|
||||||
bool m_is_local_player; // determined locally
|
bool m_is_local_player;
|
||||||
|
int m_id;
|
||||||
// Property-ish things
|
// Property-ish things
|
||||||
ObjectProperties m_prop;
|
ObjectProperties m_prop;
|
||||||
//
|
//
|
||||||
|
@ -560,6 +564,7 @@ private:
|
||||||
IrrlichtDevice *m_irr;
|
IrrlichtDevice *m_irr;
|
||||||
core::aabbox3d<f32> m_selection_box;
|
core::aabbox3d<f32> m_selection_box;
|
||||||
scene::IMeshSceneNode *m_meshnode;
|
scene::IMeshSceneNode *m_meshnode;
|
||||||
|
scene::IAnimatedMeshSceneNode *m_animated_meshnode;
|
||||||
scene::IBillboardSceneNode *m_spritenode;
|
scene::IBillboardSceneNode *m_spritenode;
|
||||||
scene::ITextSceneNode* m_textnode;
|
scene::ITextSceneNode* m_textnode;
|
||||||
v3f m_position;
|
v3f m_position;
|
||||||
|
@ -573,6 +578,14 @@ private:
|
||||||
v2s16 m_tx_basepos;
|
v2s16 m_tx_basepos;
|
||||||
bool m_initial_tx_basepos_set;
|
bool m_initial_tx_basepos_set;
|
||||||
bool m_tx_select_horiz_by_yawpitch;
|
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_frame;
|
||||||
int m_anim_num_frames;
|
int m_anim_num_frames;
|
||||||
float m_anim_framelength;
|
float m_anim_framelength;
|
||||||
|
@ -582,6 +595,7 @@ private:
|
||||||
bool m_visuals_expired;
|
bool m_visuals_expired;
|
||||||
float m_step_distance_counter;
|
float m_step_distance_counter;
|
||||||
u8 m_last_light;
|
u8 m_last_light;
|
||||||
|
bool m_is_visible;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
|
GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
|
||||||
|
@ -589,11 +603,13 @@ public:
|
||||||
//
|
//
|
||||||
m_is_player(false),
|
m_is_player(false),
|
||||||
m_is_local_player(false),
|
m_is_local_player(false),
|
||||||
|
m_id(0),
|
||||||
//
|
//
|
||||||
m_smgr(NULL),
|
m_smgr(NULL),
|
||||||
m_irr(NULL),
|
m_irr(NULL),
|
||||||
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
|
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
|
||||||
m_meshnode(NULL),
|
m_meshnode(NULL),
|
||||||
|
m_animated_meshnode(NULL),
|
||||||
m_spritenode(NULL),
|
m_spritenode(NULL),
|
||||||
m_textnode(NULL),
|
m_textnode(NULL),
|
||||||
m_position(v3f(0,10*BS,0)),
|
m_position(v3f(0,10*BS,0)),
|
||||||
|
@ -605,6 +621,14 @@ public:
|
||||||
m_tx_basepos(0,0),
|
m_tx_basepos(0,0),
|
||||||
m_initial_tx_basepos_set(false),
|
m_initial_tx_basepos_set(false),
|
||||||
m_tx_select_horiz_by_yawpitch(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_frame(0),
|
||||||
m_anim_num_frames(1),
|
m_anim_num_frames(1),
|
||||||
m_anim_framelength(0.2),
|
m_anim_framelength(0.2),
|
||||||
|
@ -612,7 +636,8 @@ public:
|
||||||
m_reset_textures_timer(-1),
|
m_reset_textures_timer(-1),
|
||||||
m_visuals_expired(false),
|
m_visuals_expired(false),
|
||||||
m_step_distance_counter(0),
|
m_step_distance_counter(0),
|
||||||
m_last_light(255)
|
m_last_light(255),
|
||||||
|
m_is_visible(false)
|
||||||
{
|
{
|
||||||
if(gamedef == NULL)
|
if(gamedef == NULL)
|
||||||
ClientActiveObject::registerType(getType(), create);
|
ClientActiveObject::registerType(getType(), create);
|
||||||
|
@ -632,6 +657,7 @@ public:
|
||||||
}
|
}
|
||||||
m_name = deSerializeString(is);
|
m_name = deSerializeString(is);
|
||||||
m_is_player = readU8(is);
|
m_is_player = readU8(is);
|
||||||
|
m_id = readS16(is);
|
||||||
m_position = readV3F1000(is);
|
m_position = readV3F1000(is);
|
||||||
m_yaw = readF1000(is);
|
m_yaw = readF1000(is);
|
||||||
m_hp = readS16(is);
|
m_hp = readS16(is);
|
||||||
|
@ -668,21 +694,113 @@ public:
|
||||||
}
|
}
|
||||||
core::aabbox3d<f32>* getSelectionBox()
|
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 NULL;
|
||||||
return &m_selection_box;
|
return &m_selection_box;
|
||||||
}
|
}
|
||||||
v3f getPosition()
|
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;
|
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){
|
if(m_meshnode){
|
||||||
m_meshnode->remove();
|
m_meshnode->remove();
|
||||||
m_meshnode = NULL;
|
m_meshnode = NULL;
|
||||||
}
|
}
|
||||||
|
if(m_animated_meshnode){
|
||||||
|
m_animated_meshnode->remove();
|
||||||
|
m_animated_meshnode = NULL;
|
||||||
|
}
|
||||||
if(m_spritenode){
|
if(m_spritenode){
|
||||||
m_spritenode->remove();
|
m_spritenode->remove();
|
||||||
m_spritenode = NULL;
|
m_spritenode = NULL;
|
||||||
|
@ -695,7 +813,7 @@ public:
|
||||||
m_smgr = smgr;
|
m_smgr = smgr;
|
||||||
m_irr = irr;
|
m_irr = irr;
|
||||||
|
|
||||||
if(m_meshnode != NULL || m_spritenode != NULL)
|
if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_visuals_expired = false;
|
m_visuals_expired = false;
|
||||||
|
@ -791,7 +909,24 @@ public:
|
||||||
m_prop.visual_size.X));
|
m_prop.visual_size.X));
|
||||||
u8 li = m_last_light;
|
u8 li = m_last_light;
|
||||||
setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
|
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<<"GenericCAO::addToScene(): node"<<std::endl;
|
||||||
infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
|
infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
|
||||||
if(m_prop.textures.size() >= 1){
|
if(m_prop.textures.size() >= 1){
|
||||||
|
@ -823,6 +958,8 @@ public:
|
||||||
scene::ISceneNode *node = NULL;
|
scene::ISceneNode *node = NULL;
|
||||||
if(m_spritenode)
|
if(m_spritenode)
|
||||||
node = m_spritenode;
|
node = m_spritenode;
|
||||||
|
else if(m_animated_meshnode)
|
||||||
|
node = m_animated_meshnode;
|
||||||
else if(m_meshnode)
|
else if(m_meshnode)
|
||||||
node = m_meshnode;
|
node = m_meshnode;
|
||||||
if(node && m_is_player && !m_is_local_player){
|
if(node && m_is_player && !m_is_local_player){
|
||||||
|
@ -833,8 +970,11 @@ public:
|
||||||
wname.c_str(), video::SColor(255,255,255,255), node);
|
wname.c_str(), video::SColor(255,255,255,255), node);
|
||||||
m_textnode->setPosition(v3f(0, BS*1.1, 0));
|
m_textnode->setPosition(v3f(0, BS*1.1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNodePos();
|
updateNodePos();
|
||||||
|
updateAnimation();
|
||||||
|
updateBonePosition();
|
||||||
|
updateAttachments();
|
||||||
}
|
}
|
||||||
|
|
||||||
void expireVisuals()
|
void expireVisuals()
|
||||||
|
@ -844,19 +984,16 @@ public:
|
||||||
|
|
||||||
void updateLight(u8 light_at_pos)
|
void updateLight(u8 light_at_pos)
|
||||||
{
|
{
|
||||||
bool is_visible = (m_hp != 0);
|
|
||||||
u8 li = decode_light(light_at_pos);
|
u8 li = decode_light(light_at_pos);
|
||||||
if(li != m_last_light){
|
if(li != m_last_light){
|
||||||
m_last_light = li;
|
m_last_light = li;
|
||||||
video::SColor color(255,li,li,li);
|
video::SColor color(255,li,li,li);
|
||||||
if(m_meshnode){
|
if(m_meshnode)
|
||||||
setMeshColor(m_meshnode->getMesh(), color);
|
setMeshColor(m_meshnode->getMesh(), color);
|
||||||
m_meshnode->setVisible(is_visible);
|
if(m_animated_meshnode)
|
||||||
}
|
setMeshColor(m_animated_meshnode->getMesh(), color);
|
||||||
if(m_spritenode){
|
if(m_spritenode)
|
||||||
m_spritenode->setColor(color);
|
m_spritenode->setColor(color);
|
||||||
m_spritenode->setVisible(is_visible);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,12 +1004,21 @@ public:
|
||||||
|
|
||||||
void updateNodePos()
|
void updateNodePos()
|
||||||
{
|
{
|
||||||
|
if(getParent() != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if(m_meshnode){
|
if(m_meshnode){
|
||||||
m_meshnode->setPosition(pos_translator.vect_show);
|
m_meshnode->setPosition(pos_translator.vect_show);
|
||||||
v3f rot = m_meshnode->getRotation();
|
v3f rot = m_meshnode->getRotation();
|
||||||
rot.Y = -m_yaw;
|
rot.Y = -m_yaw;
|
||||||
m_meshnode->setRotation(rot);
|
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){
|
if(m_spritenode){
|
||||||
m_spritenode->setPosition(pos_translator.vect_show);
|
m_spritenode->setPosition(pos_translator.vect_show);
|
||||||
}
|
}
|
||||||
|
@ -880,56 +1026,116 @@ public:
|
||||||
|
|
||||||
void step(float dtime, ClientEnvironment *env)
|
void step(float dtime, ClientEnvironment *env)
|
||||||
{
|
{
|
||||||
v3f lastpos = pos_translator.vect_show;
|
|
||||||
|
|
||||||
if(m_visuals_expired && m_smgr && m_irr){
|
if(m_visuals_expired && m_smgr && m_irr){
|
||||||
m_visuals_expired = false;
|
m_visuals_expired = false;
|
||||||
removeFromScene();
|
|
||||||
|
// 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);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_prop.physical){
|
// Make sure m_is_visible is always applied
|
||||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
if(m_meshnode)
|
||||||
box.MinEdge *= BS;
|
m_meshnode->setVisible(m_is_visible);
|
||||||
box.MaxEdge *= BS;
|
if(m_animated_meshnode)
|
||||||
collisionMoveResult moveresult;
|
m_animated_meshnode->setVisible(m_is_visible);
|
||||||
f32 pos_max_d = BS*0.125; // Distance per iteration
|
if(m_spritenode)
|
||||||
f32 stepheight = 0;
|
m_spritenode->setVisible(m_is_visible);
|
||||||
v3f p_pos = m_position;
|
if(m_textnode)
|
||||||
v3f p_velocity = m_velocity;
|
m_textnode->setVisible(m_is_visible);
|
||||||
v3f p_acceleration = m_acceleration;
|
|
||||||
IGameDef *gamedef = env->getGameDef();
|
|
||||||
moveresult = collisionMoveSimple(&env->getMap(), gamedef,
|
|
||||||
pos_max_d, box, stepheight, dtime,
|
|
||||||
p_pos, p_velocity, p_acceleration);
|
|
||||||
// Apply results
|
|
||||||
m_position = p_pos;
|
|
||||||
m_velocity = p_velocity;
|
|
||||||
m_acceleration = p_acceleration;
|
|
||||||
|
|
||||||
bool is_end_position = moveresult.collides;
|
|
||||||
pos_translator.update(m_position, is_end_position, dtime);
|
|
||||||
pos_translator.translate(dtime);
|
|
||||||
updateNodePos();
|
|
||||||
} else {
|
|
||||||
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
|
|
||||||
m_velocity += dtime * m_acceleration;
|
|
||||||
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
|
|
||||||
pos_translator.translate(dtime);
|
|
||||||
updateNodePos();
|
|
||||||
}
|
|
||||||
|
|
||||||
float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
|
if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
|
||||||
m_step_distance_counter += moved;
|
{
|
||||||
if(m_step_distance_counter > 1.5*BS){
|
// Set these for later
|
||||||
m_step_distance_counter = 0;
|
m_position = getPosition();
|
||||||
if(!m_is_local_player && m_prop.makes_footstep_sound){
|
m_velocity = v3f(0,0,0);
|
||||||
INodeDefManager *ndef = m_gamedef->ndef();
|
m_acceleration = v3f(0,0,0);
|
||||||
v3s16 p = floatToInt(getPosition() + v3f(0,
|
pos_translator.vect_show = m_position;
|
||||||
(m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
|
|
||||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
if(m_is_local_player) // Update local player attachment position
|
||||||
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
|
{
|
||||||
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
|
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;
|
||||||
|
box.MinEdge *= BS;
|
||||||
|
box.MaxEdge *= BS;
|
||||||
|
collisionMoveResult moveresult;
|
||||||
|
f32 pos_max_d = BS*0.125; // Distance per iteration
|
||||||
|
f32 stepheight = 0;
|
||||||
|
v3f p_pos = m_position;
|
||||||
|
v3f p_velocity = m_velocity;
|
||||||
|
v3f p_acceleration = m_acceleration;
|
||||||
|
IGameDef *gamedef = env->getGameDef();
|
||||||
|
moveresult = collisionMoveSimple(&env->getMap(), gamedef,
|
||||||
|
pos_max_d, box, stepheight, dtime,
|
||||||
|
p_pos, p_velocity, p_acceleration);
|
||||||
|
// Apply results
|
||||||
|
m_position = p_pos;
|
||||||
|
m_velocity = p_velocity;
|
||||||
|
m_acceleration = p_acceleration;
|
||||||
|
|
||||||
|
bool is_end_position = moveresult.collides;
|
||||||
|
pos_translator.update(m_position, is_end_position, dtime);
|
||||||
|
pos_translator.translate(dtime);
|
||||||
|
updateNodePos();
|
||||||
|
} else {
|
||||||
|
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
|
||||||
|
m_velocity += dtime * m_acceleration;
|
||||||
|
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
|
||||||
|
pos_translator.translate(dtime);
|
||||||
|
updateNodePos();
|
||||||
|
}
|
||||||
|
|
||||||
|
float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
|
||||||
|
m_step_distance_counter += moved;
|
||||||
|
if(m_step_distance_counter > 1.5*BS){
|
||||||
|
m_step_distance_counter = 0;
|
||||||
|
if(!m_is_local_player && m_prop.makes_footstep_sound){
|
||||||
|
INodeDefManager *ndef = m_gamedef->ndef();
|
||||||
|
v3s16 p = floatToInt(getPosition() + v3f(0,
|
||||||
|
(m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
|
||||||
|
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||||
|
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
|
||||||
|
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,7 +1156,7 @@ public:
|
||||||
updateTextures("");
|
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;
|
m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
|
||||||
updateNodePos();
|
updateNodePos();
|
||||||
}
|
}
|
||||||
|
@ -1008,6 +1214,10 @@ public:
|
||||||
{
|
{
|
||||||
ITextureSource *tsrc = m_gamedef->tsrc();
|
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_spritenode)
|
||||||
{
|
{
|
||||||
if(m_prop.visual == "sprite")
|
if(m_prop.visual == "sprite")
|
||||||
|
@ -1018,6 +1228,58 @@ public:
|
||||||
texturestring += mod;
|
texturestring += mod;
|
||||||
m_spritenode->setMaterialTexture(0,
|
m_spritenode->setMaterialTexture(0,
|
||||||
tsrc->getTextureRaw(texturestring));
|
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)
|
if(m_meshnode)
|
||||||
|
@ -1044,6 +1306,20 @@ public:
|
||||||
material.setTexture(0, atlas);
|
material.setTexture(0, atlas);
|
||||||
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
|
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
|
||||||
material.getTextureMatrix(0).setTextureScale(size.X, size.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")
|
else if(m_prop.visual == "upright_sprite")
|
||||||
|
@ -1057,6 +1333,20 @@ public:
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
|
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
|
||||||
buf->getMaterial().setTexture(0,
|
buf->getMaterial().setTexture(0,
|
||||||
tsrc->getTextureRaw(tname));
|
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";
|
std::string tname = "unknown_object.png";
|
||||||
|
@ -1068,11 +1358,213 @@ public:
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
|
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
|
||||||
buf->getMaterial().setTexture(0,
|
buf->getMaterial().setTexture(0,
|
||||||
tsrc->getTextureRaw(tname));
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void processMessage(const std::string &data)
|
void processMessage(const std::string &data)
|
||||||
{
|
{
|
||||||
//infostream<<"GenericCAO: Got message"<<std::endl;
|
//infostream<<"GenericCAO: Got message"<<std::endl;
|
||||||
|
@ -1099,6 +1591,8 @@ public:
|
||||||
}
|
}
|
||||||
else if(cmd == GENERIC_CMD_UPDATE_POSITION)
|
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_position = readV3F1000(is);
|
||||||
m_velocity = readV3F1000(is);
|
m_velocity = readV3F1000(is);
|
||||||
m_acceleration = readV3F1000(is);
|
m_acceleration = readV3F1000(is);
|
||||||
|
@ -1112,7 +1606,10 @@ public:
|
||||||
// the ground due to sucky collision detection...
|
// the ground due to sucky collision detection...
|
||||||
if(m_prop.physical)
|
if(m_prop.physical)
|
||||||
m_position += v3f(0,0.002,0);
|
m_position += v3f(0,0.002,0);
|
||||||
|
|
||||||
|
if(getParent() != NULL) // Just in case
|
||||||
|
return;
|
||||||
|
|
||||||
if(do_interpolate){
|
if(do_interpolate){
|
||||||
if(!m_prop.physical)
|
if(!m_prop.physical)
|
||||||
pos_translator.update(m_position, is_end_position, update_interval);
|
pos_translator.update(m_position, is_end_position, update_interval);
|
||||||
|
@ -1140,6 +1637,41 @@ public:
|
||||||
|
|
||||||
updateTexturePos();
|
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)
|
else if(cmd == GENERIC_CMD_PUNCHED)
|
||||||
{
|
{
|
||||||
/*s16 damage =*/ readS16(is);
|
/*s16 damage =*/ readS16(is);
|
||||||
|
|
|
@ -355,7 +355,10 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
|
||||||
m_last_sent_velocity(0,0,0),
|
m_last_sent_velocity(0,0,0),
|
||||||
m_last_sent_position_timer(0),
|
m_last_sent_position_timer(0),
|
||||||
m_last_sent_move_precision(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
|
// Only register type if no environment supplied
|
||||||
if(env == NULL){
|
if(env == NULL){
|
||||||
|
@ -429,6 +432,17 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
|
||||||
return sao;
|
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)
|
void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||||
{
|
{
|
||||||
if(!m_properties_sent)
|
if(!m_properties_sent)
|
||||||
|
@ -440,30 +454,52 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||||
m_messages_out.push_back(aom);
|
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;
|
m_last_sent_position_timer += dtime;
|
||||||
|
|
||||||
if(m_prop.physical){
|
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
|
||||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
// If the object gets detached this comes into effect automatically from the last known origin
|
||||||
box.MinEdge *= BS;
|
if(isAttached())
|
||||||
box.MaxEdge *= BS;
|
{
|
||||||
collisionMoveResult moveresult;
|
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||||
f32 pos_max_d = BS*0.25; // Distance per iteration
|
m_base_position = pos;
|
||||||
f32 stepheight = 0; // Maximum climbable step height
|
m_velocity = v3f(0,0,0);
|
||||||
v3f p_pos = m_base_position;
|
m_acceleration = v3f(0,0,0);
|
||||||
v3f p_velocity = m_velocity;
|
}
|
||||||
v3f p_acceleration = m_acceleration;
|
else
|
||||||
IGameDef *gamedef = m_env->getGameDef();
|
{
|
||||||
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
|
if(m_prop.physical){
|
||||||
pos_max_d, box, stepheight, dtime,
|
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||||
p_pos, p_velocity, p_acceleration);
|
box.MinEdge *= BS;
|
||||||
// Apply results
|
box.MaxEdge *= BS;
|
||||||
m_base_position = p_pos;
|
collisionMoveResult moveresult;
|
||||||
m_velocity = p_velocity;
|
f32 pos_max_d = BS*0.25; // Distance per iteration
|
||||||
m_acceleration = p_acceleration;
|
f32 stepheight = 0; // Maximum climbable step height
|
||||||
} else {
|
v3f p_pos = m_base_position;
|
||||||
m_base_position += dtime * m_velocity + 0.5 * dtime
|
v3f p_velocity = m_velocity;
|
||||||
* dtime * m_acceleration;
|
v3f p_acceleration = m_acceleration;
|
||||||
m_velocity += dtime * m_acceleration;
|
IGameDef *gamedef = m_env->getGameDef();
|
||||||
|
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
|
||||||
|
pos_max_d, box, stepheight, dtime,
|
||||||
|
p_pos, p_velocity, p_acceleration);
|
||||||
|
// Apply results
|
||||||
|
m_base_position = p_pos;
|
||||||
|
m_velocity = p_velocity;
|
||||||
|
m_acceleration = p_acceleration;
|
||||||
|
} else {
|
||||||
|
m_base_position += dtime * m_velocity + 0.5 * dtime
|
||||||
|
* dtime * m_acceleration;
|
||||||
|
m_velocity += dtime * m_acceleration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_registered){
|
if(m_registered){
|
||||||
|
@ -473,20 +509,23 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||||
|
|
||||||
if(send_recommended == false)
|
if(send_recommended == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: force send when acceleration changes enough?
|
if(!isAttached())
|
||||||
float minchange = 0.2*BS;
|
{
|
||||||
if(m_last_sent_position_timer > 1.0){
|
// TODO: force send when acceleration changes enough?
|
||||||
minchange = 0.01*BS;
|
float minchange = 0.2*BS;
|
||||||
} else if(m_last_sent_position_timer > 0.2){
|
if(m_last_sent_position_timer > 1.0){
|
||||||
minchange = 0.05*BS;
|
minchange = 0.01*BS;
|
||||||
}
|
} else if(m_last_sent_position_timer > 0.2){
|
||||||
float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
|
minchange = 0.05*BS;
|
||||||
move_d += m_last_sent_move_precision;
|
}
|
||||||
float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
|
float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
|
||||||
if(move_d > minchange || vel_d > minchange ||
|
move_d += m_last_sent_move_precision;
|
||||||
fabs(m_yaw - m_last_sent_yaw) > 1.0){
|
float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
|
||||||
sendPosition(true, false);
|
if(move_d > minchange || vel_d > minchange ||
|
||||||
|
fabs(m_yaw - m_last_sent_yaw) > 1.0){
|
||||||
|
sendPosition(true, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_armor_groups_sent == false){
|
if(m_armor_groups_sent == false){
|
||||||
|
@ -497,6 +536,32 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||||
ActiveObjectMessage aom(getId(), true, str);
|
ActiveObjectMessage aom(getId(), true, str);
|
||||||
m_messages_out.push_back(aom);
|
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()
|
std::string LuaEntitySAO::getClientInitializationData()
|
||||||
|
@ -504,13 +569,21 @@ std::string LuaEntitySAO::getClientInitializationData()
|
||||||
std::ostringstream os(std::ios::binary);
|
std::ostringstream os(std::ios::binary);
|
||||||
writeU8(os, 0); // version
|
writeU8(os, 0); // version
|
||||||
os<<serializeString(""); // name
|
os<<serializeString(""); // name
|
||||||
|
writeS16(os, getId()); //id
|
||||||
writeU8(os, 0); // is_player
|
writeU8(os, 0); // is_player
|
||||||
writeV3F1000(os, m_base_position);
|
writeV3F1000(os, m_base_position);
|
||||||
writeF1000(os, m_yaw);
|
writeF1000(os, m_yaw);
|
||||||
writeS16(os, m_hp);
|
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(getPropertyPacket()); // message 1
|
||||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
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 result
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
@ -550,6 +623,10 @@ int LuaEntitySAO::punch(v3f dir,
|
||||||
m_removed = true;
|
m_removed = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It's best that attachments cannot be punched
|
||||||
|
if(isAttached())
|
||||||
|
return 0;
|
||||||
|
|
||||||
ItemStack *punchitem = NULL;
|
ItemStack *punchitem = NULL;
|
||||||
ItemStack punchitem_static;
|
ItemStack punchitem_static;
|
||||||
|
@ -594,18 +671,25 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
|
||||||
{
|
{
|
||||||
if(!m_registered)
|
if(!m_registered)
|
||||||
return;
|
return;
|
||||||
|
// It's best that attachments cannot be clicked
|
||||||
|
if(isAttached())
|
||||||
|
return;
|
||||||
lua_State *L = m_env->getLua();
|
lua_State *L = m_env->getLua();
|
||||||
scriptapi_luaentity_rightclick(L, m_id, clicker);
|
scriptapi_luaentity_rightclick(L, m_id, clicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaEntitySAO::setPos(v3f pos)
|
void LuaEntitySAO::setPos(v3f pos)
|
||||||
{
|
{
|
||||||
|
if(isAttached())
|
||||||
|
return;
|
||||||
m_base_position = pos;
|
m_base_position = pos;
|
||||||
sendPosition(false, true);
|
sendPosition(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaEntitySAO::moveTo(v3f pos, bool continuous)
|
void LuaEntitySAO::moveTo(v3f pos, bool continuous)
|
||||||
{
|
{
|
||||||
|
if(isAttached())
|
||||||
|
return;
|
||||||
m_base_position = pos;
|
m_base_position = pos;
|
||||||
if(!continuous)
|
if(!continuous)
|
||||||
sendPosition(true, true);
|
sendPosition(true, true);
|
||||||
|
@ -644,6 +728,37 @@ void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
|
||||||
m_armor_groups_sent = false;
|
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()
|
ObjectProperties* LuaEntitySAO::accessObjectProperties()
|
||||||
{
|
{
|
||||||
return &m_prop;
|
return &m_prop;
|
||||||
|
@ -718,6 +833,10 @@ std::string LuaEntitySAO::getPropertyPacket()
|
||||||
|
|
||||||
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
|
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_move_precision = m_base_position.getDistanceFrom(
|
||||||
m_last_sent_position);
|
m_last_sent_position);
|
||||||
m_last_sent_position_timer = 0;
|
m_last_sent_position_timer = 0;
|
||||||
|
@ -765,8 +884,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
|
||||||
m_properties_sent(true),
|
m_properties_sent(true),
|
||||||
m_privs(privs),
|
m_privs(privs),
|
||||||
m_is_singleplayer(is_singleplayer),
|
m_is_singleplayer(is_singleplayer),
|
||||||
|
m_animation_sent(false),
|
||||||
|
m_bone_position_sent(false),
|
||||||
|
m_attachment_sent(false),
|
||||||
// public
|
// public
|
||||||
m_teleported(false),
|
m_moved(false),
|
||||||
m_inventory_not_sent(false),
|
m_inventory_not_sent(false),
|
||||||
m_hp_not_sent(false),
|
m_hp_not_sent(false),
|
||||||
m_wielded_item_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.physical = false;
|
||||||
m_prop.weight = 75;
|
m_prop.weight = 75;
|
||||||
m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
|
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 = "upright_sprite";
|
||||||
m_prop.visual_size = v2f(1, 2);
|
m_prop.visual_size = v2f(1, 2);
|
||||||
m_prop.textures.clear();
|
m_prop.textures.clear();
|
||||||
m_prop.textures.push_back("player.png");
|
m_prop.textures.push_back("player.png");
|
||||||
m_prop.textures.push_back("player_back.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.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;
|
m_prop.makes_footstep_sound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,12 +968,21 @@ std::string PlayerSAO::getClientInitializationData()
|
||||||
writeU8(os, 0); // version
|
writeU8(os, 0); // version
|
||||||
os<<serializeString(m_player->getName()); // name
|
os<<serializeString(m_player->getName()); // name
|
||||||
writeU8(os, 1); // is_player
|
writeU8(os, 1); // is_player
|
||||||
|
writeS16(os, getId()); //id
|
||||||
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
|
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
|
||||||
writeF1000(os, m_player->getYaw());
|
writeF1000(os, m_player->getYaw());
|
||||||
writeS16(os, getHP());
|
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(getPropertyPacket()); // message 1
|
||||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
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();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,6 +992,17 @@ std::string PlayerSAO::getStaticData()
|
||||||
return "";
|
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)
|
void PlayerSAO::step(float dtime, bool send_recommended)
|
||||||
{
|
{
|
||||||
if(!m_properties_sent)
|
if(!m_properties_sent)
|
||||||
|
@ -868,73 +1014,102 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
||||||
m_messages_out.push_back(aom);
|
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_time_from_last_punch += dtime;
|
||||||
m_nocheat_dig_time += dtime;
|
m_nocheat_dig_time += dtime;
|
||||||
|
|
||||||
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
|
// 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())
|
||||||
{
|
{
|
||||||
m_last_good_position = m_player->getPosition();
|
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||||
|
m_last_good_position = pos;
|
||||||
m_last_good_position_age = 0;
|
m_last_good_position_age = 0;
|
||||||
|
m_player->setPosition(pos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
|
||||||
Check player movements
|
{
|
||||||
|
m_last_good_position = m_player->getPosition();
|
||||||
NOTE: Actually the server should handle player physics like the
|
|
||||||
client does and compare player's position to what is calculated
|
|
||||||
on our side. This is required when eg. players fly due to an
|
|
||||||
explosion. Altough a node-based alternative might be possible
|
|
||||||
too, and much more lightweight.
|
|
||||||
*/
|
|
||||||
|
|
||||||
float player_max_speed = 0;
|
|
||||||
float player_max_speed_up = 0;
|
|
||||||
if(m_privs.count("fast") != 0){
|
|
||||||
// Fast speed
|
|
||||||
player_max_speed = BS * 20;
|
|
||||||
player_max_speed_up = BS * 20;
|
|
||||||
} else {
|
|
||||||
// Normal speed
|
|
||||||
player_max_speed = BS * 4.0;
|
|
||||||
player_max_speed_up = BS * 4.0;
|
|
||||||
}
|
|
||||||
// Tolerance
|
|
||||||
player_max_speed *= 2.5;
|
|
||||||
player_max_speed_up *= 2.5;
|
|
||||||
|
|
||||||
m_last_good_position_age += dtime;
|
|
||||||
if(m_last_good_position_age >= 1.0){
|
|
||||||
float age = m_last_good_position_age;
|
|
||||||
v3f diff = (m_player->getPosition() - m_last_good_position);
|
|
||||||
float d_vert = diff.Y;
|
|
||||||
diff.Y = 0;
|
|
||||||
float d_horiz = diff.getLength();
|
|
||||||
/*infostream<<m_player->getName()<<"'s horizontal speed is "
|
|
||||||
<<(d_horiz/age)<<std::endl;*/
|
|
||||||
if(d_horiz <= age * player_max_speed &&
|
|
||||||
(d_vert < 0 || d_vert < age * player_max_speed_up)){
|
|
||||||
m_last_good_position = m_player->getPosition();
|
|
||||||
} else {
|
|
||||||
actionstream<<"Player "<<m_player->getName()
|
|
||||||
<<" moved too fast; resetting position"
|
|
||||||
<<std::endl;
|
|
||||||
m_player->setPosition(m_last_good_position);
|
|
||||||
m_teleported = true;
|
|
||||||
}
|
|
||||||
m_last_good_position_age = 0;
|
m_last_good_position_age = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Check player movements
|
||||||
|
|
||||||
|
NOTE: Actually the server should handle player physics like the
|
||||||
|
client does and compare player's position to what is calculated
|
||||||
|
on our side. This is required when eg. players fly due to an
|
||||||
|
explosion. Altough a node-based alternative might be possible
|
||||||
|
too, and much more lightweight.
|
||||||
|
*/
|
||||||
|
|
||||||
|
float player_max_speed = 0;
|
||||||
|
float player_max_speed_up = 0;
|
||||||
|
if(m_privs.count("fast") != 0){
|
||||||
|
// Fast speed
|
||||||
|
player_max_speed = BS * 20;
|
||||||
|
player_max_speed_up = BS * 20;
|
||||||
|
} else {
|
||||||
|
// Normal speed
|
||||||
|
player_max_speed = BS * 4.0;
|
||||||
|
player_max_speed_up = BS * 4.0;
|
||||||
|
}
|
||||||
|
// Tolerance
|
||||||
|
player_max_speed *= 2.5;
|
||||||
|
player_max_speed_up *= 2.5;
|
||||||
|
|
||||||
|
m_last_good_position_age += dtime;
|
||||||
|
if(m_last_good_position_age >= 1.0){
|
||||||
|
float age = m_last_good_position_age;
|
||||||
|
v3f diff = (m_player->getPosition() - m_last_good_position);
|
||||||
|
float d_vert = diff.Y;
|
||||||
|
diff.Y = 0;
|
||||||
|
float d_horiz = diff.getLength();
|
||||||
|
/*infostream<<m_player->getName()<<"'s horizontal speed is "
|
||||||
|
<<(d_horiz/age)<<std::endl;*/
|
||||||
|
if(d_horiz <= age * player_max_speed &&
|
||||||
|
(d_vert < 0 || d_vert < age * player_max_speed_up)){
|
||||||
|
m_last_good_position = m_player->getPosition();
|
||||||
|
} else {
|
||||||
|
actionstream<<"Player "<<m_player->getName()
|
||||||
|
<<" moved too fast; resetting position"
|
||||||
|
<<std::endl;
|
||||||
|
m_player->setPosition(m_last_good_position);
|
||||||
|
m_moved = true;
|
||||||
|
}
|
||||||
|
m_last_good_position_age = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(send_recommended == false)
|
if(send_recommended == false)
|
||||||
return;
|
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;
|
m_position_not_sent = false;
|
||||||
float update_interval = m_env->getSendRecommendedInterval();
|
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(
|
std::string str = gob_cmd_update_position(
|
||||||
m_player->getPosition() + v3f(0,BS*1,0),
|
pos,
|
||||||
v3f(0,0,0),
|
v3f(0,0,0),
|
||||||
v3f(0,0,0),
|
v3f(0,0,0),
|
||||||
m_player->getYaw(),
|
m_player->getYaw(),
|
||||||
|
@ -961,32 +1136,63 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
||||||
ActiveObjectMessage aom(getId(), true, str);
|
ActiveObjectMessage aom(getId(), true, str);
|
||||||
m_messages_out.push_back(aom);
|
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)
|
void PlayerSAO::setBasePosition(const v3f &position)
|
||||||
{
|
{
|
||||||
|
// This needs to be ran for attachments too
|
||||||
ServerActiveObject::setBasePosition(position);
|
ServerActiveObject::setBasePosition(position);
|
||||||
m_position_not_sent = true;
|
m_position_not_sent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerSAO::setPos(v3f pos)
|
void PlayerSAO::setPos(v3f pos)
|
||||||
{
|
{
|
||||||
|
if(isAttached())
|
||||||
|
return;
|
||||||
m_player->setPosition(pos);
|
m_player->setPosition(pos);
|
||||||
// Movement caused by this command is always valid
|
// Movement caused by this command is always valid
|
||||||
m_last_good_position = pos;
|
m_last_good_position = pos;
|
||||||
m_last_good_position_age = 0;
|
m_last_good_position_age = 0;
|
||||||
// Force position change on client
|
// Force position change on client
|
||||||
m_teleported = true;
|
m_moved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerSAO::moveTo(v3f pos, bool continuous)
|
void PlayerSAO::moveTo(v3f pos, bool continuous)
|
||||||
{
|
{
|
||||||
|
if(isAttached())
|
||||||
|
return;
|
||||||
m_player->setPosition(pos);
|
m_player->setPosition(pos);
|
||||||
// Movement caused by this command is always valid
|
// Movement caused by this command is always valid
|
||||||
m_last_good_position = pos;
|
m_last_good_position = pos;
|
||||||
m_last_good_position_age = 0;
|
m_last_good_position_age = 0;
|
||||||
// Force position change on client
|
// Force position change on client
|
||||||
m_teleported = true;
|
m_moved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlayerSAO::punch(v3f dir,
|
int PlayerSAO::punch(v3f dir,
|
||||||
|
@ -994,6 +1200,10 @@ int PlayerSAO::punch(v3f dir,
|
||||||
ServerActiveObject *puncher,
|
ServerActiveObject *puncher,
|
||||||
float time_from_last_punch)
|
float time_from_last_punch)
|
||||||
{
|
{
|
||||||
|
// It's best that attachments cannot be punched
|
||||||
|
if(isAttached())
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(!toolcap)
|
if(!toolcap)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1075,6 +1285,39 @@ void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
|
||||||
m_armor_groups_sent = false;
|
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()
|
ObjectProperties* PlayerSAO::accessObjectProperties()
|
||||||
{
|
{
|
||||||
return &m_prop;
|
return &m_prop;
|
||||||
|
@ -1138,7 +1381,7 @@ void PlayerSAO::disconnected()
|
||||||
|
|
||||||
std::string PlayerSAO::getPropertyPacket()
|
std::string PlayerSAO::getPropertyPacket()
|
||||||
{
|
{
|
||||||
m_prop.is_visible = (getHP() != 0);
|
m_prop.is_visible = (true);
|
||||||
return gob_cmd_set_properties(m_prop);
|
return gob_cmd_set_properties(m_prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
virtual void addedToEnvironment(u32 dtime_s);
|
virtual void addedToEnvironment(u32 dtime_s);
|
||||||
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
|
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
|
||||||
const std::string &data);
|
const std::string &data);
|
||||||
|
bool isAttached();
|
||||||
void step(float dtime, bool send_recommended);
|
void step(float dtime, bool send_recommended);
|
||||||
std::string getClientInitializationData();
|
std::string getClientInitializationData();
|
||||||
std::string getStaticData();
|
std::string getStaticData();
|
||||||
|
@ -61,6 +62,9 @@ public:
|
||||||
void setHP(s16 hp);
|
void setHP(s16 hp);
|
||||||
s16 getHP() const;
|
s16 getHP() const;
|
||||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
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();
|
ObjectProperties* accessObjectProperties();
|
||||||
void notifyObjectPropertiesModified();
|
void notifyObjectPropertiesModified();
|
||||||
/* LuaEntitySAO-specific */
|
/* LuaEntitySAO-specific */
|
||||||
|
@ -96,6 +100,20 @@ private:
|
||||||
float m_last_sent_position_timer;
|
float m_last_sent_position_timer;
|
||||||
float m_last_sent_move_precision;
|
float m_last_sent_move_precision;
|
||||||
bool m_armor_groups_sent;
|
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;
|
bool unlimitedTransferDistance() const;
|
||||||
std::string getClientInitializationData();
|
std::string getClientInitializationData();
|
||||||
std::string getStaticData();
|
std::string getStaticData();
|
||||||
|
bool isAttached();
|
||||||
void step(float dtime, bool send_recommended);
|
void step(float dtime, bool send_recommended);
|
||||||
void setBasePosition(const v3f &position);
|
void setBasePosition(const v3f &position);
|
||||||
void setPos(v3f pos);
|
void setPos(v3f pos);
|
||||||
|
@ -142,6 +161,9 @@ public:
|
||||||
void setHP(s16 hp);
|
void setHP(s16 hp);
|
||||||
|
|
||||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
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();
|
ObjectProperties* accessObjectProperties();
|
||||||
void notifyObjectPropertiesModified();
|
void notifyObjectPropertiesModified();
|
||||||
|
|
||||||
|
@ -229,15 +251,32 @@ private:
|
||||||
bool m_position_not_sent;
|
bool m_position_not_sent;
|
||||||
ItemGroupList m_armor_groups;
|
ItemGroupList m_armor_groups;
|
||||||
bool m_armor_groups_sent;
|
bool m_armor_groups_sent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool m_properties_sent;
|
bool m_properties_sent;
|
||||||
struct ObjectProperties m_prop;
|
struct ObjectProperties m_prop;
|
||||||
// Cached privileges for enforcement
|
// Cached privileges for enforcement
|
||||||
std::set<std::string> m_privs;
|
std::set<std::string> m_privs;
|
||||||
bool m_is_singleplayer;
|
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:
|
public:
|
||||||
// Some flags used by Server
|
// Some flags used by Server
|
||||||
bool m_teleported;
|
bool m_moved;
|
||||||
bool m_inventory_not_sent;
|
bool m_inventory_not_sent;
|
||||||
bool m_hp_not_sent;
|
bool m_hp_not_sent;
|
||||||
bool m_wielded_item_not_sent;
|
bool m_wielded_item_not_sent;
|
||||||
|
|
|
@ -2315,7 +2315,7 @@ void ClientEnvironment::removeActiveObject(u16 id)
|
||||||
<<"id="<<id<<" not found"<<std::endl;
|
<<"id="<<id<<" not found"<<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
obj->removeFromScene();
|
obj->removeFromScene(true);
|
||||||
delete obj;
|
delete obj;
|
||||||
m_active_objects.remove(id);
|
m_active_objects.remove(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,6 +463,8 @@ public:
|
||||||
|
|
||||||
// Get event from queue. CEE_NONE is returned if queue is empty.
|
// Get event from queue. CEE_NONE is returned if queue is empty.
|
||||||
ClientEnvEvent getClientEvent();
|
ClientEnvEvent getClientEvent();
|
||||||
|
|
||||||
|
std::vector<core::vector2d<int> > attachment_list; // X is child ID, Y is parent ID
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClientMap *m_map;
|
ClientMap *m_map;
|
||||||
|
|
16
src/game.cpp
16
src/game.cpp
|
@ -1881,6 +1881,8 @@ void the_game(
|
||||||
bool a_jump,
|
bool a_jump,
|
||||||
bool a_superspeed,
|
bool a_superspeed,
|
||||||
bool a_sneak,
|
bool a_sneak,
|
||||||
|
bool a_LMB,
|
||||||
|
bool a_RMB,
|
||||||
float a_pitch,
|
float a_pitch,
|
||||||
float a_yaw*/
|
float a_yaw*/
|
||||||
PlayerControl control(
|
PlayerControl control(
|
||||||
|
@ -1891,10 +1893,24 @@ void the_game(
|
||||||
input->isKeyDown(getKeySetting("keymap_jump")),
|
input->isKeyDown(getKeySetting("keymap_jump")),
|
||||||
input->isKeyDown(getKeySetting("keymap_special1")),
|
input->isKeyDown(getKeySetting("keymap_special1")),
|
||||||
input->isKeyDown(getKeySetting("keymap_sneak")),
|
input->isKeyDown(getKeySetting("keymap_sneak")),
|
||||||
|
input->getLeftState(),
|
||||||
|
input->getRightState(),
|
||||||
camera_pitch,
|
camera_pitch,
|
||||||
camera_yaw
|
camera_yaw
|
||||||
);
|
);
|
||||||
client.setPlayerControl(control);
|
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();
|
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::string gob_cmd_punched(s16 damage, s16 result_hp)
|
||||||
{
|
{
|
||||||
std::ostringstream os(std::ios::binary);
|
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_UPDATE_POSITION 1
|
||||||
#define GENERIC_CMD_SET_TEXTURE_MOD 2
|
#define GENERIC_CMD_SET_TEXTURE_MOD 2
|
||||||
#define GENERIC_CMD_SET_SPRITE 3
|
#define GENERIC_CMD_SET_SPRITE 3
|
||||||
#define GENERIC_CMD_PUNCHED 4
|
#define GENERIC_CMD_SET_ANIMATION 4
|
||||||
#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 5
|
#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"
|
#include "object_properties.h"
|
||||||
std::string gob_cmd_set_properties(const ObjectProperties &prop);
|
std::string gob_cmd_set_properties(const ObjectProperties &prop);
|
||||||
|
@ -54,6 +57,12 @@ std::string gob_cmd_set_sprite(
|
||||||
bool select_horiz_by_yawpitch
|
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);
|
std::string gob_cmd_punched(s16 damage, s16 result_hp);
|
||||||
|
|
||||||
#include "itemgroup.h"
|
#include "itemgroup.h"
|
||||||
|
|
|
@ -199,6 +199,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||||
|
|
||||||
m_inventorylists.clear();
|
m_inventorylists.clear();
|
||||||
m_images.clear();
|
m_images.clear();
|
||||||
|
m_backgrounds.clear();
|
||||||
m_fields.clear();
|
m_fields.clear();
|
||||||
|
|
||||||
Strfnd f(m_formspec_string);
|
Strfnd f(m_formspec_string);
|
||||||
|
@ -278,9 +279,26 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
if(bp_set != 2)
|
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));
|
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")
|
else if(type == "field")
|
||||||
{
|
{
|
||||||
std::string fname = f.next(";");
|
std::string fname = f.next(";");
|
||||||
|
@ -458,6 +476,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||||
|
|
||||||
video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
|
video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
|
||||||
gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
|
gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
|
||||||
|
e->setUseAlphaChannel(true);
|
||||||
e->setImage(texture);
|
e->setImage(texture);
|
||||||
e->setPressedImage(texture);
|
e->setPressedImage(texture);
|
||||||
e->setScaleImage(true);
|
e->setScaleImage(true);
|
||||||
|
@ -691,6 +710,26 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
|
|
||||||
m_tooltip_element->setVisible(false);
|
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
|
Draw images
|
||||||
*/
|
*/
|
||||||
|
@ -715,8 +754,11 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
Draw items
|
Draw items
|
||||||
Phase 0: Item slot rectangles
|
Phase 0: Item slot rectangles
|
||||||
Phase 1: Item images; prepare tooltip
|
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++)
|
for(u32 i=0; i<m_inventorylists.size(); i++)
|
||||||
{
|
{
|
||||||
drawList(m_inventorylists[i], phase);
|
drawList(m_inventorylists[i], phase);
|
||||||
|
|
|
@ -206,6 +206,7 @@ protected:
|
||||||
TextDest *m_text_dst;
|
TextDest *m_text_dst;
|
||||||
|
|
||||||
core::array<ListDrawSpec> m_inventorylists;
|
core::array<ListDrawSpec> m_inventorylists;
|
||||||
|
core::array<ImageDrawSpec> m_backgrounds;
|
||||||
core::array<ImageDrawSpec> m_images;
|
core::array<ImageDrawSpec> m_images;
|
||||||
core::array<FieldSpec> m_fields;
|
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):
|
LocalPlayer::LocalPlayer(IGameDef *gamedef):
|
||||||
Player(gamedef),
|
Player(gamedef),
|
||||||
|
isAttached(false),
|
||||||
|
overridePosition(v3f(0,0,0)),
|
||||||
m_sneak_node(32767,32767,32767),
|
m_sneak_node(32767,32767,32767),
|
||||||
m_sneak_node_exists(false),
|
m_sneak_node_exists(false),
|
||||||
m_old_node_below(32767,32767,32767),
|
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;
|
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
|
// Skip collision detection if a special movement mode is used
|
||||||
bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
|
bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
|
||||||
bool free_move = fly_allowed && g_settings->getBool("free_move");
|
bool free_move = fly_allowed && g_settings->getBool("free_move");
|
||||||
|
@ -352,7 +361,14 @@ void LocalPlayer::applyControl(float dtime)
|
||||||
|
|
||||||
setPitch(control.pitch);
|
setPitch(control.pitch);
|
||||||
setYaw(control.yaw);
|
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);
|
v3f move_direction = v3f(0,0,1);
|
||||||
move_direction.rotateXZBy(getYaw());
|
move_direction.rotateXZBy(getYaw());
|
||||||
|
|
||||||
|
|
|
@ -22,53 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
#include "player.h"
|
#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
|
class LocalPlayer : public Player
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -79,6 +32,10 @@ public:
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isAttached;
|
||||||
|
|
||||||
|
v3f overridePosition;
|
||||||
|
|
||||||
void move(f32 dtime, Map &map, f32 pos_max_d,
|
void move(f32 dtime, Map &map, f32 pos_max_d,
|
||||||
core::list<CollisionInfo> *collision_info);
|
core::list<CollisionInfo> *collision_info);
|
||||||
|
@ -87,9 +44,6 @@ public:
|
||||||
void applyControl(float dtime);
|
void applyControl(float dtime);
|
||||||
|
|
||||||
v3s16 getStandingNodePos();
|
v3s16 getStandingNodePos();
|
||||||
|
|
||||||
PlayerControl control;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This is used for determining the sneaking range
|
// This is used for determining the sneaking range
|
||||||
v3s16 m_sneak_node;
|
v3s16 m_sneak_node;
|
||||||
|
|
|
@ -132,7 +132,8 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
|
||||||
for(s16 ii=0; ii<trunk_h; ii++)
|
for(s16 ii=0; ii<trunk_h; ii++)
|
||||||
{
|
{
|
||||||
if(vmanip.m_area.contains(p1))
|
if(vmanip.m_area.contains(p1))
|
||||||
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
|
if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
|
||||||
|
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
|
||||||
p1.Y++;
|
p1.Y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -433,9 +433,6 @@ video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create render target texture
|
// Create render target texture
|
||||||
video::ITexture *oldtexture = driver->findTexture(texture_name.c_str());
|
|
||||||
if(oldtexture)
|
|
||||||
driver->removeTexture(oldtexture);
|
|
||||||
video::ITexture *rtt = driver->addRenderTargetTexture(
|
video::ITexture *rtt = driver->addRenderTargetTexture(
|
||||||
dim, texture_name.c_str(), video::ECF_A8R8G8B8);
|
dim, texture_name.c_str(), video::ECF_A8R8G8B8);
|
||||||
if(rtt == NULL)
|
if(rtt == NULL)
|
||||||
|
|
|
@ -217,7 +217,7 @@ void ContentFeatures::reset()
|
||||||
|
|
||||||
void ContentFeatures::serialize(std::ostream &os)
|
void ContentFeatures::serialize(std::ostream &os)
|
||||||
{
|
{
|
||||||
writeU8(os, 5); // version
|
writeU8(os, 6); // version
|
||||||
os<<serializeString(name);
|
os<<serializeString(name);
|
||||||
writeU16(os, groups.size());
|
writeU16(os, groups.size());
|
||||||
for(ItemGroupList::const_iterator
|
for(ItemGroupList::const_iterator
|
||||||
|
@ -254,6 +254,7 @@ void ContentFeatures::serialize(std::ostream &os)
|
||||||
os<<serializeString(liquid_alternative_flowing);
|
os<<serializeString(liquid_alternative_flowing);
|
||||||
os<<serializeString(liquid_alternative_source);
|
os<<serializeString(liquid_alternative_source);
|
||||||
writeU8(os, liquid_viscosity);
|
writeU8(os, liquid_viscosity);
|
||||||
|
writeU8(os, liquid_renewable);
|
||||||
writeU8(os, light_source);
|
writeU8(os, light_source);
|
||||||
writeU32(os, damage_per_second);
|
writeU32(os, damage_per_second);
|
||||||
node_box.serialize(os);
|
node_box.serialize(os);
|
||||||
|
@ -265,13 +266,12 @@ void ContentFeatures::serialize(std::ostream &os)
|
||||||
serializeSimpleSoundSpec(sound_dug, os);
|
serializeSimpleSoundSpec(sound_dug, os);
|
||||||
// Stuff below should be moved to correct place in a version that otherwise changes
|
// Stuff below should be moved to correct place in a version that otherwise changes
|
||||||
// the protocol version
|
// the protocol version
|
||||||
writeU8(os, liquid_renewable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentFeatures::deSerialize(std::istream &is)
|
void ContentFeatures::deSerialize(std::istream &is)
|
||||||
{
|
{
|
||||||
int version = readU8(is);
|
int version = readU8(is);
|
||||||
if(version != 5)
|
if(version != 6)
|
||||||
throw SerializationError("unsupported ContentFeatures version");
|
throw SerializationError("unsupported ContentFeatures version");
|
||||||
name = deSerializeString(is);
|
name = deSerializeString(is);
|
||||||
groups.clear();
|
groups.clear();
|
||||||
|
@ -311,6 +311,7 @@ void ContentFeatures::deSerialize(std::istream &is)
|
||||||
liquid_alternative_flowing = deSerializeString(is);
|
liquid_alternative_flowing = deSerializeString(is);
|
||||||
liquid_alternative_source = deSerializeString(is);
|
liquid_alternative_source = deSerializeString(is);
|
||||||
liquid_viscosity = readU8(is);
|
liquid_viscosity = readU8(is);
|
||||||
|
liquid_renewable = readU8(is);
|
||||||
light_source = readU8(is);
|
light_source = readU8(is);
|
||||||
damage_per_second = readU32(is);
|
damage_per_second = readU32(is);
|
||||||
node_box.deSerialize(is);
|
node_box.deSerialize(is);
|
||||||
|
@ -325,7 +326,6 @@ void ContentFeatures::deSerialize(std::istream &is)
|
||||||
try{
|
try{
|
||||||
// Stuff below should be moved to correct place in a version that
|
// Stuff below should be moved to correct place in a version that
|
||||||
// otherwise changes the protocol version
|
// otherwise changes the protocol version
|
||||||
liquid_renewable = readU8(is);
|
|
||||||
}catch(SerializationError &e) {};
|
}catch(SerializationError &e) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "object_properties.h"
|
#include "object_properties.h"
|
||||||
|
#include "irrlichttypes_bloated.h"
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||||
#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
|
#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
|
||||||
|
@ -30,6 +32,7 @@ ObjectProperties::ObjectProperties():
|
||||||
weight(5),
|
weight(5),
|
||||||
collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
|
collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
|
||||||
visual("sprite"),
|
visual("sprite"),
|
||||||
|
mesh(""),
|
||||||
visual_size(1,1),
|
visual_size(1,1),
|
||||||
spritediv(1,1),
|
spritediv(1,1),
|
||||||
initial_sprite_basepos(0,0),
|
initial_sprite_basepos(0,0),
|
||||||
|
@ -38,6 +41,7 @@ ObjectProperties::ObjectProperties():
|
||||||
automatic_rotate(0)
|
automatic_rotate(0)
|
||||||
{
|
{
|
||||||
textures.push_back("unknown_object.png");
|
textures.push_back("unknown_object.png");
|
||||||
|
colors.push_back(video::SColor(255,255,255,255));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ObjectProperties::dump()
|
std::string ObjectProperties::dump()
|
||||||
|
@ -48,12 +52,18 @@ std::string ObjectProperties::dump()
|
||||||
os<<", weight="<<weight;
|
os<<", weight="<<weight;
|
||||||
os<<", collisionbox="<<PP(collisionbox.MinEdge)<<","<<PP(collisionbox.MaxEdge);
|
os<<", collisionbox="<<PP(collisionbox.MinEdge)<<","<<PP(collisionbox.MaxEdge);
|
||||||
os<<", visual="<<visual;
|
os<<", visual="<<visual;
|
||||||
|
os<<", mesh="<<mesh;
|
||||||
os<<", visual_size="<<PP2(visual_size);
|
os<<", visual_size="<<PP2(visual_size);
|
||||||
os<<", textures=[";
|
os<<", textures=[";
|
||||||
for(u32 i=0; i<textures.size(); i++){
|
for(u32 i=0; i<textures.size(); i++){
|
||||||
os<<"\""<<textures[i]<<"\" ";
|
os<<"\""<<textures[i]<<"\" ";
|
||||||
}
|
}
|
||||||
os<<"]";
|
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<<", spritediv="<<PP2(spritediv);
|
||||||
os<<", initial_sprite_basepos="<<PP2(initial_sprite_basepos);
|
os<<", initial_sprite_basepos="<<PP2(initial_sprite_basepos);
|
||||||
os<<", is_visible="<<is_visible;
|
os<<", is_visible="<<is_visible;
|
||||||
|
@ -71,11 +81,16 @@ void ObjectProperties::serialize(std::ostream &os) const
|
||||||
writeV3F1000(os, collisionbox.MinEdge);
|
writeV3F1000(os, collisionbox.MinEdge);
|
||||||
writeV3F1000(os, collisionbox.MaxEdge);
|
writeV3F1000(os, collisionbox.MaxEdge);
|
||||||
os<<serializeString(visual);
|
os<<serializeString(visual);
|
||||||
|
os<<serializeString(mesh);
|
||||||
writeV2F1000(os, visual_size);
|
writeV2F1000(os, visual_size);
|
||||||
writeU16(os, textures.size());
|
writeU16(os, textures.size());
|
||||||
for(u32 i=0; i<textures.size(); i++){
|
for(u32 i=0; i<textures.size(); i++){
|
||||||
os<<serializeString(textures[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, spritediv);
|
||||||
writeV2S16(os, initial_sprite_basepos);
|
writeV2S16(os, initial_sprite_basepos);
|
||||||
writeU8(os, is_visible);
|
writeU8(os, is_visible);
|
||||||
|
@ -94,12 +109,17 @@ void ObjectProperties::deSerialize(std::istream &is)
|
||||||
collisionbox.MinEdge = readV3F1000(is);
|
collisionbox.MinEdge = readV3F1000(is);
|
||||||
collisionbox.MaxEdge = readV3F1000(is);
|
collisionbox.MaxEdge = readV3F1000(is);
|
||||||
visual = deSerializeString(is);
|
visual = deSerializeString(is);
|
||||||
|
mesh = deSerializeString(is);
|
||||||
visual_size = readV2F1000(is);
|
visual_size = readV2F1000(is);
|
||||||
textures.clear();
|
textures.clear();
|
||||||
u32 texture_count = readU16(is);
|
u32 texture_count = readU16(is);
|
||||||
for(u32 i=0; i<texture_count; i++){
|
for(u32 i=0; i<texture_count; i++){
|
||||||
textures.push_back(deSerializeString(is));
|
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);
|
spritediv = readV2S16(is);
|
||||||
initial_sprite_basepos = readV2S16(is);
|
initial_sprite_basepos = readV2S16(is);
|
||||||
is_visible = readU8(is);
|
is_visible = readU8(is);
|
||||||
|
|
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
struct ObjectProperties
|
struct ObjectProperties
|
||||||
{
|
{
|
||||||
|
@ -32,14 +33,17 @@ struct ObjectProperties
|
||||||
float weight;
|
float weight;
|
||||||
core::aabbox3d<f32> collisionbox;
|
core::aabbox3d<f32> collisionbox;
|
||||||
std::string visual;
|
std::string visual;
|
||||||
|
std::string mesh;
|
||||||
v2f visual_size;
|
v2f visual_size;
|
||||||
core::array<std::string> textures;
|
core::array<std::string> textures;
|
||||||
|
core::array<video::SColor> colors;
|
||||||
v2s16 spritediv;
|
v2s16 spritediv;
|
||||||
v2s16 initial_sprite_basepos;
|
v2s16 initial_sprite_basepos;
|
||||||
bool is_visible;
|
bool is_visible;
|
||||||
bool makes_footstep_sound;
|
bool makes_footstep_sound;
|
||||||
float automatic_rotate;
|
float automatic_rotate;
|
||||||
|
|
||||||
|
|
||||||
ObjectProperties();
|
ObjectProperties();
|
||||||
std::string dump();
|
std::string dump();
|
||||||
void serialize(std::ostream &os) const;
|
void serialize(std::ostream &os) const;
|
||||||
|
|
69
src/player.h
69
src/player.h
|
@ -28,6 +28,61 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
#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 Map;
|
||||||
class IGameDef;
|
class IGameDef;
|
||||||
struct CollisionInfo;
|
struct CollisionInfo;
|
||||||
|
@ -155,9 +210,17 @@ public:
|
||||||
u16 hp;
|
u16 hp;
|
||||||
|
|
||||||
u16 peer_id;
|
u16 peer_id;
|
||||||
|
|
||||||
std::string inventory_formspec;
|
std::string inventory_formspec;
|
||||||
|
|
||||||
|
PlayerControl control;
|
||||||
|
PlayerControl getPlayerControl()
|
||||||
|
{
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 keyPressed;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
IGameDef *m_gamedef;
|
IGameDef *m_gamedef;
|
||||||
|
|
||||||
|
@ -182,7 +245,7 @@ public:
|
||||||
void setPlayerSAO(PlayerSAO *sao)
|
void setPlayerSAO(PlayerSAO *sao)
|
||||||
{ m_sao = sao; }
|
{ m_sao = sao; }
|
||||||
void setPosition(const v3f &position);
|
void setPosition(const v3f &position);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PlayerSAO *m_sao;
|
PlayerSAO *m_sao;
|
||||||
};
|
};
|
||||||
|
|
|
@ -936,6 +936,8 @@ static void read_object_properties(lua_State *L, int index,
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
getstringfield(L, -1, "visual", prop->visual);
|
getstringfield(L, -1, "visual", prop->visual);
|
||||||
|
|
||||||
|
getstringfield(L, -1, "mesh", prop->mesh);
|
||||||
|
|
||||||
lua_getfield(L, -1, "visual_size");
|
lua_getfield(L, -1, "visual_size");
|
||||||
if(lua_istable(L, -1))
|
if(lua_istable(L, -1))
|
||||||
|
@ -958,6 +960,23 @@ static void read_object_properties(lua_State *L, int index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
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");
|
lua_getfield(L, -1, "spritediv");
|
||||||
if(lua_istable(L, -1))
|
if(lua_istable(L, -1))
|
||||||
|
@ -2697,6 +2716,80 @@ private:
|
||||||
return 0;
|
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)
|
// set_properties(self, properties)
|
||||||
static int l_set_properties(lua_State *L)
|
static int l_set_properties(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -2932,7 +3025,54 @@ private:
|
||||||
lua_pushlstring(L, formspec.c_str(), formspec.size());
|
lua_pushlstring(L, formspec.c_str(), formspec.size());
|
||||||
return 1;
|
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:
|
public:
|
||||||
ObjectRef(ServerActiveObject *object):
|
ObjectRef(ServerActiveObject *object):
|
||||||
m_object(object)
|
m_object(object)
|
||||||
|
@ -3011,6 +3151,10 @@ const luaL_reg ObjectRef::methods[] = {
|
||||||
method(ObjectRef, get_wielded_item),
|
method(ObjectRef, get_wielded_item),
|
||||||
method(ObjectRef, set_wielded_item),
|
method(ObjectRef, set_wielded_item),
|
||||||
method(ObjectRef, set_armor_groups),
|
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),
|
method(ObjectRef, set_properties),
|
||||||
// LuaEntitySAO-only
|
// LuaEntitySAO-only
|
||||||
method(ObjectRef, setvelocity),
|
method(ObjectRef, setvelocity),
|
||||||
|
@ -3031,6 +3175,8 @@ const luaL_reg ObjectRef::methods[] = {
|
||||||
method(ObjectRef, get_look_yaw),
|
method(ObjectRef, get_look_yaw),
|
||||||
method(ObjectRef, set_inventory_formspec),
|
method(ObjectRef, set_inventory_formspec),
|
||||||
method(ObjectRef, get_inventory_formspec),
|
method(ObjectRef, get_inventory_formspec),
|
||||||
|
method(ObjectRef, get_player_control),
|
||||||
|
method(ObjectRef, get_player_control_bits),
|
||||||
{0,0}
|
{0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6588,6 +6734,8 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
getstringfield(L, -1, "visual", prop->visual);
|
getstringfield(L, -1, "visual", prop->visual);
|
||||||
|
|
||||||
|
getstringfield(L, -1, "mesh", prop->mesh);
|
||||||
|
|
||||||
// Deprecated: read object properties directly
|
// Deprecated: read object properties directly
|
||||||
read_object_properties(L, -1, prop);
|
read_object_properties(L, -1, prop);
|
||||||
|
|
|
@ -1371,9 +1371,9 @@ void Server::AsyncRunStep()
|
||||||
/*
|
/*
|
||||||
Send player inventories and HPs if necessary
|
Send player inventories and HPs if necessary
|
||||||
*/
|
*/
|
||||||
if(playersao->m_teleported){
|
if(playersao->m_moved){
|
||||||
SendMovePlayer(client->peer_id);
|
SendMovePlayer(client->peer_id);
|
||||||
playersao->m_teleported = false;
|
playersao->m_moved = false;
|
||||||
}
|
}
|
||||||
if(playersao->m_inventory_not_sent){
|
if(playersao->m_inventory_not_sent){
|
||||||
UpdateCrafting(client->peer_id);
|
UpdateCrafting(client->peer_id);
|
||||||
|
@ -2369,7 +2369,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
|
|
||||||
if(command == TOSERVER_PLAYERPOS)
|
if(command == TOSERVER_PLAYERPOS)
|
||||||
{
|
{
|
||||||
if(datasize < 2+12+12+4+4)
|
if(datasize < 2+12+12+4+4+4)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u32 start = 0;
|
u32 start = 0;
|
||||||
|
@ -2377,6 +2377,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
v3s32 ss = readV3S32(&data[start+2+12]);
|
v3s32 ss = readV3S32(&data[start+2+12]);
|
||||||
f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
|
f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
|
||||||
f32 yaw = (f32)readS32(&data[2+12+12+4]) / 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 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.);
|
v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
|
||||||
pitch = wrapDegrees(pitch);
|
pitch = wrapDegrees(pitch);
|
||||||
|
@ -2386,6 +2387,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
player->setSpeed(speed);
|
player->setSpeed(speed);
|
||||||
player->setPitch(pitch);
|
player->setPitch(pitch);
|
||||||
player->setYaw(yaw);
|
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 "
|
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
|
||||||
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
|
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
|
||||||
|
@ -3166,6 +3177,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
} // action == 4
|
} // action == 4
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Catch invalid actions
|
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 + "textures");
|
||||||
paths.push_back(mod.path + DIR_DELIM + "sounds");
|
paths.push_back(mod.path + DIR_DELIM + "sounds");
|
||||||
paths.push_back(mod.path + DIR_DELIM + "media");
|
paths.push_back(mod.path + DIR_DELIM + "media");
|
||||||
|
paths.push_back(mod.path + DIR_DELIM + "models");
|
||||||
}
|
}
|
||||||
std::string path_all = "textures";
|
std::string path_all = "textures";
|
||||||
paths.push_back(path_all + DIR_DELIM + "all");
|
paths.push_back(path_all + DIR_DELIM + "all");
|
||||||
|
@ -4054,6 +4067,7 @@ void Server::fillMediaCache()
|
||||||
".png", ".jpg", ".bmp", ".tga",
|
".png", ".jpg", ".bmp", ".tga",
|
||||||
".pcx", ".ppm", ".psd", ".wal", ".rgb",
|
".pcx", ".ppm", ".psd", ".wal", ".rgb",
|
||||||
".ogg",
|
".ogg",
|
||||||
|
".x", ".b3d", ".md2", ".obj",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
if(removeStringEnd(filename, supported_ext) == ""){
|
if(removeStringEnd(filename, supported_ext) == ""){
|
||||||
|
|
|
@ -152,6 +152,12 @@ public:
|
||||||
|
|
||||||
virtual void setArmorGroups(const ItemGroupList &armor_groups)
|
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()
|
virtual ObjectProperties* accessObjectProperties()
|
||||||
{ return NULL; }
|
{ return NULL; }
|
||||||
virtual void notifyObjectPropertiesModified()
|
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
|
// Apply transform to image data
|
||||||
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
|
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".
|
Generate image based on a string like "stone.png" or "[crack0".
|
||||||
if baseimg is NULL, it is created. Otherwise stuff is made on it.
|
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 \""<<name<<"\""<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create texture from resulting image
|
|
||||||
if(baseimg != NULL)
|
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)
|
Add texture to caches (add NULL textures too)
|
||||||
|
@ -816,7 +809,7 @@ void TextureSource::rebuildImagesAndTextures()
|
||||||
// Create texture from resulting image
|
// Create texture from resulting image
|
||||||
video::ITexture *t = NULL;
|
video::ITexture *t = NULL;
|
||||||
if(img)
|
if(img)
|
||||||
t = register_texture(driver, sap->name, img);
|
t = driver->addTexture(sap->name.c_str(), img);
|
||||||
|
|
||||||
// Replace texture
|
// Replace texture
|
||||||
sap->a.atlas = t;
|
sap->a.atlas = t;
|
||||||
|
@ -1051,7 +1044,7 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
|
||||||
/*
|
/*
|
||||||
Make texture
|
Make texture
|
||||||
*/
|
*/
|
||||||
video::ITexture *t = register_texture(driver, "__main_atlas__", atlas_img);
|
video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1142,15 +1135,6 @@ video::IImage* generate_image_from_scratch(std::string name,
|
||||||
return baseimg;
|
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,
|
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||||
IrrlichtDevice *device, SourceImageCache *sourcecache)
|
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);
|
assert(img_top && img_left && img_right);
|
||||||
|
|
||||||
// Create textures from images
|
// Create textures from images
|
||||||
video::ITexture *texture_top = register_texture(driver,
|
video::ITexture *texture_top = driver->addTexture(
|
||||||
imagename_top + "__temp1__", img_top);
|
(imagename_top + "__temp__").c_str(), img_top);
|
||||||
video::ITexture *texture_left = register_texture(driver,
|
video::ITexture *texture_left = driver->addTexture(
|
||||||
imagename_left + "__temp2__", img_left);
|
(imagename_left + "__temp__").c_str(), img_left);
|
||||||
video::ITexture *texture_right = register_texture(driver,
|
video::ITexture *texture_right = driver->addTexture(
|
||||||
imagename_right + "__temp3__", img_right);
|
(imagename_right + "__temp__").c_str(), img_right);
|
||||||
assert(texture_top && texture_left && texture_right);
|
assert(texture_top && texture_left && texture_right);
|
||||||
|
|
||||||
// Drop images
|
// Drop images
|
||||||
|
|
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#define UTIL_SERIALIZE_HEADER
|
#define UTIL_SERIALIZE_HEADER
|
||||||
|
|
||||||
#include "../irrlichttypes.h"
|
#include "../irrlichttypes.h"
|
||||||
|
#include "../irrlichttypes_bloated.h"
|
||||||
#include "../irr_v2d.h"
|
#include "../irr_v2d.h"
|
||||||
#include "../irr_v3d.h"
|
#include "../irr_v3d.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -197,6 +198,24 @@ inline v3s16 readV3S16(u8 *data)
|
||||||
return p;
|
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
|
The above stuff directly interfaced to iostream
|
||||||
*/
|
*/
|
||||||
|
@ -344,6 +363,20 @@ inline v3s16 readV3S16(std::istream &is)
|
||||||
return readV3S16((u8*)buf);
|
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
|
More serialization stuff
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue