Merge remote-tracking branch 'upstream/master'

This commit is contained in:
sfan5 2012-11-25 20:59:08 +01:00
commit 6c43e29c54
29 changed files with 1481 additions and 269 deletions

View File

@ -215,8 +215,8 @@ minetest.register_chatcommand("clearpassword", {
privs = {password=true},
func = function(name, param)
toname = param
if not toname then
minetest.chat_send_player(toname, "Name field required")
if toname == "" then
minetest.chat_send_player(name, "Name field required")
return
end
minetest.set_player_password(toname, '')

View File

@ -1,4 +1,4 @@
Minetest Lua Modding API Reference 0.4.0
Minetest Lua Modding API Reference 0.4.3
==========================================
More information at http://c55.me/minetest/
@ -694,6 +694,11 @@ image[<X>,<Y>;<W>,<H>;<texture name>]
^ Show an image
^ Position and size units are inventory slots
background[<X>,<Y>;<W>,<H>;<texture name>]
^ Use a background. Inventory rectangles are not drawn then.
^ Position and size units are inventory slots
^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
^ Textual field; will be sent to server when a button is clicked
^ x and y position the field relative to the top left of the menu
@ -1098,6 +1103,10 @@ methods:
- get_wielded_item() -> ItemStack
- set_wielded_item(item): replaces the wielded item, returns true if successful
- set_armor_groups({group1=rating, group2=rating, ...})
- set_animation({x=1,y=1}, frame_speed=15, frame_blend=0)
- set_attach(parent, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
- set_detach()
- set_bone_position("", {x=0,y=0,z=0}, {x=0,y=0,z=0})
- set_properties(object property table)
LuaEntitySAO-only: (no-op for other objects)
- setvelocity({x=num, y=num, z=num})
@ -1123,6 +1132,10 @@ Player-only: (no-op for other objects)
^ Redefine player's inventory form
^ Should usually be called in on_joinplayer
- get_inventory_formspec() -> formspec string
- get_player_control(): returns table with player pressed keys
{jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
- get_player_control_bits(): returns integer with bit packed player pressed keys
bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
InvRef: Reference to an inventory
methods:
@ -1222,9 +1235,11 @@ Object Properties
physical = true,
weight = 5,
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
visual = "cube"/"sprite"/"upright_sprite",
visual = "cube"/"sprite"/"upright_sprite"/"mesh",
visual_size = {x=1, y=1},
mesh = "model",
textures = {}, -- number of required textures depends on visual
colors = {}, -- number of required colors depends on visual
spritediv = {x=1, y=1},
initial_sprite_basepos = {x=0, y=0},
is_visible = true,

View File

@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound.h"
#include "util/string.h"
#include "hex.h"
#include "IMeshCache.h"
static std::string getMediaCacheDir()
{
@ -860,6 +861,28 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
return true;
}
const char *model_ext[] = {
".x", ".b3d", ".md2", ".obj",
NULL
};
name = removeStringEnd(filename, model_ext);
if(name != "")
{
verbosestream<<"Client: Storing model into Irrlicht: "
<<"\""<<filename<<"\""<<std::endl;
io::IFileSystem *irrfs = m_device->getFileSystem();
io::IReadFile *rfile = irrfs->createMemoryReadFile(
*data_rw, data_rw.getSize(), filename.c_str());
assert(rfile);
scene::ISceneManager *smgr = m_device->getSceneManager();
scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
return true;
}
errorstream<<"Client: Don't know how to load file \""
<<filename<<"\""<<std::endl;
return false;
@ -1961,7 +1984,7 @@ void Client::sendPlayerPos()
v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
s32 pitch = myplayer->getPitch() * 100;
s32 yaw = myplayer->getYaw() * 100;
u32 keyPressed=myplayer->keyPressed;
/*
Format:
[0] u16 command
@ -1969,15 +1992,15 @@ void Client::sendPlayerPos()
[2+12] v3s32 speed*100
[2+12+12] s32 pitch*100
[2+12+12+4] s32 yaw*100
[2+12+12+4+4] u32 keyPressed
*/
SharedBuffer<u8> data(2+12+12+4+4);
SharedBuffer<u8> data(2+12+12+4+4+4);
writeU16(&data[0], TOSERVER_PLAYERPOS);
writeV3S32(&data[2], position);
writeV3S32(&data[2+12], speed);
writeS32(&data[2+12+12], pitch);
writeS32(&data[2+12+12+4], yaw);
writeU32(&data[2+12+12+4+4], keyPressed);
// Send as unreliable
Send(0, data, false);
}

View File

@ -36,7 +36,7 @@ ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef,
ClientActiveObject::~ClientActiveObject()
{
removeFromScene();
removeFromScene(true);
}
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,

View File

@ -49,13 +49,19 @@ public:
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr){}
virtual void removeFromScene(){}
virtual void removeFromScene(bool permanent){}
// 0 <= light_at_pos <= LIGHT_SUN
virtual void updateLight(u8 light_at_pos){}
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
virtual v3f getPosition(){return v3f(0,0,0);}
virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;}
virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode(){return NULL;}
virtual scene::IBillboardSceneNode *getSpriteSceneNode(){return NULL;}
virtual bool isPlayer(){return false;}
virtual bool isLocalPlayer(){return false;}
virtual void setAttachments(){}
virtual bool doShowSelectionBox(){return true;}
// Step object in time

View File

@ -67,9 +67,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
TOCLIENT_DETACHED_INVENTORY
PROTOCOL_VERSION 13:
InventoryList field "Width" (deserialization fails with old versions)
PROTOCOL_VERSION 14:
Added transfer of player pressed keys to the server
Added new messages for mesh and bone animation, as well as attachments
GENERIC_CMD_SET_ANIMATION
GENERIC_CMD_SET_BONE_POSITION
GENERIC_CMD_SET_ATTACHMENT
*/
#define PROTOCOL_VERSION 13
#define PROTOCOL_VERSION 14
#define PROTOCOL_ID 0x4f457403
@ -366,6 +372,7 @@ enum ToServerCommand
[2+12] v3s32 speed*100
[2+12+12] s32 pitch*100
[2+12+12+4] s32 yaw*100
[2+12+12+4+4] u32 keyPressed
*/
TOSERVER_GOTBLOCKS = 0x24,

View File

@ -40,7 +40,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h"
#include "util/mathconstants.h"
#include "map.h"
#include "main.h" // g_settings
#include <IMeshManipulator.h>
#include <IAnimatedMeshSceneNode.h>
#include <IBoneSceneNode.h>
class Settings;
struct ToolCapabilities;
@ -552,7 +555,8 @@ private:
// Only set at initialization
std::string m_name;
bool m_is_player;
bool m_is_local_player; // determined locally
bool m_is_local_player;
int m_id;
// Property-ish things
ObjectProperties m_prop;
//
@ -560,6 +564,7 @@ private:
IrrlichtDevice *m_irr;
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_meshnode;
scene::IAnimatedMeshSceneNode *m_animated_meshnode;
scene::IBillboardSceneNode *m_spritenode;
scene::ITextSceneNode* m_textnode;
v3f m_position;
@ -573,6 +578,14 @@ private:
v2s16 m_tx_basepos;
bool m_initial_tx_basepos_set;
bool m_tx_select_horiz_by_yawpitch;
v2f m_animation_range;
int m_animation_speed;
int m_animation_blend;
std::map<std::string, core::vector2d<v3f> > m_bone_position; // stores position and rotation for each bone name
std::string m_attachment_bone;
v3f m_attachment_position;
v3f m_attachment_rotation;
bool m_attached_to_local;
int m_anim_frame;
int m_anim_num_frames;
float m_anim_framelength;
@ -582,6 +595,7 @@ private:
bool m_visuals_expired;
float m_step_distance_counter;
u8 m_last_light;
bool m_is_visible;
public:
GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
@ -589,11 +603,13 @@ public:
//
m_is_player(false),
m_is_local_player(false),
m_id(0),
//
m_smgr(NULL),
m_irr(NULL),
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
m_meshnode(NULL),
m_animated_meshnode(NULL),
m_spritenode(NULL),
m_textnode(NULL),
m_position(v3f(0,10*BS,0)),
@ -605,6 +621,14 @@ public:
m_tx_basepos(0,0),
m_initial_tx_basepos_set(false),
m_tx_select_horiz_by_yawpitch(false),
m_animation_range(v2f(0,0)),
m_animation_speed(15),
m_animation_blend(0),
m_bone_position(std::map<std::string, core::vector2d<v3f> >()),
m_attachment_bone(""),
m_attachment_position(v3f(0,0,0)),
m_attachment_rotation(v3f(0,0,0)),
m_attached_to_local(false),
m_anim_frame(0),
m_anim_num_frames(1),
m_anim_framelength(0.2),
@ -612,7 +636,8 @@ public:
m_reset_textures_timer(-1),
m_visuals_expired(false),
m_step_distance_counter(0),
m_last_light(255)
m_last_light(255),
m_is_visible(false)
{
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
@ -632,6 +657,7 @@ public:
}
m_name = deSerializeString(is);
m_is_player = readU8(is);
m_id = readS16(is);
m_position = readV3F1000(is);
m_yaw = readF1000(is);
m_hp = readS16(is);
@ -668,21 +694,113 @@ public:
}
core::aabbox3d<f32>* getSelectionBox()
{
if(!m_prop.is_visible || m_is_local_player)
if(!m_prop.is_visible || !m_is_visible || m_is_local_player || getParent() != NULL)
return NULL;
return &m_selection_box;
}
v3f getPosition()
{
if(getParent() != NULL){
if(m_meshnode)
return m_meshnode->getAbsolutePosition();
if(m_animated_meshnode)
return m_animated_meshnode->getAbsolutePosition();
if(m_spritenode)
return m_spritenode->getAbsolutePosition();
return m_position;
}
return pos_translator.vect_show;
}
void removeFromScene()
scene::IMeshSceneNode *getMeshSceneNode()
{
if(m_meshnode)
return m_meshnode;
return NULL;
}
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode()
{
if(m_animated_meshnode)
return m_animated_meshnode;
return NULL;
}
scene::IBillboardSceneNode *getSpriteSceneNode()
{
if(m_spritenode)
return m_spritenode;
return NULL;
}
bool isPlayer()
{
return m_is_player;
}
bool isLocalPlayer()
{
return m_is_local_player;
}
void setAttachments()
{
updateAttachments();
}
ClientActiveObject *getParent()
{
ClientActiveObject *obj = NULL;
for(std::vector<core::vector2d<int> >::const_iterator cii = m_env->attachment_list.begin(); cii != m_env->attachment_list.end(); cii++)
{
if(cii->X == getId()){ // This ID is our child
if(cii->Y > 0){ // A parent ID exists for our child
if(cii->X != cii->Y){ // The parent and child ID are not the same
obj = m_env->getActiveObject(cii->Y);
}
}
break;
}
}
if(obj)
return obj;
return NULL;
}
void removeFromScene(bool permanent)
{
if(permanent) // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
{
// Detach this object's children
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
{
if(ii->Y == getId()) // Is a child of our object
{
ii->Y = 0;
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
obj->setAttachments();
}
}
// Delete this object from the attachments list
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
{
if(ii->X == getId()) // Is our object
{
m_env->attachment_list.erase(ii);
break;
}
}
}
if(m_meshnode){
m_meshnode->remove();
m_meshnode = NULL;
}
if(m_animated_meshnode){
m_animated_meshnode->remove();
m_animated_meshnode = NULL;
}
if(m_spritenode){
m_spritenode->remove();
m_spritenode = NULL;
@ -695,7 +813,7 @@ public:
m_smgr = smgr;
m_irr = irr;
if(m_meshnode != NULL || m_spritenode != NULL)
if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL)
return;
m_visuals_expired = false;
@ -791,7 +909,24 @@ public:
m_prop.visual_size.X));
u8 li = m_last_light;
setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
} else if(m_prop.visual == "wielditem"){
}
else if(m_prop.visual == "mesh"){
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
scene::IAnimatedMesh *mesh = smgr->getMesh(m_prop.mesh.c_str());
if(mesh)
{
m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
m_animated_meshnode->animateJoints(); // Needed for some animations
m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
m_prop.visual_size.Y,
m_prop.visual_size.X));
u8 li = m_last_light;
setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
}
else
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
}
else if(m_prop.visual == "wielditem"){
infostream<<"GenericCAO::addToScene(): node"<<std::endl;
infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
if(m_prop.textures.size() >= 1){
@ -823,6 +958,8 @@ public:
scene::ISceneNode *node = NULL;
if(m_spritenode)
node = m_spritenode;
else if(m_animated_meshnode)
node = m_animated_meshnode;
else if(m_meshnode)
node = m_meshnode;
if(node && m_is_player && !m_is_local_player){
@ -835,6 +972,9 @@ public:
}
updateNodePos();
updateAnimation();
updateBonePosition();
updateAttachments();
}
void expireVisuals()
@ -844,19 +984,16 @@ public:
void updateLight(u8 light_at_pos)
{
bool is_visible = (m_hp != 0);
u8 li = decode_light(light_at_pos);
if(li != m_last_light){
m_last_light = li;
video::SColor color(255,li,li,li);
if(m_meshnode){
if(m_meshnode)
setMeshColor(m_meshnode->getMesh(), color);
m_meshnode->setVisible(is_visible);
}
if(m_spritenode){
if(m_animated_meshnode)
setMeshColor(m_animated_meshnode->getMesh(), color);
if(m_spritenode)
m_spritenode->setColor(color);
m_spritenode->setVisible(is_visible);
}
}
}
@ -867,12 +1004,21 @@ public:
void updateNodePos()
{
if(getParent() != NULL)
return;
if(m_meshnode){
m_meshnode->setPosition(pos_translator.vect_show);
v3f rot = m_meshnode->getRotation();
rot.Y = -m_yaw;
m_meshnode->setRotation(rot);
}
if(m_animated_meshnode){
m_animated_meshnode->setPosition(pos_translator.vect_show);
v3f rot = m_animated_meshnode->getRotation();
rot.Y = -m_yaw;
m_animated_meshnode->setRotation(rot);
}
if(m_spritenode){
m_spritenode->setPosition(pos_translator.vect_show);
}
@ -880,13 +1026,72 @@ public:
void step(float dtime, ClientEnvironment *env)
{
v3f lastpos = pos_translator.vect_show;
if(m_visuals_expired && m_smgr && m_irr){
m_visuals_expired = false;
removeFromScene();
addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
// Attachments, part 1: All attached objects must be unparented first, or Irrlicht causes a segmentation fault
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
{
if(ii->Y == getId()) // This is a child of our parent
{
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
{
scene::IMeshSceneNode *m_child_meshnode = obj->getMeshSceneNode();
scene::IAnimatedMeshSceneNode *m_child_animated_meshnode = obj->getAnimatedMeshSceneNode();
scene::IBillboardSceneNode *m_child_spritenode = obj->getSpriteSceneNode();
if(m_child_meshnode)
m_child_meshnode->setParent(m_smgr->getRootSceneNode());
if(m_child_animated_meshnode)
m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode());
if(m_child_spritenode)
m_child_spritenode->setParent(m_smgr->getRootSceneNode());
}
}
}
removeFromScene(false);
addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
{
if(ii->Y == getId()) // This is a child of our parent
{
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
obj->setAttachments();
}
}
}
// Make sure m_is_visible is always applied
if(m_meshnode)
m_meshnode->setVisible(m_is_visible);
if(m_animated_meshnode)
m_animated_meshnode->setVisible(m_is_visible);
if(m_spritenode)
m_spritenode->setVisible(m_is_visible);
if(m_textnode)
m_textnode->setVisible(m_is_visible);
if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
{
// Set these for later
m_position = getPosition();
m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0);
pos_translator.vect_show = m_position;
if(m_is_local_player) // Update local player attachment position
{
LocalPlayer *player = m_env->getLocalPlayer();
player->overridePosition = getParent()->getPosition();
}
}
else
{
v3f lastpos = pos_translator.vect_show;
if(m_prop.physical){
core::aabbox3d<f32> box = m_prop.collisionbox;
@ -932,6 +1137,7 @@ public:
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
}
}
}
m_anim_timer += dtime;
if(m_anim_timer >= m_anim_framelength){
@ -950,7 +1156,7 @@ public:
updateTextures("");
}
}
if(fabs(m_prop.automatic_rotate) > 0.001){
if(getParent() == NULL && fabs(m_prop.automatic_rotate) > 0.001){
m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
updateNodePos();
}
@ -1008,6 +1214,10 @@ public:
{
ITextureSource *tsrc = m_gamedef->tsrc();
bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
if(m_spritenode)
{
if(m_prop.visual == "sprite")
@ -1018,6 +1228,58 @@ public:
texturestring += mod;
m_spritenode->setMaterialTexture(0,
tsrc->getTextureRaw(texturestring));
// This allows setting per-material colors. However, until a real lighting
// system is added, the code below will have no effect. Once MineTest
// has directional lighting, it should work automatically.
if(m_prop.colors.size() >= 1)
{
m_spritenode->getMaterial(0).AmbientColor = m_prop.colors[0];
m_spritenode->getMaterial(0).DiffuseColor = m_prop.colors[0];
m_spritenode->getMaterial(0).SpecularColor = m_prop.colors[0];
}
m_spritenode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
m_spritenode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
m_spritenode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
}
}
if(m_animated_meshnode)
{
if(m_prop.visual == "mesh")
{
for (u32 i = 0; i < m_prop.textures.size() && i < m_animated_meshnode->getMaterialCount(); ++i)
{
std::string texturestring = m_prop.textures[i];
if(texturestring == "")
continue; // Empty texture string means don't modify that material
texturestring += mod;
video::ITexture* texture = tsrc->getTextureRaw(texturestring);
if(!texture)
{
errorstream<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring<<std::endl;
continue;
}
// Set material flags and texture
m_animated_meshnode->setMaterialTexture(i, texture);
video::SMaterial& material = m_animated_meshnode->getMaterial(i);
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
}
for (u32 i = 0; i < m_prop.colors.size() && i < m_animated_meshnode->getMaterialCount(); ++i)
{
// This allows setting per-material colors. However, until a real lighting
// system is added, the code below will have no effect. Once MineTest
// has directional lighting, it should work automatically.
m_animated_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
m_animated_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
}
}
}
if(m_meshnode)
@ -1044,6 +1306,20 @@ public:
material.setTexture(0, atlas);
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
// This allows setting per-material colors. However, until a real lighting
// system is added, the code below will have no effect. Once MineTest
// has directional lighting, it should work automatically.
if(m_prop.colors.size() > i)
{
m_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
m_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
m_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
}
m_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
m_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
m_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
}
}
else if(m_prop.visual == "upright_sprite")
@ -1057,6 +1333,20 @@ public:
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw(tname));
// This allows setting per-material colors. However, until a real lighting
// system is added, the code below will have no effect. Once MineTest
// has directional lighting, it should work automatically.
if(m_prop.colors.size() >= 1)
{
buf->getMaterial().AmbientColor = m_prop.colors[0];
buf->getMaterial().DiffuseColor = m_prop.colors[0];
buf->getMaterial().SpecularColor = m_prop.colors[0];
}
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
}
{
std::string tname = "unknown_object.png";
@ -1068,7 +1358,209 @@ public:
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
buf->getMaterial().setTexture(0,
tsrc->getTextureRaw(tname));
// This allows setting per-material colors. However, until a real lighting
// system is added, the code below will have no effect. Once MineTest
// has directional lighting, it should work automatically.
if(m_prop.colors.size() >= 2)
{
buf->getMaterial().AmbientColor = m_prop.colors[1];
buf->getMaterial().DiffuseColor = m_prop.colors[1];
buf->getMaterial().SpecularColor = m_prop.colors[1];
}
else if(m_prop.colors.size() >= 1)
{
buf->getMaterial().AmbientColor = m_prop.colors[0];
buf->getMaterial().DiffuseColor = m_prop.colors[0];
buf->getMaterial().SpecularColor = m_prop.colors[0];
}
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
}
}
}
}
void updateAnimation()
{
if(m_animated_meshnode == NULL)
return;
m_animated_meshnode->setFrameLoop((int)m_animation_range.X, (int)m_animation_range.Y);
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
m_animated_meshnode->setTransitionTime(m_animation_blend);
}
void updateBonePosition()
{
if(!m_bone_position.size() || m_animated_meshnode == NULL)
return;
m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
std::string bone_name = (*ii).first;
v3f bone_pos = (*ii).second.X;
v3f bone_rot = (*ii).second.Y;
irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
if(bone)
{
bone->setPosition(bone_pos);
bone->setRotation(bone_rot);
}
}
}
void updateAttachments()
{
m_attached_to_local = getParent() != NULL && getParent()->isLocalPlayer();
m_is_visible = !m_attached_to_local; // Objects attached to the local player should always be hidden
if(getParent() == NULL || m_attached_to_local) // Detach or don't attach
{
if(m_meshnode)
{
v3f old_position = m_meshnode->getAbsolutePosition();
v3f old_rotation = m_meshnode->getRotation();
m_meshnode->setParent(m_smgr->getRootSceneNode());
m_meshnode->setPosition(old_position);
m_meshnode->setRotation(old_rotation);
m_meshnode->updateAbsolutePosition();
}
if(m_animated_meshnode)
{
v3f old_position = m_animated_meshnode->getAbsolutePosition();
v3f old_rotation = m_animated_meshnode->getRotation();
m_animated_meshnode->setParent(m_smgr->getRootSceneNode());
m_animated_meshnode->setPosition(old_position);
m_animated_meshnode->setRotation(old_rotation);
m_animated_meshnode->updateAbsolutePosition();
}
if(m_spritenode)
{
v3f old_position = m_spritenode->getAbsolutePosition();
v3f old_rotation = m_spritenode->getRotation();
m_spritenode->setParent(m_smgr->getRootSceneNode());
m_spritenode->setPosition(old_position);
m_spritenode->setRotation(old_rotation);
m_spritenode->updateAbsolutePosition();
}
if(m_is_local_player)
{
LocalPlayer *player = m_env->getLocalPlayer();
player->isAttached = false;
}
}
else // Attach
{
scene::IMeshSceneNode *parent_mesh = NULL;
if(getParent()->getMeshSceneNode())
parent_mesh = getParent()->getMeshSceneNode();
scene::IAnimatedMeshSceneNode *parent_animated_mesh = NULL;
if(getParent()->getAnimatedMeshSceneNode())
parent_animated_mesh = getParent()->getAnimatedMeshSceneNode();
scene::IBillboardSceneNode *parent_sprite = NULL;
if(getParent()->getSpriteSceneNode())
parent_sprite = getParent()->getSpriteSceneNode();
scene::IBoneSceneNode *parent_bone = NULL;
if(parent_animated_mesh && m_attachment_bone != "")
parent_bone = parent_animated_mesh->getJointNode(m_attachment_bone.c_str());
// The spaghetti code below makes sure attaching works if either the parent or child is a spritenode, meshnode, or animatedmeshnode
// TODO: Perhaps use polymorphism here to save code duplication
if(m_meshnode){
if(parent_bone){
m_meshnode->setParent(parent_bone);
m_meshnode->setPosition(m_attachment_position);
m_meshnode->setRotation(m_attachment_rotation);
m_meshnode->updateAbsolutePosition();
}
else
{
if(parent_mesh){
m_meshnode->setParent(parent_mesh);
m_meshnode->setPosition(m_attachment_position);
m_meshnode->setRotation(m_attachment_rotation);
m_meshnode->updateAbsolutePosition();
}
else if(parent_animated_mesh){
m_meshnode->setParent(parent_animated_mesh);
m_meshnode->setPosition(m_attachment_position);
m_meshnode->setRotation(m_attachment_rotation);
m_meshnode->updateAbsolutePosition();
}
else if(parent_sprite){
m_meshnode->setParent(parent_sprite);
m_meshnode->setPosition(m_attachment_position);
m_meshnode->setRotation(m_attachment_rotation);
m_meshnode->updateAbsolutePosition();
}
}
}
if(m_animated_meshnode){
if(parent_bone){
m_animated_meshnode->setParent(parent_bone);
m_animated_meshnode->setPosition(m_attachment_position);
m_animated_meshnode->setRotation(m_attachment_rotation);
m_animated_meshnode->updateAbsolutePosition();
}
else
{
if(parent_mesh){
m_animated_meshnode->setParent(parent_mesh);
m_animated_meshnode->setPosition(m_attachment_position);
m_animated_meshnode->setRotation(m_attachment_rotation);
m_animated_meshnode->updateAbsolutePosition();
}
else if(parent_animated_mesh){
m_animated_meshnode->setParent(parent_animated_mesh);
m_animated_meshnode->setPosition(m_attachment_position);
m_animated_meshnode->setRotation(m_attachment_rotation);
m_animated_meshnode->updateAbsolutePosition();
}
else if(parent_sprite){
m_animated_meshnode->setParent(parent_sprite);
m_animated_meshnode->setPosition(m_attachment_position);
m_animated_meshnode->setRotation(m_attachment_rotation);
m_animated_meshnode->updateAbsolutePosition();
}
}
}
if(m_spritenode){
if(parent_bone){
m_spritenode->setParent(parent_bone);
m_spritenode->setPosition(m_attachment_position);
m_spritenode->setRotation(m_attachment_rotation);
m_spritenode->updateAbsolutePosition();
}
else
{
if(parent_mesh){
m_spritenode->setParent(parent_mesh);
m_spritenode->setPosition(m_attachment_position);
m_spritenode->setRotation(m_attachment_rotation);
m_spritenode->updateAbsolutePosition();
}
else if(parent_animated_mesh){
m_spritenode->setParent(parent_animated_mesh);
m_spritenode->setPosition(m_attachment_position);
m_spritenode->setRotation(m_attachment_rotation);
m_spritenode->updateAbsolutePosition();
}
else if(parent_sprite){
m_spritenode->setParent(parent_sprite);
m_spritenode->setPosition(m_attachment_position);
m_spritenode->setRotation(m_attachment_rotation);
m_spritenode->updateAbsolutePosition();
}
}
}
if(m_is_local_player)
{
LocalPlayer *player = m_env->getLocalPlayer();
player->isAttached = true;
}
}
}
@ -1099,6 +1591,8 @@ public:
}
else if(cmd == GENERIC_CMD_UPDATE_POSITION)
{
// Not sent by the server if this object is an attachment.
// We might however get here if the server notices the object being detached before the client.
m_position = readV3F1000(is);
m_velocity = readV3F1000(is);
m_acceleration = readV3F1000(is);
@ -1113,6 +1607,9 @@ public:
if(m_prop.physical)
m_position += v3f(0,0.002,0);
if(getParent() != NULL) // Just in case
return;
if(do_interpolate){
if(!m_prop.physical)
pos_translator.update(m_position, is_end_position, update_interval);
@ -1140,6 +1637,41 @@ public:
updateTexturePos();
}
else if(cmd == GENERIC_CMD_SET_ANIMATION)
{
m_animation_range = readV2F1000(is);
m_animation_speed = readF1000(is);
m_animation_blend = readF1000(is);
updateAnimation();
}
else if(cmd == GENERIC_CMD_SET_BONE_POSITION)
{
std::string bone = deSerializeString(is);
v3f position = readV3F1000(is);
v3f rotation = readV3F1000(is);
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
updateBonePosition();
}
else if(cmd == GENERIC_CMD_SET_ATTACHMENT)
{
// If an entry already exists for this object, delete it first to avoid duplicates
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
{
if(ii->X == getId()) // This is the ID of our object
{
m_env->attachment_list.erase(ii);
break;
}
}
m_env->attachment_list.push_back(core::vector2d<int>(getId(), readS16(is)));
m_attachment_bone = deSerializeString(is);
m_attachment_position = readV3F1000(is);
m_attachment_rotation = readV3F1000(is);
updateAttachments();
}
else if(cmd == GENERIC_CMD_PUNCHED)
{
/*s16 damage =*/ readS16(is);

View File

@ -355,7 +355,10 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
m_last_sent_velocity(0,0,0),
m_last_sent_position_timer(0),
m_last_sent_move_precision(0),
m_armor_groups_sent(false)
m_armor_groups_sent(false),
m_animation_sent(false),
m_bone_position_sent(false),
m_attachment_sent(false)
{
// Only register type if no environment supplied
if(env == NULL){
@ -429,6 +432,17 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
return sao;
}
bool LuaEntitySAO::isAttached()
{
if(!m_attachment_parent_id)
return false;
// Check if the parent still exists
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
if(obj)
return true;
return false;
}
void LuaEntitySAO::step(float dtime, bool send_recommended)
{
if(!m_properties_sent)
@ -440,8 +454,29 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
m_messages_out.push_back(aom);
}
// If attached, check that our parent is still there. If it isn't, detach.
if(m_attachment_parent_id && !isAttached())
{
m_attachment_parent_id = 0;
m_attachment_bone = "";
m_attachment_position = v3f(0,0,0);
m_attachment_rotation = v3f(0,0,0);
sendPosition(false, true);
}
m_last_sent_position_timer += dtime;
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
// If the object gets detached this comes into effect automatically from the last known origin
if(isAttached())
{
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
m_base_position = pos;
m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0);
}
else
{
if(m_prop.physical){
core::aabbox3d<f32> box = m_prop.collisionbox;
box.MinEdge *= BS;
@ -465,6 +500,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
* dtime * m_acceleration;
m_velocity += dtime * m_acceleration;
}
}
if(m_registered){
lua_State *L = m_env->getLua();
@ -474,6 +510,8 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
if(send_recommended == false)
return;
if(!isAttached())
{
// TODO: force send when acceleration changes enough?
float minchange = 0.2*BS;
if(m_last_sent_position_timer > 1.0){
@ -488,6 +526,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
fabs(m_yaw - m_last_sent_yaw) > 1.0){
sendPosition(true, false);
}
}
if(m_armor_groups_sent == false){
m_armor_groups_sent = true;
@ -497,6 +536,32 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
if(m_animation_sent == false){
m_animation_sent = true;
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
if(m_bone_position_sent == false){
m_bone_position_sent = true;
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
}
if(m_attachment_sent == false){
m_attachment_sent = true;
std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
}
std::string LuaEntitySAO::getClientInitializationData()
@ -504,13 +569,21 @@ std::string LuaEntitySAO::getClientInitializationData()
std::ostringstream os(std::ios::binary);
writeU8(os, 0); // version
os<<serializeString(""); // name
writeS16(os, getId()); //id
writeU8(os, 0); // is_player
writeV3F1000(os, m_base_position);
writeF1000(os, m_yaw);
writeS16(os, m_hp);
writeU8(os, 2); // number of messages stuffed in here
writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
os<<serializeLongString(getPropertyPacket()); // message 1
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
}
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
// return result
return os.str();
}
@ -551,6 +624,10 @@ int LuaEntitySAO::punch(v3f dir,
return 0;
}
// It's best that attachments cannot be punched
if(isAttached())
return 0;
ItemStack *punchitem = NULL;
ItemStack punchitem_static;
if(puncher){
@ -594,18 +671,25 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
{
if(!m_registered)
return;
// It's best that attachments cannot be clicked
if(isAttached())
return;
lua_State *L = m_env->getLua();
scriptapi_luaentity_rightclick(L, m_id, clicker);
}
void LuaEntitySAO::setPos(v3f pos)
{
if(isAttached())
return;
m_base_position = pos;
sendPosition(false, true);
}
void LuaEntitySAO::moveTo(v3f pos, bool continuous)
{
if(isAttached())
return;
m_base_position = pos;
if(!continuous)
sendPosition(true, true);
@ -644,6 +728,37 @@ void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
m_armor_groups_sent = false;
}
void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
{
m_animation_range = frame_range;
m_animation_speed = frame_speed;
m_animation_blend = frame_blend;
m_animation_sent = false;
}
void LuaEntitySAO::setBonePosition(std::string bone, v3f position, v3f rotation)
{
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
m_bone_position_sent = false;
}
void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
{
// Attachments need to be handled on both the server and client.
// If we just attach on the server, we can only copy the position of the parent. Attachments
// are still sent to clients at an interval so players might see them lagging, plus we can't
// read and attach to skeletal bones.
// If we just attach on the client, the server still sees the child at its original location.
// This breaks some things so we also give the server the most accurate representation
// even if players only see the client changes.
m_attachment_parent_id = parent_id;
m_attachment_bone = bone;
m_attachment_position = position;
m_attachment_rotation = rotation;
m_attachment_sent = false;
}
ObjectProperties* LuaEntitySAO::accessObjectProperties()
{
return &m_prop;
@ -718,6 +833,10 @@ std::string LuaEntitySAO::getPropertyPacket()
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
{
// If the object is attached client-side, don't waste bandwidth sending its position to clients
if(isAttached())
return;
m_last_sent_move_precision = m_base_position.getDistanceFrom(
m_last_sent_position);
m_last_sent_position_timer = 0;
@ -765,8 +884,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
m_properties_sent(true),
m_privs(privs),
m_is_singleplayer(is_singleplayer),
m_animation_sent(false),
m_bone_position_sent(false),
m_attachment_sent(false),
// public
m_teleported(false),
m_moved(false),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_wielded_item_not_sent(false)
@ -782,13 +904,17 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
m_prop.physical = false;
m_prop.weight = 75;
m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
// start of default appearance, this should be overwritten by LUA
m_prop.visual = "upright_sprite";
m_prop.visual_size = v2f(1, 2);
m_prop.textures.clear();
m_prop.textures.push_back("player.png");
m_prop.textures.push_back("player_back.png");
m_prop.colors.clear();
m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
m_prop.spritediv = v2s16(1,1);
m_prop.is_visible = (getHP() != 0);
// end of default appearance
m_prop.is_visible = true;
m_prop.makes_footstep_sound = true;
}
@ -842,12 +968,21 @@ std::string PlayerSAO::getClientInitializationData()
writeU8(os, 0); // version
os<<serializeString(m_player->getName()); // name
writeU8(os, 1); // is_player
writeS16(os, getId()); //id
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
writeF1000(os, m_player->getYaw());
writeS16(os, getHP());
writeU8(os, 2); // number of messages stuffed in here
writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
os<<serializeLongString(getPropertyPacket()); // message 1
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
}
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
// return result
return os.str();
}
@ -857,6 +992,17 @@ std::string PlayerSAO::getStaticData()
return "";
}
bool PlayerSAO::isAttached()
{
if(!m_attachment_parent_id)
return false;
// Check if the parent still exists
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
if(obj)
return true;
return false;
}
void PlayerSAO::step(float dtime, bool send_recommended)
{
if(!m_properties_sent)
@ -868,9 +1014,31 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_messages_out.push_back(aom);
}
// If attached, check that our parent is still there. If it isn't, detach.
if(m_attachment_parent_id && !isAttached())
{
m_attachment_parent_id = 0;
m_attachment_bone = "";
m_attachment_position = v3f(0,0,0);
m_attachment_rotation = v3f(0,0,0);
m_player->setPosition(m_last_good_position);
m_moved = true;
}
m_time_from_last_punch += dtime;
m_nocheat_dig_time += dtime;
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
// If the object gets detached this comes into effect automatically from the last known origin
if(isAttached())
{
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
m_last_good_position = pos;
m_last_good_position_age = 0;
m_player->setPosition(pos);
}
else
{
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
{
m_last_good_position = m_player->getPosition();
@ -920,21 +1088,28 @@ void PlayerSAO::step(float dtime, bool send_recommended)
<<" moved too fast; resetting position"
<<std::endl;
m_player->setPosition(m_last_good_position);
m_teleported = true;
m_moved = true;
}
m_last_good_position_age = 0;
}
}
}
if(send_recommended == false)
return;
if(m_position_not_sent)
// If the object is attached client-side, don't waste bandwidth sending its position to clients
if(m_position_not_sent && !isAttached())
{
m_position_not_sent = false;
float update_interval = m_env->getSendRecommendedInterval();
v3f pos;
if(isAttached()) // Just in case we ever do send attachment position too
pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
else
pos = m_player->getPosition() + v3f(0,BS*1,0);
std::string str = gob_cmd_update_position(
m_player->getPosition() + v3f(0,BS*1,0),
pos,
v3f(0,0,0),
v3f(0,0,0),
m_player->getYaw(),
@ -961,32 +1136,63 @@ void PlayerSAO::step(float dtime, bool send_recommended)
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
if(m_animation_sent == false){
m_animation_sent = true;
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
if(m_bone_position_sent == false){
m_bone_position_sent = true;
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
}
if(m_attachment_sent == false){
m_attachment_sent = true;
std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
}
void PlayerSAO::setBasePosition(const v3f &position)
{
// This needs to be ran for attachments too
ServerActiveObject::setBasePosition(position);
m_position_not_sent = true;
}
void PlayerSAO::setPos(v3f pos)
{
if(isAttached())
return;
m_player->setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
// Force position change on client
m_teleported = true;
m_moved = true;
}
void PlayerSAO::moveTo(v3f pos, bool continuous)
{
if(isAttached())
return;
m_player->setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
// Force position change on client
m_teleported = true;
m_moved = true;
}
int PlayerSAO::punch(v3f dir,
@ -994,6 +1200,10 @@ int PlayerSAO::punch(v3f dir,
ServerActiveObject *puncher,
float time_from_last_punch)
{
// It's best that attachments cannot be punched
if(isAttached())
return 0;
if(!toolcap)
return 0;
@ -1075,6 +1285,39 @@ void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
m_armor_groups_sent = false;
}
void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
{
// store these so they can be updated to clients
m_animation_range = frame_range;
m_animation_speed = frame_speed;
m_animation_blend = frame_blend;
m_animation_sent = false;
}
void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
{
// store these so they can be updated to clients
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
m_bone_position_sent = false;
}
void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
{
// Attachments need to be handled on both the server and client.
// If we just attach on the server, we can only copy the position of the parent. Attachments
// are still sent to clients at an interval so players might see them lagging, plus we can't
// read and attach to skeletal bones.
// If we just attach on the client, the server still sees the child at its original location.
// This breaks some things so we also give the server the most accurate representation
// even if players only see the client changes.
m_attachment_parent_id = parent_id;
m_attachment_bone = bone;
m_attachment_position = position;
m_attachment_rotation = rotation;
m_attachment_sent = false;
}
ObjectProperties* PlayerSAO::accessObjectProperties()
{
return &m_prop;
@ -1138,7 +1381,7 @@ void PlayerSAO::disconnected()
std::string PlayerSAO::getPropertyPacket()
{
m_prop.is_visible = (getHP() != 0);
m_prop.is_visible = (true);
return gob_cmd_set_properties(m_prop);
}

View File

@ -46,6 +46,7 @@ public:
virtual void addedToEnvironment(u32 dtime_s);
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
bool isAttached();
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
@ -61,6 +62,9 @@ public:
void setHP(s16 hp);
s16 getHP() const;
void setArmorGroups(const ItemGroupList &armor_groups);
void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
void setBonePosition(std::string bone, v3f position, v3f rotation);
void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
ObjectProperties* accessObjectProperties();
void notifyObjectPropertiesModified();
/* LuaEntitySAO-specific */
@ -96,6 +100,20 @@ private:
float m_last_sent_position_timer;
float m_last_sent_move_precision;
bool m_armor_groups_sent;
v2f m_animation_range;
float m_animation_speed;
float m_animation_blend;
bool m_animation_sent;
std::map<std::string, core::vector2d<v3f> > m_bone_position;
bool m_bone_position_sent;
int m_attachment_parent_id;
std::string m_attachment_bone;
v3f m_attachment_position;
v3f m_attachment_rotation;
bool m_attachment_sent;
};
/*
@ -124,6 +142,7 @@ public:
bool unlimitedTransferDistance() const;
std::string getClientInitializationData();
std::string getStaticData();
bool isAttached();
void step(float dtime, bool send_recommended);
void setBasePosition(const v3f &position);
void setPos(v3f pos);
@ -142,6 +161,9 @@ public:
void setHP(s16 hp);
void setArmorGroups(const ItemGroupList &armor_groups);
void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
void setBonePosition(std::string bone, v3f position, v3f rotation);
void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
ObjectProperties* accessObjectProperties();
void notifyObjectPropertiesModified();
@ -229,15 +251,32 @@ private:
bool m_position_not_sent;
ItemGroupList m_armor_groups;
bool m_armor_groups_sent;
bool m_properties_sent;
struct ObjectProperties m_prop;
// Cached privileges for enforcement
std::set<std::string> m_privs;
bool m_is_singleplayer;
v2f m_animation_range;
float m_animation_speed;
float m_animation_blend;
bool m_animation_sent;
std::map<std::string, core::vector2d<v3f> > m_bone_position; // Stores position and rotation for each bone name
bool m_bone_position_sent;
int m_attachment_parent_id;
std::string m_attachment_bone;
v3f m_attachment_position;
v3f m_attachment_rotation;
bool m_attachment_sent;
public:
// Some flags used by Server
bool m_teleported;
bool m_moved;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_wielded_item_not_sent;

View File

@ -2315,7 +2315,7 @@ void ClientEnvironment::removeActiveObject(u16 id)
<<"id="<<id<<" not found"<<std::endl;
return;
}
obj->removeFromScene();
obj->removeFromScene(true);
delete obj;
m_active_objects.remove(id);
}

View File

@ -464,6 +464,8 @@ public:
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
std::vector<core::vector2d<int> > attachment_list; // X is child ID, Y is parent ID
private:
ClientMap *m_map;
scene::ISceneManager *m_smgr;

View File

@ -1881,6 +1881,8 @@ void the_game(
bool a_jump,
bool a_superspeed,
bool a_sneak,
bool a_LMB,
bool a_RMB,
float a_pitch,
float a_yaw*/
PlayerControl control(
@ -1891,10 +1893,24 @@ void the_game(
input->isKeyDown(getKeySetting("keymap_jump")),
input->isKeyDown(getKeySetting("keymap_special1")),
input->isKeyDown(getKeySetting("keymap_sneak")),
input->getLeftState(),
input->getRightState(),
camera_pitch,
camera_yaw
);
client.setPlayerControl(control);
u32 keyPressed=
1*(int)input->isKeyDown(getKeySetting("keymap_forward"))+
2*(int)input->isKeyDown(getKeySetting("keymap_backward"))+
4*(int)input->isKeyDown(getKeySetting("keymap_left"))+
8*(int)input->isKeyDown(getKeySetting("keymap_right"))+
16*(int)input->isKeyDown(getKeySetting("keymap_jump"))+
32*(int)input->isKeyDown(getKeySetting("keymap_special1"))+
64*(int)input->isKeyDown(getKeySetting("keymap_sneak"))+
128*(int)input->getLeftState()+
256*(int)input->getRightState();
LocalPlayer* player = client.getEnv().getLocalPlayer();
player->keyPressed=keyPressed;
}
/*

View File

@ -92,6 +92,43 @@ std::string gob_cmd_set_sprite(
return os.str();
}
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend)
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, GENERIC_CMD_SET_ANIMATION);
// parameters
writeV2F1000(os, frames);
writeF1000(os, frame_speed);
writeF1000(os, frame_blend);
return os.str();
}
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation)
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, GENERIC_CMD_SET_BONE_POSITION);
// parameters
os<<serializeString(bone);
writeV3F1000(os, position);
writeV3F1000(os, rotation);
return os.str();
}
std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation)
{
std::ostringstream os(std::ios::binary);
// command
writeU8(os, GENERIC_CMD_SET_ATTACHMENT);
// parameters
writeS16(os, parent_id);
os<<serializeString(bone);
writeV3F1000(os, position);
writeV3F1000(os, rotation);
return os.str();
}
std::string gob_cmd_punched(s16 damage, s16 result_hp)
{
std::ostringstream os(std::ios::binary);

View File

@ -28,8 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GENERIC_CMD_UPDATE_POSITION 1
#define GENERIC_CMD_SET_TEXTURE_MOD 2
#define GENERIC_CMD_SET_SPRITE 3
#define GENERIC_CMD_PUNCHED 4
#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 5
#define GENERIC_CMD_SET_ANIMATION 4
#define GENERIC_CMD_SET_BONE_POSITION 5
#define GENERIC_CMD_SET_ATTACHMENT 6
#define GENERIC_CMD_PUNCHED 7
#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 8
#include "object_properties.h"
std::string gob_cmd_set_properties(const ObjectProperties &prop);
@ -54,6 +57,12 @@ std::string gob_cmd_set_sprite(
bool select_horiz_by_yawpitch
);
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend);
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation);
std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation);
std::string gob_cmd_punched(s16 damage, s16 result_hp);
#include "itemgroup.h"

View File

@ -199,6 +199,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_inventorylists.clear();
m_images.clear();
m_backgrounds.clear();
m_fields.clear();
Strfnd f(m_formspec_string);
@ -278,9 +279,26 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
if(bp_set != 2)
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
m_images.push_back(ImageDrawSpec(name, pos, geom));
}
else if(type == "background")
{
v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
pos.Y += stof(f.next(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
v2s32 geom;
geom.X = stof(f.next(",")) * (float)spacing.X;
geom.Y = stof(f.next(";")) * (float)spacing.Y;
std::string name = f.next("]");
infostream<<"image name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
if(bp_set != 2)
errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
}
else if(type == "field")
{
std::string fname = f.next(";");
@ -458,6 +476,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
e->setUseAlphaChannel(true);
e->setImage(texture);
e->setPressedImage(texture);
e->setScaleImage(true);
@ -691,6 +710,26 @@ void GUIFormSpecMenu::drawMenu()
m_tooltip_element->setVisible(false);
/*
Draw backgrounds
*/
for(u32 i=0; i<m_backgrounds.size(); i++)
{
const ImageDrawSpec &spec = m_backgrounds[i];
video::ITexture *texture =
m_gamedef->tsrc()->getTextureRaw(spec.name);
// Image size on screen
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
// Image rectangle on screen
core::rect<s32> rect = imgrect + spec.pos;
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
driver->draw2DImage(texture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())),
NULL/*&AbsoluteClippingRect*/, colors, true);
}
/*
Draw images
*/
@ -715,8 +754,11 @@ void GUIFormSpecMenu::drawMenu()
Draw items
Phase 0: Item slot rectangles
Phase 1: Item images; prepare tooltip
If backgrounds used, do not draw Item slot rectangles
*/
for(int phase=0; phase<=1; phase++)
int start_phase=0;
if (m_backgrounds.size() > 0) start_phase=1;
for(int phase=start_phase; phase<=1; phase++)
for(u32 i=0; i<m_inventorylists.size(); i++)
{
drawList(m_inventorylists[i], phase);

View File

@ -206,6 +206,7 @@ protected:
TextDest *m_text_dst;
core::array<ListDrawSpec> m_inventorylists;
core::array<ImageDrawSpec> m_backgrounds;
core::array<ImageDrawSpec> m_images;
core::array<FieldSpec> m_fields;

View File

@ -34,6 +34,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
LocalPlayer::LocalPlayer(IGameDef *gamedef):
Player(gamedef),
isAttached(false),
overridePosition(v3f(0,0,0)),
m_sneak_node(32767,32767,32767),
m_sneak_node_exists(false),
m_old_node_below(32767,32767,32767),
@ -59,6 +61,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
v3f old_speed = m_speed;
// Copy parent position if local player is attached
if(isAttached)
{
setPosition(overridePosition);
return;
}
// Skip collision detection if a special movement mode is used
bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
bool free_move = fly_allowed && g_settings->getBool("free_move");
@ -353,6 +362,13 @@ void LocalPlayer::applyControl(float dtime)
setPitch(control.pitch);
setYaw(control.yaw);
// Nullify speed and don't run positioning code if the player is attached
if(isAttached)
{
setSpeed(v3f(0,0,0));
return;
}
v3f move_direction = v3f(0,0,1);
move_direction.rotateXZBy(getYaw());

View File

@ -22,53 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "player.h"
struct PlayerControl
{
PlayerControl()
{
up = false;
down = false;
left = false;
right = false;
jump = false;
aux1 = false;
sneak = false;
pitch = 0;
yaw = 0;
}
PlayerControl(
bool a_up,
bool a_down,
bool a_left,
bool a_right,
bool a_jump,
bool a_aux1,
bool a_sneak,
float a_pitch,
float a_yaw
)
{
up = a_up;
down = a_down;
left = a_left;
right = a_right;
jump = a_jump;
aux1 = a_aux1;
sneak = a_sneak;
pitch = a_pitch;
yaw = a_yaw;
}
bool up;
bool down;
bool left;
bool right;
bool jump;
bool aux1;
bool sneak;
float pitch;
float yaw;
};
class LocalPlayer : public Player
{
public:
@ -80,6 +33,10 @@ public:
return true;
}
bool isAttached;
v3f overridePosition;
void move(f32 dtime, Map &map, f32 pos_max_d,
core::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d);
@ -87,9 +44,6 @@ public:
void applyControl(float dtime);
v3s16 getStandingNodePos();
PlayerControl control;
private:
// This is used for determining the sneaking range
v3s16 m_sneak_node;

View File

@ -132,6 +132,7 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
for(s16 ii=0; ii<trunk_h; ii++)
{
if(vmanip.m_area.contains(p1))
if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
p1.Y++;
}

View File

@ -433,9 +433,6 @@ video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
}
// Create render target texture
video::ITexture *oldtexture = driver->findTexture(texture_name.c_str());
if(oldtexture)
driver->removeTexture(oldtexture);
video::ITexture *rtt = driver->addRenderTargetTexture(
dim, texture_name.c_str(), video::ECF_A8R8G8B8);
if(rtt == NULL)

View File

@ -217,7 +217,7 @@ void ContentFeatures::reset()
void ContentFeatures::serialize(std::ostream &os)
{
writeU8(os, 5); // version
writeU8(os, 6); // version
os<<serializeString(name);
writeU16(os, groups.size());
for(ItemGroupList::const_iterator
@ -254,6 +254,7 @@ void ContentFeatures::serialize(std::ostream &os)
os<<serializeString(liquid_alternative_flowing);
os<<serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
writeU8(os, light_source);
writeU32(os, damage_per_second);
node_box.serialize(os);
@ -265,13 +266,12 @@ void ContentFeatures::serialize(std::ostream &os)
serializeSimpleSoundSpec(sound_dug, os);
// Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version
writeU8(os, liquid_renewable);
}
void ContentFeatures::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 5)
if(version != 6)
throw SerializationError("unsupported ContentFeatures version");
name = deSerializeString(is);
groups.clear();
@ -311,6 +311,7 @@ void ContentFeatures::deSerialize(std::istream &is)
liquid_alternative_flowing = deSerializeString(is);
liquid_alternative_source = deSerializeString(is);
liquid_viscosity = readU8(is);
liquid_renewable = readU8(is);
light_source = readU8(is);
damage_per_second = readU32(is);
node_box.deSerialize(is);
@ -325,7 +326,6 @@ void ContentFeatures::deSerialize(std::istream &is)
try{
// Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version
liquid_renewable = readU8(is);
}catch(SerializationError &e) {};
}

View File

@ -18,8 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "object_properties.h"
#include "irrlichttypes_bloated.h"
#include "util/serialize.h"
#include <sstream>
#include <map>
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
@ -30,6 +32,7 @@ ObjectProperties::ObjectProperties():
weight(5),
collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
visual("sprite"),
mesh(""),
visual_size(1,1),
spritediv(1,1),
initial_sprite_basepos(0,0),
@ -38,6 +41,7 @@ ObjectProperties::ObjectProperties():
automatic_rotate(0)
{
textures.push_back("unknown_object.png");
colors.push_back(video::SColor(255,255,255,255));
}
std::string ObjectProperties::dump()
@ -48,12 +52,18 @@ std::string ObjectProperties::dump()
os<<", weight="<<weight;
os<<", collisionbox="<<PP(collisionbox.MinEdge)<<","<<PP(collisionbox.MaxEdge);
os<<", visual="<<visual;
os<<", mesh="<<mesh;
os<<", visual_size="<<PP2(visual_size);
os<<", textures=[";
for(u32 i=0; i<textures.size(); i++){
os<<"\""<<textures[i]<<"\" ";
}
os<<"]";
os<<", colors=[";
for(u32 i=0; i<colors.size(); i++){
os<<"\""<<colors[i].getAlpha()<<","<<colors[i].getRed()<<","<<colors[i].getGreen()<<","<<colors[i].getBlue()<<"\" ";
}
os<<"]";
os<<", spritediv="<<PP2(spritediv);
os<<", initial_sprite_basepos="<<PP2(initial_sprite_basepos);
os<<", is_visible="<<is_visible;
@ -71,11 +81,16 @@ void ObjectProperties::serialize(std::ostream &os) const
writeV3F1000(os, collisionbox.MinEdge);
writeV3F1000(os, collisionbox.MaxEdge);
os<<serializeString(visual);
os<<serializeString(mesh);
writeV2F1000(os, visual_size);
writeU16(os, textures.size());
for(u32 i=0; i<textures.size(); i++){
os<<serializeString(textures[i]);
}
writeU16(os, colors.size());
for(u32 i=0; i<colors.size(); i++){
writeARGB8(os, colors[i]);
}
writeV2S16(os, spritediv);
writeV2S16(os, initial_sprite_basepos);
writeU8(os, is_visible);
@ -94,12 +109,17 @@ void ObjectProperties::deSerialize(std::istream &is)
collisionbox.MinEdge = readV3F1000(is);
collisionbox.MaxEdge = readV3F1000(is);
visual = deSerializeString(is);
mesh = deSerializeString(is);
visual_size = readV2F1000(is);
textures.clear();
u32 texture_count = readU16(is);
for(u32 i=0; i<texture_count; i++){
textures.push_back(deSerializeString(is));
}
u32 color_count = readU16(is);
for(u32 i=0; i<color_count; i++){
colors.push_back(readARGB8(is));
}
spritediv = readV2S16(is);
initial_sprite_basepos = readV2S16(is);
is_visible = readU8(is);

View File

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include "irrlichttypes_bloated.h"
#include <iostream>
#include <map>
struct ObjectProperties
{
@ -32,14 +33,17 @@ struct ObjectProperties
float weight;
core::aabbox3d<f32> collisionbox;
std::string visual;
std::string mesh;
v2f visual_size;
core::array<std::string> textures;
core::array<video::SColor> colors;
v2s16 spritediv;
v2s16 initial_sprite_basepos;
bool is_visible;
bool makes_footstep_sound;
float automatic_rotate;
ObjectProperties();
std::string dump();
void serialize(std::ostream &os) const;

View File

@ -28,6 +28,61 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
struct PlayerControl
{
PlayerControl()
{
up = false;
down = false;
left = false;
right = false;
jump = false;
aux1 = false;
sneak = false;
LMB = false;
RMB = false;
pitch = 0;
yaw = 0;
}
PlayerControl(
bool a_up,
bool a_down,
bool a_left,
bool a_right,
bool a_jump,
bool a_aux1,
bool a_sneak,
bool a_LMB,
bool a_RMB,
float a_pitch,
float a_yaw
)
{
up = a_up;
down = a_down;
left = a_left;
right = a_right;
jump = a_jump;
aux1 = a_aux1;
sneak = a_sneak;
LMB = a_LMB;
RMB = a_RMB;
pitch = a_pitch;
yaw = a_yaw;
}
bool up;
bool down;
bool left;
bool right;
bool jump;
bool aux1;
bool sneak;
bool LMB;
bool RMB;
float pitch;
float yaw;
};
class Map;
class IGameDef;
struct CollisionInfo;
@ -158,6 +213,14 @@ public:
std::string inventory_formspec;
PlayerControl control;
PlayerControl getPlayerControl()
{
return control;
}
u32 keyPressed;
protected:
IGameDef *m_gamedef;

View File

@ -937,6 +937,8 @@ static void read_object_properties(lua_State *L, int index,
getstringfield(L, -1, "visual", prop->visual);
getstringfield(L, -1, "mesh", prop->mesh);
lua_getfield(L, -1, "visual_size");
if(lua_istable(L, -1))
prop->visual_size = read_v2f(L, -1);
@ -959,6 +961,23 @@ static void read_object_properties(lua_State *L, int index,
}
lua_pop(L, 1);
lua_getfield(L, -1, "colors");
if(lua_istable(L, -1)){
prop->colors.clear();
int table = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, table) != 0){
// key at index -2 and value at index -1
if(lua_isstring(L, -1))
prop->colors.push_back(readARGB8(L, -1));
else
prop->colors.push_back(video::SColor(255, 255, 255, 255));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
}
lua_pop(L, 1);
lua_getfield(L, -1, "spritediv");
if(lua_istable(L, -1))
prop->spritediv = read_v2s16(L, -1);
@ -2697,6 +2716,80 @@ private:
return 0;
}
// set_animation(self, frame_range, frame_speed, frame_blend)
static int l_set_animation(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
v2f frames = v2f(1, 1);
if(!lua_isnil(L, 2))
frames = read_v2f(L, 2);
float frame_speed = 15;
if(!lua_isnil(L, 3))
frame_speed = lua_tonumber(L, 3);
float frame_blend = 0;
if(!lua_isnil(L, 4))
frame_blend = lua_tonumber(L, 4);
co->setAnimation(frames, frame_speed, frame_blend);
return 0;
}
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
static int l_set_bone_position(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
std::string bone = "";
if(!lua_isnil(L, 2))
bone = lua_tostring(L, 2);
v3f position = v3f(0, 0, 0);
if(!lua_isnil(L, 3))
position = read_v3f(L, 3);
v3f rotation = v3f(0, 0, 0);
if(!lua_isnil(L, 4))
rotation = read_v3f(L, 4);
co->setBonePosition(bone, position, rotation);
return 0;
}
// set_attach(self, parent, bone, position, rotation)
static int l_set_attach(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ObjectRef *parent_ref = checkobject(L, 2);
ServerActiveObject *co = getobject(ref);
ServerActiveObject *parent = getobject(parent_ref);
if(co == NULL) return 0;
if(parent == NULL) return 0;
// Do it
std::string bone = "";
if(!lua_isnil(L, 3))
bone = lua_tostring(L, 3);
v3f position = v3f(0, 0, 0);
if(!lua_isnil(L, 4))
position = read_v3f(L, 4);
v3f rotation = v3f(0, 0, 0);
if(!lua_isnil(L, 5))
rotation = read_v3f(L, 5);
co->setAttachment(parent->getId(), bone, position, rotation);
return 0;
}
// set_detach(self)
static int l_set_detach(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
return 0;
}
// set_properties(self, properties)
static int l_set_properties(lua_State *L)
{
@ -2933,6 +3026,53 @@ private:
return 1;
}
// get_player_control(self)
static int l_get_player_control(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if(player == NULL){
lua_pushlstring(L, "", 0);
return 1;
}
// Do it
PlayerControl control = player->getPlayerControl();
lua_newtable(L);
lua_pushboolean(L, control.up);
lua_setfield(L, -2, "up");
lua_pushboolean(L, control.down);
lua_setfield(L, -2, "down");
lua_pushboolean(L, control.left);
lua_setfield(L, -2, "left");
lua_pushboolean(L, control.right);
lua_setfield(L, -2, "right");
lua_pushboolean(L, control.jump);
lua_setfield(L, -2, "jump");
lua_pushboolean(L, control.aux1);
lua_setfield(L, -2, "aux1");
lua_pushboolean(L, control.sneak);
lua_setfield(L, -2, "sneak");
lua_pushboolean(L, control.LMB);
lua_setfield(L, -2, "LMB");
lua_pushboolean(L, control.RMB);
lua_setfield(L, -2, "RMB");
return 1;
}
// get_player_control_bits(self)
static int l_get_player_control_bits(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if(player == NULL){
lua_pushlstring(L, "", 0);
return 1;
}
// Do it
lua_pushnumber(L, player->keyPressed);
return 1;
}
public:
ObjectRef(ServerActiveObject *object):
m_object(object)
@ -3011,6 +3151,10 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, get_wielded_item),
method(ObjectRef, set_wielded_item),
method(ObjectRef, set_armor_groups),
method(ObjectRef, set_animation),
method(ObjectRef, set_bone_position),
method(ObjectRef, set_attach),
method(ObjectRef, set_detach),
method(ObjectRef, set_properties),
// LuaEntitySAO-only
method(ObjectRef, setvelocity),
@ -3031,6 +3175,8 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, get_look_yaw),
method(ObjectRef, set_inventory_formspec),
method(ObjectRef, get_inventory_formspec),
method(ObjectRef, get_player_control),
method(ObjectRef, get_player_control_bits),
{0,0}
};
@ -6589,6 +6735,8 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
getstringfield(L, -1, "visual", prop->visual);
getstringfield(L, -1, "mesh", prop->mesh);
// Deprecated: read object properties directly
read_object_properties(L, -1, prop);

View File

@ -1371,9 +1371,9 @@ void Server::AsyncRunStep()
/*
Send player inventories and HPs if necessary
*/
if(playersao->m_teleported){
if(playersao->m_moved){
SendMovePlayer(client->peer_id);
playersao->m_teleported = false;
playersao->m_moved = false;
}
if(playersao->m_inventory_not_sent){
UpdateCrafting(client->peer_id);
@ -2369,7 +2369,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(command == TOSERVER_PLAYERPOS)
{
if(datasize < 2+12+12+4+4)
if(datasize < 2+12+12+4+4+4)
return;
u32 start = 0;
@ -2377,6 +2377,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
v3s32 ss = readV3S32(&data[start+2+12]);
f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
u32 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
pitch = wrapDegrees(pitch);
@ -2386,6 +2387,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
player->setSpeed(speed);
player->setPitch(pitch);
player->setYaw(yaw);
player->keyPressed=keyPressed;
player->control.up = (bool)(keyPressed&1);
player->control.down = (bool)(keyPressed&2);
player->control.left = (bool)(keyPressed&4);
player->control.right = (bool)(keyPressed&8);
player->control.jump = (bool)(keyPressed&16);
player->control.aux1 = (bool)(keyPressed&32);
player->control.sneak = (bool)(keyPressed&64);
player->control.LMB = (bool)(keyPressed&128);
player->control.RMB = (bool)(keyPressed&256);
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
@ -3167,6 +3178,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} // action == 4
/*
Catch invalid actions
*/
@ -4029,6 +4041,7 @@ void Server::fillMediaCache()
paths.push_back(mod.path + DIR_DELIM + "textures");
paths.push_back(mod.path + DIR_DELIM + "sounds");
paths.push_back(mod.path + DIR_DELIM + "media");
paths.push_back(mod.path + DIR_DELIM + "models");
}
std::string path_all = "textures";
paths.push_back(path_all + DIR_DELIM + "all");
@ -4054,6 +4067,7 @@ void Server::fillMediaCache()
".png", ".jpg", ".bmp", ".tga",
".pcx", ".ppm", ".psd", ".wal", ".rgb",
".ogg",
".x", ".b3d", ".md2", ".obj",
NULL
};
if(removeStringEnd(filename, supported_ext) == ""){

View File

@ -152,6 +152,12 @@ public:
virtual void setArmorGroups(const ItemGroupList &armor_groups)
{}
virtual void setAnimation(v2f frames, float frame_speed, float frame_blend)
{}
virtual void setBonePosition(std::string bone, v3f position, v3f rotation)
{}
virtual void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
{}
virtual ObjectProperties* accessObjectProperties()
{ return NULL; }
virtual void notifyObjectPropertiesModified()

View File

@ -518,15 +518,6 @@ core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<
// Apply transform to image data
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
/*
Adds a new texture to the video driver and returns a pointer to it.
This pointer should not be dropped. Any texture that was registered
with that name before is removed (this may invalidate some ITexture
pointers).
*/
video::ITexture* register_texture(video::IVideoDriver *driver,
std::string name, video::IImage *img);
/*
Generate image based on a string like "stone.png" or "[crack0".
if baseimg is NULL, it is created. Otherwise stuff is made on it.
@ -695,9 +686,11 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
" create texture \""<<name<<"\""<<std::endl;
}
// Create texture from resulting image
if(baseimg != NULL)
t = register_texture(driver, name, baseimg);
{
// Create texture from resulting image
t = driver->addTexture(name.c_str(), baseimg);
}
/*
Add texture to caches (add NULL textures too)
@ -816,7 +809,7 @@ void TextureSource::rebuildImagesAndTextures()
// Create texture from resulting image
video::ITexture *t = NULL;
if(img)
t = register_texture(driver, sap->name, img);
t = driver->addTexture(sap->name.c_str(), img);
// Replace texture
sap->a.atlas = t;
@ -1051,7 +1044,7 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
/*
Make texture
*/
video::ITexture *t = register_texture(driver, "__main_atlas__", atlas_img);
video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
assert(t);
/*
@ -1142,15 +1135,6 @@ video::IImage* generate_image_from_scratch(std::string name,
return baseimg;
}
video::ITexture* register_texture(video::IVideoDriver *driver,
std::string name, video::IImage *img)
{
video::ITexture *old_texture = driver->findTexture(name.c_str());
if(old_texture)
driver->removeTexture(old_texture);
return driver->addTexture(name.c_str(), img);
}
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
IrrlichtDevice *device, SourceImageCache *sourcecache)
{
@ -1557,12 +1541,12 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
assert(img_top && img_left && img_right);
// Create textures from images
video::ITexture *texture_top = register_texture(driver,
imagename_top + "__temp1__", img_top);
video::ITexture *texture_left = register_texture(driver,
imagename_left + "__temp2__", img_left);
video::ITexture *texture_right = register_texture(driver,
imagename_right + "__temp3__", img_right);
video::ITexture *texture_top = driver->addTexture(
(imagename_top + "__temp__").c_str(), img_top);
video::ITexture *texture_left = driver->addTexture(
(imagename_left + "__temp__").c_str(), img_left);
video::ITexture *texture_right = driver->addTexture(
(imagename_right + "__temp__").c_str(), img_right);
assert(texture_top && texture_left && texture_right);
// Drop images

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define UTIL_SERIALIZE_HEADER
#include "../irrlichttypes.h"
#include "../irrlichttypes_bloated.h"
#include "../irr_v2d.h"
#include "../irr_v3d.h"
#include <iostream>
@ -197,6 +198,24 @@ inline v3s16 readV3S16(u8 *data)
return p;
}
inline void writeARGB8(u8 *data, video::SColor p)
{
writeU8(&data[0], p.getAlpha());
writeU8(&data[1], p.getRed());
writeU8(&data[2], p.getGreen());
writeU8(&data[3], p.getBlue());
}
inline video::SColor readARGB8(u8 *data)
{
video::SColor p;
p.setAlpha(readU8(&data[0]));
p.setRed(readU8(&data[1]));
p.setGreen(readU8(&data[2]));
p.setBlue(readU8(&data[3]));
return p;
}
/*
The above stuff directly interfaced to iostream
*/
@ -344,6 +363,20 @@ inline v3s16 readV3S16(std::istream &is)
return readV3S16((u8*)buf);
}
inline void writeARGB8(std::ostream &os, video::SColor p)
{
char buf[4] = {0};
writeARGB8((u8*)buf, p);
os.write(buf, 4);
}
inline video::SColor readARGB8(std::istream &is)
{
char buf[4] = {0};
is.read(buf, 4);
return readARGB8((u8*)buf);
}
/*
More serialization stuff
*/