diff --git a/Content/Tangibles/TangibleCharacter.uasset b/Content/Tangibles/TangibleCharacter.uasset index e00ec4d2..f904704a 100644 --- a/Content/Tangibles/TangibleCharacter.uasset +++ b/Content/Tangibles/TangibleCharacter.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca12fdbfc628a39a87b1253ed7a7b2f2b3b262a8754d6b9c14c724544445a2de -size 534389 +oid sha256:d0b118706fa908857aa5263c9ee31998b98cbcde6148b0c14ff16c49e5c77419 +size 453893 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index b3066b1e..ad5a4440 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -279,6 +279,9 @@ FlxAnimTracker::FlxAnimTracker() { void FlxAnimTracker::Clear() { AQ.Empty(); Changed = true; + AutoFinish = false; + AutoFinishAction.Empty(); + AutoFinishXYZ.Set(0,0,0); } void FlxAnimTracker::FinishedAnimation(uint64 hash) { @@ -358,7 +361,6 @@ void FlxAnimTracker::Update(std::string_view encqueue) { while (!newsteps.IsEmpty()) { FlxAnimationStepView step = newsteps.Pop(); AQ.EmplaceLast(step.Hash, step.Body); - } // If there are too many animations in AQ, discard @@ -374,6 +376,36 @@ void FlxAnimTracker::Update(std::string_view encqueue) { AQ.PopFirst(); } } + + // Autofinish up to one animation. + // + if (AutoFinish) { + for (int i = 0; i < AQ.Num(); i++) { + if (!AQ[i].Finished) { + if (MatchesAutoFinish(AQ[i])) { + AQ[i].Finished = true; + } + break; + } + } + AutoFinish = false; + AutoFinishAction.Empty(); + AutoFinishXYZ.Set(0,0,0); + } +} + +void FlxAnimTracker::SetAutoFinish(const FString &action, const FVector &xyz) { + AutoFinish = true; + AutoFinishAction = action; + AutoFinishXYZ = xyz; +} + +bool FlxAnimTracker::MatchesAutoFinish(const FlxAnimationStep &step) { + FVector xyz = UlxAnimationStepLibrary::AnimationStepGetVector(step, TEXT("xyz")); + if (xyz != AutoFinishXYZ) return false; + FString action = UlxAnimationStepLibrary::AnimationStepGetString(step, TEXT("action")); + if (action != AutoFinishAction) return false; + return true; } FString FlxAnimTracker::GetCurrentBlueprintName() { @@ -393,6 +425,8 @@ FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() { } } result = AQ.Last(); - result.Hash = 0; + // This next line is a hack. We need the idle step to have a unique + // hash. This is a passable way to get a unique hash value. + result.Hash += 1; return result; } diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 18c94184..9a7f8012 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -259,7 +259,15 @@ public: // bool Changed; + // Autofinish parameters. + // + bool AutoFinish; + FString AutoFinishAction; + FVector AutoFinishXYZ; + private: + bool MatchesAutoFinish(const FlxAnimationStep &step); + public: // Construct a tracker. // @@ -278,6 +286,14 @@ public: // void Update(std::string_view encqueue); + // Auto-finish animation. + // + // Next time 'update' is called, we will check for the presence + // of a new animation matching these parameters. If there is + // one, it is automatically marked 'finished'. + // + void SetAutoFinish(const FString &action, const FVector &xyz); + // Get the current blueprint name, as a string. // FString GetCurrentBlueprintName(); diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 843fefb7..26f9b452 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -132,7 +132,7 @@ void AIntegrationGameModeBase::UpdateTangibles() { TangibleManager->DeleteFarawayTangibles(); } -void AIntegrationGameModeBase::InvokeEngioMove(const FString &action, const FVector &xyz) { +void AIntegrationGameModeBase::InvokeEngioMove(const FString &action, const FVector &xyz, double facing) { FTCHARToUTF8 utf8action(action); std::string uaction(utf8action.Get(), utf8action.Length()); FlxStreamBuffer sb; @@ -141,6 +141,8 @@ void AIntegrationGameModeBase::InvokeEngioMove(const FString &action, const FVec sb.write_string(uaction); sb.write_simple_dynamic_tag(SimpleDynamicTag::VECTOR); sb.write_fvector(xyz); + sb.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER); + sb.write_double(facing); std::string_view datapk = sb.view(); FlxLockedWrapper w(LockableWrapper); int64 player = w.GetActor(); @@ -197,6 +199,8 @@ void AIntegrationGameModeBase::OnWorldPreActorTick(UWorld* InWorld, ELevelTick I { LuprexUpdateTask.Wait(); EngineSeconds += deltaseconds; + UpdateConsoleOutput(); + UpdateTangibles(); } } diff --git a/Source/Integration/IntegrationGameModeBase.h b/Source/Integration/IntegrationGameModeBase.h index 1849cae0..ef6c938b 100644 --- a/Source/Integration/IntegrationGameModeBase.h +++ b/Source/Integration/IntegrationGameModeBase.h @@ -43,7 +43,7 @@ public: int64 GetPlayerId(); UFUNCTION(BlueprintCallable, Category = "Luprex") - void InvokeEngioMove(const FString &action, const FVector &xyz); + void InvokeEngioMove(const FString &action, const FVector &xyz, double facing); // Execute a debugging command, typed on the GUI. void ExecuteDebuggingCommand(FlxLockedWrapper &w, const FString &fs); diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp index bcb9e7bf..eac680f4 100644 --- a/Source/Integration/Tangible.cpp +++ b/Source/Integration/Tangible.cpp @@ -162,4 +162,9 @@ bool UlxTangible::IsCurrentPlayer(AActor* target) { UlxTangible *tan = GetActorTangible(target); AIntegrationGameModeBase *gamemode = tan->Manager->GetGameMode(); return (tan->TangibleId == gamemode->PlayerId); +} + +void UlxTangible::SetAutoFinish(AActor *target, const FString &action, const FVector &xyz) { + UlxTangible *tan = GetActorTangible(target); + tan->AnimTracker.SetAutoFinish(action, xyz); } \ No newline at end of file diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h index baf69d68..22096c5a 100644 --- a/Source/Integration/Tangible.h +++ b/Source/Integration/Tangible.h @@ -165,6 +165,9 @@ public: UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) static bool IsCurrentPlayer(AActor *target); + + UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) + static void SetAutoFinish(AActor *target, const FString &action, const FVector &xyz); }; diff --git a/Source/Integration/TriggeredTask.h b/Source/Integration/TriggeredTask.h index 7a9fc39e..d84aee66 100644 --- a/Source/Integration/TriggeredTask.h +++ b/Source/Integration/TriggeredTask.h @@ -37,14 +37,19 @@ private: // This event is used to wake up the thread. // + // This is an auto-reset event, meaning that each time we + // call trigger, the background thread is gated exactly once. + // // Normally, this means we want the worker to run the task // once. But if ThreadStopRequested is true, it means we // want the thread to exit. // FEvent* CallEvent; - // This event is used when the thread is done - // with its work. + // This event is used when the thread is done with its work. + // + // This is not an auto-reset event. This event stays triggered + // whenever the background thread is not running. // FEvent* ReturnEvent;