mirror of
https://github.com/minetest/minetest.git
synced 2024-11-30 03:23:45 +01:00
Extend bone override capabilities (#12388)
This commit is contained in:
parent
61d0f613df
commit
0d61598d8a
@ -7556,17 +7556,32 @@ child will follow movement and rotation of that bone.
|
|||||||
object.
|
object.
|
||||||
* `set_detach()`: Detaches object. No-op if object was not attached.
|
* `set_detach()`: Detaches object. No-op if object was not attached.
|
||||||
* `set_bone_position([bone, position, rotation])`
|
* `set_bone_position([bone, position, rotation])`
|
||||||
* `bone`: string. Default is `""`, the root bone
|
* Shorthand for `set_bone_override(bone, {position = position, rotation = rotation:apply(math.rad)})` using absolute values.
|
||||||
* `position`: `{x=num, y=num, z=num}`, relative, `default {x=0, y=0, z=0}`
|
* **Note:** Rotation is in degrees, not radians.
|
||||||
* `rotation`: `{x=num, y=num, z=num}`, default `{x=0, y=0, z=0}`
|
* **Deprecated:** Use `set_bone_override` instead.
|
||||||
* `get_bone_position(bone)`:
|
* `get_bone_position(bone)`: returns the previously set position and rotation of the bone
|
||||||
* returns bone parameters previously set by `set_bone_position`
|
* Shorthand for `get_bone_override(bone).position.vec, get_bone_override(bone).rotation.vec:apply(math.deg)`.
|
||||||
* returns `position, rotation` of the specified bone (as vectors)
|
* **Note:** Returned rotation is in degrees, not radians.
|
||||||
* note: position is relative to the object
|
* **Deprecated:** Use `get_bone_override` instead.
|
||||||
* `set_properties(object property table)`:
|
* `set_bone_override(bone, override)`
|
||||||
* set a number of object properties in the given table
|
* `bone`: string
|
||||||
* only properties listed in the table will be changed
|
* `override`: `{ position = property, rotation = property, scale = property }` or `nil`
|
||||||
* see the 'Object properties' section for details
|
* `property`: `{ vec = vector, interpolation = 0, absolute = false}` or `nil`;
|
||||||
|
* `vec` is in the same coordinate system as the model, and in degrees for rotation
|
||||||
|
* `property = nil` is equivalent to no override on that property
|
||||||
|
* `absolute`: If set to `false`, the override will be relative to the animated property:
|
||||||
|
* Transposition in the case of `position`;
|
||||||
|
* Composition in the case of `rotation`;
|
||||||
|
* Multiplication in the case of `scale`
|
||||||
|
* `interpolation`: Old and new values are interpolated over this timeframe (in seconds)
|
||||||
|
* `override = nil` (including omission) is shorthand for `override = {}` which clears the override
|
||||||
|
* **Note:** Unlike `set_bone_position`, the rotation is in radians, not degrees.
|
||||||
|
* Compatibility note: Clients prior to 5.9.0 only support absolute position and rotation.
|
||||||
|
All values are treated as absolute and are set immediately (no interpolation).
|
||||||
|
* `get_bone_override(bone)`: returns `override` in the above format
|
||||||
|
* **Note:** Unlike `get_bone_position`, the returned rotation is in radians, not degrees.
|
||||||
|
* `get_bone_overrides()`: returns all bone overrides as table `{[bonename] = override, ...}`
|
||||||
|
* `set_properties(object property table)`
|
||||||
* `get_properties()`: returns a table of all object properties
|
* `get_properties()`: returns a table of all object properties
|
||||||
* `is_player()`: returns true for players, false otherwise
|
* `is_player()`: returns true for players, false otherwise
|
||||||
* `get_nametag_attributes()`
|
* `get_nametag_attributes()`
|
||||||
|
@ -21,7 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "irr_aabb3d.h"
|
#include "irr_aabb3d.h"
|
||||||
#include "irr_v3d.h"
|
#include "irr_v3d.h"
|
||||||
|
#include <quaternion.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|
||||||
enum ActiveObjectType {
|
enum ActiveObjectType {
|
||||||
@ -72,6 +74,78 @@ enum ActiveObjectCommand {
|
|||||||
AO_CMD_SET_ANIMATION_SPEED
|
AO_CMD_SET_ANIMATION_SPEED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BoneOverride
|
||||||
|
{
|
||||||
|
struct PositionProperty
|
||||||
|
{
|
||||||
|
v3f previous;
|
||||||
|
v3f vector;
|
||||||
|
bool absolute = false;
|
||||||
|
f32 interp_timer = 0;
|
||||||
|
} position;
|
||||||
|
|
||||||
|
v3f getPosition(v3f anim_pos) const {
|
||||||
|
f32 progress = dtime_passed / position.interp_timer;
|
||||||
|
if (progress > 1.0f || position.interp_timer == 0.0f)
|
||||||
|
progress = 1.0f;
|
||||||
|
return position.vector.getInterpolated(position.previous, progress)
|
||||||
|
+ (position.absolute ? v3f() : anim_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RotationProperty
|
||||||
|
{
|
||||||
|
core::quaternion previous;
|
||||||
|
core::quaternion next;
|
||||||
|
bool absolute = false;
|
||||||
|
f32 interp_timer = 0;
|
||||||
|
} rotation;
|
||||||
|
|
||||||
|
v3f getRotationEulerDeg(v3f anim_rot_euler) const {
|
||||||
|
core::quaternion rot;
|
||||||
|
|
||||||
|
f32 progress = dtime_passed / rotation.interp_timer;
|
||||||
|
if (progress > 1.0f || rotation.interp_timer == 0.0f)
|
||||||
|
progress = 1.0f;
|
||||||
|
rot.slerp(rotation.previous, rotation.next, progress);
|
||||||
|
if (!rotation.absolute) {
|
||||||
|
core::quaternion anim_rot(anim_rot_euler * core::DEGTORAD);
|
||||||
|
rot = rot * anim_rot; // first rotate by anim. bone rot., then rot.
|
||||||
|
}
|
||||||
|
|
||||||
|
v3f rot_euler;
|
||||||
|
rot.toEuler(rot_euler);
|
||||||
|
return rot_euler * core::RADTODEG;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ScaleProperty
|
||||||
|
{
|
||||||
|
v3f previous;
|
||||||
|
v3f vector{1, 1, 1};
|
||||||
|
bool absolute = false;
|
||||||
|
f32 interp_timer = 0;
|
||||||
|
} scale;
|
||||||
|
|
||||||
|
v3f getScale(v3f anim_scale) const {
|
||||||
|
f32 progress = dtime_passed / scale.interp_timer;
|
||||||
|
if (progress > 1.0f || scale.interp_timer == 0.0f)
|
||||||
|
progress = 1.0f;
|
||||||
|
return scale.vector.getInterpolated(scale.previous, progress)
|
||||||
|
* (scale.absolute ? v3f(1) : anim_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 dtime_passed = 0;
|
||||||
|
|
||||||
|
bool isIdentity() const
|
||||||
|
{
|
||||||
|
return !position.absolute && position.vector == v3f()
|
||||||
|
&& !rotation.absolute && rotation.next == core::quaternion()
|
||||||
|
&& !scale.absolute && scale.vector == v3f(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unordered_map<std::string, BoneOverride> BoneOverrideMap;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parent class for ServerActiveObject and ClientActiveObject
|
Parent class for ServerActiveObject and ClientActiveObject
|
||||||
*/
|
*/
|
||||||
|
@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "client/shader.h"
|
#include "client/shader.h"
|
||||||
#include "client/minimap.h"
|
#include "client/minimap.h"
|
||||||
|
#include <quaternion.h>
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
struct ToolCapabilities;
|
struct ToolCapabilities;
|
||||||
@ -828,7 +829,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
|||||||
updateMarker();
|
updateMarker();
|
||||||
updateNodePos();
|
updateNodePos();
|
||||||
updateAnimation();
|
updateAnimation();
|
||||||
updateBonePosition();
|
updateBones(.0f);
|
||||||
updateAttachments();
|
updateAttachments();
|
||||||
setNodeLight(m_last_light);
|
setNodeLight(m_last_light);
|
||||||
updateMeshCulling();
|
updateMeshCulling();
|
||||||
@ -1246,7 +1247,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
|||||||
updatePositionRecursive(m_matrixnode);
|
updatePositionRecursive(m_matrixnode);
|
||||||
m_animated_meshnode->updateAbsolutePosition();
|
m_animated_meshnode->updateAbsolutePosition();
|
||||||
m_animated_meshnode->animateJoints();
|
m_animated_meshnode->animateJoints();
|
||||||
updateBonePosition();
|
updateBones(dtime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1527,19 +1528,28 @@ void GenericCAO::updateAnimationSpeed()
|
|||||||
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
|
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericCAO::updateBonePosition()
|
void GenericCAO::updateBones(f32 dtime)
|
||||||
{
|
{
|
||||||
if (m_bone_position.empty() || !m_animated_meshnode)
|
if (!m_animated_meshnode)
|
||||||
return;
|
return;
|
||||||
|
if (m_bone_override.empty()) {
|
||||||
|
m_animated_meshnode->setJointMode(scene::EJUOR_NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_animated_meshnode->setJointMode(scene::EJUOR_CONTROL); // To write positions to the mesh on render
|
m_animated_meshnode->setJointMode(scene::EJUOR_CONTROL); // To write positions to the mesh on render
|
||||||
for (auto &it : m_bone_position) {
|
for (auto &it : m_bone_override) {
|
||||||
std::string bone_name = it.first;
|
std::string bone_name = it.first;
|
||||||
scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
|
scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
|
||||||
if (bone) {
|
if (!bone)
|
||||||
bone->setPosition(it.second.X);
|
continue;
|
||||||
bone->setRotation(it.second.Y);
|
|
||||||
}
|
BoneOverride &props = it.second;
|
||||||
|
props.dtime_passed += dtime;
|
||||||
|
|
||||||
|
bone->setPosition(props.getPosition(bone->getPosition()));
|
||||||
|
bone->setRotation(props.getRotationEulerDeg(bone->getRotation()));
|
||||||
|
bone->setScale(props.getScale(bone->getScale()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// search through bones to find mistakenly rotated bones due to bug in Irrlicht
|
// search through bones to find mistakenly rotated bones due to bug in Irrlicht
|
||||||
@ -1550,7 +1560,7 @@ void GenericCAO::updateBonePosition()
|
|||||||
|
|
||||||
//If bone is manually positioned there is no need to perform the bug check
|
//If bone is manually positioned there is no need to perform the bug check
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
for (auto &it : m_bone_position) {
|
for (auto &it : m_bone_override) {
|
||||||
if (it.first == bone->getName()) {
|
if (it.first == bone->getName()) {
|
||||||
skip = true;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
@ -1852,11 +1862,46 @@ void GenericCAO::processMessage(const std::string &data)
|
|||||||
updateAnimationSpeed();
|
updateAnimationSpeed();
|
||||||
} else if (cmd == AO_CMD_SET_BONE_POSITION) {
|
} else if (cmd == AO_CMD_SET_BONE_POSITION) {
|
||||||
std::string bone = deSerializeString16(is);
|
std::string bone = deSerializeString16(is);
|
||||||
v3f position = readV3F32(is);
|
auto it = m_bone_override.find(bone);
|
||||||
v3f rotation = readV3F32(is);
|
BoneOverride props;
|
||||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
if (it != m_bone_override.end()) {
|
||||||
|
props = it->second;
|
||||||
// updateBonePosition(); now called every step
|
// Reset timer
|
||||||
|
props.dtime_passed = 0;
|
||||||
|
// Save previous values for interpolation
|
||||||
|
props.position.previous = props.position.vector;
|
||||||
|
props.rotation.previous = props.rotation.next;
|
||||||
|
props.scale.previous = props.scale.vector;
|
||||||
|
} else {
|
||||||
|
// Disable interpolation
|
||||||
|
props.position.interp_timer = 0.0f;
|
||||||
|
props.rotation.interp_timer = 0.0f;
|
||||||
|
props.scale.interp_timer = 0.0f;
|
||||||
|
}
|
||||||
|
// Read new values
|
||||||
|
props.position.vector = readV3F32(is);
|
||||||
|
props.rotation.next = core::quaternion(readV3F32(is) * core::DEGTORAD);
|
||||||
|
props.scale.vector = readV3F32(is); // reads past end of string on older cmds
|
||||||
|
if (is.eof()) {
|
||||||
|
// Backwards compatibility
|
||||||
|
props.scale.vector = v3f(1, 1, 1); // restore the scale which was not sent
|
||||||
|
props.position.absolute = true;
|
||||||
|
props.rotation.absolute = true;
|
||||||
|
} else {
|
||||||
|
props.position.interp_timer = readF32(is);
|
||||||
|
props.rotation.interp_timer = readF32(is);
|
||||||
|
props.scale.interp_timer = readF32(is);
|
||||||
|
u8 absoluteFlag = readU8(is);
|
||||||
|
props.position.absolute = (absoluteFlag & 1) > 0;
|
||||||
|
props.rotation.absolute = (absoluteFlag & 2) > 0;
|
||||||
|
props.scale.absolute = (absoluteFlag & 4) > 0;
|
||||||
|
}
|
||||||
|
if (props.isIdentity()) {
|
||||||
|
m_bone_override.erase(bone);
|
||||||
|
} else {
|
||||||
|
m_bone_override[bone] = props;
|
||||||
|
}
|
||||||
|
// updateBones(); now called every step
|
||||||
} else if (cmd == AO_CMD_ATTACH_TO) {
|
} else if (cmd == AO_CMD_ATTACH_TO) {
|
||||||
u16 parent_id = readS16(is);
|
u16 parent_id = readS16(is);
|
||||||
std::string bone = deSerializeString16(is);
|
std::string bone = deSerializeString16(is);
|
||||||
|
@ -104,7 +104,7 @@ private:
|
|||||||
float m_animation_blend = 0.0f;
|
float m_animation_blend = 0.0f;
|
||||||
bool m_animation_loop = true;
|
bool m_animation_loop = true;
|
||||||
// stores position and rotation for each bone name
|
// stores position and rotation for each bone name
|
||||||
std::unordered_map<std::string, core::vector2d<v3f>> m_bone_position;
|
BoneOverrideMap m_bone_override;
|
||||||
|
|
||||||
int m_attachment_parent_id = 0;
|
int m_attachment_parent_id = 0;
|
||||||
std::unordered_set<int> m_attachment_child_ids;
|
std::unordered_set<int> m_attachment_child_ids;
|
||||||
@ -267,7 +267,7 @@ public:
|
|||||||
|
|
||||||
void updateAnimationSpeed();
|
void updateAnimationSpeed();
|
||||||
|
|
||||||
void updateBonePosition();
|
void updateBones(f32 dtime);
|
||||||
|
|
||||||
void processMessage(const std::string &data) override;
|
void processMessage(const std::string &data) override;
|
||||||
|
|
||||||
|
@ -219,9 +219,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
"start_time" added to TOCLIENT_PLAY_SOUND
|
"start_time" added to TOCLIENT_PLAY_SOUND
|
||||||
place_param2 type change u8 -> optional<u8>
|
place_param2 type change u8 -> optional<u8>
|
||||||
[scheduled bump for 5.8.0]
|
[scheduled bump for 5.8.0]
|
||||||
|
PROTOCOL VERSION 44:
|
||||||
|
AO_CMD_SET_BONE_POSITION extended
|
||||||
|
[scheduled bump for 5.9.0]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LATEST_PROTOCOL_VERSION 43
|
#define LATEST_PROTOCOL_VERSION 44
|
||||||
#define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
|
#define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
|
||||||
|
|
||||||
// Server's supported network protocol range
|
// Server's supported network protocol range
|
||||||
|
@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "server/luaentity_sao.h"
|
#include "server/luaentity_sao.h"
|
||||||
#include "server/player_sao.h"
|
#include "server/player_sao.h"
|
||||||
#include "server/serverinventorymgr.h"
|
#include "server/serverinventorymgr.h"
|
||||||
|
#include "server/unit_sao.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ObjectRef
|
ObjectRef
|
||||||
@ -518,16 +519,25 @@ int ObjectRef::l_set_animation_frame_speed(lua_State *L)
|
|||||||
int ObjectRef::l_set_bone_position(lua_State *L)
|
int ObjectRef::l_set_bone_position(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
log_deprecated(L,"Deprecated call to set_bone_position, use set_bone_override instead");
|
||||||
|
|
||||||
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||||
ServerActiveObject *sao = getobject(ref);
|
ServerActiveObject *sao = getobject(ref);
|
||||||
if (sao == nullptr)
|
if (sao == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
std::string bone = readParam<std::string>(L, 2, "");
|
std::string bone;
|
||||||
v3f position = readParam<v3f>(L, 3, v3f(0, 0, 0));
|
if (!lua_isnil(L, 2))
|
||||||
v3f rotation = readParam<v3f>(L, 4, v3f(0, 0, 0));
|
bone = readParam<std::string>(L, 2);
|
||||||
|
BoneOverride props;
|
||||||
sao->setBonePosition(bone, position, rotation);
|
if (!lua_isnil(L, 3))
|
||||||
|
props.position.vector = check_v3f(L, 3);
|
||||||
|
if (!lua_isnil(L, 4))
|
||||||
|
props.rotation.next = core::quaternion(check_v3f(L, 4) * core::DEGTORAD);
|
||||||
|
props.position.absolute = true;
|
||||||
|
props.rotation.absolute = true;
|
||||||
|
sao->setBoneOverride(bone, props);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,22 +545,144 @@ int ObjectRef::l_set_bone_position(lua_State *L)
|
|||||||
int ObjectRef::l_get_bone_position(lua_State *L)
|
int ObjectRef::l_get_bone_position(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
log_deprecated(L,"Deprecated call to get_bone_position, use get_bone_override instead");
|
||||||
|
|
||||||
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||||
ServerActiveObject *sao = getobject(ref);
|
ServerActiveObject *sao = getobject(ref);
|
||||||
if (sao == nullptr)
|
if (sao == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
std::string bone = readParam<std::string>(L, 2, "");
|
std::string bone = readParam<std::string>(L, 2, "");
|
||||||
|
BoneOverride props = sao->getBoneOverride(bone);
|
||||||
v3f position = v3f(0, 0, 0);
|
push_v3f(L, props.position.vector);
|
||||||
v3f rotation = v3f(0, 0, 0);
|
v3f euler_rot;
|
||||||
sao->getBonePosition(bone, &position, &rotation);
|
props.rotation.next.toEuler(euler_rot);
|
||||||
|
push_v3f(L, euler_rot * core::RADTODEG);
|
||||||
push_v3f(L, position);
|
|
||||||
push_v3f(L, rotation);
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set_bone_override(self, bone, override)
|
||||||
|
int ObjectRef::l_set_bone_override(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||||
|
ServerActiveObject *sao = getobject(ref);
|
||||||
|
if (sao == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::string bone = readParam<std::string>(L, 2);
|
||||||
|
|
||||||
|
BoneOverride props;
|
||||||
|
if (lua_isnoneornil(L, 3)) {
|
||||||
|
sao->setBoneOverride(bone, props);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read_prop_attrs = [L](auto &prop) {
|
||||||
|
lua_getfield(L, -1, "absolute");
|
||||||
|
prop.absolute = lua_toboolean(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
lua_getfield(L, -1, "interpolate");
|
||||||
|
if (lua_isnumber(L, -1))
|
||||||
|
prop.interp_timer = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
lua_getfield(L, 3, "position");
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
lua_getfield(L, -1, "vec");
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
props.position.vector = check_v3f(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
read_prop_attrs(props.position);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
lua_getfield(L, 3, "rotation");
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
lua_getfield(L, -1, "vec");
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
props.rotation.next = core::quaternion(check_v3f(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
read_prop_attrs(props.rotation);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
lua_getfield(L, 3, "scale");
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
lua_getfield(L, -1, "vec");
|
||||||
|
props.scale.vector = lua_isnil(L, -1) ? v3f(1) : check_v3f(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
read_prop_attrs(props.scale);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
sao->setBoneOverride(bone, props);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void push_bone_override(lua_State *L, const BoneOverride &props)
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
auto push_prop = [L](const char *name, const auto &prop, v3f vec) {
|
||||||
|
lua_newtable(L);
|
||||||
|
push_v3f(L, vec);
|
||||||
|
lua_setfield(L, -2, "vec");
|
||||||
|
lua_pushnumber(L, prop.interp_timer);
|
||||||
|
lua_setfield(L, -2, "interpolate");
|
||||||
|
lua_pushboolean(L, prop.absolute);
|
||||||
|
lua_setfield(L, -2, "absolute");
|
||||||
|
lua_setfield(L, -2, name);
|
||||||
|
};
|
||||||
|
|
||||||
|
push_prop("position", props.position, props.position.vector);
|
||||||
|
|
||||||
|
v3f euler_rot;
|
||||||
|
props.rotation.next.toEuler(euler_rot);
|
||||||
|
push_prop("rotation", props.rotation, euler_rot);
|
||||||
|
|
||||||
|
push_prop("scale", props.scale, props.scale.vector);
|
||||||
|
|
||||||
|
// leave only override table on top of the stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_bone_override(self, bone)
|
||||||
|
int ObjectRef::l_get_bone_override(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||||
|
ServerActiveObject *sao = getobject(ref);
|
||||||
|
if (sao == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::string bone = readParam<std::string>(L, 2);
|
||||||
|
|
||||||
|
push_bone_override(L, sao->getBoneOverride(bone));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_bone_overrides(self)
|
||||||
|
int ObjectRef::l_get_bone_overrides(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
ObjectRef *ref = checkObject<ObjectRef>(L, 1);
|
||||||
|
ServerActiveObject *co = getobject(ref);
|
||||||
|
if (co == NULL)
|
||||||
|
return 0;
|
||||||
|
lua_newtable(L);
|
||||||
|
for (const auto &bone_pos : co->getBoneOverrides()) {
|
||||||
|
push_bone_override(L, bone_pos.second);
|
||||||
|
lua_setfield(L, -2, bone_pos.first.c_str());
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// set_attach(self, parent, bone, position, rotation, force_visible)
|
// set_attach(self, parent, bone, position, rotation, force_visible)
|
||||||
int ObjectRef::l_set_attach(lua_State *L)
|
int ObjectRef::l_set_attach(lua_State *L)
|
||||||
{
|
{
|
||||||
@ -2471,6 +2603,9 @@ luaL_Reg ObjectRef::methods[] = {
|
|||||||
luamethod(ObjectRef, set_animation_frame_speed),
|
luamethod(ObjectRef, set_animation_frame_speed),
|
||||||
luamethod(ObjectRef, set_bone_position),
|
luamethod(ObjectRef, set_bone_position),
|
||||||
luamethod(ObjectRef, get_bone_position),
|
luamethod(ObjectRef, get_bone_position),
|
||||||
|
luamethod(ObjectRef, set_bone_override),
|
||||||
|
luamethod(ObjectRef, get_bone_override),
|
||||||
|
luamethod(ObjectRef, get_bone_overrides),
|
||||||
luamethod(ObjectRef, set_attach),
|
luamethod(ObjectRef, set_attach),
|
||||||
luamethod(ObjectRef, get_attach),
|
luamethod(ObjectRef, get_attach),
|
||||||
luamethod(ObjectRef, get_children),
|
luamethod(ObjectRef, get_children),
|
||||||
|
@ -130,6 +130,15 @@ private:
|
|||||||
// get_bone_position(self, bone)
|
// get_bone_position(self, bone)
|
||||||
static int l_get_bone_position(lua_State *L);
|
static int l_get_bone_position(lua_State *L);
|
||||||
|
|
||||||
|
// set_bone_override(self, bone)
|
||||||
|
static int l_set_bone_override(lua_State *L);
|
||||||
|
|
||||||
|
// get_bone_override(self, bone)
|
||||||
|
static int l_get_bone_override(lua_State *L);
|
||||||
|
|
||||||
|
// get_bone_override(self)
|
||||||
|
static int l_get_bone_overrides(lua_State *L);
|
||||||
|
|
||||||
// set_attach(self, parent, bone, position, rotation)
|
// set_attach(self, parent, bone, position, rotation)
|
||||||
static int l_set_attach(lua_State *L);
|
static int l_set_attach(lua_State *L);
|
||||||
|
|
||||||
|
@ -256,13 +256,13 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
|
|||||||
msg_os << serializeString32(getPropertyPacket()); // message 1
|
msg_os << serializeString32(getPropertyPacket()); // message 1
|
||||||
msg_os << serializeString32(generateUpdateArmorGroupsCommand()); // 2
|
msg_os << serializeString32(generateUpdateArmorGroupsCommand()); // 2
|
||||||
msg_os << serializeString32(generateUpdateAnimationCommand()); // 3
|
msg_os << serializeString32(generateUpdateAnimationCommand()); // 3
|
||||||
for (const auto &bone_pos : m_bone_position) {
|
for (const auto &bone_override : m_bone_override) {
|
||||||
msg_os << serializeString32(generateUpdateBonePositionCommand(
|
msg_os << serializeString32(generateUpdateBoneOverrideCommand(
|
||||||
bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); // 3 + N
|
bone_override.first, bone_override.second)); // 3 + N
|
||||||
}
|
}
|
||||||
msg_os << serializeString32(generateUpdateAttachmentCommand()); // 4 + m_bone_position.size
|
msg_os << serializeString32(generateUpdateAttachmentCommand()); // 4 + m_bone_override.size
|
||||||
|
|
||||||
int message_count = 4 + m_bone_position.size();
|
int message_count = 4 + m_bone_override.size();
|
||||||
|
|
||||||
for (const auto &id : getAttachmentChildIds()) {
|
for (const auto &id : getAttachmentChildIds()) {
|
||||||
if (ServerActiveObject *obj = m_env->getActiveObject(id)) {
|
if (ServerActiveObject *obj = m_env->getActiveObject(id)) {
|
||||||
|
@ -121,14 +121,14 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
|
|||||||
msg_os << serializeString32(getPropertyPacket()); // message 1
|
msg_os << serializeString32(getPropertyPacket()); // message 1
|
||||||
msg_os << serializeString32(generateUpdateArmorGroupsCommand()); // 2
|
msg_os << serializeString32(generateUpdateArmorGroupsCommand()); // 2
|
||||||
msg_os << serializeString32(generateUpdateAnimationCommand()); // 3
|
msg_os << serializeString32(generateUpdateAnimationCommand()); // 3
|
||||||
for (const auto &bone_pos : m_bone_position) {
|
for (const auto &it : m_bone_override) {
|
||||||
msg_os << serializeString32(generateUpdateBonePositionCommand(
|
msg_os << serializeString32(generateUpdateBoneOverrideCommand(
|
||||||
bone_pos.first, bone_pos.second.X, bone_pos.second.Y)); // 3 + N
|
it.first, it.second)); // 3 + N
|
||||||
}
|
}
|
||||||
msg_os << serializeString32(generateUpdateAttachmentCommand()); // 4 + m_bone_position.size
|
msg_os << serializeString32(generateUpdateAttachmentCommand()); // 4 + m_bone_override.size
|
||||||
msg_os << serializeString32(generateUpdatePhysicsOverrideCommand()); // 5 + m_bone_position.size
|
msg_os << serializeString32(generateUpdatePhysicsOverrideCommand()); // 5 + m_bone_override.size
|
||||||
|
|
||||||
int message_count = 5 + m_bone_position.size();
|
int message_count = 5 + m_bone_override.size();
|
||||||
|
|
||||||
for (const auto &id : getAttachmentChildIds()) {
|
for (const auto &id : getAttachmentChildIds()) {
|
||||||
if (ServerActiveObject *obj = m_env->getActiveObject(id)) {
|
if (ServerActiveObject *obj = m_env->getActiveObject(id)) {
|
||||||
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "itemgroup.h"
|
#include "itemgroup.h"
|
||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Some planning
|
Some planning
|
||||||
@ -167,14 +168,16 @@ public:
|
|||||||
{}
|
{}
|
||||||
virtual void setAnimationSpeed(float frame_speed)
|
virtual void setAnimationSpeed(float frame_speed)
|
||||||
{}
|
{}
|
||||||
virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation)
|
virtual void setBoneOverride(const std::string &bone, const BoneOverride &props)
|
||||||
{}
|
|
||||||
virtual void getBonePosition(const std::string &bone, v3f *position, v3f *lotation)
|
|
||||||
{}
|
{}
|
||||||
|
virtual BoneOverride getBoneOverride(const std::string &bone)
|
||||||
|
{ BoneOverride props; return props; }
|
||||||
|
virtual const BoneOverrideMap &getBoneOverrides() const
|
||||||
|
{ static BoneOverrideMap rv; return rv; }
|
||||||
virtual const std::unordered_set<int> &getAttachmentChildIds() const
|
virtual const std::unordered_set<int> &getAttachmentChildIds() const
|
||||||
{ static std::unordered_set<int> rv; return rv; }
|
{ static std::unordered_set<int> rv; return rv; }
|
||||||
virtual ServerActiveObject *getParent() const { return nullptr; }
|
virtual ServerActiveObject *getParent() const { return nullptr; }
|
||||||
virtual ObjectProperties* accessObjectProperties()
|
virtual ObjectProperties *accessObjectProperties()
|
||||||
{ return NULL; }
|
{ return NULL; }
|
||||||
virtual void notifyObjectPropertiesModified()
|
virtual void notifyObjectPropertiesModified()
|
||||||
{}
|
{}
|
||||||
|
@ -76,20 +76,20 @@ void UnitSAO::setAnimationSpeed(float frame_speed)
|
|||||||
m_animation_speed_sent = false;
|
m_animation_speed_sent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
|
void UnitSAO::setBoneOverride(const std::string &bone, const BoneOverride &props)
|
||||||
{
|
{
|
||||||
// store these so they can be updated to clients
|
// store these so they can be updated to clients
|
||||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
m_bone_override[bone] = props;
|
||||||
m_bone_position_sent = false;
|
m_bone_override_sent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
|
BoneOverride UnitSAO::getBoneOverride(const std::string &bone)
|
||||||
{
|
{
|
||||||
auto it = m_bone_position.find(bone);
|
auto it = m_bone_override.find(bone);
|
||||||
if (it != m_bone_position.end()) {
|
BoneOverride props;
|
||||||
*position = it->second.X;
|
if (it != m_bone_override.end())
|
||||||
*rotation = it->second.Y;
|
props = it->second;
|
||||||
}
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnitSAO::sendOutdatedData()
|
void UnitSAO::sendOutdatedData()
|
||||||
@ -109,11 +109,11 @@ void UnitSAO::sendOutdatedData()
|
|||||||
m_messages_out.emplace(getId(), true, generateUpdateAnimationSpeedCommand());
|
m_messages_out.emplace(getId(), true, generateUpdateAnimationSpeedCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_bone_position_sent) {
|
if (!m_bone_override_sent) {
|
||||||
m_bone_position_sent = true;
|
m_bone_override_sent = true;
|
||||||
for (const auto &bone_pos : m_bone_position) {
|
for (const auto &bone_pos : m_bone_override) {
|
||||||
m_messages_out.emplace(getId(), true, generateUpdateBonePositionCommand(
|
m_messages_out.emplace(getId(), true, generateUpdateBoneOverrideCommand(
|
||||||
bone_pos.first, bone_pos.second.X, bone_pos.second.Y));
|
bone_pos.first, bone_pos.second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,16 +275,25 @@ std::string UnitSAO::generateUpdateAttachmentCommand() const
|
|||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UnitSAO::generateUpdateBonePositionCommand(
|
std::string UnitSAO::generateUpdateBoneOverrideCommand(
|
||||||
const std::string &bone, const v3f &position, const v3f &rotation)
|
const std::string &bone, const BoneOverride &props)
|
||||||
{
|
{
|
||||||
std::ostringstream os(std::ios::binary);
|
std::ostringstream os(std::ios::binary);
|
||||||
// command
|
// command
|
||||||
writeU8(os, AO_CMD_SET_BONE_POSITION);
|
writeU8(os, AO_CMD_SET_BONE_POSITION);
|
||||||
// parameters
|
// parameters
|
||||||
os << serializeString16(bone);
|
os << serializeString16(bone);
|
||||||
writeV3F32(os, position);
|
writeV3F32(os, props.position.vector);
|
||||||
writeV3F32(os, rotation);
|
v3f euler_rot;
|
||||||
|
props.rotation.next.toEuler(euler_rot);
|
||||||
|
writeV3F32(os, euler_rot * core::RADTODEG);
|
||||||
|
writeV3F32(os, props.scale.vector);
|
||||||
|
writeF32(os, props.position.interp_timer);
|
||||||
|
writeF32(os, props.rotation.interp_timer);
|
||||||
|
writeF32(os, props.scale.interp_timer);
|
||||||
|
writeU8(os, (props.position.absolute & 1) << 0
|
||||||
|
| (props.rotation.absolute & 1) << 1
|
||||||
|
| (props.scale.absolute & 1) << 2);
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,10 @@ public:
|
|||||||
void setAnimationSpeed(float frame_speed);
|
void setAnimationSpeed(float frame_speed);
|
||||||
|
|
||||||
// Bone position
|
// Bone position
|
||||||
void setBonePosition(const std::string &bone, v3f position, v3f rotation);
|
void setBoneOverride(const std::string &bone, const BoneOverride &props);
|
||||||
void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
|
BoneOverride getBoneOverride(const std::string &bone);
|
||||||
|
const std::unordered_map<std::string, BoneOverride>
|
||||||
|
&getBoneOverrides() const { return m_bone_override; };
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
ServerActiveObject *getParent() const;
|
ServerActiveObject *getParent() const;
|
||||||
@ -100,8 +102,8 @@ public:
|
|||||||
const v3f &velocity, const v3f &acceleration, const v3f &rotation,
|
const v3f &velocity, const v3f &acceleration, const v3f &rotation,
|
||||||
bool do_interpolate, bool is_movement_end, f32 update_interval);
|
bool do_interpolate, bool is_movement_end, f32 update_interval);
|
||||||
std::string generateSetPropertiesCommand(const ObjectProperties &prop) const;
|
std::string generateSetPropertiesCommand(const ObjectProperties &prop) const;
|
||||||
static std::string generateUpdateBonePositionCommand(const std::string &bone,
|
static std::string generateUpdateBoneOverrideCommand(
|
||||||
const v3f &position, const v3f &rotation);
|
const std::string &bone, const BoneOverride &props);
|
||||||
void sendPunchCommand();
|
void sendPunchCommand();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -117,7 +119,7 @@ protected:
|
|||||||
ObjectProperties m_prop;
|
ObjectProperties m_prop;
|
||||||
|
|
||||||
// Stores position and rotation for each bone name
|
// Stores position and rotation for each bone name
|
||||||
std::unordered_map<std::string, core::vector2d<v3f>> m_bone_position;
|
std::unordered_map<std::string, BoneOverride> m_bone_override;
|
||||||
|
|
||||||
int m_attachment_parent_id = 0;
|
int m_attachment_parent_id = 0;
|
||||||
|
|
||||||
@ -139,7 +141,7 @@ private:
|
|||||||
bool m_animation_speed_sent = false;
|
bool m_animation_speed_sent = false;
|
||||||
|
|
||||||
// Bone positions
|
// Bone positions
|
||||||
bool m_bone_position_sent = false;
|
bool m_bone_override_sent = false;
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
std::unordered_set<int> m_attachment_child_ids;
|
std::unordered_set<int> m_attachment_child_ids;
|
||||||
|
Loading…
Reference in New Issue
Block a user