当前位置:网站首页>[UE4] replay game playback for ue4.26
[UE4] replay game playback for ue4.26
2022-07-29 02:00:00 【The north of the city is no longer beautiful】
Preface :UE4.26 Playback tutorial for , It's useful recently ,So Combed the whole construction process , I hope I can help you !( There is a video tutorial at the end , Long time )
1. preparation :
Create a UE4C++ project , add to First person and third person Function pack ;
Shut down the engine , Find project directory :../ContentDir/Config/DefaultEngine.ini Add the following code :
[/Script/Engine.GameEngine]
+NetDriverDefinitions=(DefName="DemoNetDriver",DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver")Reopen the project . Create a new C++ class MyGameInstance Inherited from :GameInstance

XXX.Build.cs Add modules to :Json
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","Json"});MyGameInstance.h in :
#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_ReplayInfo1
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
FString ReplayName;
UPROPERTY(BlueprintReadOnly)
FString FriendlyName;
UPROPERTY(BlueprintReadOnly)
FDateTime Timestamp;
UPROPERTY(BlueprintReadOnly)
int32 LengthInMS;
UPROPERTY(BlueprintReadOnly)
bool bIsValid;
FS_ReplayInfo1()
{
ReplayName = "Replay";
FriendlyName = "Replay";
Timestamp = FDateTime::MinValue();
LengthInMS = 0;
bIsValid = false;
}
FS_ReplayInfo1(FString NewName, FString NewFriendlyName, FDateTime NewTimestamp, int32 NewLengthInMS)
{
ReplayName = NewName;
FriendlyName = NewFriendlyName;
Timestamp = NewTimestamp;
LengthInMS = NewLengthInMS;
bIsValid = true;
}
};
/**
*
*/
UCLASS()
class REPLAYTEST_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_ReplayInfo1>& AllReplaysm);
};
MyGameInstance.cpp in :
#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 function
OnEnumerateStreamsCompleteDelegate1 = FEnumerateStreamsCallback::CreateUObject(this, &UMyGameInstance::OnEnumerateStreamsComplete1);
// Link DeleteReplay() delegate to function
OnDeleteFinishedStreamCompleteDelegate1 = 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_ReplayInfo1> AllReplays;
for (FNetworkReplayStreamInfo StreamInfo : Result.FoundStreams)
{
void BP_OnFindReplaysComplete1(const TArray<FS_ReplayInfo1> &AllReplaysm);
if (!StreamInfo.bIsLive)
{
AllReplays.Add(FS_ReplayInfo1(StreamInfo.Name, StreamInfo.FriendlyName, StreamInfo.Timestamp, StreamInfo.LengthInMS));
}
}
BP_OnFindReplaysComplete1(AllReplays);
}
void UMyGameInstance::RenameReplay(const FString& ReplayName, const FString& NewFriendlyReplayName)
{
// Get File Info
FNullReplayInfo 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 FriendlyName
Info.FriendlyName = NewFriendlyReplayName;
// Write File Info
TUniquePtr<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();
}
//void UMyGameInstance::BP_OnFindReplaysComplete1(TArray<FS_ReplayInfo1>& AllReplays)
//{
//}
Create a new C++ class PC_Spectator Inherited from :PlayerController
PC_Spectator.h in :
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "PC_ReplaySpectator.generated.h"
/**
*
*/
UCLASS()
class REPLAYTEST_API APC_ReplaySpectator : public APlayerController
{
GENERATED_BODY()
public:
/** we must set some Pause-Behavior values in the ctor */
APC_ReplaySpectator(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);
};
PC_Spectator.cpp in :
// Fill out your copyright notice in the Description page of Project Settings.
#include "PC_ReplaySpectator.h"
#include "Engine/World.h"
#include "Engine/DemoNetDriver.h"
APC_ReplaySpectator::APC_ReplaySpectator(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
bShowMouseCursor = true;
PrimaryActorTick.bTickEvenWhenPaused = true;
bShouldPerformFullTickWhenPaused = true;
}
bool APC_ReplaySpectator::SetCurrentReplayPausedState(bool bDoPause)
{
AWorldSettings* WorldSettings = GetWorldSettings();
// Set MotionBlur off and Anti Aliasing to FXAA in order to bypass the pause-bug of both
static 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 FXAA
CVarAA->Set(1);
CVarMB->Set(0);
WorldSettings->Pauser = PlayerState;
return true;
}
// Rest MotionBlur and AA
CVarAA->Set(PreviousAASetting);
CVarMB->Set(PreviousMBSetting);
WorldSettings->Pauser = NULL;
return false;
}
int32 APC_ReplaySpectator::GetCurrentReplayTotalTimeInSeconds() const
{
if (GetWorld())
{
if (GetWorld()->DemoNetDriver)
{
return GetWorld()->DemoNetDriver->DemoTotalTime;
}
}
return 0.f;
}
int32 APC_ReplaySpectator::GetCurrentReplayCurrentTimeInSeconds() const
{
if (GetWorld())
{
if (GetWorld()->DemoNetDriver)
{
return GetWorld()->DemoNetDriver->DemoCurrentTime;
}
}
return 0.f;
}
void APC_ReplaySpectator::SetCurrentReplayTimeToSeconds(int32 Seconds)
{
if (GetWorld())
{
if (GetWorld()->DemoNetDriver)
{
GetWorld()->DemoNetDriver->GotoTimeInSeconds(Seconds);
}
}
}
void APC_ReplaySpectator::SetCurrentReplayPlayRate(float PlayRate)
{
if (GetWorld())
{
if (GetWorld()->DemoNetDriver)
{
GetWorld()->GetWorldSettings()->DemoPlayTimeDilation = PlayRate;
}
}
}
After the compilation is successful, start the engine and go to the next step ;
2. Write blueprints and other settings :
Create user controls separately WBP_ReplayChild;WBP_ReplayMenu;WBP_ReplaySpectator:











Create a new blueprint class GI_Replay Inherited from MyGameInstance And overload functions BP on Find Replays Complete 1:

Create a new controller class BP_PB_ReplaySpectator Inherited from PC_ReplaySpectator:

open first person & third person Game mode blueprint , Set replay spectator to create PC_ReplaySpectator:

Two person In the role blueprint Class is enabled by default Copy & Copy motion , Write recording logic :



open The map you need to record ( A three person map ) They correspond to each other World scene Set up Game mode and Turn on all Movable animals In the details column Of Copy :


Project setting Set up Default map And Game examples :

Create an empty map MainMenuMap, Game mode selection None, Level blueprint Add menus to viewports :

3. Began to run , Enter recording or playback .
Video tutorial :BV17L4y1A7eF【 unreal 4】Replay Replay system -UE4.26 course
边栏推荐
- [7.21-26] code source - [good sequence] [social circle] [namonamo]
- Day01 job
- StoneDB 邀请您参与开源社区月会!
- Tomorrow infinite plan, 2022 conceptual planning scheme for a company's yuanuniverse product launch
- DSP vibration seat
- 数学建模——带相变材料的低温防护服御寒仿真模拟
- FPGA实现10M多功能信号发生器
- [web technology] 1395 esbuild bundler HMR
- [7.21-26] code source - [sports festival] [Dan fishing war] [maximum weight division]
- 【流放之路-第二章】
猜你喜欢

【10点公开课】:快手GPU/FPGA/ASIC异构平台的应用探索
![[WesternCTF2018]shrine](/img/c1/c099f8930902197590052630281258.png)
[WesternCTF2018]shrine

Day01作业

We summarized the three recommendations for the use of Nacos and first published the Nacos 3.0 plan for the 4th anniversary of the open source of Nacos

数学建模——自来水管道铺设问题

Data platform data access practice

把逻辑做在Sigma-DSP中的优化实例-数据分配器

What are the common cyber threats faced by manufacturers and how do they protect themselves

Reinforcement learning (I): Q-learning, with source code interpretation

Top network security prediction: nearly one-third of countries will regulate blackmail software response within three years
随机推荐
The brutal rule of blackmail software continues, and attacks increase by 105%
【Web技术】1395- Esbuild Bundler HMR
Practical experience of Google cloud spanner
【流放之路-第二章】
Sigma-DSP-OUTPUT
使用本地缓存+全局缓存实现小型系统用户权限管理
Autoware reports an error: can't generate global path for start solution
FPGA实现10M多功能信号发生器
Leetcode 113: path sum II
Nine days later, we are together to focus on the new development of audio and video and mystery technology
JS 定时器setInterval clearInterval 延时器setTimeOut 异步 动画
Comprehensive explanation of "search engine crawl"
Internship: tool class writing for type judgment
Reinforcement learning (III): dqn, nature dqn, double dqn, with source code interpretation
Overview of Qualcomm 5g intelligent platform
Planning mathematics final simulation exam I
Thirty years of MPEG audio coding
剑指offer专项突击版第13天
Tomorrow infinite plan, 2022 conceptual planning scheme for a company's yuanuniverse product launch
Planning mathematics final exam simulation II



















