UE5.4.3 录屏回放系统ReplaySystem蓝图版

news/2024/12/22 1:57:12/

这是ReplaySystem的蓝图使用方法版,以第三人称模版为例,需要几个必须步骤

项目config内DefaultEngine.ini的最后添加:

[/Script/Engine.GameEngine]
+NetDriverDefinitions=(DefName="DemoNetDriver",DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver")

项目的.build.cs用添加Josn模块

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput","Json" });

创建MyGameInstance继承至GameInstance

MyGameInstance.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "Engine/GameInstance.h"#include "NetworkReplayStreaming.h"
#include "Runtime/NetworkReplayStreaming/NullNetworkReplayStreaming/Public/NullNetworkReplayStreaming.h"
#include "Misc/NetworkVersion.h"#include "MyGameInstance.generated.h"USTRUCT(BlueprintType)
struct FS_ReplayInfo
{GENERATED_USTRUCT_BODY()UPROPERTY(BlueprintReadOnly)FString ReplayName;UPROPERTY(BlueprintReadOnly)FString FriendlyName;UPROPERTY(BlueprintReadOnly)FDateTime Timestamp;UPROPERTY(BlueprintReadOnly)int32 LengthInMS;UPROPERTY(BlueprintReadOnly)bool bIsValid;FS_ReplayInfo(){ReplayName = "Replay";FriendlyName = "Replay";Timestamp = FDateTime::MinValue();LengthInMS = 0;bIsValid = false;}FS_ReplayInfo(FString NewName, FString NewFriendlyName, FDateTime NewTimestamp, int32 NewLengthInMS){ReplayName = NewName;FriendlyName = NewFriendlyName;Timestamp = NewTimestamp;LengthInMS = NewLengthInMS;bIsValid = true;}
};UCLASS()
class REPLAYUE54_API UMyGameInstance : public UGameInstance
{GENERATED_BODY()public:UFUNCTION(BlueprintCallable, Category = "Replays")void StartRecordingReplayFromBP(FString ReplayName, FString FriendlyName);UFUNCTION(BlueprintCallable, Category = "Replays")void StopRecordingReplayFromBP();UFUNCTION(BlueprintCallable, Category = "Replays")void PlayReplayFromBP(FString ReplayName);UFUNCTION(BlueprintCallable, Category = "Replays")void FindReplays();UFUNCTION(BlueprintCallable, Category = "Replays")void RenameReplay(const FString& ReplayName, const FString& NewFriendlyReplayName);UFUNCTION(BlueprintCallable, Category = "Replays")void DeleteReplay(const FString& ReplayName);virtual void Init() override;TSharedPtr<INetworkReplayStreamer> EnumerateStreamsPtr;FEnumerateStreamsCallback OnEnumerateStreamsCompleteDelegate1;void OnEnumerateStreamsComplete1(const FEnumerateStreamsResult& Result);FDeleteFinishedStreamCallback OnDeleteFinishedStreamCompleteDelegate1;void OnDeleteFinishedStreamComplete1(const FDeleteFinishedStreamResult& Result);UFUNCTION(BlueprintImplementableEvent, Category = "Replays")void BP_OnFindReplaysComplete1(const TArray<FS_ReplayInfo>& AllReplaysm);	};

MyGmaeInstance.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "MyGameInstance.h"#include "Modules/ModuleManager.h"
#include "Runtime/Core/Public/HAL/FileManager.h"
#include "Runtime/Core/Public/Misc/FileHelper.h"void UMyGameInstance::Init()
{Super::Init();// create a ReplayStreamer for FindReplays() and DeleteReplay(..)EnumerateStreamsPtr = FNetworkReplayStreaming::Get().GetFactory().CreateReplayStreamer();// Link FindReplays() delegate to functionOnEnumerateStreamsCompleteDelegate1 = FEnumerateStreamsCallback::CreateUObject(this, &UMyGameInstance::OnEnumerateStreamsComplete1);// Link DeleteReplay() delegate to functionOnDeleteFinishedStreamCompleteDelegate1 = FDeleteFinishedStreamCallback::CreateUObject(this, &UMyGameInstance::OnDeleteFinishedStreamComplete1);
}
void UMyGameInstance::StartRecordingReplayFromBP(FString ReplayName, FString FriendlyName)
{StartRecordingReplay(ReplayName, FriendlyName);
}void UMyGameInstance::StopRecordingReplayFromBP()
{StopRecordingReplay();
}void UMyGameInstance::PlayReplayFromBP(FString ReplayName)
{PlayReplay(ReplayName);
}
void UMyGameInstance::FindReplays()
{if (EnumerateStreamsPtr.Get()){EnumerateStreamsPtr.Get()->EnumerateStreams(FNetworkReplayVersion(), int32(), FString(), TArray<FString>(), OnEnumerateStreamsCompleteDelegate1);}
}void UMyGameInstance::OnEnumerateStreamsComplete1(const FEnumerateStreamsResult& Result)
{TArray<FS_ReplayInfo> AllReplays;for (FNetworkReplayStreamInfo StreamInfo : Result.FoundStreams){void BP_OnFindReplaysComplete1(const TArray<FS_ReplayInfo> &AllReplaysm);if (!StreamInfo.bIsLive){AllReplays.Add(FS_ReplayInfo(StreamInfo.Name, StreamInfo.FriendlyName, StreamInfo.Timestamp, StreamInfo.LengthInMS));}}BP_OnFindReplaysComplete1(AllReplays);
}void UMyGameInstance::RenameReplay(const FString& ReplayName, const FString& NewFriendlyReplayName)
{// Get File InfoFNullReplayInfo Info;const FString DemoPath = FPaths::Combine(*FPaths::ProjectSavedDir(), TEXT("Demos/"));const FString StreamDirectory = FPaths::Combine(*DemoPath, *ReplayName);const FString StreamFullBaseFilename = FPaths::Combine(*StreamDirectory, *ReplayName);const FString InfoFilename = StreamFullBaseFilename + TEXT(".replayinfo");TUniquePtr<FArchive> InfoFileArchive(IFileManager::Get().CreateFileReader(*InfoFilename));if (InfoFileArchive.IsValid() && InfoFileArchive->TotalSize() != 0){FString JsonString;*InfoFileArchive << JsonString;Info.FromJson(JsonString);Info.bIsValid = true;InfoFileArchive->Close();}// Set FriendlyNameInfo.FriendlyName = NewFriendlyReplayName;// Write File InfoTUniquePtr<FArchive> ReplayInfoFileAr(IFileManager::Get().CreateFileWriter(*InfoFilename));if (ReplayInfoFileAr.IsValid()){FString JsonString = Info.ToJson();*ReplayInfoFileAr << JsonString;ReplayInfoFileAr->Close();}
}
void UMyGameInstance::DeleteReplay(const FString& ReplayName)
{if (EnumerateStreamsPtr.Get()){EnumerateStreamsPtr.Get()->DeleteFinishedStream(ReplayName, OnDeleteFinishedStreamCompleteDelegate1);}
}void UMyGameInstance::OnDeleteFinishedStreamComplete1(const FDeleteFinishedStreamResult& Result)
{FindReplays();
}

创建ReplayControllerplayer类继承至PlayerController类

ReplayControllerplayer.h
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "ReplayControllerplayer.generated.h"/*** */
UCLASS()
class REPLAYUE54_API AReplayControllerplayer : public APlayerController
{GENERATED_BODY()public:/** we must set some Pause-Behavior values in the ctor */AReplayControllerplayer(const FObjectInitializer& ObjectInitializer);protected:/** for saving Anti-Aliasing and Motion-Blur settings during Pause State */int32 PreviousAASetting;int32 PreviousMBSetting;public:/** Set the Paused State of the Running Replay to bDoPause. Return new Pause State */UFUNCTION(BlueprintCallable, Category = "CurrentReplay")bool SetCurrentReplayPausedState(bool bDoPause);/** Gets the Max Number of Seconds that were recorded in the current Replay */UFUNCTION(BlueprintCallable, Category = "CurrentReplay")int32 GetCurrentReplayTotalTimeInSeconds() const;/** Gets the Second we are currently watching in the Replay */UFUNCTION(BlueprintCallable, Category = "CurrentReplay")int32 GetCurrentReplayCurrentTimeInSeconds() const;/** Jumps to the specified Second in the Replay we are watching */UFUNCTION(BlueprintCallable, Category = "CurrentReplay")void SetCurrentReplayTimeToSeconds(int32 Seconds);/** Changes the PlayRate of the Replay we are watching, enabling FastForward or SlowMotion */UFUNCTION(BlueprintCallable, Category = "CurrentReplay")void SetCurrentReplayPlayRate(float PlayRate = 1.f);
};

ReplayControllerplayer.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "ReplayControllerplayer.h"
#include "Engine/World.h"
#include "Engine/DemoNetDriver.h"AReplayControllerplayer::AReplayControllerplayer(const FObjectInitializer& ObjectInitializer)
{bShowMouseCursor = true;PrimaryActorTick.bTickEvenWhenPaused = true;bShouldPerformFullTickWhenPaused = true;
}bool AReplayControllerplayer::SetCurrentReplayPausedState(bool bDoPause)
{AWorldSettings* WorldSettings = GetWorldSettings();// Set MotionBlur off and Anti Aliasing to FXAA in order to bypass the pause-bug of bothstatic const auto CVarAA = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DefaultFeature.AntiAliasing"));static const auto CVarMB = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DefaultFeature.MotionBlur"));if (bDoPause){PreviousAASetting = CVarAA->GetInt();PreviousMBSetting = CVarMB->GetInt();// Set MotionBlur to OFF, Anti-Aliasing to FXAACVarAA->Set(1);CVarMB->Set(0);WorldSettings->SetPauserPlayerState(PlayerState);return true;}// Rest MotionBlur and AACVarAA->Set(PreviousAASetting);CVarMB->Set(PreviousMBSetting);WorldSettings->SetPauserPlayerState(NULL);return false;
}int32 AReplayControllerplayer::GetCurrentReplayTotalTimeInSeconds() const
{if (GetWorld()){if (UDemoNetDriver* DemoNetDriver = GetWorld()->GetDemoNetDriver()){return DemoNetDriver->GetDemoTotalTime();}}return 0;
}int32 AReplayControllerplayer::GetCurrentReplayCurrentTimeInSeconds() const
{if (GetWorld()){if (UDemoNetDriver* DemoNetDriver = GetWorld()->GetDemoNetDriver()){return DemoNetDriver->GetDemoCurrentTime();}}return 0;
}void AReplayControllerplayer::SetCurrentReplayTimeToSeconds(int32 Seconds)
{if (GetWorld()){if (UDemoNetDriver* DemoNetDriver = GetWorld()->GetDemoNetDriver()){DemoNetDriver->GotoTimeInSeconds(Seconds);}}
}void AReplayControllerplayer::SetCurrentReplayPlayRate(float PlayRate)
{if (GetWorld()){if (UDemoNetDriver* DemoNetDriver = GetWorld()->GetDemoNetDriver()){GetWorld()->GetWorldSettings()->DemoPlayTimeDilation = PlayRate;}}
}

创建MyGmaeInstance与ReplayController的BP蓝图类

UserInterface类:ReplayChild,ReplayMenu,ReplaySpectator

项目设置中

BP_MyGameInstance

 BP_ReplayController

 BP_ThirdPersonGameMode中的设置

 ReplayChild

ReplayMenu 

 

 

 ReplaySpectator

 


http://www.ppmy.cn/news/1536802.html

相关文章

Qt 中的 QChartView

深入理解 Qt 的 QChartView&#xff1a;图表展示与交互 QChartView 是 Qt Charts 模块中的一个核心类&#xff0c;它用于在 Qt 应用程序中显示图表&#xff0c;并支持多种用户交互方式。它继承自 QGraphicsView&#xff0c;通过封装 QChart&#xff0c;为用户提供了强大的图表…

Oracle中处理空值函数(NVL、NVL2、NULLIF等)详解

文章目录 前言一、函数语法NVL函数NVL2函数NULLIF函数COALESCE函数DECODE函数 二、用法区别三、测试用例总结 前言 本文将介绍Oracle中处理空值的函数。常用的处理函数有&#xff1a;NVL()、NVL2()、NULLIF()、COALESCE()。此外DECODE()和CASE()函数也可以起到处理空值的效果。…

日记学习小迪安全27

感觉复制粘贴没有意思&#xff0c;而且还有点浪费时间&#xff0c;主要是学习&#xff0c;不是复制&#xff0c;那就复制别人的吧 第27关就参考这篇文章吧&#xff0c;以下大部分内容都是参考以下文章&#xff08;侵权删除&#xff09; 第27天&#xff1a;WEB攻防-通用漏洞&a…

虚拟化数据恢复—互斥不当导致vmfs卷损坏的数据恢复案例

虚拟化数据恢复环境&#xff1a; 某企业信息管理平台&#xff0c; 几台VMware ESX Server主机共享一台存储设备&#xff0c;大约有几十台虚拟机。 虚拟化故障&原因&#xff1a; Vcenter报告虚拟磁盘丢失。管理员通过ssh远程到ESX中执行fdisk -l命令查看磁盘&#xff0c;发…

计算机网络:计算机网络概述:网络、互联网与因特网的区别

文章目录 网络、互联网与因特网的区别网络分类 互联网因特网基于 ISP 的多层次结构的互连网络因特网的标准化工作因特网管理机构因特网的组成 网络、互联网与因特网的区别 若干节点和链路互连形成网络&#xff0c;若干网络通过路由器互连形成互联网 互联网是全球范围内的网络…

【论文阅读】超分辨率图像重建算法综述

0. 摘要 研究背景和意义 在人类视觉感知系统中&#xff0c;高分辨率&#xff08;HR&#xff09;图像对于清晰表达空间结构、细节特征、边缘纹理等信息至关重要&#xff0c;在医学、刑侦、卫星等多个领域具有广泛实用价值。超分辨率图像重建&#xff08;SRIR&#xff09;旨在从低…

TypeScript面向对象 02

抽象类 以abstract开头的类是抽象类。抽象类和其他类区别不大&#xff0c;只是不能用来创建对象。抽象类就是专门用来被继承的类。 抽象类中可以添加抽象方法。定义一个抽象方法使用abstract&#xff0c;没有方法体。抽象方法只能定义在抽象类中&#xff0c;子类必须对抽象方…

如何计算Pi?python

怎样计算PI&#xff1f; 下面是python程序&#xff1a; def calculate_pi(iterations): pi 0 for i in range(iterations): term (-1) ** i / (2 * i 1) pi term pi * 4 return pi # 设置迭代次数 iterations 1000000 estimated_pi ca…