Fix blank animqueues, and add facing=math.auto to animate

This commit is contained in:
2024-03-12 11:46:48 -04:00
parent 044bb89edf
commit 357e3766fb
9 changed files with 147 additions and 42 deletions

View File

@@ -10,6 +10,12 @@
#include <cstdlib>
util::SharedStdString AnimQueue::blankqueue_;
void AnimQueue::initialize_module() {
AnimQueue queue;
blankqueue_ = queue.get_encoded_queue();
}
static uint64_t hash_encstep(uint64_t prev, std::string_view s) {
return util::hash_string(util::HashValue(123, prev), s).first;
@@ -67,6 +73,10 @@ static AnimValue parse_anim_value(LuaCoreStack &LS, LuaSlot val, LuaSlot tmp) {
if (!LS.isnumber(tmp)) return result;
xyz.z = LS.cknumber(tmp);
result.set_dxyz(xyz);
} else if (LS.rawequal(val, LuaToken("auto"))) {
result.set_auto();
} else {
result.set_uninitialized();
}
return result;
}
@@ -111,6 +121,8 @@ void AnimState::print_debug_string(eng::ostringstream &oss) {
oss << ":";
}
switch (value.type) {
case SimpleDynamicTag::UNINITIALIZED: oss << "UNINITIALIZED"; break;
case SimpleDynamicTag::AUTO: oss << "AUTO"; break;
case SimpleDynamicTag::NUMBER: oss << value.x; break;
case SimpleDynamicTag::BOOLEAN: oss << ((value.x == 1.0) ? "true":"false"); break;
case SimpleDynamicTag::VECTOR: oss << value.x << "," << value.y << "," << value.z; break;
@@ -205,46 +217,91 @@ eng::string AnimState::add_defaults(const AnimState *other) {
err = add_default("facing", defval, other);
if (!err.empty()) return err;
defval.set_string("stdbp");
defval.set_string("unknown");
err = add_default("bp", defval, other);
if (!err.empty()) return err;
defval.set_string("stdmodel");
err = add_default("model", defval, other);
if (!err.empty()) return err;
return "";
}
eng::string AnimState::apply_lua(LuaCoreStack &LS0, LuaSlot tab, bool setpersist) {
eng::string AnimState::from_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent, bool allowauto) {
LuaVar key, val, tmp;
LuaExtStack LS(LS0.state(), key, val, tmp);
util::DXYZ xyz;
clear();
if (!LS.istable(tab)) {
return "An animstate must be a table.";
return "A lua animstate must be a table.";
}
LS.set(key, LuaNil);
while (LS.next(tab, key, val)) {
if (!LS.isstring(key)) {
return "in animation key-value pairs, key must be a string.";
}
eng::string name = LS.ckstring(key);
if (!LS.valididentifier(name)) {
return "in animation key-value pairs, key must be a valid lua identifier.";
}
AnimValue parsedvalue = parse_anim_value(LS, val, tmp);
if (parsedvalue.type == SimpleDynamicTag::UNINITIALIZED) {
return "in animation key-value pairs, val must be number, string, boolean, or xyz";
return "in animation key-value pairs, value must be number, string, boolean, or xyz";
}
if ((parsedvalue.type == SimpleDynamicTag::AUTO) && !allowauto) {
return "in animation key-value pairs, value must not be AUTO here.";
}
eng::string name = LS.ckstring(key);
AnimValue &mapentry = map_[name];
if ((mapentry.type != SimpleDynamicTag::UNINITIALIZED) && (mapentry.type != parsedvalue.type)) {
return util::ss("animation '", name, "' must be a ", mapentry.type_name());
}
mapentry.copy_value(parsedvalue);
if (setpersist) mapentry.persistent = true;
mapentry.persistent = persistent;
}
return "";
}
eng::string AnimState::merge(const AnimState &previous, const AnimState &update) {
// Copy everything over from the previous entry.
map_ = previous.map_;
for (const auto &pair : update.map_) {
const eng::string &name = pair.first;
AnimValue &dst = map_[name];
const AnimValue &src = pair.second;
// Handle autocalculation rules.
if (src.type == SimpleDynamicTag::AUTO) {
if (name == "facing") {
if (!dst.persistent || dst.type != SimpleDynamicTag::NUMBER) {
return "Cannot auto-calculate facing because facing has not been specified as a persistent number";
}
const auto xyz_previous = previous.map_.find("xyz");
const auto xyz_update = update.map_.find("xyz");
if ((xyz_previous == previous.map_.end()) ||
(xyz_update == update.map_.end()) ||
(xyz_previous->second.type != SimpleDynamicTag::VECTOR) ||
(xyz_update->second.type != SimpleDynamicTag::VECTOR)) {
return "Cannot auto-calculate facing because before/after xyz coordinates are not present";
}
double dx = xyz_update->second.x - xyz_previous->second.x;
double dy = xyz_update->second.y - xyz_previous->second.y;
// If dx and dy are both zero, leave the facing unmodified.
if ((dx != 0.0) || (dy != 0.0)) {
double facing = atan2(dy, dx) * 180.0 / M_PI;
dst.set_number(facing);
}
} else {
return util::ss("No rule to automatically calculate ", name);
}
continue;
}
if (dst.persistent && (src.type != dst.type)) {
return util::ss("Wrong data type for ", name, ", should be ", dst.type_name());
}
dst.copy_value(src);
}
return "";
}
void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent) {
LuaVar name, val;
LuaExtStack LS(LS0.state(), name, val);
@@ -269,6 +326,7 @@ void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent) {
}
}
// The syntax used by this parser is not general enough to represent all
// possible strings. That's OK, though, since it's just for unit testing.
void AnimState::parse(std::string_view config) {