diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 78ce2563..cea94d5b 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -36,28 +36,28 @@ static bool SetProperty(const FString& prefix, UObject* obj, const FlxAnimationF FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data()); FName nname(prefix + sname); switch (field.Type) { - case ElxAnimValueType::STRING: { + case SimpleDynamicTag::STRING: { FStrProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; FString* pptr = fprop->ContainerPtrToValuePtr(obj); *pptr = FString(field.S.size(), (const UTF8CHAR*)field.S.data()); return true; } - case ElxAnimValueType::NUMBER: { + case SimpleDynamicTag::NUMBER: { FDoubleProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; double* pptr = fprop->ContainerPtrToValuePtr(obj); *pptr = field.X; return true; } - case ElxAnimValueType::BOOLEAN: { + case SimpleDynamicTag::BOOLEAN: { FBoolProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; uint8* pptr = fprop->ContainerPtrToValuePtr(obj); fprop->SetPropertyValue(pptr, (field.X == 1.0)); return true; } - case ElxAnimValueType::XYZ: { + case SimpleDynamicTag::VECTOR: { FStructProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; if (fprop->Struct != TBaseStructure::Get()) return false; @@ -84,7 +84,7 @@ bool FlxAnimationStep::Unpack(const FString& prefix, UObject* into) const { FlxAnimationField field; field.Name = "action"; field.Persistent = false; - field.Type = ElxAnimValueType::STRING; + field.Type = SimpleDynamicTag::STRING; field.S = "idle"; ok &= SetProperty(prefix, into, field); } @@ -110,7 +110,7 @@ static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std: return result; } } - result.Type = ElxAnimValueType::INVALID; + result.Type = SimpleDynamicTag::UNINITIALIZED; return result; } @@ -122,21 +122,21 @@ static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const void FlxAnimationStep::AutoUpdateXYZ(AActor *actor) const { FlxAnimationField xyz = FindAnimationFieldLL(*this, "xyz"); - if (xyz.Type == ElxAnimValueType::XYZ) { + if (xyz.Type == SimpleDynamicTag::VECTOR) { actor->SetActorLocation(FVector(xyz.X, xyz.Y, xyz.Z)); } } void FlxAnimationStep::AutoUpdateFacing(AActor *actor) const { FlxAnimationField facing = FindAnimationFieldLL(*this, "facing"); - if (facing.Type == ElxAnimValueType::NUMBER) { + if (facing.Type == SimpleDynamicTag::NUMBER) { actor->SetActorRotation(FRotator(0, facing.X, 0)); } } void FlxAnimationStep::AutoUpdatePlane(FName *planep) const { FlxAnimationField plane = FindAnimationFieldLL(*this, "plane"); - if (plane.Type == ElxAnimValueType::STRING) { + if (plane.Type == SimpleDynamicTag::STRING) { FString pname(plane.S.size(), (const UTF8CHAR*)(plane.S.data())); *planep = FName(pname); } @@ -152,13 +152,13 @@ bool UlxAnimationStepLibrary::AnimationStepIsIdle(const FlxAnimationStep &step) FVector UlxAnimationStepLibrary::AnimationStepGetVector(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::XYZ) return FVector(0, 0, 0); + if (field.Type != SimpleDynamicTag::VECTOR) return FVector(0, 0, 0); return FVector(field.X, field.Y, field.Z); } double UlxAnimationStepLibrary::AnimationStepGetFloat(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::NUMBER) return 0.0; + if (field.Type != SimpleDynamicTag::NUMBER) return 0.0; return field.X; } @@ -167,58 +167,44 @@ FString UlxAnimationStepLibrary::AnimationStepGetString(const FlxAnimationStep& return TEXT("idle"); } FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::STRING) return TEXT(""); + if (field.Type != SimpleDynamicTag::STRING) return TEXT(""); return FString(field.S.size(), (const UTF8CHAR*)(field.S.data())); } bool UlxAnimationStepLibrary::AnimationStepGetBool(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::BOOLEAN) return false; + if (field.Type != SimpleDynamicTag::BOOLEAN) return false; return field.X == 1.0; } -FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() { - FlxAnimationStepView result; - result.Hash = Decoder.read_uint64(); - result.Body = Decoder.read_string_view(); - return result; -} - -uint64 FlxAnimQueueDecoder::PeekHash() { - std::string_view rest = Decoder.GetRest(); - uint64 result = Decoder.read_uint64(); - Decoder.Reset(rest, false); - return result; -} FlxAnimationField FlxAnimationStepDecoder::ReadField() { FlxAnimationField result; result.Name = Decoder.read_string_view(); result.Persistent = Decoder.read_bool(); - result.Type = (ElxAnimValueType)Decoder.read_uint8(); + result.Type = (SimpleDynamicTag)Decoder.read_uint8(); switch (result.Type) { - case ElxAnimValueType::STRING: { + case SimpleDynamicTag::STRING: { result.S = Decoder.read_string_view(); break; } - case ElxAnimValueType::NUMBER: { + case SimpleDynamicTag::NUMBER: { result.X = Decoder.read_double(); break; } - case ElxAnimValueType::BOOLEAN: { + case SimpleDynamicTag::BOOLEAN: { result.X = Decoder.read_bool() ? 1.0 : 0.0; break; } - case ElxAnimValueType::XYZ: { + case SimpleDynamicTag::VECTOR: { result.X = Decoder.read_double(); result.Y = Decoder.read_double(); result.Z = Decoder.read_double(); break; } default: { - Decoder.set_at_eof(); - result.Type = ElxAnimValueType::BOOLEAN; - result.X = 0; + Decoder.read_bytes(Decoder.fill()); + result.Type = SimpleDynamicTag::UNINITIALIZED; break; } } @@ -239,16 +225,16 @@ FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonl result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data())); result.Append(field.Persistent ? TEXT("=") : TEXT(":")); switch (field.Type) { - case ElxAnimValueType::STRING: + case SimpleDynamicTag::STRING: result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data())); break; - case ElxAnimValueType::NUMBER: + case SimpleDynamicTag::NUMBER: result.Appendf(TEXT("%lf"), field.X); break; - case ElxAnimValueType::BOOLEAN: + case SimpleDynamicTag::BOOLEAN: result.Append((field.X) == 1.0 ? TEXT("true") : TEXT("false")); break; - case ElxAnimValueType::XYZ: + case SimpleDynamicTag::VECTOR: result.Appendf(TEXT("%lf,%lf,%lf"), field.X, field.Y, field.Z); break; } @@ -256,6 +242,20 @@ FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonl return result; } +FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() { + FlxAnimationStepView result; + result.Hash = Decoder.read_uint64(); + result.Body = Decoder.read_string_view(); + return result; +} + +uint64 FlxAnimQueueDecoder::PeekHash() { + int64_t read_count = Decoder.total_reads(); + uint64 result = Decoder.read_uint64(); + Decoder.unread_to(read_count); + return result; +} + FlxAnimQueueDecoder::FlxAnimQueueDecoder(std::string_view queue) : Decoder(queue) { SizeLimit = Decoder.read_uint8(); ActualSize = Decoder.read_uint8(); diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index ff576088..52d0aa14 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -5,20 +5,6 @@ #include "Containers/Deque.h" #include "AnimQueue.generated.h" -//////////////////////////////////////////////// -// -// This is copied over from Luprex source. Not ideal. -// -//////////////////////////////////////////////// - -enum class ElxAnimValueType { - STRING, - NUMBER, - BOOLEAN, - XYZ, - INVALID -}; - //////////////////////////////////////////////// // // An single animation step. @@ -161,7 +147,7 @@ struct FlxAnimationStepView { struct FlxAnimationField { std::string_view Name; bool Persistent; - ElxAnimValueType Type; + SimpleDynamicTag Type; double X, Y, Z; std::string_view S; }; @@ -179,7 +165,7 @@ struct FlxAnimationField { class FlxAnimQueueDecoder { private: - FlxStringDecoder Decoder; + FlxStreamBuffer Decoder; // These values are immediately read from the header. // @@ -201,7 +187,7 @@ public: // Return true if the parser has reached the end of the string. // - bool AtEOF() { return Decoder.at_eof(); } + bool AtEOF() { return Decoder.empty(); } // Read one animation step. // @@ -229,7 +215,7 @@ public: class FlxAnimationStepDecoder { private: - FlxStringDecoder Decoder; + FlxStreamBuffer Decoder; public: // Initialize the FlxAnimationStepDecoder from the FlxAnimationStepView. @@ -238,7 +224,7 @@ public: // Return true if the parser has reached the end of the string. // - bool AtEOF() { return Decoder.at_eof(); } + bool AtEOF() { return Decoder.empty(); } // Read one field. // diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 7cbcc519..8b965dc6 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -132,24 +132,41 @@ void AIntegrationGameModeBase::UpdateTangibles() { TangibleManager->DeleteFarawayTangibles(); } +void AIntegrationGameModeBase::ExecuteDebuggingCommand(const FString &fs) { + if (fs == "\\invokeplayer") { + // FlxLockedWrapper w(LockableWrapper); + // int64 player = w.GetActor(); + // w->play_invoke_player(w.Get(), player, datapk); + } else { + ConsoleOutput.AppendLine(TEXT("Unknown Command")); + } +} + + void AIntegrationGameModeBase::ConsoleSendInput(const FString& fs) { FlxLockedWrapper w(LockableWrapper); if (w->engine != nullptr) { - const TCHAR* fstchar = *fs; - if (sizeof(TCHAR) == 2) - { - ConsoleOutput.AppendLine(FString("> ") + fs); - std::u16string_view fsview((const char16_t*)fstchar, fs.Len()); - std::string utf8 = drvutil::utf16_to_utf8(fsview); - utf8 = utf8 + "\n"; - w->play_recv_incoming(w.Get(), 0, utf8.size(), utf8.c_str()); + ConsoleOutput.AppendLine(FString("> ") + fs); + // This is a bad way to do this. The problem is that if some + // lua code contains '\\', we'll catch it instead of passing it + // through. There's no simple solution, though. + if (fs[0] == '\\') { + ExecuteDebuggingCommand(fs); + } else { + const TCHAR* fstchar = *fs; + if (sizeof(TCHAR) == 2) + { + std::u16string_view fsview((const char16_t*)fstchar, fs.Len()); + std::string utf8 = drvutil::utf16_to_utf8(fsview); + utf8 = utf8 + "\n"; + w->play_recv_incoming(w.Get(), 0, utf8.size(), utf8.c_str()); + } } } } - void AIntegrationGameModeBase::Tick(float deltaseconds) { Super::Tick(deltaseconds); diff --git a/Source/Integration/IntegrationGameModeBase.h b/Source/Integration/IntegrationGameModeBase.h index da155315..62acb052 100644 --- a/Source/Integration/IntegrationGameModeBase.h +++ b/Source/Integration/IntegrationGameModeBase.h @@ -43,6 +43,9 @@ public: UPROPERTY(EditDefaultsOnly, Category = TangibleClasses) TSubclassOf ClassTangibleActor; + // Execute a debugging command, typed on the GUI. + void ExecuteDebuggingCommand(const FString &fs); + // Transfer console output from the Luprex engine to unreal. void UpdateConsoleOutput(); diff --git a/Source/Integration/StringDecoder.cpp b/Source/Integration/StringDecoder.cpp index a5b5a75f..a25b4a7a 100644 --- a/Source/Integration/StringDecoder.cpp +++ b/Source/Integration/StringDecoder.cpp @@ -1,38 +1,2 @@ #include "StringDecoder.h" -FlxStringDecoder::FlxStringDecoder(std::string_view s) { - Text = s.data(); - Size = s.size(); - ErrBeyondEOF = false; - ErrStringTooLong = false; -} - -void FlxStringDecoder::Reset(std::string_view s, bool clear) { - Text = s.data(); - Size = s.size(); - if (clear) { - ErrBeyondEOF = false; - ErrStringTooLong = false; - } -} - -std::string_view FlxStringDecoder::GetRest() { - return std::string_view(Text, Size); -} - -std::string_view FlxStringDecoder::read_string_view() { - size_t length = read_length(); - if (length > Size) { - ErrBeyondEOF = true; - return std::string_view(); - } - std::string_view result(Text, length); - Text += length; - Size -= length; - return result; -} - -void FlxStringDecoder::set_at_eof() { - Text += Size; - Size = 0; -} diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index 79378c0c..44ebf251 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -3,125 +3,42 @@ #include "CoreMinimal.h" #include "lpx-basebuffer.hpp" -///////////////////////////////////////////////////// -// -// FlxStringDecoder -// -// This class is used to decipher 8-bit strings that -// contain packed ints, strings, and other data. -// The typical example of usage is to decipher the -// serialized animation queues fed to us by Luprex. -// -// The FlxStringDecoder doesn't make a copy of the string -// you pass in, instead, it stores a pointer to it. -// So be sure not to free the string until you're -// done analyzing it. -// -// You'll note that some of the function names are -// lowercase, with underscores. That's because they're -// inherited from Luprex classes, and luprex classes -// use that naming convention. There's not any easy -// workaround for that. -// -///////////////////////////////////////////////////// - -class FlxStringDecoder : public BaseReader { +class FlxStreamBufferCore { private: - const char* Text; - size_t Size; + bool err_eof_on_read_; + bool err_string_too_long_; + bool err_integer_truncated_; +protected: -public: - // You can check and clear these error flags at will. - // - bool ErrBeyondEOF; - bool ErrStringTooLong; - -public: - // This function is required by BaseReader. - // It's not meant for end users. - // - void read_bytes_into(char* buffer, size_t size) { - if (size > Size) { - memset(buffer, 0, size); - ErrBeyondEOF = true; - set_at_eof(); - } - else { - memcpy(buffer, Text, size); - Text += size; - Size -= size; - } - } - - // This function is required by BaseReader. - // It's not meant for end users. - // - void raise_string_too_long() { - ErrStringTooLong = true; - } - -public: - // The type returned by read_string. - // - using read_string_type = std::string; - - // Initialize the string decoder with a text to analyze. - // - FlxStringDecoder(std::string_view s); - - // Get the remaining text as a string_view. - // - std::string_view GetRest(); - - // Reinitialize with a new string_view. - // - // If clear is true, clears the error flags. - // - void Reset(std::string_view s, bool clear); - - // Get the size of the remaining text. - // - size_t get_size() { return Size; } + void *basebuffer_malloc(size_t size) { return malloc(size); } + void basebuffer_free(void *p) { free(p); } + void clear_error_flags() { err_eof_on_read_ = err_string_too_long_ = err_integer_truncated_ = false; } + void raise_eof_on_read() { err_eof_on_read_ = true; } + void raise_string_too_long() { err_string_too_long_ = true; } + void raise_integer_truncated() { err_integer_truncated_ = true; } - // Return true if the remaining text is empty. - // - bool at_eof() { return Size == 0; } - - // Move the cursor to EOF. - // - void set_at_eof(); - - - // Read a string as a string_view - // - // This reads a string from the source, returning - // it as a string_view that points into the buffer. - // Naturally, if you release the buffer, the - // string_view is invalidated. - // - // This is considerably faster than read_string. - // - std::string_view read_string_view(); - - // Inherited Methods: - // - // The following methods are inherited from BaseReader: - // - // uint8_t read_uint8(); - // uint16_t read_uint16(); - // uint32_t read_uint32(); - // uint64_t read_uint64(); - // int8_t read_int8(); - // int16_t read_int16(); - // int32_t read_int32(); - // int64_t read_int64(); - // bool read_bool(); - // char read_char(); - // float read_float(); - // double read_double(); - // size_t read_length(); - // std::string read_string_limit(uint64_t size); - // std::string read_string(); - // + bool get_err_eof_on_read() const { return err_eof_on_read_; } + bool get_err_string_too_long() const { return err_string_too_long_; } + bool get_err_integer_truncated() const { return err_integer_truncated_; } + bool any_error() const { return err_eof_on_read_ || err_string_too_long_ || err_integer_truncated_; } }; + +class FlxStreamBuffer : public BaseBuffer { +public: + using BaseBuffer::BaseBuffer; + + void write_dxyz(const FVector &xyz) { + write_double(xyz.X); + write_double(xyz.Y); + write_double(xyz.Z); + } + + FVector read_dxyz() { + double x = read_double(); + double y = read_double(); + double z = read_double(); + return FVector(x, y, z); + } +}; +