diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 7cc130eb..b19f6343 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -41,6 +41,13 @@ static bool SetProperty(const FString& prefix, UObject* obj, const FlxAnimationF *pptr = FString(field.S.size(), (const UTF8CHAR*)field.S.data()); return true; } + case SimpleDynamicTag::TOKEN: { + FNameProperty* fprop = FindFProperty(uclass, nname); + if (fprop == nullptr) return false; + FName* pptr = fprop->ContainerPtrToValuePtr(obj); + *pptr = FName(field.S.size(), (const UTF8CHAR*)field.S.data(), FNAME_Add); + return true; + } case SimpleDynamicTag::NUMBER: { FDoubleProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; @@ -206,6 +213,12 @@ FString UlxAnimationStepLibrary::AnimationStepGetString(const FlxAnimationStep& return FString(field.S.size(), (const UTF8CHAR*)(field.S.data())); } +FName UlxAnimationStepLibrary::AnimationStepGetName(const FlxAnimationStep& step, const FString& name) { + FlxAnimationField field = FindAnimationField(step, name); + if (field.Type != SimpleDynamicTag::TOKEN) return FName(); + return FName(field.S.size(), (const UTF8CHAR*)(field.S.data()), FNAME_Add); +} + bool UlxAnimationStepLibrary::AnimationStepGetBool(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); if (field.Type != SimpleDynamicTag::BOOLEAN) return false; @@ -223,6 +236,10 @@ FlxAnimationField FlxAnimationStepDecoder::ReadField() { result.S = Decoder.read_string_view(); break; } + case SimpleDynamicTag::TOKEN: { + result.S = Decoder.read_string_view(); + break; + } case SimpleDynamicTag::NUMBER: { result.X = Decoder.read_double(); break; @@ -263,6 +280,9 @@ FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonl case SimpleDynamicTag::STRING: result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data())); break; + case SimpleDynamicTag::TOKEN: + result.Appendf(TEXT("[%s]"), *FString(field.S.size(), (const UTF8CHAR*)field.S.data())); + break; case SimpleDynamicTag::NUMBER: result.Appendf(TEXT("%lf"), field.X); break; diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 35dc4f2d..c5ad8441 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -106,6 +106,9 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Animation Step") static FString AnimationStepGetString(const FlxAnimationStep& step, const FString& name); + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Animation Step") + static FName AnimationStepGetName(const FlxAnimationStep& step, const FString& name); + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Animation Step") static bool AnimationStepGetBool(const FlxAnimationStep& step, const FString& name); }; diff --git a/luprex/cpp/core/animqueue.cpp b/luprex/cpp/core/animqueue.cpp index 8f628cf8..297f82c4 100644 --- a/luprex/cpp/core/animqueue.cpp +++ b/luprex/cpp/core/animqueue.cpp @@ -55,33 +55,31 @@ static void parse_value(std::string_view vstr, AnimValue *v) { } -static AnimValue parse_anim_value(LuaCoreStack &LS, LuaSlot val, LuaSlot tmp) { +static AnimValue parse_anim_value(LuaCoreStack &LS, LuaSlot val) { AnimValue result; - auto tboolean = LS.tryboolean(val); - if (tboolean) { - result.set_boolean(*tboolean); - return result; + int type = LS.type(val); + switch (type) { + case LUA_TBOOLEAN: { + auto tbool = LS.tryboolean(val); + if (tbool) result.set_boolean(*tbool); + } + case LUA_TNUMBER: { + auto tnum = LS.trynumber(val); + if (tnum) result.set_number(*tnum); + } + case LUA_TSTRING: { + auto tstr = LS.trystringview(val); + if (tstr) result.set_string(*tstr); + } + case LUA_TTABLE: { + auto txyz = LS.tryxyz(val); + if (txyz) result.set_dxyz(*txyz); + } + case LUA_TLIGHTUSERDATA: { + auto ttoken = LS.trytoken(val); + if (ttoken) result.set_token(*ttoken); + } } - auto tnumber = LS.trynumber(val); - if (tnumber) { - result.set_number(*tnumber); - return result; - } - auto tstring = LS.trystringview(val); - if (tstring) { - result.set_string(*tstring); - return result; - } - auto txyz = LS.tryxyz(val); - if (txyz) { - result.set_dxyz(*txyz); - return result; - } - if (LS.rawequal(val, LuaToken("auto"))) { - result.set_auto(); - return result; - } - result.set_uninitialized(); return result; } @@ -89,26 +87,6 @@ void AnimState::set_persistent(const eng::string &name) { map_[name].persistent = true; } -void AnimState::set_boolean(const eng::string &name, bool v) { - AnimValue &value = map_[name]; - value.set_boolean(v); -} - -void AnimState::set_number(const eng::string &name, double v) { - AnimValue &value = map_[name]; - value.set_number(v); -} - -void AnimState::set_dxyz(const eng::string &name, const util::DXYZ &v) { - AnimValue &value = map_[name]; - value.set_dxyz(v); -} - -void AnimState::set_string(const eng::string &name, std::string_view v) { - AnimValue &value = map_[name]; - value.set_string(v); -} - void AnimState::print_debug_string(eng::ostringstream &oss) { bool first = true; if (map_.empty()) { @@ -126,11 +104,11 @@ void AnimState::print_debug_string(eng::ostringstream &oss) { } switch (value.type) { case SimpleDynamicTag::UNINITIALIZED: oss << "UNINITIALIZED"; break; - case SimpleDynamicTag::AUTO: oss << "AUTO"; break; + case SimpleDynamicTag::STRING: oss << value.s; break; + case SimpleDynamicTag::TOKEN: oss << "[" << value.s << "]"; 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; - case SimpleDynamicTag::STRING: oss << value.s; break; default: assert(false); } first = false; @@ -230,8 +208,8 @@ eng::string AnimState::add_defaults(const AnimState *other) { eng::string AnimState::from_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent, bool allowauto) { - LuaVar key, val, tmp; - LuaExtStack LS(LS0.state(), key, val, tmp); + LuaVar key, val; + LuaExtStack LS(LS0.state(), key, val); util::DXYZ xyz; clear(); @@ -247,12 +225,12 @@ eng::string AnimState::from_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent, if (!sv::is_lua_id(name)) { return "in animation key-value pairs, key must be a valid lua identifier."; } - AnimValue parsedvalue = parse_anim_value(LS, val, tmp); + AnimValue parsedvalue = parse_anim_value(LS, val); if (parsedvalue.type == SimpleDynamicTag::UNINITIALIZED) { - return "in animation key-value pairs, value must be number, string, boolean, or xyz"; + return "in animation key-value pairs, value must be string, token, number, boolean, or xyz"; } - if ((parsedvalue.type == SimpleDynamicTag::AUTO) && !allowauto) { - return "in animation key-value pairs, value must not be AUTO here."; + if (parsedvalue.is_token("auto") && !allowauto) { + return "in animation key-value pairs, value must not be [auto] here."; } AnimValue &mapentry = map_[name]; mapentry.copy_value(parsedvalue); @@ -271,7 +249,7 @@ eng::string AnimState::merge(const AnimState &previous, const AnimState &update) const AnimValue &src = pair.second; // Handle autocalculation rules. - if (src.type == SimpleDynamicTag::AUTO) { + if (src.is_token("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"; @@ -306,12 +284,16 @@ eng::string AnimState::merge(const AnimState &previous, const AnimState &update) } -void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent) { +void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool transient, bool persistent) { LuaVar name, val; LuaExtStack LS(LS0.state(), name, val); LS.newtable(tab); for (const auto &pair : map_) { - if (pair.second.persistent != persistent) continue; + if (pair.second.persistent) { + if (!persistent) continue; + } else { + if (!transient) continue; + } LS.set(name, pair.first); const AnimValue &value = pair.second; if (value.type == SimpleDynamicTag::BOOLEAN) { @@ -320,6 +302,8 @@ void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent) { LS.set(val, value.x); } else if (value.type == SimpleDynamicTag::STRING) { LS.set(val, std::string_view(value.s)); + } else if (value.type == SimpleDynamicTag::TOKEN) { + LS.set(val, LuaToken(value.s)); } else if (value.type == SimpleDynamicTag::VECTOR) { LS.newtable(val); LS.rawset(val, 1, value.x); diff --git a/luprex/cpp/core/animqueue.hpp b/luprex/cpp/core/animqueue.hpp index 13910233..72bfa828 100644 --- a/luprex/cpp/core/animqueue.hpp +++ b/luprex/cpp/core/animqueue.hpp @@ -52,12 +52,7 @@ // for all key-value pairs do: // write_string(key) // write_bool(persistent) -// write_uint8(type) // T_STRING, T_NUMBER, T_BOOL, or T_XYZ -// switch type: -// T_STRING: write_string(value) -// T_NUMBER: write_double(value) -// T_BOOL: write_bool(value) -// T_XYZ: write_xyz(value) +// write_simple_dynamic(value) // // The encoded string produced by the loop above is called an "encstep". // That's short for "encoded animation step". The encstep has a hash @@ -107,10 +102,19 @@ struct AnimValue : public SimpleDynamicValue { AnimValue() { persistent = false; } + void set_token(LuaToken token) { + type = SimpleDynamicTag::TOKEN; + s=token.str(); x=y=z=0; + } + void set_dxyz(const util::DXYZ &xyz) { type = SimpleDynamicTag::VECTOR; s.clear(); x = xyz.x; y = xyz.y; z = xyz.z; } + + bool is_token(const char *t) const { + return (type == SimpleDynamicTag::TOKEN) && (s == t); + } }; @@ -141,10 +145,11 @@ public: // Set a single variable to a value of a specified type. // If the variable isn't present, add it. // - void set_boolean(const eng::string &name, bool v); - void set_number(const eng::string &name, double v); - void set_dxyz(const eng::string &name, const util::DXYZ &value); - void set_string(const eng::string &name, std::string_view value); + void set_string(const eng::string &name, std::string_view v) { map_[name].set_string(v); } + void set_token(const eng::string &name, LuaToken v) { map_[name].set_token(v); } + void set_number(const eng::string &name, double v) { map_[name].set_number(v); } + void set_boolean(const eng::string &name, bool v) { map_[name].set_boolean(v); } + void set_dxyz(const eng::string &name, const util::DXYZ &v) { map_[name].set_dxyz(v); } // Print a debug string into the stringstream. // @@ -217,10 +222,10 @@ public: // Convert an animstate to a lua table. // - // You can either convert the persistent key-value pairs, or the - // nonpersistent. So you'll need two lua tables to store both. + // You can specify whether you want to include the transient values, the + // persistent values, or both. // - void to_lua(LuaCoreStack &LS, LuaSlot tab, bool persistent); + void to_lua(LuaCoreStack &LS, LuaSlot tab, bool transient, bool persistent); // Parse a string, for unit testing. // diff --git a/luprex/cpp/core/luastack.hpp b/luprex/cpp/core/luastack.hpp index a0a7aad2..cc52a1e4 100644 --- a/luprex/cpp/core/luastack.hpp +++ b/luprex/cpp/core/luastack.hpp @@ -409,15 +409,14 @@ enum LuaTableType { struct LuaToken { private: // Convert a base36 number into a token. If the base36 number is - // not valid, or if it exceeds 64 bits, then return maxint, ie, - // the invalid token. + // not valid, or if it exceeds 64 bits, then return zero. // static constexpr uint64_t parse(std::string_view str) { uint64_t result = 0; uint64_t maxint = uint64_t(-1); // Leading zeros are not allowed. - if ((!str.empty()) && (str[0]=='0')) return maxint; + if ((!str.empty()) && (str[0]=='0')) return 0; for (int i = 0; i < int(str.size()); i++) { char c = str[i]; @@ -433,9 +432,9 @@ private: } // Multiply existing number by 36, then add the digit. // We have two checks to prevent integer overflow. - if (result > (maxint / 36)) return maxint; + if (result > (maxint / 36)) return 0; result *= 36; - if (digit > (maxint - result)) return maxint; + if (digit > (maxint - result)) return 0; result += digit; } return result; @@ -451,20 +450,21 @@ public: // Construct a token from a string. // - // If the string is not a valid token, then this initializes the - // token to the invalid token. + // If the string is not a valid base36 number, then this + // initializes the token to the empty token (zero) // LuaToken(std::string_view s) : value(parse(s)) {} + LuaToken(const eng::string &s) : value(parse(s)) {} // Construct a token from a compile-time constant string. // // It appears that the code below throws an exception if the - // string is invalid. But in reality, since this function is + // string not parseable. But in reality, since this function is // consteval (evaluated at compile time), the error is // generated during the compilation. // consteval LuaToken(const char *s) : value(parse(s)) { - if (is_invalid()) throw "Invalid token"; + if (empty()) throw "cannot parse token"; } // Construct a token from an int64. @@ -482,9 +482,9 @@ public: // Assignment operator. void operator =(const LuaToken &other) { value = other.value; } - // Empty: return true if the token is all zero bytes. + // Empty: return true if the token is zero. // - bool empty() const { return value == 0; } + constexpr bool empty() const { return value == 0; } // Compare two tokens for equality. // @@ -494,19 +494,12 @@ public: // void *voidvalue() const { return (void*)value; } - // Return true if it's the invalid token. - // - constexpr bool is_invalid() { return value == uint64_t(-1); } - // Convert the token to a string. // // The conversion to string consists of expressing the value - // in base 36. The value 0 is expressed as the empty string. + // in base 36. // eng::string str() const; - -public: - }; //////////////////////////////////////////////////////////////////// diff --git a/luprex/cpp/core/world-accessor.cpp b/luprex/cpp/core/world-accessor.cpp index b81532c2..702df5dd 100644 --- a/luprex/cpp/core/world-accessor.cpp +++ b/luprex/cpp/core/world-accessor.cpp @@ -4,6 +4,8 @@ #include "serializelua.hpp" #include +LuaTokenConstant(tangible_auto, "auto", ""); + static void tangible_getall(LuaCoreStack &LS0, LuaSlot list, const util::IdVector &idv) { LuaVar tangibles, tan; LuaExtStack LS(LS0.state(), tangibles, tan); @@ -73,7 +75,7 @@ LuaDefine(tangible_animfinal, "tan", World *w = World::fetch_global_pointer(L); Tangible *tan = w->tangible_get(LS, tanobj, false); AnimState state = tan->anim_queue_.get_final_everything(); - state.to_lua(LS, result, true); + state.to_lua(LS, result, true, true); return LS.result(); } diff --git a/luprex/cpp/drv/drvutil.cpp b/luprex/cpp/drv/drvutil.cpp index 310ff26f..cd57c6f4 100644 --- a/luprex/cpp/drv/drvutil.cpp +++ b/luprex/cpp/drv/drvutil.cpp @@ -275,7 +275,7 @@ static std::vector parse_control_lst(std::string_view ctrl) { static std::string read_file(const std::filesystem::path &fn, std::string &err) { std::ifstream t(fn); if (t.fail()) { - err = std::string("Could not open ") + fn.u8string(); + err = std::string("Could not open ") + fn.string(); return ""; } t.seekg(0, std::ios::end); @@ -284,7 +284,7 @@ static std::string read_file(const std::filesystem::path &fn, std::string &err) t.seekg(0); t.read(&result[0], size); if ((t.fail()) || (size_t(t.tellg()) != size)) { - err = std::string("Could not read ") + fn.u8string(); + err = std::string("Could not read ") + fn.string(); return ""; } err = ""; @@ -347,7 +347,7 @@ std::string package_lua_source(const std::filesystem::path &base, std::ostream * sbwrite_string(s, names[i]); std::filesystem::path lfn = base / "lua" / names[i]; if (!sbwrite_file(s, lfn)) { - return std::string("Cannot read source file: ") + lfn.u8string(); + return std::string("Cannot read source file: ") + lfn.string(); } } return ""; diff --git a/luprex/ext/base-buffer.hpp b/luprex/ext/base-buffer.hpp index ee3d22e3..67b4ef04 100644 --- a/luprex/ext/base-buffer.hpp +++ b/luprex/ext/base-buffer.hpp @@ -33,8 +33,8 @@ enum class SimpleDynamicTag { UNINITIALIZED, - AUTO, STRING, + TOKEN, NUMBER, BOOLEAN, VECTOR, @@ -55,9 +55,10 @@ struct SimpleDynamic { static const char *type_name_of(SimpleDynamicTag t) { switch (t) { case SimpleDynamicTag::UNINITIALIZED: return "uninitialized"; + case SimpleDynamicTag::STRING: return "string"; + case SimpleDynamicTag::TOKEN: return "token"; case SimpleDynamicTag::BOOLEAN: return "boolean"; case SimpleDynamicTag::NUMBER: return "number"; - case SimpleDynamicTag::STRING: return "string"; case SimpleDynamicTag::VECTOR: return "vector"; default: return "unknown"; } @@ -71,14 +72,14 @@ struct SimpleDynamic { type=SimpleDynamicTag::UNINITIALIZED; s.clear(); x=y=z=0; } - void set_auto() { - type=SimpleDynamicTag::AUTO; s.clear(); x=y=z=0; - } - void set_string(std::string_view is) { type=SimpleDynamicTag::STRING; s=is; x=y=z=0; } + void set_token(std::string_view is) { + type=SimpleDynamicTag::TOKEN; s=is; x=y=z=0; + } + void set_number(double n) { type = SimpleDynamicTag::NUMBER; s.clear(); x=n; y=z=0; } @@ -116,7 +117,6 @@ struct SimpleDynamic { // void write_double(double data) // void write_length(size_t data) // void write_string(std::string_view data) -// void write_simple_dynamic(const SimpleDynamic &sd); // // You should derive from BaseWriter using the CRTP pattern: // @@ -197,7 +197,6 @@ public: // size_t read_length(); // String read_string_limit(uint64_t size); // String read_string(); -// SimpleDynamic read_simple_dynamic(); // // You should derive from BaseReader using the CRTP pattern: // @@ -501,17 +500,18 @@ public: // Write a SimpleDynamic value. // - // This works regardless of what kind of string is present in the + // This works regardless of what kind of data is present in the // SimpleDynamic. // template void write_simple_dynamic(const SimpleDynamic &sd) { write_simple_dynamic_tag(sd.type); switch(sd.type) { + case SimpleDynamicTag::STRING: write_string(sd.s); break; + case SimpleDynamicTag::TOKEN: write_string(sd.s); break; case SimpleDynamicTag::NUMBER: write_double(sd.x); break; case SimpleDynamicTag::BOOLEAN: write_bool(sd.x == 1.0); break; case SimpleDynamicTag::VECTOR: write_double(sd.x); write_double(sd.y); write_double(sd.z); break; - case SimpleDynamicTag::STRING: write_string(sd.s); break; default: assert(false); } } @@ -628,6 +628,8 @@ public: void read_simple_dynamic(SimpleDynamic *result) { SimpleDynamicTag type = read_simple_dynamic_tag(); switch (type) { + case SimpleDynamicTag::STRING: result->set_string(read_string()); break; + case SimpleDynamicTag::TOKEN: result->set_token(read_string()); break; case SimpleDynamicTag::NUMBER: result->set_number(read_double()); break; case SimpleDynamicTag::BOOLEAN: result->set_boolean(read_bool()); break; case SimpleDynamicTag::VECTOR: { @@ -637,7 +639,6 @@ public: result->set_vector(x,y,z); break; } - case SimpleDynamicTag::STRING: result->set_string(read_string()); break; default: result->set_uninitialized(); break; } }