Add support for animate replace=true
This commit is contained in:
@@ -21,7 +21,7 @@ static const char *vtname(AnimValueType vt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint64_t hash_encstep(uint64_t prev, std::string_view s) {
|
static uint64_t hash_encstep(uint64_t prev, std::string_view s) {
|
||||||
return util::hash_string(util::HashValue(123, prev), s).first;
|
return util::hash_string(util::HashValue(123, prev), s).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,102 +420,114 @@ void AnimCoreState::decode(std::string_view s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AnimQueue::get_size_limit() const {
|
int AnimQueue::get_size_limit() const {
|
||||||
|
if (encqueue_ == nullptr) return 0;
|
||||||
StreamBuffer sb(*encqueue_);
|
StreamBuffer sb(*encqueue_);
|
||||||
return sb.read_uint8();
|
return sb.read_uint8();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AnimQueue::get_actual_size() const {
|
int AnimQueue::get_actual_size() const {
|
||||||
|
if (encqueue_ == nullptr) return 0;
|
||||||
StreamBuffer sb(*encqueue_);
|
StreamBuffer sb(*encqueue_);
|
||||||
sb.read_bytes(1);
|
sb.read_bytes(1);
|
||||||
return sb.read_uint8();
|
return sb.read_uint8();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t AnimQueue::get_final_hash() const {
|
uint64_t AnimQueue::get_final_hash() const {
|
||||||
|
if (encqueue_ == nullptr) return 0;
|
||||||
StreamBuffer sb(*encqueue_);
|
StreamBuffer sb(*encqueue_);
|
||||||
sb.read_bytes(2);
|
sb.read_bytes(2);
|
||||||
return sb.read_uint64();
|
return sb.read_uint64();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view AnimQueue::get_final_encstep() const {
|
std::string_view AnimQueue::get_final_encstep() const {
|
||||||
|
if (encqueue_ == nullptr) return std::string_view();
|
||||||
StreamBuffer sb(*encqueue_);
|
StreamBuffer sb(*encqueue_);
|
||||||
sb.read_bytes(10);
|
sb.read_bytes(10);
|
||||||
return sb.read_string_view();
|
return sb.read_string_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::update_encqueue(int limit, bool add, std::string_view add_enc, bool keepold) {
|
AnimQueue::QueueRange AnimQueue::get_range(int lo, int hi) {
|
||||||
// Make sure the size limit is reasonable.
|
// Clamp lo and hi to the valid range (0 to actual_size).
|
||||||
assert((limit >= 2) && (limit <= 250));
|
//
|
||||||
|
int actual_size = get_actual_size();
|
||||||
|
if (lo < 0) lo = 0;
|
||||||
|
if (hi > actual_size) hi = actual_size;
|
||||||
|
|
||||||
// You must either add a new step or retain an old step. The queue can't be empty.
|
// Abort early if the range is empty. This avoids several edge cases.
|
||||||
assert(keepold || add);
|
//
|
||||||
|
if (lo >= hi) return QueueRange(0, std::string_view());
|
||||||
|
|
||||||
// Find out how many old steps we'll be retaining, ignoring the size limit.
|
// Get the entries.
|
||||||
int nretain = 0;
|
//
|
||||||
if (keepold) nretain = get_actual_size();
|
std::string_view queueview(*encqueue_);
|
||||||
|
StreamBuffer sb(queueview);
|
||||||
// If retaining all steps would overflow the size limit, retain fewer.
|
|
||||||
int retain_limit = limit;
|
|
||||||
if (add) retain_limit -= 1;
|
|
||||||
if (nretain > retain_limit) nretain = retain_limit;
|
|
||||||
|
|
||||||
// Calculate the new size of the queue.
|
|
||||||
int new_size = add ? (nretain + 1) : nretain;
|
|
||||||
|
|
||||||
// If we're retaining steps, extract them from the old queue.
|
|
||||||
std::string_view retain;
|
|
||||||
if (nretain > 0) {
|
|
||||||
std::string_view oldqueue(*encqueue_);
|
|
||||||
StreamBuffer sb(oldqueue);
|
|
||||||
sb.read_bytes(2); // Skip over the header.
|
sb.read_bytes(2); // Skip over the header.
|
||||||
|
for (int i = 0; i < lo; i++) {
|
||||||
|
sb.read_uint64();
|
||||||
|
sb.read_string_view();
|
||||||
|
}
|
||||||
int pos1 = sb.total_reads();
|
int pos1 = sb.total_reads();
|
||||||
for (int i = 0; i < nretain; i++) {
|
for (int i = lo; i < hi; i++) {
|
||||||
sb.read_uint64();
|
sb.read_uint64();
|
||||||
sb.read_string_view();
|
sb.read_string_view();
|
||||||
}
|
}
|
||||||
int pos2 = sb.total_reads();
|
int pos2 = sb.total_reads();
|
||||||
retain = oldqueue.substr(pos1, pos2 - pos1);
|
return QueueRange(hi-lo, queueview.substr(pos1, pos2 - pos1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're adding a step, calculate its hash.
|
uint64_t AnimQueue::hash_encstep(const QueueRange &prev, std::string_view s) {
|
||||||
uint64_t add_hash = 0;
|
|
||||||
if (add) {
|
|
||||||
uint64_t prev_hash = 0;
|
uint64_t prev_hash = 0;
|
||||||
if (nretain > 0) prev_hash = get_final_hash();
|
if (prev.size > 0) {
|
||||||
add_hash = hash_encstep(prev_hash, add_enc);
|
StreamBuffer retsb(prev.entries);
|
||||||
|
prev_hash = retsb.read_uint64();
|
||||||
}
|
}
|
||||||
|
return ::hash_encstep(prev_hash, s);
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, encode everything into a binary blob.
|
void AnimQueue::update_encqueue(int limit, bool add, std::string_view add_enc, int keeplo, int keephi) {
|
||||||
|
// Get the retained entries.
|
||||||
|
QueueRange keeprange = get_range(keeplo, keephi);
|
||||||
|
|
||||||
|
// Encode everything into a binary blob.
|
||||||
StreamBuffer result;
|
StreamBuffer result;
|
||||||
result.write_uint8(limit);
|
result.write_uint8(limit);
|
||||||
result.write_uint8(new_size);
|
result.write_uint8(keeprange.size + (add ? 1:0));
|
||||||
if (add) {
|
if (add) {
|
||||||
|
uint64_t add_hash = hash_encstep(keeprange, add_enc);
|
||||||
result.write_uint64(add_hash);
|
result.write_uint64(add_hash);
|
||||||
result.write_string(add_enc);
|
result.write_string(add_enc);
|
||||||
}
|
}
|
||||||
result.write_bytes(retain);
|
result.write_bytes(keeprange.entries);
|
||||||
|
|
||||||
// Replace the shared string.
|
// Replace the shared string.
|
||||||
encqueue_ = std::make_shared<std::string>(result.view());
|
encqueue_ = std::make_shared<std::string>(result.view());
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimQueue::AnimQueue() {
|
AnimQueue::AnimQueue() {
|
||||||
update_encqueue(10, true, AnimState().encode(), false);
|
update_encqueue(10, true, AnimState().encode(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::clear(const AnimState &state) {
|
void AnimQueue::clear(const AnimState &state) {
|
||||||
update_encqueue(get_size_limit(), true, state.encode(), false);
|
update_encqueue(get_size_limit(), true, state.encode(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::clear() {
|
void AnimQueue::clear() {
|
||||||
update_encqueue(get_size_limit(), true, AnimState().encode(), false);
|
update_encqueue(get_size_limit(), true, AnimState().encode(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::set_limit(int limit) {
|
void AnimQueue::set_limit(int limit) {
|
||||||
update_encqueue(limit, false, "", true);
|
assert((limit >= 2) && (limit <= 250));
|
||||||
|
update_encqueue(limit, false, std::string_view(), 0, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::add(const AnimState &state) {
|
void AnimQueue::add(const AnimState &state) {
|
||||||
update_encqueue(get_size_limit(), true, state.encode(), true);
|
int limit = get_size_limit();
|
||||||
|
update_encqueue(limit, true, state.encode(), 0, limit - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimQueue::replace(const AnimState &state) {
|
||||||
|
int limit = get_size_limit();
|
||||||
|
update_encqueue(limit, true, state.encode(), 1, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimQueue::serialize(StreamBuffer *sb) const {
|
void AnimQueue::serialize(StreamBuffer *sb) const {
|
||||||
|
|||||||
@@ -268,6 +268,13 @@ public:
|
|||||||
//
|
//
|
||||||
void add(const AnimState &state);
|
void add(const AnimState &state);
|
||||||
|
|
||||||
|
// Replace the most recent animation step.
|
||||||
|
//
|
||||||
|
// Note: replace does not automatically compose the step with the previous
|
||||||
|
// step, you have to do that yourself.
|
||||||
|
//
|
||||||
|
void replace(const AnimState &state);
|
||||||
|
|
||||||
// Serialize or deserialize to a StreamBuffer
|
// Serialize or deserialize to a StreamBuffer
|
||||||
//
|
//
|
||||||
void serialize(StreamBuffer *sb) const;
|
void serialize(StreamBuffer *sb) const;
|
||||||
@@ -316,13 +323,40 @@ public:
|
|||||||
util::SharedStdString get_encoded_queue() const { return encqueue_; }
|
util::SharedStdString get_encoded_queue() const { return encqueue_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Update the encoded queue.
|
struct QueueRange {
|
||||||
|
int size;
|
||||||
|
std::string_view entries;
|
||||||
|
QueueRange(int sz, std::string_view ent) : size(sz), entries(ent) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a range of entries from the queue.
|
||||||
//
|
//
|
||||||
// You must specify the new size limit.
|
// You must specify a range (lo-hi) of steps. In this numbering, 0 is the
|
||||||
// You may optionally specify an encstep to add.
|
// most recent entry in the queue. The indices lo and hi are automatically
|
||||||
// If keepold, then old steps will be retained up to the size limit.
|
// clamped to the valid range (0 to actual_size). If lo >= hi, then an
|
||||||
|
// empty range is returned.
|
||||||
//
|
//
|
||||||
void update_encqueue(int limit, bool add, std::string_view add_enc, bool keepold);
|
QueueRange get_range(int lo, int hi);
|
||||||
|
|
||||||
|
// Hash a new step given the range of steps that precede it.
|
||||||
|
//
|
||||||
|
static uint64_t hash_encstep(const QueueRange &prev, std::string_view step);
|
||||||
|
|
||||||
|
// Update the animation queue.
|
||||||
|
//
|
||||||
|
// The range (keeplo to keephi) specifies which old steps should be
|
||||||
|
// retained. The numbers keephi and keeplo are automatically clamped
|
||||||
|
// so that they lie inside the actual size of the queue.
|
||||||
|
//
|
||||||
|
// If add is true, then an additional step is added to the queue.
|
||||||
|
// The hash of the new step is calculated automatically.
|
||||||
|
//
|
||||||
|
// There is no enforcement that you respected the size limit that you
|
||||||
|
// specified. For example, you could say "keep 0-5, and add 1." That
|
||||||
|
// would make 6 entries in the queue. It is up to the caller to respect
|
||||||
|
// the size limit. The value passed in is just for reporting.
|
||||||
|
//
|
||||||
|
void update_encqueue(int limit, bool add, std::string_view add_enc, int keeplo, int keephi);
|
||||||
|
|
||||||
// Read values from the header of the encqueue.
|
// Read values from the header of the encqueue.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -45,85 +45,85 @@ LuaDefine(tangible_animdebug, "tan",
|
|||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_animstate, "tan",
|
LuaDefine(tangible_animfinal, "tan",
|
||||||
"|Return the animation state variables of the tangible as a table."
|
"|Return the final step in the animation queue."
|
||||||
"|"
|
"|"
|
||||||
"|The animation system stores 'animation state variables. "
|
"|The animation queue stores animation steps. This function returns"
|
||||||
"|There are several builtin animation state variables. The"
|
"|the final animation step. An animation step consists of key-value"
|
||||||
"|following is a list, along with some example values that"
|
"|pairs. Some of those key-value pairs describe the last thing that"
|
||||||
"|might be used if the object were a pirate treasure chest."
|
"|happened to the tangible. Others describe the final resting place"
|
||||||
|
"|of the tangible."
|
||||||
"|"
|
"|"
|
||||||
|
"|For example, if the tangible were a pirate chest, the key-value"
|
||||||
|
"|pairs might be:"
|
||||||
|
"|"
|
||||||
|
"| action='open' # last thing the chest did"
|
||||||
"| xyz={1,2,3} # xyz coordinate"
|
"| xyz={1,2,3} # xyz coordinate"
|
||||||
"| plane='earth' # plane where the chest is located"
|
"| plane='earth' # plane where the chest is located"
|
||||||
"| facing=0 # rotation of the chest"
|
"| facing=0 # rotation of the chest"
|
||||||
"| bp='BP_piratechest' # name of an unreal blueprint"
|
|
||||||
"| model='SM_piratechest' # name of an unreal mesh"
|
|
||||||
"|"
|
|
||||||
"|There can also be user-defined animation state variables."
|
|
||||||
"|For example, for a pirate chest, you might want to add two"
|
|
||||||
"|more state variables:"
|
|
||||||
"|"
|
|
||||||
"| open=true # chest can be open or closed"
|
"| open=true # chest can be open or closed"
|
||||||
"| fullness=0.8 # how big the heap of coins is"
|
"| fullness=0.8 # how big the heap of coins is"
|
||||||
"|"
|
"|"
|
||||||
"|All state variables must be one of four types: number, string,"
|
"|See doc(tangible.animinit) for more information about animation queues."
|
||||||
"|boolean, or coordinate. All state variables must have simple"
|
|
||||||
"|identifiers for names."
|
|
||||||
"|"
|
|
||||||
"|Animation state variables are updated when you use"
|
|
||||||
"|tangible.animate to create an animation record. For example,"
|
|
||||||
"|suppose your character is initialized at xyz={1,1,1}. Then"
|
|
||||||
"|he walks to xyz={2,2,2}, then he walks to xyz={3,3,3}."
|
|
||||||
"|The animation queue now contains three animation steps:"
|
|
||||||
"|"
|
|
||||||
"|Animation Queue:"
|
|
||||||
"| Step 1: action:initialize xyz={1,1,1} ..."
|
|
||||||
"| Step 2: action:walkto xyz={2,2,2} ..."
|
|
||||||
"| Step 3: action:walkto xyz={3,3,3} ..."
|
|
||||||
"|"
|
|
||||||
"|Notice that the state variable xyz is stored three times, once"
|
|
||||||
"|in each animation step. All animation state variables are stored"
|
|
||||||
"|in every animation step. When you use tangible.animstate to fetch"
|
|
||||||
"|the current value of the animation state variables, you're"
|
|
||||||
"|actually fetching the state variables from the last step in"
|
|
||||||
"|the animation queue."
|
|
||||||
"|"
|
|
||||||
"|You can use this function, tangible.animstate, to view the"
|
|
||||||
"|current set of state variables. You can use tangible.animinit"
|
|
||||||
"|to reconfigure the set of user-defined state variables. You"
|
|
||||||
"|can use tangible.animate to create animation steps, which can"
|
|
||||||
"|alter any of the state variables."
|
|
||||||
"|") {
|
"|") {
|
||||||
LuaArg tanobj;
|
LuaArg tanobj;
|
||||||
LuaRet result;
|
LuaRet result;
|
||||||
LuaDefStack LS(L, tanobj, result);
|
LuaDefStack LS(L, tanobj, result);
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
AnimState state = tan->anim_queue_.get_final_persistent();
|
AnimState state = tan->anim_queue_.get_final_everything();
|
||||||
state.to_lua(LS, result, true);
|
state.to_lua(LS, result, true);
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_animinit, "tan,config",
|
LuaDefine(tangible_animinit, "tan,config",
|
||||||
"|Reinitialize the animation queue."
|
"|Reinitialize the animation queue and specify persistent state."
|
||||||
"|"
|
"|"
|
||||||
"|The animation queue stores certain animation state variables."
|
"|Every tangible has an animation queue. The queue consists of a"
|
||||||
"|See doc(tangible.animstate) for more information about animation"
|
"|sequence of animation steps. Each step consists of a list of"
|
||||||
"|state variables."
|
"|key-value pairs. For example, if you want a human person to jump"
|
||||||
|
"|three feet in the air, you might find this animation step in the"
|
||||||
|
"|animation queue:"
|
||||||
|
"|"
|
||||||
|
"| action='jump' - the name of the animation to perform"
|
||||||
|
"| height=3.0 - the height to which you want him to jump"
|
||||||
|
"| xyz={1,2,3} - person's xyz coordinate during the jump"
|
||||||
|
"| plane=earth - plane where the jump takes place"
|
||||||
|
"|"
|
||||||
|
"|Some of those key-value pairs are 'persistent'. For example, xyz is"
|
||||||
|
"|persistent. That means that the player must always have an xyz"
|
||||||
|
"|coordinate. Every single animation step in the queue must"
|
||||||
|
"|contain a value for xyz. Likewise, 'plane' is a persistent variable."
|
||||||
|
"|The player must always be on some plane or another."
|
||||||
|
"|"
|
||||||
|
"|When you add an animation step to the animation queue, you do not have"
|
||||||
|
"|to always specify xyz and plane. For example, you can legally say:"
|
||||||
|
"|"
|
||||||
|
"| tangible.animate(a, nil, {action='jump', height=3.0}))"
|
||||||
|
"|"
|
||||||
|
"|This adds a step to the animation queue. That step contains"
|
||||||
|
"|xyz and plane, even though we didn't specify xyz and plane in"
|
||||||
|
"|the 'animate' command above. The values for xyz and plane will be"
|
||||||
|
"|copied over from the previous animation step. In this way, those values"
|
||||||
|
"|get persisted: they stay the same unless you change them in"
|
||||||
|
"|the 'animate' command."
|
||||||
|
"|"
|
||||||
|
"|There are five hardwired persistent variables: plane,xyz,facing,bp,model."
|
||||||
|
"|These five variables are persistent no matter what. This function,"
|
||||||
|
"|tangible.animinit, optionally allows you to create more persistent"
|
||||||
|
"|variables. For example, let's say you have a pirate chest. You might"
|
||||||
|
"|want to add two persistent variables in addition to the usual set:"
|
||||||
|
"|"
|
||||||
|
"| open=true - whether the chest is open or closed"
|
||||||
|
"| heapsize=0.8 - the size of the heap of coins"
|
||||||
|
"|"
|
||||||
|
"|Making a variable persistent means that it will always have a value"
|
||||||
|
"|no matter what you do."
|
||||||
"|"
|
"|"
|
||||||
"|This function, tangible.animinit, is used to reconfigure the set of"
|
"|This function, tangible.animinit, is used to reconfigure the set of"
|
||||||
"|user-defined state variables. The config table that you pass in must"
|
"|persistent state variables that are retained by the tangible's"
|
||||||
"|be key-value pairs. Keys must be simple identifiers. Values can be"
|
"|animation queue. You must provide a table containing all the"
|
||||||
"|numbers, strings, booleans, or coordinates."
|
"|persistent values you want, and their initial values."
|
||||||
"|"
|
|
||||||
"|After tangible.animinit, the tangible's animation state variables will"
|
|
||||||
"|consist of the user-defined variables listed in the config table,"
|
|
||||||
"|plus all the builtin animation state variables."
|
|
||||||
"|"
|
|
||||||
"|Optionally, the config table can also supply values for some or all"
|
|
||||||
"|of the builtin state variables. For example, you could supply xyz"
|
|
||||||
"|in the config table. If you do, the tangible will move to a new xyz"
|
|
||||||
"|coordinate. If not, the tangible will retain its old xyz coordinate."
|
|
||||||
"|") {
|
"|") {
|
||||||
LuaArg tanobj, config;
|
LuaArg tanobj, config;
|
||||||
LuaDefStack LS(L, tanobj, config);
|
LuaDefStack LS(L, tanobj, config);
|
||||||
@@ -144,46 +144,65 @@ LuaDefine(tangible_animinit, "tan,config",
|
|||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_animate, "tan,options,config",
|
||||||
LuaDefine(tangible_animate, "tan,config",
|
|
||||||
"|Add an animation step to the tangible."
|
"|Add an animation step to the tangible."
|
||||||
"|"
|
"|"
|
||||||
"|The animation queue stores animation steps. This function, "
|
"|The animation queue stores animation steps. This function, "
|
||||||
"|tangible.animate, adds one new animation step to the queue."
|
"|tangible.animate, adds one new animation step to the queue."
|
||||||
"|"
|
"|"
|
||||||
"|It might be useful to read about 'animation state variables' before"
|
"|It might be useful to read doc(tangible.animinit) before reading"
|
||||||
"|reading this explanation. See doc(tangible.animstate)."
|
"|more."
|
||||||
"|"
|
"|"
|
||||||
"|An animation step is just a list of key-value pairs. Therefore,"
|
"|An animation step is just a list of key-value pairs. Therefore,"
|
||||||
"|the config table must be key-value pairs. Keys must be simple"
|
"|the config table must be key-value pairs. Keys must be simple"
|
||||||
"|identifiers. Values can be numbers, strings, booleans, or"
|
"|identifiers. Values can be numbers, strings, booleans, or"
|
||||||
"|coordinates."
|
"|coordinates."
|
||||||
"|"
|
"|"
|
||||||
"|Some of the key-value pairs may match the name of an animation state"
|
"|Some of the key-value pairs may match the name of a persistent"
|
||||||
"|variable. If so, that key-value pair permanently changes the"
|
"|variable. If so, that key-value pair permanently changes the"
|
||||||
"|value of that animation state variable. The new value will"
|
"|value of that persistent variable. The new value will"
|
||||||
"|be retained for all future animation steps."
|
"|be retained for all future animation steps."
|
||||||
"|"
|
"|"
|
||||||
"|Some of the key-value pairs may NOT match the name of any animation"
|
"|Some of the key-value pairs may not match the name of any persistent"
|
||||||
"|state variable. If so, that key-value pair is part of the"
|
"|variable. If so, that key-value pair is part of the"
|
||||||
"|animation step, but nothing is propagated forward to future animation"
|
"|animation step, but nothing is propagated forward to future animation"
|
||||||
"|steps."
|
"|steps."
|
||||||
"|"
|
"|"
|
||||||
|
"|The options can be nil, or options can be a table containing"
|
||||||
|
"|the following flags:"
|
||||||
|
"|"
|
||||||
|
"| replace: if true, then the last step in the queue is removed,"
|
||||||
|
"| and the new animation replaces it. Persistent state is carried"
|
||||||
|
"| over from the step that was replaced."
|
||||||
|
"|"
|
||||||
"|") {
|
"|") {
|
||||||
LuaArg tanobj, config;
|
LuaArg tanobj, options, steptab;
|
||||||
LuaDefStack LS(L, tanobj, config);
|
LuaVar option;
|
||||||
|
LuaDefStack LS(L, option, tanobj, options, steptab);
|
||||||
|
bool replace = false;
|
||||||
|
if (!LS.isnil(options)) {
|
||||||
|
LuaKeywordParser kp(LS, options);
|
||||||
|
if (kp.parse(option, "replace")) {
|
||||||
|
replace = LS.ckboolean(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
AnimState state = tan->anim_queue_.get_final_persistent();
|
AnimState state = tan->anim_queue_.get_final_persistent();
|
||||||
eng::string error = state.apply_lua(LS, config, false);
|
eng::string error = state.apply_lua(LS, steptab, false);
|
||||||
if (!error.empty()) {
|
if (!error.empty()) {
|
||||||
luaL_error(L, "%s", error.c_str());
|
luaL_error(L, "%s", error.c_str());
|
||||||
}
|
}
|
||||||
|
if (replace) {
|
||||||
|
tan->anim_queue_.replace(state);
|
||||||
|
} else {
|
||||||
tan->anim_queue_.add(state);
|
tan->anim_queue_.add(state);
|
||||||
|
}
|
||||||
tan->update_plane_item();
|
tan->update_plane_item();
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LuaDefine(tangible_setclass, "tan,class",
|
LuaDefine(tangible_setclass, "tan,class",
|
||||||
"|Set the class of the tangible."
|
"|Set the class of the tangible."
|
||||||
"|The class can be a 'class table' (ie, a table of methods), "
|
"|The class can be a 'class table' (ie, a table of methods), "
|
||||||
|
|||||||
Reference in New Issue
Block a user