feature/fix-time-sync #1

Merged
kingsmedia merged 3 commits from feature/fix-time-sync into develop 2022-05-17 21:47:58 +00:00
31 changed files with 1203 additions and 907 deletions

5
.gitignore vendored
View File

@ -75,4 +75,7 @@ Intermediate/*
Plugins/*/Intermediate/* Plugins/*/Intermediate/*
# Cache files for the editor to use # Cache files for the editor to use
DerivedDataCache/* DerivedDataCache/*
#Config files
Config/User*.ini

View File

@ -22,6 +22,14 @@
"Editor" "Editor"
] ]
}, },
{
"Name": "OnlineSubsystemSteam",
"Enabled": true
},
{
"Name": "OnlineSubsystemEOS",
"Enabled": true
},
{ {
"Name": "Bridge", "Name": "Bridge",
"Enabled": true, "Enabled": true,

View File

@ -21,6 +21,8 @@ r.ReflectionMethod=1
r.Shadow.Virtual.Enable=1 r.Shadow.Virtual.Enable=1
[/Script/WorldPartitionEditor.WorldPartitionEditorSettings] [/Script/WorldPartitionEditor.WorldPartitionEditorSettings]
bEnableWorldPartition=False
bEnableConversionPrompt=True
CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet' CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet'
[/Script/Engine.Engine] [/Script/Engine.Engine]
@ -43,19 +45,25 @@ bUseManualIPAddress=False
ManualIPAddress= ManualIPAddress=
[/Script/Engine.GameEngine] [/Script/Engine.GameEngine]
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver") +NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemEOS.NetDriverEOS",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
[OnlineSubsystem] [OnlineSubsystem]
DefaultPlatformService=Steam DefaultPlatformService=EOS
[OnlineSubsystemSteam] [OnlineSubsystemSteam]
bEnabled=true bEnabled=false
SteamDevAppId=480 SteamDevAppId=480
bInitServerOnClient=true bInitServerOnClient=true
[/Script/OnlineSubsystemSteam.SteamNetDriver] [/Script/OnlineSubsystemSteam.SteamNetDriver]
NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection" NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"
[OnlineSubsystemEOS]
bEnabled=true
[/Script/OnlineSubsystemEOS.NetDriverEOS]
bIsUsingP2PSockets=true
[/Script/OnlineSubsystemUtils.IpNetDriver] [/Script/OnlineSubsystemUtils.IpNetDriver]
NetServerMaxTickRate=120 NetServerMaxTickRate=120
@ -116,3 +124,18 @@ NetServerMaxTickRate=120
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle") +CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn") +CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
[/Script/OnlineSubsystemEOS.EOSSettings]
CacheDir=CacheDir
DefaultArtifactName=Blaster
TickBudgetInMilliseconds=0
bEnableOverlay=True
bEnableSocialOverlay=True
bShouldEnforceBeingLaunchedByEGS=False
TitleStorageReadChunkLength=0
bUseEAS=False
bUseEOSConnect=False
bMirrorStatsToEOS=False
bMirrorAchievementsToEOS=False
bUseEOSSessions=False
bMirrorPresenceToEAS=False

View File

@ -10,8 +10,7 @@ MaxPlayers=100
Build=IfProjectHasCode Build=IfProjectHasCode
BuildConfiguration=PPBC_Development BuildConfiguration=PPBC_Development
BuildTarget= BuildTarget=
LaunchOnTarget= StagingDirectory=(Path="")
StagingDirectory=(Path="C:/UEProjects/Blaster/Build")
FullRebuild=False FullRebuild=False
ForDistribution=False ForDistribution=False
IncludeDebugFiles=False IncludeDebugFiles=False
@ -20,7 +19,6 @@ bIncludeNativizedAssetsInProjectGeneration=False
bExcludeMonolithicEngineHeadersInNativizedCode=False bExcludeMonolithicEngineHeadersInNativizedCode=False
UsePakFile=True UsePakFile=True
bUseIoStore=True bUseIoStore=True
bUseZenStore=False
bMakeBinaryConfig=False bMakeBinaryConfig=False
bGenerateChunks=False bGenerateChunks=False
bGenerateNoChunks=False bGenerateNoChunks=False
@ -91,12 +89,10 @@ bSkipMovies=False
+IniKeyBlacklist=MobileProvision +IniKeyBlacklist=MobileProvision
+IniKeyBlacklist=IniKeyBlacklist +IniKeyBlacklist=IniKeyBlacklist
+IniKeyBlacklist=IniSectionBlacklist +IniKeyBlacklist=IniSectionBlacklist
-IniSectionBlacklist=HordeStorageServers
+IniSectionBlacklist=HordeStorageServers
+MapsToCook=(FilePath="/Game/Maps/Lobby") +MapsToCook=(FilePath="/Game/Maps/Lobby")
+MapsToCook=(FilePath="/Game/Maps/GameStartupMap") +MapsToCook=(FilePath="/Game/Maps/GameStartupMap")
+MapsToCook=(FilePath="/Game/Maps/TransitionMap")
+MapsToCook=(FilePath="/Game/Maps/BlasterMap") +MapsToCook=(FilePath="/Game/Maps/BlasterMap")
PerPlatformBuildConfig=() PerPlatformBuildConfig=()
PerPlatformTargetFlavorName=(("Android", "Android_ASTC")) PerPlatformTargetPlatformName=()
PerPlatformBuildTarget=()

View File

@ -18,6 +18,10 @@
+AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
@ -65,7 +69,6 @@ bUseMouseForTouch=False
bEnableMouseSmoothing=True bEnableMouseSmoothing=True
bEnableFOVScaling=True bEnableFOVScaling=True
bCaptureMouseOnLaunch=True bCaptureMouseOnLaunch=True
bEnableLegacyInputScales=True
bAlwaysShowTouchInterface=False bAlwaysShowTouchInterface=False
bShowConsoleOnFourFingerTap=True bShowConsoleOnFourFingerTap=True
bEnableGestureRecognizer=False bEnableGestureRecognizer=False

Binary file not shown.

Binary file not shown.

View File

@ -29,6 +29,10 @@
{ {
"Name": "OnlineSubsystemSteam", "Name": "OnlineSubsystemSteam",
"Enabled": true "Enabled": true
},
{
"Name": "OnlineSubsystemEOS",
"Enabled": true
} }
] ]
} }

View File

@ -28,6 +28,7 @@ public class MultiplayerSessions : ModuleRules
"Core", "Core",
"OnlineSubsystem", "OnlineSubsystem",
"OnlineSubsystemSteam", "OnlineSubsystemSteam",
"OnlineSubsystemEOS",
"UMG", "UMG",
"Slate", "Slate",
"SlateCore" "SlateCore"

View File

@ -32,7 +32,7 @@ void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch, FStr
} }
UGameInstance* GameInstance = GetGameInstance(); UGameInstance* GameInstance = GetGameInstance();
if (GetGameInstance()) if (GameInstance)
{ {
MultiplayerSessionsSubsystem = GameInstance->GetSubsystem<UMultiplayerSessionsSubsystem>(); MultiplayerSessionsSubsystem = GameInstance->GetSubsystem<UMultiplayerSessionsSubsystem>();
} }
@ -44,6 +44,20 @@ void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch, FStr
MultiplayerSessionsSubsystem->MultiplayerOnJoinSessionComplete.AddUObject(this, &ThisClass::OnJoinSession); MultiplayerSessionsSubsystem->MultiplayerOnJoinSessionComplete.AddUObject(this, &ThisClass::OnJoinSession);
MultiplayerSessionsSubsystem->MultiplayerOnDestroySessionComplete.AddDynamic(this, &ThisClass::OnDestroySession); MultiplayerSessionsSubsystem->MultiplayerOnDestroySessionComplete.AddDynamic(this, &ThisClass::OnDestroySession);
MultiplayerSessionsSubsystem->MultiplayerOnStartSessionComplete.AddDynamic(this, &ThisClass::OnStartSession); MultiplayerSessionsSubsystem->MultiplayerOnStartSessionComplete.AddDynamic(this, &ThisClass::OnStartSession);
MultiplayerSessionsSubsystem->MultiplayerOnLoginComplete.AddDynamic(this, &ThisClass::OnLoginComplete);
if (!MultiplayerSessionsSubsystem->IsLoggedIn())
{
LoginButton->SetIsEnabled(true);
HostButton->SetIsEnabled(false);
JoinButton->SetIsEnabled(false);
}
else
{
LoginButton->SetIsEnabled(false);
HostButton->SetIsEnabled(true);
JoinButton->SetIsEnabled(true);
}
} }
} }
@ -64,6 +78,11 @@ bool UMenu::Initialize()
JoinButton->OnClicked.AddDynamic(this, &UMenu::JoinButtonClicked); JoinButton->OnClicked.AddDynamic(this, &UMenu::JoinButtonClicked);
} }
if (LoginButton)
{
LoginButton->OnClicked.AddDynamic(this, &UMenu::LoginButtonClicked);
}
return true; return true;
} }
@ -164,6 +183,13 @@ void UMenu::OnStartSession(bool bWasSuccessful)
{ {
} }
void UMenu::OnLoginComplete(bool bWasSuccessful)
{
JoinButton->SetIsEnabled(!bWasSuccessful);
HostButton->SetIsEnabled(bWasSuccessful);
JoinButton->SetIsEnabled(bWasSuccessful);
}
void UMenu::HostButtonClicked() void UMenu::HostButtonClicked()
{ {
HostButton->SetIsEnabled(false); HostButton->SetIsEnabled(false);
@ -184,6 +210,16 @@ void UMenu::JoinButtonClicked()
} }
} }
void UMenu::LoginButtonClicked()
{
LoginButton->SetIsEnabled(false);
if (MultiplayerSessionsSubsystem)
{
MultiplayerSessionsSubsystem->Login();
}
}
void UMenu::MenuTearDown() void UMenu::MenuTearDown()
{ {
RemoveFromParent(); RemoveFromParent();

View File

@ -13,16 +13,76 @@ UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem():
DestroySessionCompleteDelegate(FOnDestroySessionCompleteDelegate::CreateUObject(this, &ThisClass::OnDestroySessionComplete)), DestroySessionCompleteDelegate(FOnDestroySessionCompleteDelegate::CreateUObject(this, &ThisClass::OnDestroySessionComplete)),
StartSessionCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnStartSessionComplete)) StartSessionCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnStartSessionComplete))
{ {
IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(); Subsystem = IOnlineSubsystem::Get();
if (Subsystem) if (Subsystem)
{ {
Identity = Subsystem->GetIdentityInterface();
SessionInterface = Subsystem->GetSessionInterface(); SessionInterface = Subsystem->GetSessionInterface();
if (GetSubsystemName() != EOS_SUBSYSTEM) // Non EOS OSS don't need to login
{
bIsLoggedIn = true;
}
} }
}
FName UMultiplayerSessionsSubsystem::GetSubsystemName()
{
return Subsystem ? Subsystem->GetSubsystemName() : FName("NULL");
}
void UMultiplayerSessionsSubsystem::Login()
{
if (IsLoggedIn())
{
MultiplayerOnLoginComplete.Broadcast(true);
return;
}
EOSLogin();
}
void UMultiplayerSessionsSubsystem::EOSLogin()
{
if (!Identity.IsValid()) return;
LoginDelegateHandle = Identity->OnLoginCompleteDelegates->AddUObject(this, &UMultiplayerSessionsSubsystem::HandleLoginComplete);
FOnlineAccountCredentials Credentials;
Credentials.Id = FString();
Credentials.Token = FString();
Credentials.Type = FString("accountportal");
if (!Identity->Login(0, Credentials))
{
UE_LOG(LogTemp, Error, TEXT("Unable to perform EOS Login"));
}
else
{
UE_LOG(LogTemp, Display, TEXT("Performed EOS Login successful"));
}
}
void UMultiplayerSessionsSubsystem::HandleLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error)
{
bIsLoggedIn = bWasSuccessful;
if (Identity)
{
// Deregister the event handler.
Identity->ClearOnLoginCompleteDelegate_Handle(LocalUserNum, LoginDelegateHandle);
LoginDelegateHandle.Reset();
}
// Broadcast our own custom delegate
MultiplayerOnLoginComplete.Broadcast(bWasSuccessful);
} }
void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType) void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType)
{ {
if (!IsLoggedIn()) return;
DesiredNumPublicConnections = NumPublicConnections;
DesiredMatchType = MatchType;
if (!SessionInterface.IsValid()) if (!SessionInterface.IsValid())
{ {
return; return;
@ -42,16 +102,18 @@ void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FS
CreateSessionCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate); CreateSessionCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);
LastSessionSettings = MakeShareable(new FOnlineSessionSettings()); LastSessionSettings = MakeShareable(new FOnlineSessionSettings());
LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false; LastSessionSettings->bIsDedicated = false;
LastSessionSettings->bIsLANMatch = GetSubsystemName() == "NULL" || GetSubsystemName() == "LAN" ? true : false;
LastSessionSettings->NumPublicConnections = NumPublicConnections; LastSessionSettings->NumPublicConnections = NumPublicConnections;
LastSessionSettings->bAllowJoinInProgress = true; LastSessionSettings->bAllowJoinInProgress = true;
LastSessionSettings->bAllowJoinViaPresence = true; LastSessionSettings->bAllowJoinViaPresence = true;
LastSessionSettings->bShouldAdvertise = true; LastSessionSettings->bShouldAdvertise = true;
LastSessionSettings->bUsesPresence = true; LastSessionSettings->bUsesPresence = true;
LastSessionSettings->bUseLobbiesIfAvailable = true; // For UE5 when not finding sessions LastSessionSettings->Set(SEARCH_KEYWORDS, FString("BlasterLobby"), EOnlineDataAdvertisementType::ViaOnlineService);
LastSessionSettings->Set(FName("MatchType"), FString(MatchType), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing); LastSessionSettings->Set(FName("MatchType"), MatchType, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
LastSessionSettings->BuildUniqueId = 1; LastSessionSettings->BuildUniqueId = 1;
LastSessionSettings->bUseLobbiesIfAvailable = true;
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings)) if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))
{ {
@ -64,22 +126,29 @@ void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FS
void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults) void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults)
{ {
if (!IsLoggedIn())
{
return;
}
if (!SessionInterface.IsValid()) if (!SessionInterface.IsValid())
{ {
return; return;
} }
FindSessionCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate); FindSessionsCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate);
LastSessionSearch = MakeShareable(new FOnlineSessionSearch); LastSessionSearch = MakeShareable(new FOnlineSessionSearch());
LastSessionSearch->MaxSearchResults = MaxSearchResults; LastSessionSearch->MaxSearchResults = MaxSearchResults;
LastSessionSearch->bIsLanQuery = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false; LastSessionSearch->bIsLanQuery = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;
LastSessionSearch->QuerySettings.Set(SEARCH_KEYWORDS, FString("BlasterLobby"), EOnlineComparisonOp::Equals);
LastSessionSearch->QuerySettings.Set(SEARCH_LOBBIES, true, EOnlineComparisonOp::Equals);
LastSessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); LastSessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef())) if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef()))
{ {
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle); SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);
MultiplayerOnFindSessionsComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false); MultiplayerOnFindSessionsComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);
} }
@ -87,6 +156,8 @@ void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults)
void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult) void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
{ {
if (!IsLoggedIn()) return;
if (!SessionInterface.IsValid()) if (!SessionInterface.IsValid())
{ {
MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError); MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);
@ -127,13 +198,13 @@ void UMultiplayerSessionsSubsystem::StartSession()
{ {
return; return;
} }
StartSessionCompleteDelegateHandle = SessionInterface->AddOnStartSessionCompleteDelegate_Handle(StartSessionCompleteDelegate); StartSessionCompleteDelegateHandle = SessionInterface->AddOnStartSessionCompleteDelegate_Handle(StartSessionCompleteDelegate);
if (!SessionInterface->StartSession(NAME_GameSession)) if (!SessionInterface->StartSession(NAME_GameSession))
{ {
SessionInterface->ClearOnStartSessionCompleteDelegate_Handle(StartSessionCompleteDelegateHandle); SessionInterface->ClearOnStartSessionCompleteDelegate_Handle(StartSessionCompleteDelegateHandle);
MultiplayerOnStartSessionComplete.Broadcast(false); MultiplayerOnStartSessionComplete.Broadcast(false);
} }
} }
@ -152,7 +223,7 @@ void UMultiplayerSessionsSubsystem::OnFindSessionsComplete(bool bWasSuccessful)
{ {
if (SessionInterface) if (SessionInterface)
{ {
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegateHandle); SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);
} }
if (LastSessionSearch->SearchResults.Num() <= 0) if (LastSessionSearch->SearchResults.Num() <= 0)
@ -180,22 +251,20 @@ void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName,
{ {
SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle); SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);
} }
if (bWasSuccessful && bCreateSessionOnDestroy) if (bWasSuccessful && bCreateSessionOnDestroy)
{ {
bCreateSessionOnDestroy = false; bCreateSessionOnDestroy = false;
CreateSession(LastNumPublicConnections, LastMatchType); CreateSession(LastNumPublicConnections, LastMatchType);
} }
MultiplayerOnDestroySessionComplete.Broadcast(bWasSuccessful); MultiplayerOnDestroySessionComplete.Broadcast(bWasSuccessful);
} }
void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionNAme, bool bWasSuccessful) void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionName, bool bWasSuccessful)
{ {
if (SessionInterface) if (SessionInterface)
{ {
SessionInterface->ClearOnStartSessionCompleteDelegate_Handle(StartSessionCompleteDelegateHandle); SessionInterface->ClearOnStartSessionCompleteDelegate_Handle(StartSessionCompleteDelegateHandle);
} }
MultiplayerOnStartSessionComplete.Broadcast(bWasSuccessful); MultiplayerOnStartSessionComplete.Broadcast(bWasSuccessful);
} }

View File

@ -18,7 +18,7 @@ class MULTIPLAYERSESSIONS_API UMenu : public UUserWidget
public: public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void MenuSetup(int32 NumberOfPublicConnections = 4, FString TypeOfMatch = FString(TEXT("FreeForAll")), FString LobbyPath = FString(TEXT("/Game/ThirdPerson/Maps/Lobby"))); void MenuSetup(int32 NumberOfPublicConnections = 4, FString TypeOfMatch = FString(TEXT("FreeForAll")), FString LobbyPath = FString(TEXT("/Game/Maps/Lobby")));
protected: protected:
@ -36,6 +36,8 @@ protected:
void OnDestroySession(bool bWasSuccessful); void OnDestroySession(bool bWasSuccessful);
UFUNCTION() UFUNCTION()
void OnStartSession(bool bWasSuccessful); void OnStartSession(bool bWasSuccessful);
UFUNCTION()
void OnLoginComplete(bool bWasSuccessful);
private: private:
@ -44,6 +46,9 @@ private:
UPROPERTY(meta=(BindWidget)) UPROPERTY(meta=(BindWidget))
UButton* JoinButton; UButton* JoinButton;
UPROPERTY(meta=(BindWidget))
UButton* LoginButton;
UFUNCTION() UFUNCTION()
void HostButtonClicked(); void HostButtonClicked();
@ -51,9 +56,13 @@ private:
UFUNCTION() UFUNCTION()
void JoinButtonClicked(); void JoinButtonClicked();
UFUNCTION()
void LoginButtonClicked();
void MenuTearDown(); void MenuTearDown();
// The subsystem designed to handle all online session functionality // The subsystem designed to handle all online session functionality
UPROPERTY()
class UMultiplayerSessionsSubsystem* MultiplayerSessionsSubsystem; class UMultiplayerSessionsSubsystem* MultiplayerSessionsSubsystem;
int32 NumPublicConnections {4}; int32 NumPublicConnections {4};

View File

@ -4,17 +4,21 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "OnlineSessionSettings.h" #include "OnlineSessionSettings.h"
#include "OnlineSubsystem.h"
#include "Interfaces/OnlineIdentityInterface.h"
#include "Subsystems/GameInstanceSubsystem.h" #include "Subsystems/GameInstanceSubsystem.h"
#include "Interfaces/OnlineSessionInterface.h" #include "Interfaces/OnlineSessionInterface.h"
#include "MultiplayerSessionsSubsystem.generated.h" #include "MultiplayerSessionsSubsystem.generated.h"
//
// Declaring our own custom delegates for the Menu class to bind callbacks to // Declaring our own custom delegates for the Menu class to bind callbacks to
//
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, bool, bWasSuccessful); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, bool, bWasSuccessful);
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiplayerOnFindSessionsComplete, const TArray<FOnlineSessionSearchResult>& SessionResults, bool bWasSuccessful); DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiplayerOnFindSessionsComplete, const TArray<FOnlineSessionSearchResult>& SessionResults, bool bWasSuccessful);
DECLARE_MULTICAST_DELEGATE_OneParam(FMultiplayerOnJoinSessionComplete, EOnJoinSessionCompleteResult::Type Result) DECLARE_MULTICAST_DELEGATE_OneParam(FMultiplayerOnJoinSessionComplete, EOnJoinSessionCompleteResult::Type Result)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnDestroySessionComplete, bool, bWasSuccessful); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnDestroySessionComplete, bool, bWasSuccessful);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnStartSessionComplete, bool, bWasSuccessful); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnStartSessionComplete, bool, bWasSuccessful);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnLoginComplete, bool, bWasSuccessful);
/** /**
* *
@ -27,7 +31,9 @@ class MULTIPLAYERSESSIONS_API UMultiplayerSessionsSubsystem : public UGameInstan
public: public:
UMultiplayerSessionsSubsystem(); UMultiplayerSessionsSubsystem();
void Login();
FORCEINLINE bool IsLoggedIn() const { return bIsLoggedIn; }
/* /*
* To handle session functionality. The Menu class will call these * To handle session functionality. The Menu class will call these
*/ */
@ -45,7 +51,10 @@ public:
FMultiplayerOnJoinSessionComplete MultiplayerOnJoinSessionComplete; FMultiplayerOnJoinSessionComplete MultiplayerOnJoinSessionComplete;
FMultiplayerOnDestroySessionComplete MultiplayerOnDestroySessionComplete; FMultiplayerOnDestroySessionComplete MultiplayerOnDestroySessionComplete;
FMultiplayerOnStartSessionComplete MultiplayerOnStartSessionComplete; FMultiplayerOnStartSessionComplete MultiplayerOnStartSessionComplete;
FMultiplayerOnLoginComplete MultiplayerOnLoginComplete;
int32 DesiredNumPublicConnections{};
FString DesiredMatchType{};
protected: protected:
/* /*
@ -56,22 +65,24 @@ protected:
void OnFindSessionsComplete(bool bWasSuccessful); void OnFindSessionsComplete(bool bWasSuccessful);
void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result); void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);
void OnDestroySessionComplete(FName SessionName, bool bWasSuccessful); void OnDestroySessionComplete(FName SessionName, bool bWasSuccessful);
void OnStartSessionComplete(FName SessionNAme, bool bWasSuccessful); void OnStartSessionComplete(FName SessionName, bool bWasSuccessful);
private: private:
IOnlineSubsystem* Subsystem;
IOnlineIdentityPtr Identity;
IOnlineSessionPtr SessionInterface; IOnlineSessionPtr SessionInterface;
TSharedPtr<FOnlineSessionSettings> LastSessionSettings; TSharedPtr<FOnlineSessionSettings> LastSessionSettings;
TSharedPtr<FOnlineSessionSearch> LastSessionSearch; TSharedPtr<FOnlineSessionSearch> LastSessionSearch;
/* /*
* To add to the Online Session Interface delegate list. * To add to the Online Session Interface delegate list.
* We'll bind our MultiplayerSessionSubsystem internal callbacks to these. * We'll bind our MultiplayerSessionsSubsystem internal callbacks to these.
*/ */
FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate; FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;
FDelegateHandle CreateSessionCompleteDelegateHandle; FDelegateHandle CreateSessionCompleteDelegateHandle;
FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate; FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate;
FDelegateHandle FindSessionCompleteDelegateHandle; FDelegateHandle FindSessionsCompleteDelegateHandle;
FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate; FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;
FDelegateHandle JoinSessionCompleteDelegateHandle; FDelegateHandle JoinSessionCompleteDelegateHandle;
FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate; FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate;
@ -82,4 +93,12 @@ private:
bool bCreateSessionOnDestroy { false }; bool bCreateSessionOnDestroy { false };
int32 LastNumPublicConnections; int32 LastNumPublicConnections;
FString LastMatchType; FString LastMatchType;
void EOSLogin();
FDelegateHandle LoginDelegateHandle;
void HandleLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error);
FName GetSubsystemName();
bool bIsLoggedIn = false;
}; };

View File

@ -8,7 +8,7 @@ public class Blaster : ModuleRules
{ {
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "MultiplayerSessions", "OnlineSubsystem", "OnlineSubsystemSteam" });
PrivateDependencyModuleNames.AddRange(new string[] { }); PrivateDependencyModuleNames.AddRange(new string[] { });

View File

@ -2,11 +2,11 @@
#include "BlasterAnimInstance.h" #include "BlasterAnimInstance.h"
#include "BlasterCharacter.h" #include "BlasterCharacter.h"
#include "Blaster/Weapon/Weapon.h"
#include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "Blaster/Weapon/Weapon.h"
#include "Blaster/Types/CombatState.h"
void UBlasterAnimInstance::NativeInitializeAnimation() void UBlasterAnimInstance::NativeInitializeAnimation()
{ {
@ -15,15 +15,14 @@ void UBlasterAnimInstance::NativeInitializeAnimation()
BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner()); BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());
} }
void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds) void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaTime)
{ {
Super::NativeUpdateAnimation(DeltaSeconds); Super::NativeUpdateAnimation(DeltaTime);
if (BlasterCharacter == nullptr) if (BlasterCharacter == nullptr)
{ {
BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner()); BlasterCharacter = Cast<ABlasterCharacter>(TryGetPawnOwner());
} }
if (BlasterCharacter == nullptr) return; if (BlasterCharacter == nullptr) return;
FVector Velocity = BlasterCharacter->GetVelocity(); FVector Velocity = BlasterCharacter->GetVelocity();
@ -31,7 +30,7 @@ void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
Speed = Velocity.Size(); Speed = Velocity.Size();
bIsInAir = BlasterCharacter->GetCharacterMovement()->IsFalling(); bIsInAir = BlasterCharacter->GetCharacterMovement()->IsFalling();
bIsAccelerating = BlasterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0.f; bIsAccelerating = BlasterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0.f ? true : false;
bWeaponEquipped = BlasterCharacter->IsWeaponEquipped(); bWeaponEquipped = BlasterCharacter->IsWeaponEquipped();
EquippedWeapon = BlasterCharacter->GetEquippedWeapon(); EquippedWeapon = BlasterCharacter->GetEquippedWeapon();
bIsCrouched = BlasterCharacter->bIsCrouched; bIsCrouched = BlasterCharacter->bIsCrouched;
@ -43,23 +42,22 @@ void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
FRotator AimRotation = BlasterCharacter->GetBaseAimRotation(); FRotator AimRotation = BlasterCharacter->GetBaseAimRotation();
FRotator MovementRotation = UKismetMathLibrary::MakeRotFromX(BlasterCharacter->GetVelocity()); FRotator MovementRotation = UKismetMathLibrary::MakeRotFromX(BlasterCharacter->GetVelocity());
FRotator DeltaRot = UKismetMathLibrary::NormalizedDeltaRotator(MovementRotation, AimRotation); FRotator DeltaRot = UKismetMathLibrary::NormalizedDeltaRotator(MovementRotation, AimRotation);
DeltaRotation = FMath::RInterpTo(DeltaRotation, DeltaRot, DeltaSeconds, 6.f); DeltaRotation = FMath::RInterpTo(DeltaRotation, DeltaRot, DeltaTime, 6.f);
YawOffset = DeltaRotation.Yaw; YawOffset = DeltaRotation.Yaw;
CharacterRotationLastFrame = CharacterRotation; CharacterRotationLastFrame = CharacterRotation;
CharacterRotation = BlasterCharacter->GetActorRotation(); CharacterRotation = BlasterCharacter->GetActorRotation();
const FRotator Delta = UKismetMathLibrary::NormalizedDeltaRotator(CharacterRotation, CharacterRotationLastFrame); const FRotator Delta = UKismetMathLibrary::NormalizedDeltaRotator(CharacterRotation, CharacterRotationLastFrame);
const float Target = Delta.Yaw / DeltaSeconds; const float Target = Delta.Yaw / DeltaTime;
const float Interp = FMath::FInterpTo(Lean, Target, DeltaSeconds, 6.f); const float Interp = FMath::FInterpTo(Lean, Target, DeltaTime, 6.f);
Lean = FMath::Clamp(Interp, -90.f, 90.f); Lean = FMath::Clamp(Interp, -90.f, 90.f);
// Aim offset
AO_Yaw = BlasterCharacter->GetAO_Yaw(); AO_Yaw = BlasterCharacter->GetAO_Yaw();
AO_Pitch = BlasterCharacter->GetAO_Pitch(); AO_Pitch = BlasterCharacter->GetAO_Pitch();
if (bWeaponEquipped && EquippedWeapon && EquippedWeapon->GetWeaponMesh() && BlasterCharacter->GetMesh()) if (bWeaponEquipped && EquippedWeapon && EquippedWeapon->GetWeaponMesh() && BlasterCharacter->GetMesh())
{ {
LeftHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("LeftHandSocket"), RTS_World); LeftHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("LeftHandSocket"), ERelativeTransformSpace::RTS_World);
FVector OutPosition; FVector OutPosition;
FRotator OutRotation; FRotator OutRotation;
BlasterCharacter->GetMesh()->TransformToBoneSpace(FName("hand_r"), LeftHandTransform.GetLocation(), FRotator::ZeroRotator, OutPosition, OutRotation); BlasterCharacter->GetMesh()->TransformToBoneSpace(FName("hand_r"), LeftHandTransform.GetLocation(), FRotator::ZeroRotator, OutPosition, OutRotation);
@ -69,9 +67,9 @@ void UBlasterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
if (BlasterCharacter->IsLocallyControlled()) if (BlasterCharacter->IsLocallyControlled())
{ {
bLocallyControlled = true; bLocallyControlled = true;
const FTransform RightHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("Hand_R"), RTS_World); FTransform RightHandTransform = EquippedWeapon->GetWeaponMesh()->GetSocketTransform(FName("Hand_R"), ERelativeTransformSpace::RTS_World);
FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(RightHandTransform.GetLocation(), RightHandTransform.GetLocation() + (RightHandTransform.GetLocation() - BlasterCharacter->GetHitTarget())); FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(RightHandTransform.GetLocation(), RightHandTransform.GetLocation() + (RightHandTransform.GetLocation() - BlasterCharacter->GetHitTarget()));
RightHandRotation = FMath::RInterpTo(RightHandRotation, LookAtRotation, DeltaSeconds, 30.f); RightHandRotation = FMath::RInterpTo(RightHandRotation, LookAtRotation, DeltaTime, 30.f);
} }
} }

View File

@ -18,7 +18,7 @@ class BLASTER_API UBlasterAnimInstance : public UAnimInstance
public: public:
virtual void NativeInitializeAnimation() override; virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaSeconds) override; virtual void NativeUpdateAnimation(float DeltaTime) override;
private: private:

View File

@ -27,7 +27,7 @@ ABlasterCharacter::ABlasterCharacter()
SpawnCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; SpawnCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(GetMesh()); CameraBoom->SetupAttachment(GetMesh());
CameraBoom->TargetArmLength = 350.f; CameraBoom->TargetArmLength = 600.f;
CameraBoom->bUsePawnControlRotation = true; CameraBoom->bUsePawnControlRotation = true;
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera")); FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
@ -44,11 +44,12 @@ ABlasterCharacter::ABlasterCharacter()
Combat->SetIsReplicated(true); Combat->SetIsReplicated(true);
GetCharacterMovement()->NavAgentProps.bCanCrouch = true; GetCharacterMovement()->NavAgentProps.bCanCrouch = true;
GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore); GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
GetMesh()->SetCollisionObjectType(ECC_SkeletalMesh); GetMesh()->SetCollisionObjectType(ECC_SkeletalMesh);
GetMesh()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore); GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block); GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
GetCharacterMovement()->RotationRate = FRotator(0.f, 850.f, 0.f); GetCharacterMovement()->RotationRate = FRotator(0.f, 850.f, 0.f);
TurningInPlace = ETurningInPlace::ETIP_NotTurning; TurningInPlace = ETurningInPlace::ETIP_NotTurning;
NetUpdateFrequency = 66.f; NetUpdateFrequency = 66.f;
MinNetUpdateFrequency = 33.f; MinNetUpdateFrequency = 33.f;
@ -56,17 +57,6 @@ ABlasterCharacter::ABlasterCharacter()
DissolveTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("DissolveTimelineComponent")); DissolveTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("DissolveTimelineComponent"));
} }
void ABlasterCharacter::BeginPlay()
{
Super::BeginPlay();
UpdateHUDHealth();
if (HasAuthority())
{
OnTakeAnyDamage.AddDynamic(this, &ABlasterCharacter::ReceiveDamage);
}
}
void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{ {
Super::GetLifetimeReplicatedProps(OutLifetimeProps); Super::GetLifetimeReplicatedProps(OutLifetimeProps);
@ -79,11 +69,81 @@ void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Ou
void ABlasterCharacter::OnRep_ReplicatedMovement() void ABlasterCharacter::OnRep_ReplicatedMovement()
{ {
Super::OnRep_ReplicatedMovement(); Super::OnRep_ReplicatedMovement();
SimProxiesTurn(); SimProxiesTurn();
TimeSinceLastMovementReplication = 0.f; TimeSinceLastMovementReplication = 0.f;
} }
void ABlasterCharacter::Eliminated()
{
if (Combat && Combat->EquippedWeapon)
{
Combat->EquippedWeapon->Dropped();
}
MulticastEliminated();
GetWorldTimerManager().SetTimer(
EliminationTimer,
this,
&ABlasterCharacter::EliminationTimerFinished,
EliminationDelay
);
}
void ABlasterCharacter::MulticastEliminated_Implementation()
{
if (BlasterPlayerController)
{
BlasterPlayerController->SetHUDWeaponAmmo(0);
}
bEliminated = true;
PlayEliminatedMontage();
// Start dissolve effect
if (DissolveMaterialInstance)
{
DynamicDissolveMaterialInstance = UMaterialInstanceDynamic::Create(DissolveMaterialInstance, this);
GetMesh()->SetMaterial(0, DynamicDissolveMaterialInstance);
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Dissolve"), 0.55f);
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Glow"), 200.f);
}
StartDissolve();
// Disable character movement
GetCharacterMovement()->DisableMovement();
GetCharacterMovement()->StopMovementImmediately();
bDisableGameplay = true;
// Disable collision
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Elimination bot
if (EliminationBotEffect)
{
const FVector EliminationBotSpawnPoint(GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z + 200.f);
EliminationBotComponent = UGameplayStatics::SpawnEmitterAtLocation(
GetWorld(),
EliminationBotEffect,
EliminationBotSpawnPoint,
GetActorRotation()
);
}
if (EliminationBotSound)
{
UGameplayStatics::SpawnSoundAtLocation(
this,
EliminationBotSound,
GetActorLocation()
);
}
}
void ABlasterCharacter::EliminationTimerFinished()
{
ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
if (BlasterGameMode)
{
BlasterGameMode->RequestRespawn(this, Controller);
}
}
void ABlasterCharacter::Destroyed() void ABlasterCharacter::Destroyed()
{ {
Super::Destroyed(); Super::Destroyed();
@ -98,151 +158,24 @@ void ABlasterCharacter::Destroyed()
} }
} }
void ABlasterCharacter::PostInitializeComponents() void ABlasterCharacter::BeginPlay()
{ {
Super::PostInitializeComponents(); Super::BeginPlay();
if (Combat)
{
Combat->Character = this;
}
}
void ABlasterCharacter::PlayFireMontage(bool bAiming)
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && FireWeaponMontage)
{
AnimInstance->Montage_Play(FireWeaponMontage);
const FName SectionName = bAiming ? FName("RifleADS") : FName("RifleHip");
AnimInstance->Montage_JumpToSection(SectionName);
}
}
void ABlasterCharacter::PlayReloadMontage()
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && ReloadMontage)
{
AnimInstance->Montage_Play(ReloadMontage);
FName SectionName;
switch (Combat->EquippedWeapon->GetWeaponType())
{
case EWeaponType::EWT_AssaultRifle:
SectionName = FName("Rifle");
break;
}
AnimInstance->Montage_JumpToSection(SectionName);
}
}
void ABlasterCharacter::PlayEliminatedMontage()
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && EliminatedMontage)
{
AnimInstance->Montage_Play(EliminatedMontage);
}
}
void ABlasterCharacter::Eliminated()
{
if (Combat && Combat->EquippedWeapon)
{
Combat->EquippedWeapon->Dropped();
}
MulticastEliminated();
GetWorldTimerManager().SetTimer(EliminationTimer, this, &ABlasterCharacter::EliminationTimerFinished, EliminationDelay);
}
void ABlasterCharacter::MulticastEliminated_Implementation()
{
if (BlasterPlayerController)
{
BlasterPlayerController->SetHUDWeaponAmmo(0);
}
bEliminated = true;
PlayEliminatedMontage();
// Start dissolve effect
if (DissolveMaterialInstance)
{
DynamicDissolveMaterialInstance = UMaterialInstanceDynamic::Create(DissolveMaterialInstance, this);
GetMesh()->SetMaterial(0, DynamicDissolveMaterialInstance);
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Dissolve"), 0.55f);
DynamicDissolveMaterialInstance->SetScalarParameterValue(TEXT("Glow"), 200.f);
}
StartDissolve();
// Disable character movement
GetCharacterMovement()->DisableMovement();
GetCharacterMovement()->StopMovementImmediately();
bDisableGameplay = true;
// Disable collision
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Elimination bot
if (EliminationBotEffect)
{
const FVector EliminationBotSpawnPoint(GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z + 200.f);
EliminationBotComponent = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), EliminationBotEffect, EliminationBotSpawnPoint, GetActorRotation());
}
if (EliminationBotSound)
{
UGameplayStatics::SpawnSoundAtLocation(this, EliminationBotSound, GetActorLocation());
}
}
void ABlasterCharacter::EliminationTimerFinished()
{
ABlasterGameMode* GameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
if (GameMode)
{
GameMode->RequestRespawn(this, Controller);
}
}
void ABlasterCharacter::PlayHitReactMontage()
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && HitReactMontage)
{
AnimInstance->Montage_Play(HitReactMontage);
const FName SectionName = FName("FromFront");
AnimInstance->Montage_JumpToSection(SectionName);
}
}
void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController,
AActor* DamageCauser)
{
Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);
UpdateHUDHealth(); UpdateHUDHealth();
if (Health > 0.f) if (HasAuthority())
{ {
PlayHitReactMontage(); OnTakeAnyDamage.AddDynamic(this, &ABlasterCharacter::ReceiveDamage);
} }
}
if (Health == 0.f) void ABlasterCharacter::Tick(float DeltaTime)
{ {
ABlasterGameMode* GameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>(); Super::Tick(DeltaTime);
if (GameMode)
{ RotateInPlace(DeltaTime);
BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController; HideCameraIfCharacterClose();
ABlasterPlayerController* AttackerController = Cast<ABlasterPlayerController>(InstigatorController); PollInit();
GameMode->PlayerEliminated(this, BlasterPlayerController, AttackerController);
}
}
} }
void ABlasterCharacter::RotateInPlace(float DeltaTime) void ABlasterCharacter::RotateInPlace(float DeltaTime)
@ -253,7 +186,7 @@ void ABlasterCharacter::RotateInPlace(float DeltaTime)
TurningInPlace = ETurningInPlace::ETIP_NotTurning; TurningInPlace = ETurningInPlace::ETIP_NotTurning;
return; return;
} }
if (GetLocalRole() > ROLE_SimulatedProxy && IsLocallyControlled()) if (GetLocalRole() > ENetRole::ROLE_SimulatedProxy && IsLocallyControlled())
{ {
AimOffset(DeltaTime); AimOffset(DeltaTime);
} }
@ -268,46 +201,111 @@ void ABlasterCharacter::RotateInPlace(float DeltaTime)
} }
} }
void ABlasterCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
RotateInPlace(DeltaTime);
HideCameraIfCharacterClose();
PollInit();
}
void ABlasterCharacter::PollInit()
{
if (BlasterPlayerState == nullptr)
{
BlasterPlayerState = GetPlayerState<ABlasterPlayerState>();
if (BlasterPlayerState)
{
// Initialize Score now we have the PlayerState
BlasterPlayerState->IncreaseScore(0.f);
BlasterPlayerState->IncreaseDefeats(0);
}
}
}
void ABlasterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) void ABlasterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{ {
Super::SetupPlayerInputComponent(PlayerInputComponent); Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ABlasterCharacter::Jump); PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ABlasterCharacter::Jump);
PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed);
PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABlasterCharacter::ReloadButtonPressed);
PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABlasterCharacter::CrouchButtonPressed);
PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &ABlasterCharacter::AimButtonPressed);
PlayerInputComponent->BindAction("Aim", IE_Released, this, &ABlasterCharacter::AimButtonReleased);
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABlasterCharacter::FireButtonPressed);
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ABlasterCharacter::FireButtonReleased);
PlayerInputComponent->BindAxis("MoveForward", this, &ABlasterCharacter::MoveForward); PlayerInputComponent->BindAxis("MoveForward", this, &ABlasterCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ABlasterCharacter::MoveRight); PlayerInputComponent->BindAxis("MoveRight", this, &ABlasterCharacter::MoveRight);
PlayerInputComponent->BindAxis("Turn", this, &ABlasterCharacter::Turn); PlayerInputComponent->BindAxis("Turn", this, &ABlasterCharacter::Turn);
PlayerInputComponent->BindAxis("LookUp", this, &ABlasterCharacter::LookUp); PlayerInputComponent->BindAxis("LookUp", this, &ABlasterCharacter::LookUp);
PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed);
PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABlasterCharacter::CrouchButtonPressed);
PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &ABlasterCharacter::AimButtonPressed);
PlayerInputComponent->BindAction("Aim", IE_Released, this, &ABlasterCharacter::AimButtonReleased);
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABlasterCharacter::FireButtonPressed);
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ABlasterCharacter::FireButtonReleased);
PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABlasterCharacter::ReloadButtonPressed);
}
void ABlasterCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
if (Combat)
{
Combat->Character = this;
}
}
void ABlasterCharacter::PlayFireMontage(bool bAiming)
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && FireWeaponMontage)
{
AnimInstance->Montage_Play(FireWeaponMontage);
FName SectionName;
SectionName = bAiming ? FName("RifleADS") : FName("RifleHip");
AnimInstance->Montage_JumpToSection(SectionName);
}
}
void ABlasterCharacter::PlayReloadMontage()
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && ReloadMontage)
{
AnimInstance->Montage_Play(ReloadMontage);
FName SectionName;
switch (Combat->EquippedWeapon->GetWeaponType())
{
case EWeaponType::EWT_AssaultRifle:
SectionName = FName("Rifle");
break;
}
AnimInstance->Montage_JumpToSection(SectionName);
}
}
void ABlasterCharacter::PlayEliminatedMontage()
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && EliminatedMontage)
{
AnimInstance->Montage_Play(EliminatedMontage);
}
}
void ABlasterCharacter::PlayHitReactMontage()
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && HitReactMontage)
{
AnimInstance->Montage_Play(HitReactMontage);
FName SectionName("FromFront");
AnimInstance->Montage_JumpToSection(SectionName);
}
}
void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController, AActor* DamageCauser)
{
Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);
UpdateHUDHealth();
if (Health > 0.f)
{
PlayHitReactMontage();
}
if (Health == 0.f)
{
ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
if (BlasterGameMode)
{
BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController;
ABlasterPlayerController* AttackerController = Cast<ABlasterPlayerController>(InstigatorController);
BlasterGameMode->PlayerEliminated(this, BlasterPlayerController, AttackerController);
}
}
} }
void ABlasterCharacter::MoveForward(float Value) void ABlasterCharacter::MoveForward(float Value)
@ -317,7 +315,6 @@ void ABlasterCharacter::MoveForward(float Value)
{ {
const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f); const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X)); const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X));
AddMovementInput(Direction, Value); AddMovementInput(Direction, Value);
} }
} }
@ -329,7 +326,6 @@ void ABlasterCharacter::MoveRight(float Value)
{ {
const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f); const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y)); const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y));
AddMovementInput(Direction, Value); AddMovementInput(Direction, Value);
} }
} }
@ -360,13 +356,9 @@ void ABlasterCharacter::EquipButtonPressed()
} }
} }
void ABlasterCharacter::ReloadButtonPressed() void ABlasterCharacter::ServerEquipButtonPressed_Implementation()
{ {
if (bDisableGameplay) return; EquipButtonPressed();
if (Combat)
{
Combat->Reload();
}
} }
void ABlasterCharacter::CrouchButtonPressed() void ABlasterCharacter::CrouchButtonPressed()
@ -382,6 +374,15 @@ void ABlasterCharacter::CrouchButtonPressed()
} }
} }
void ABlasterCharacter::ReloadButtonPressed()
{
if (bDisableGameplay) return;
if (Combat)
{
Combat->Reload();
}
}
void ABlasterCharacter::AimButtonPressed() void ABlasterCharacter::AimButtonPressed()
{ {
if (bDisableGameplay) return; if (bDisableGameplay) return;
@ -400,47 +401,24 @@ void ABlasterCharacter::AimButtonReleased()
} }
} }
void ABlasterCharacter::Jump() float ABlasterCharacter::CalculateSpeed()
{ {
if (bDisableGameplay) return; FVector Velocity = GetVelocity();
if (bIsCrouched) Velocity.Z = 0.f;
{ return Velocity.Size();
UnCrouch();
}
else
{
Super::Jump();
}
}
void ABlasterCharacter::FireButtonPressed()
{
if (Combat)
{
Combat->FireButtonPressed(true);
}
}
void ABlasterCharacter::FireButtonReleased()
{
if (Combat)
{
Combat->FireButtonPressed(false);
}
} }
void ABlasterCharacter::AimOffset(float DeltaTime) void ABlasterCharacter::AimOffset(float DeltaTime)
{ {
if (Combat && Combat->EquippedWeapon == nullptr) return; if (Combat && Combat->EquippedWeapon == nullptr) return;
float Speed = CalculateSpeed();
const float Speed = CalculateSpeed(); bool bIsInAir = GetCharacterMovement()->IsFalling();
const bool bIsInAir = GetCharacterMovement()->IsFalling();
if (Speed == 0.f && !bIsInAir) // Standing still, not jumping if (Speed == 0.f && !bIsInAir) // Standing still, not jumping
{ {
bRotateRootBone = true; bRotateRootBone = true;
const FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f); FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);
const FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation); FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation);
AO_Yaw = DeltaAimRotation.Yaw; AO_Yaw = DeltaAimRotation.Yaw;
if (TurningInPlace == ETurningInPlace::ETIP_NotTurning) if (TurningInPlace == ETurningInPlace::ETIP_NotTurning)
{ {
@ -464,13 +442,11 @@ void ABlasterCharacter::AimOffset(float DeltaTime)
void ABlasterCharacter::CalculateAO_Pitch() void ABlasterCharacter::CalculateAO_Pitch()
{ {
AO_Pitch = GetBaseAimRotation().Pitch; AO_Pitch = GetBaseAimRotation().Pitch;
// Fix pitch/yaw compression
if (AO_Pitch > 90.f && !IsLocallyControlled()) if (AO_Pitch > 90.f && !IsLocallyControlled())
{ {
// map pitch from [270, 360) to [-90, 0) // map pitch from [270, 360) to [-90, 0)
const FVector2d InRange(270.f, 360.f); FVector2D InRange(270.f, 360.f);
const FVector2d OutRange(-90.f, 0.f); FVector2D OutRange(-90.f, 0.f);
AO_Pitch = FMath::GetMappedRangeValueClamped(InRange, OutRange, AO_Pitch); AO_Pitch = FMath::GetMappedRangeValueClamped(InRange, OutRange, AO_Pitch);
} }
} }
@ -478,20 +454,18 @@ void ABlasterCharacter::CalculateAO_Pitch()
void ABlasterCharacter::SimProxiesTurn() void ABlasterCharacter::SimProxiesTurn()
{ {
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return; if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
bRotateRootBone = false; bRotateRootBone = false;
float Speed = CalculateSpeed();
const float Speed = CalculateSpeed();
if (Speed > 0.f) if (Speed > 0.f)
{ {
TurningInPlace = ETurningInPlace::ETIP_NotTurning; TurningInPlace = ETurningInPlace::ETIP_NotTurning;
return; return;
} }
ProxyRotationLastFrame = ProxyRotation; ProxyRotationLastFrame = ProxyRotation;
ProxyRotation = GetActorRotation(); ProxyRotation = GetActorRotation();
ProxyYaw = UKismetMathLibrary::NormalizedDeltaRotator(ProxyRotation, ProxyRotationLastFrame).Yaw; ProxyYaw = UKismetMathLibrary::NormalizedDeltaRotator(ProxyRotation, ProxyRotationLastFrame).Yaw;
if (FMath::Abs(ProxyYaw) > TurnThreshold) if (FMath::Abs(ProxyYaw) > TurnThreshold)
{ {
if (ProxyYaw > TurnThreshold) if (ProxyYaw > TurnThreshold)
@ -508,13 +482,39 @@ void ABlasterCharacter::SimProxiesTurn()
} }
return; return;
} }
TurningInPlace = ETurningInPlace::ETIP_NotTurning; TurningInPlace = ETurningInPlace::ETIP_NotTurning;
} }
void ABlasterCharacter::ServerEquipButtonPressed_Implementation() void ABlasterCharacter::Jump()
{ {
EquipButtonPressed(); if (bDisableGameplay) return;
if (bIsCrouched)
{
UnCrouch();
}
else
{
Super::Jump();
}
}
void ABlasterCharacter::FireButtonPressed()
{
if (bDisableGameplay) return;
if (Combat)
{
Combat->FireButtonPressed(true);
}
}
void ABlasterCharacter::FireButtonReleased()
{
if (bDisableGameplay) return;
if (Combat)
{
Combat->FireButtonPressed(false);
}
} }
void ABlasterCharacter::TurnInPlace(float DeltaTime) void ABlasterCharacter::TurnInPlace(float DeltaTime)
@ -537,18 +537,6 @@ void ABlasterCharacter::TurnInPlace(float DeltaTime)
StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f); StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);
} }
} }
// switch (TurningInPlace)
// {
// case ETurningInPlace::ETIP_Left:
// UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: Left"));
// break;
// case ETurningInPlace::ETIP_Right:
// UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: Right"));
// break;
// case ETurningInPlace::ETIP_NotTurning:
// UE_LOG(LogTemp, Warning, TEXT("TurningInPlace: NotTurning"));
// break;
// }
} }
void ABlasterCharacter::HideCameraIfCharacterClose() void ABlasterCharacter::HideCameraIfCharacterClose()
@ -572,13 +560,6 @@ void ABlasterCharacter::HideCameraIfCharacterClose()
} }
} }
float ABlasterCharacter::CalculateSpeed()
{
FVector Velocity = GetVelocity();
Velocity.Z = 0.f;
return Velocity.Size();
}
void ABlasterCharacter::OnRep_Health() void ABlasterCharacter::OnRep_Health()
{ {
UpdateHUDHealth(); UpdateHUDHealth();
@ -597,6 +578,20 @@ void ABlasterCharacter::UpdateHUDHealth()
} }
} }
void ABlasterCharacter::PollInit()
{
if (BlasterPlayerState == nullptr)
{
BlasterPlayerState = GetPlayerState<ABlasterPlayerState>();
if (BlasterPlayerState)
{
// Initialize Score now we have the PlayerState
BlasterPlayerState->IncreaseScore(0.f);
BlasterPlayerState->IncreaseDefeats(0);
}
}
}
void ABlasterCharacter::UpdateDissolveMaterial(float DissolveValue) void ABlasterCharacter::UpdateDissolveMaterial(float DissolveValue)
{ {
if (DynamicDissolveMaterialInstance) if (DynamicDissolveMaterialInstance)
@ -621,7 +616,6 @@ void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon)
{ {
OverlappingWeapon->ShowPickupWidget(false); OverlappingWeapon->ShowPickupWidget(false);
} }
OverlappingWeapon = Weapon; OverlappingWeapon = Weapon;
if (IsLocallyControlled()) if (IsLocallyControlled())
{ {
@ -632,6 +626,18 @@ void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon)
} }
} }
void ABlasterCharacter::OnRep_OverlappingWeapon(AWeapon* LastWeapon)
{
if (OverlappingWeapon)
{
OverlappingWeapon->ShowPickupWidget(true);
}
if (LastWeapon)
{
LastWeapon->ShowPickupWidget(false);
}
}
bool ABlasterCharacter::IsWeaponEquipped() bool ABlasterCharacter::IsWeaponEquipped()
{ {
return Combat && Combat->EquippedWeapon; return Combat && Combat->EquippedWeapon;
@ -645,14 +651,12 @@ bool ABlasterCharacter::IsAiming()
AWeapon* ABlasterCharacter::GetEquippedWeapon() AWeapon* ABlasterCharacter::GetEquippedWeapon()
{ {
if (Combat == nullptr) return nullptr; if (Combat == nullptr) return nullptr;
return Combat->EquippedWeapon; return Combat->EquippedWeapon;
} }
FVector ABlasterCharacter::GetHitTarget() const FVector ABlasterCharacter::GetHitTarget() const
{ {
if (Combat == nullptr) return FVector(); if (Combat == nullptr) return FVector();
return Combat->HitTarget; return Combat->HitTarget;
} }
@ -660,16 +664,4 @@ ECombatState ABlasterCharacter::GetCombatState() const
{ {
if (Combat == nullptr) return ECombatState::ECS_MAX; if (Combat == nullptr) return ECombatState::ECS_MAX;
return Combat->CombatState; return Combat->CombatState;
} }
void ABlasterCharacter::OnRep_OverlappingWeapon(AWeapon* LastWeapon)
{
if (OverlappingWeapon)
{
OverlappingWeapon->ShowPickupWidget(true);
}
if (LastWeapon)
{
LastWeapon->ShowPickupWidget(false);
}
}

View File

@ -25,8 +25,8 @@ void UCombatComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out
Super::GetLifetimeReplicatedProps(OutLifetimeProps); Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UCombatComponent, EquippedWeapon); DOREPLIFETIME(UCombatComponent, EquippedWeapon);
DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly);
DOREPLIFETIME(UCombatComponent, bAiming); DOREPLIFETIME(UCombatComponent, bAiming);
DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly);
DOREPLIFETIME(UCombatComponent, CombatState); DOREPLIFETIME(UCombatComponent, CombatState);
} }
@ -65,6 +65,273 @@ void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActo
} }
} }
void UCombatComponent::FireButtonPressed(bool bPressed)
{
bFireButtonPressed = bPressed;
if (bFireButtonPressed && EquippedWeapon)
{
Fire();
}
}
void UCombatComponent::Fire()
{
if (CanFire())
{
bCanFire = false;
ServerFire(HitTarget);
if (EquippedWeapon)
{
CrosshairShootingFactor = .75f;
}
StartFireTimer();
}
}
void UCombatComponent::StartFireTimer()
{
if (EquippedWeapon == nullptr || Character == nullptr) return;
Character->GetWorldTimerManager().SetTimer(
FireTimer,
this,
&UCombatComponent::FireTimerFinished,
EquippedWeapon->FireDelay
);
}
void UCombatComponent::FireTimerFinished()
{
if (EquippedWeapon == nullptr) return;
bCanFire = true;
if (bFireButtonPressed && EquippedWeapon->bAutomatic)
{
Fire();
}
if (EquippedWeapon->IsEmpty())
{
Reload();
}
}
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
MulticastFire(TraceHitTarget);
}
void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
if (EquippedWeapon == nullptr) return;
if (Character && CombatState == ECombatState::ECS_Unoccupied)
{
Character->PlayFireMontage(bAiming);
EquippedWeapon->Fire(TraceHitTarget);
}
}
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
{
if (Character == nullptr || WeaponToEquip == nullptr) return;
if (EquippedWeapon)
{
EquippedWeapon->Dropped();
}
EquippedWeapon = WeaponToEquip;
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
}
EquippedWeapon->SetOwner(Character);
EquippedWeapon->SetHUDAmmo();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
if (EquippedWeapon->EquipSound)
{
UGameplayStatics::PlaySoundAtLocation(
this,
EquippedWeapon->EquipSound,
Character->GetActorLocation()
);
}
if (EquippedWeapon->IsEmpty())
{
Reload();
}
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
Character->bUseControllerRotationYaw = true;
}
void UCombatComponent::Reload()
{
if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading)
{
ServerReload();
}
}
void UCombatComponent::ServerReload_Implementation()
{
if (Character == nullptr || EquippedWeapon == nullptr) return;
// return if weapon mag is at max capacity
if (EquippedWeapon->GetAmmo() == EquippedWeapon->GetMagCapacity()) return;
CombatState = ECombatState::ECS_Reloading;
HandleReload();
}
void UCombatComponent::FinishedReloading()
{
if (Character == nullptr) return;
if (Character->HasAuthority())
{
CombatState = ECombatState::ECS_Unoccupied;
UpdateAmmoValues();
}
if (bFireButtonPressed)
{
Fire();
}
}
void UCombatComponent::UpdateAmmoValues()
{
if (Character == nullptr || EquippedWeapon == nullptr) return;
int32 ReloadAmount = AmountToReload();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount;
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
EquippedWeapon->AddAmmo(-ReloadAmount);
}
void UCombatComponent::OnRep_CombatState()
{
switch (CombatState)
{
case ECombatState::ECS_Reloading:
HandleReload();
break;
case ECombatState::ECS_Unoccupied:
if (bFireButtonPressed)
{
Fire();
}
break;
}
}
void UCombatComponent::HandleReload()
{
Character->PlayReloadMontage();
}
int32 UCombatComponent::AmountToReload()
{
if (EquippedWeapon == nullptr) return 0;
int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
int32 Least = FMath::Min(RoomInMag, AmountCarried);
return FMath::Clamp(RoomInMag, 0, Least);
}
return 0;
}
void UCombatComponent::OnRep_EquippedWeapon()
{
if (EquippedWeapon && Character)
{
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
}
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
Character->bUseControllerRotationYaw = true;
if (EquippedWeapon->EquipSound)
{
UGameplayStatics::PlaySoundAtLocation(
this,
EquippedWeapon->EquipSound,
Character->GetActorLocation()
);
}
}
}
void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult)
{
FVector2D ViewportSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
UGameplayStatics::GetPlayerController(this, 0),
CrosshairLocation,
CrosshairWorldPosition,
CrosshairWorldDirection
);
if (bScreenToWorld)
{
FVector Start = CrosshairWorldPosition;
if (Character)
{
float DistanceToCharacter = (Character->GetActorLocation() - Start).Size();
Start += CrosshairWorldDirection * (DistanceToCharacter + 100.f);
}
FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH;
GetWorld()->LineTraceSingleByChannel(
TraceHitResult,
Start,
End,
ECollisionChannel::ECC_Visibility
);
if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairInterface>())
{
HUDPackage.CrosshairsColor = FLinearColor::Red;
}
else
{
HUDPackage.CrosshairsColor = FLinearColor::White;
}
if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End;
}
}
void UCombatComponent::SetHUDCrosshairs(float DeltaTime) void UCombatComponent::SetHUDCrosshairs(float DeltaTime)
{ {
if (Character == nullptr || Character->Controller == nullptr) return; if (Character == nullptr || Character->Controller == nullptr) return;
@ -80,22 +347,22 @@ void UCombatComponent::SetHUDCrosshairs(float DeltaTime)
HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter; HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter;
HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft; HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft;
HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight; HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight;
HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop;
HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom; HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom;
HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop;
} }
else else
{ {
HUDPackage.CrosshairsCenter = nullptr; HUDPackage.CrosshairsCenter = nullptr;
HUDPackage.CrosshairsLeft = nullptr; HUDPackage.CrosshairsLeft = nullptr;
HUDPackage.CrosshairsRight = nullptr; HUDPackage.CrosshairsRight = nullptr;
HUDPackage.CrosshairsTop = nullptr;
HUDPackage.CrosshairsBottom = nullptr; HUDPackage.CrosshairsBottom = nullptr;
HUDPackage.CrosshairsTop = nullptr;
} }
// Calculate crosshair spread // Calculate crosshair spread
// Velocity [0, 600] -> Spread [0, 1]
const FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed); // [0, 600] -> [0, 1]
const FVector2D VelocityMultiplierRange(0.f, 1.f); FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed);
FVector2D VelocityMultiplierRange(0.f, 1.f);
FVector Velocity = Character->GetVelocity(); FVector Velocity = Character->GetVelocity();
Velocity.Z = 0.f; Velocity.Z = 0.f;
@ -170,59 +437,9 @@ void UCombatComponent::ServerSetAiming_Implementation(bool bIsAiming)
} }
} }
void UCombatComponent::Fire()
{
if (CanFire())
{
bCanFire = false;
ServerFire(HitTarget);
if (EquippedWeapon)
{
CrosshairShootingFactor = 0.75f;
}
StartFireTimer();
}
}
void UCombatComponent::FireButtonPressed(bool bPressed)
{
bFireButtonPressed = bPressed;
if (bFireButtonPressed && EquippedWeapon)
{
Fire();
}
}
void UCombatComponent::StartFireTimer()
{
if (EquippedWeapon == nullptr || Character == nullptr) return;
Character->GetWorldTimerManager().SetTimer(FireTimer, this, &UCombatComponent::FireTimerFinished, EquippedWeapon->FireDelay);
}
void UCombatComponent::FireTimerFinished()
{
if (EquippedWeapon == nullptr) return;
bCanFire = true;
if (bFireButtonPressed && EquippedWeapon->bAutomatic)
{
Fire();
}
if (EquippedWeapon->IsEmpty())
{
Reload();
}
}
bool UCombatComponent::CanFire() bool UCombatComponent::CanFire()
{ {
if (EquippedWeapon == nullptr) return false; if (EquippedWeapon == nullptr) return false;
return !EquippedWeapon->IsEmpty() && bCanFire && CombatState == ECombatState::ECS_Unoccupied; return !EquippedWeapon->IsEmpty() && bCanFire && CombatState == ECombatState::ECS_Unoccupied;
} }
@ -239,212 +456,3 @@ void UCombatComponent::InitializeCarriedAmmo()
{ {
CarriedAmmoMap.Emplace(EWeaponType::EWT_AssaultRifle, StartingARAmmo); CarriedAmmoMap.Emplace(EWeaponType::EWT_AssaultRifle, StartingARAmmo);
} }
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
MulticastFire(TraceHitTarget);
}
void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
if (EquippedWeapon == nullptr) return;
if (Character && CombatState == ECombatState::ECS_Unoccupied)
{
Character->PlayFireMontage(bAiming);
EquippedWeapon->Fire(TraceHitTarget);
}
}
void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult)
{
FVector2d ViewPortSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewPortSize);
}
FVector2d CrosshairLocation(ViewPortSize.X / 2.f, ViewPortSize.Y / 2.0f);
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
UGameplayStatics::GetPlayerController(this, 0),
CrosshairLocation,
CrosshairWorldPosition,
CrosshairWorldDirection
);
if (bScreenToWorld)
{
FVector Start = CrosshairWorldPosition;
if (Character)
{
float DistanceToCharacter = (Character->GetActorLocation() - Start).Size();
Start += CrosshairWorldDirection * (DistanceToCharacter + 60.f);
}
FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH;
GetWorld()->LineTraceSingleByChannel(
TraceHitResult,
Start,
End,
ECollisionChannel::ECC_Visibility
);
if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairInterface>())
{
HUDPackage.CrosshairColor = FLinearColor::Red;
}
else
{
HUDPackage.CrosshairColor = FLinearColor::White;
}
if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End;
}
}
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
{
if (Character == nullptr || WeaponToEquip == nullptr) return;
if (EquippedWeapon)
{
EquippedWeapon->Dropped();
}
EquippedWeapon = WeaponToEquip;
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
}
EquippedWeapon->SetOwner(Character);
EquippedWeapon->SetHUDAmmo();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
if (EquippedWeapon->EquipSound)
{
UGameplayStatics::PlaySoundAtLocation(this, EquippedWeapon->EquipSound, Character->GetActorLocation());
}
if (EquippedWeapon->IsEmpty())
{
Reload();
}
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
Character->bUseControllerRotationYaw = true;
}
void UCombatComponent::Reload()
{
if (CarriedAmmo > 0 && CombatState != ECombatState::ECS_Reloading)
{
ServerReload();
}
}
void UCombatComponent::FinishedReloading()
{
if (Character == nullptr) return;
if (Character->HasAuthority())
{
CombatState = ECombatState::ECS_Unoccupied;
UpdateAmmoValues();
}
if (bFireButtonPressed)
{
Fire();
}
}
void UCombatComponent::UpdateAmmoValues()
{
if (Character == nullptr || EquippedWeapon == nullptr) return;
const int32 ReloadAmount = AmountToReload();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount;
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
EquippedWeapon->AddAmmo(-ReloadAmount);
}
void UCombatComponent::ServerReload_Implementation()
{
if (Character == nullptr || EquippedWeapon == nullptr) return;
// return if weapon mag is at max capacity
if (EquippedWeapon->GetAmmo() == EquippedWeapon->GetMagCapacity()) return;
CombatState = ECombatState::ECS_Reloading;
HandleReload();
}
void UCombatComponent::OnRep_CombatState()
{
switch (CombatState)
{
case ECombatState::ECS_Reloading:
HandleReload();
break;
case ECombatState::ECS_Unoccupied:
if (bFireButtonPressed)
{
Fire();
}
break;
}
}
void UCombatComponent::HandleReload()
{
Character->PlayReloadMontage();
}
int32 UCombatComponent::AmountToReload()
{
if (EquippedWeapon == nullptr) return 0;
const int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo();
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
{
const int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
const int32 Least = FMath::Min(RoomInMag, AmountCarried);
return FMath::Clamp(RoomInMag, 0, Least);
}
return 0;
}
void UCombatComponent::OnRep_EquippedWeapon()
{
if (EquippedWeapon && Character)
{
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
}
if (EquippedWeapon->EquipSound)
{
UGameplayStatics::PlaySoundAtLocation(this, EquippedWeapon->EquipSound, Character->GetActorLocation());
}
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
Character->bUseControllerRotationYaw = true;
}
}

View File

@ -27,30 +27,30 @@ void ABlasterGameMode::BeginPlay()
LevelStartingTime = GetWorld()->GetTimeSeconds(); LevelStartingTime = GetWorld()->GetTimeSeconds();
} }
void ABlasterGameMode::Tick(float DeltaSeconds) void ABlasterGameMode::Tick(float DeltaTime)
{ {
Super::Tick(DeltaSeconds); Super::Tick(DeltaTime);
if (MatchState == MatchState::WaitingToStart) if (MatchState == MatchState::WaitingToStart)
{ {
CountDownTime = WarmupTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; CountdownTime = WarmupTime - GetWorld()->GetTimeSeconds(); // + LevelStartingTime;
if (CountDownTime <= 0.f) if (CountdownTime <= 0.f)
{ {
StartMatch(); StartMatch();
} }
} }
else if (MatchState == MatchState::InProgress) else if (MatchState == MatchState::InProgress)
{ {
CountDownTime = WarmupTime + MatchTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; CountdownTime = WarmupTime + MatchTime - GetWorld()->GetTimeSeconds(); // + LevelStartingTime;
if (CountDownTime <= 0.f) if (CountdownTime <= 0.f)
{ {
SetMatchState(MatchState::Cooldown); SetMatchState(MatchState::Cooldown);
} }
} }
else if (MatchState == MatchState::Cooldown) else if (MatchState == MatchState::Cooldown)
{ {
CountDownTime = WarmupTime + MatchTime + CooldownTime - GetWorld()->GetTimeSeconds() + LevelStartingTime; CountdownTime = WarmupTime + MatchTime + CooldownTime - GetWorld()->GetTimeSeconds(); // + LevelStartingTime;
if (CountDownTime <= 0.f) if (CountdownTime <= 0.f)
{ {
RestartGame(); RestartGame();
} }
@ -61,19 +61,20 @@ void ABlasterGameMode::OnMatchStateSet()
{ {
Super::OnMatchStateSet(); Super::OnMatchStateSet();
for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
{ {
ABlasterPlayerController* PlayerController = Cast<ABlasterPlayerController>(*Iterator); ABlasterPlayerController* BlasterPlayer = Cast<ABlasterPlayerController>(*It);
if (PlayerController) if (BlasterPlayer)
{ {
PlayerController->OnMatchStateSet(MatchState); BlasterPlayer->OnMatchStateSet(MatchState);
} }
} }
} }
void ABlasterGameMode::PlayerEliminated(ABlasterCharacter* EliminatedCharacter, ABlasterPlayerController* VictimController, void ABlasterGameMode::PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController, ABlasterPlayerController* AttackerController)
ABlasterPlayerController* AttackerController)
{ {
if (AttackerController == nullptr || AttackerController->PlayerState == nullptr) return;
if (VictimController == nullptr || VictimController->PlayerState == nullptr) return;
ABlasterPlayerState* AttackerPlayerState = AttackerController ? Cast<ABlasterPlayerState>(AttackerController->PlayerState) : nullptr; ABlasterPlayerState* AttackerPlayerState = AttackerController ? Cast<ABlasterPlayerState>(AttackerController->PlayerState) : nullptr;
ABlasterPlayerState* VictimPlayerState = VictimController ? Cast<ABlasterPlayerState>(VictimController->PlayerState) : nullptr; ABlasterPlayerState* VictimPlayerState = VictimController ? Cast<ABlasterPlayerState>(VictimController->PlayerState) : nullptr;
@ -99,12 +100,11 @@ void ABlasterGameMode::RequestRespawn(ACharacter* EliminatedCharacter, AControll
EliminatedCharacter->Reset(); EliminatedCharacter->Reset();
EliminatedCharacter->Destroy(); EliminatedCharacter->Destroy();
} }
if (EliminatedController) if (EliminatedController)
{ {
TArray<AActor*> PlayerStarts; TArray<AActor*> PlayerStarts;
UGameplayStatics::GetAllActorsOfClass(this, APlayerStart::StaticClass(), PlayerStarts); UGameplayStatics::GetAllActorsOfClass(this, APlayerStart::StaticClass(), PlayerStarts);
const int32 Selection = FMath::RandRange(0, PlayerStarts.Num() - 1); int32 Selection = FMath::RandRange(0, PlayerStarts.Num() - 1);
RestartPlayerAtPlayerStart(EliminatedController, PlayerStarts[Selection]); RestartPlayerAtPlayerStart(EliminatedController, PlayerStarts[Selection]);
} }
} }

View File

@ -22,7 +22,7 @@ class BLASTER_API ABlasterGameMode : public AGameMode
public: public:
ABlasterGameMode(); ABlasterGameMode();
virtual void Tick(float DeltaSeconds) override; virtual void Tick(float DeltaTime) override;
virtual void PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController, virtual void PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController,
class ABlasterPlayerController* AttackerController); class ABlasterPlayerController* AttackerController);
virtual void RequestRespawn(ACharacter* EliminatedCharacter, AController* EliminatedController); virtual void RequestRespawn(ACharacter* EliminatedCharacter, AController* EliminatedController);
@ -43,8 +43,8 @@ protected:
virtual void OnMatchStateSet() override; virtual void OnMatchStateSet() override;
private: private:
float CountDownTime = 0.f; float CountdownTime = 0.f;
public: public:
FORCEINLINE float GetCountdownTime() const { return CountDownTime; } FORCEINLINE float GetCountdownTime() const { return CountdownTime; }
}; };

View File

@ -5,13 +5,25 @@
#include "Announcement.h" #include "Announcement.h"
#include "CharacterOverlay.h" #include "CharacterOverlay.h"
#include "DebugWidget.h"
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
void ABlasterHUD::BeginPlay() void ABlasterHUD::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
} }
void ABlasterHUD::AddDebugWidget()
{
APlayerController* PlayerController = GetOwningPlayerController();
if (PlayerController && DebugWidgetClass)
{
DebugWidget = CreateWidget<UDebugWidget>(PlayerController, DebugWidgetClass);
DebugWidget->AddToViewport();
}
}
void ABlasterHUD::AddCharacterOverlay() void ABlasterHUD::AddCharacterOverlay()
{ {
APlayerController* PlayerController = GetOwningPlayerController(); APlayerController* PlayerController = GetOwningPlayerController();
@ -46,27 +58,27 @@ void ABlasterHUD::DrawHUD()
if (HUDPackage.CrosshairsCenter) if (HUDPackage.CrosshairsCenter)
{ {
const FVector2D Spread(0.f, 0.f); const FVector2D Spread(0.f, 0.f);
DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spread, HUDPackage.CrosshairColor); DrawCrosshair(HUDPackage.CrosshairsCenter, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
} }
if (HUDPackage.CrosshairsLeft) if (HUDPackage.CrosshairsLeft)
{ {
const FVector2D Spread(-SpreadScaled, 0.f); const FVector2D Spread(-SpreadScaled, 0.f);
DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter, Spread, HUDPackage.CrosshairColor); DrawCrosshair(HUDPackage.CrosshairsLeft, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
} }
if (HUDPackage.CrosshairsRight) if (HUDPackage.CrosshairsRight)
{ {
const FVector2D Spread(SpreadScaled, 0.f); const FVector2D Spread(SpreadScaled, 0.f);
DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter, Spread, HUDPackage.CrosshairColor); DrawCrosshair(HUDPackage.CrosshairsRight, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
} }
if (HUDPackage.CrosshairsTop) if (HUDPackage.CrosshairsTop)
{ {
const FVector2D Spread(0.f, -SpreadScaled); const FVector2D Spread(0.f, -SpreadScaled);
DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter, Spread, HUDPackage.CrosshairColor); DrawCrosshair(HUDPackage.CrosshairsTop, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
} }
if (HUDPackage.CrosshairsBottom) if (HUDPackage.CrosshairsBottom)
{ {
const FVector2D Spread(0.f, SpreadScaled); const FVector2D Spread(0.f, SpreadScaled);
DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter, Spread, HUDPackage.CrosshairColor); DrawCrosshair(HUDPackage.CrosshairsBottom, ViewportCenter, Spread, HUDPackage.CrosshairsColor);
} }
} }
} }

View File

@ -18,7 +18,7 @@ public:
UTexture2D* CrosshairsTop; UTexture2D* CrosshairsTop;
UTexture2D* CrosshairsBottom; UTexture2D* CrosshairsBottom;
float CrosshairSpread; float CrosshairSpread;
FLinearColor CrosshairColor; FLinearColor CrosshairsColor;
}; };
/** /**
@ -31,6 +31,7 @@ class BLASTER_API ABlasterHUD : public AHUD
public: public:
virtual void DrawHUD() override; virtual void DrawHUD() override;
void AddDebugWidget();
void AddCharacterOverlay(); void AddCharacterOverlay();
void AddAnnouncementOverlay(); void AddAnnouncementOverlay();
@ -40,6 +41,12 @@ public:
UPROPERTY() UPROPERTY()
class UCharacterOverlay* CharacterOverlay; class UCharacterOverlay* CharacterOverlay;
UPROPERTY()
class UDebugWidget* DebugWidget;
UPROPERTY(EditAnywhere, Category = "Widget")
TSubclassOf<class UUserWidget> DebugWidgetClass;
UPROPERTY(EditAnywhere, Category = "Announcements") UPROPERTY(EditAnywhere, Category = "Announcements")
TSubclassOf<class UUserWidget> AnnouncementClass; TSubclassOf<class UUserWidget> AnnouncementClass;

View File

@ -0,0 +1,5 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DebugWidget.h"

View File

@ -0,0 +1,41 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "DebugWidget.generated.h"
/**
*
*/
UCLASS()
class BLASTER_API UDebugWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(meta = (BindWidget))
class UTextBlock* DebugMsg1;
UPROPERTY(meta = (BindWidget))
UTextBlock* DebugMsg2;
UPROPERTY(meta = (BindWidget))
UTextBlock* DebugMsg3;
UPROPERTY(meta = (BindWidget))
UTextBlock* DebugMsg4;
UPROPERTY(meta = (BindWidget))
UTextBlock* DebugMsg5;
UPROPERTY(meta = (BindWidget))
UTextBlock* DebugMsg6;
UPROPERTY(meta = (BindWidget))
UTextBlock* DebugMsg7;
};

View File

@ -9,6 +9,7 @@
#include "Blaster/HUD/Announcement.h" #include "Blaster/HUD/Announcement.h"
#include "Blaster/HUD/BlasterHUD.h" #include "Blaster/HUD/BlasterHUD.h"
#include "Blaster/HUD/CharacterOverlay.h" #include "Blaster/HUD/CharacterOverlay.h"
#include "Blaster/HUD/DebugWidget.h"
#include "Components/ProgressBar.h" #include "Components/ProgressBar.h"
#include "Components/TextBlock.h" #include "Components/TextBlock.h"
#include "GameFramework/GameMode.h" #include "GameFramework/GameMode.h"
@ -31,38 +32,69 @@ void ABlasterPlayerController::GetLifetimeReplicatedProps(TArray<FLifetimeProper
DOREPLIFETIME(ABlasterPlayerController, MatchState); DOREPLIFETIME(ABlasterPlayerController, MatchState);
} }
void ABlasterPlayerController::Tick(float DeltaSeconds) void ABlasterPlayerController::Tick(float DeltaTime)
{ {
Super::Tick(DeltaSeconds); Super::Tick(DeltaTime);
SetHUDTime(); SetHUDTime();
CheckTimeSync(DeltaSeconds); CheckTimeSync(DeltaTime);
PollInit(); PollInit();
}
void ABlasterPlayerController::OnPossess(APawn* InPawn) if (DebugWidget)
{
Super::OnPossess(InPawn);
if (const ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(InPawn))
{ {
SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth()); SetDebugMsg1(TEXT("GetWorld()->GetTimeSeconds(): "), FString::Printf(TEXT("%02f"), GetWorld()->GetTimeSeconds()));
SetDebugMsg2(TEXT("GetServerTime(): "), FString::Printf(TEXT("%02f"), GetServerTime()));
SetDebugMsg3(TEXT("ClientServerDelta: "), FString::Printf(TEXT("%f"), ClientServerDelta));
SetDebugMsg4(TEXT("LevelStartingTime: "), FString::Printf(TEXT("%f"), LevelStartingTime));
SetDebugMsg5(TEXT("CountdownInt: "), FString::Printf(TEXT("%d"), CountdownInt));
} }
} }
void ABlasterPlayerController::ReceivedPlayer() void ABlasterPlayerController::SetDebugMsg1(FString Key, FString Value)
{ {
Super::ReceivedPlayer(); bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg1;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg1->SetText(FText::FromString(Key.Append(Value)));
if (IsLocalController())
{
ServerRequestServerTime(GetWorld()->GetTimeSeconds());
}
} }
void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds) void ABlasterPlayerController::SetDebugMsg2(FString Key, FString Value)
{ {
TimeSyncRunningTime += DeltaSeconds; bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg2;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg2->SetText(FText::FromString(Key.Append(Value)));
}
void ABlasterPlayerController::SetDebugMsg3(FString Key, FString Value)
{
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg3;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg3->SetText(FText::FromString(Key.Append(Value)));
}
void ABlasterPlayerController::SetDebugMsg4(FString Key, FString Value)
{
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg4;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg4->SetText(FText::FromString(Key.Append(Value)));
}
void ABlasterPlayerController::SetDebugMsg5(FString Key, FString Value)
{
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg5;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg5->SetText(FText::FromString(Key.Append(Value)));
}
void ABlasterPlayerController::SetDebugMsg6(FString Key, FString Value)
{
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg6;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg6->SetText(FText::FromString(Key.Append(Value)));
}
void ABlasterPlayerController::SetDebugMsg7(FString Key, FString Value)
{
bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg7;
if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg7->SetText(FText::FromString(Key.Append(Value)));
}
void ABlasterPlayerController::CheckTimeSync(float DeltaTime)
{
TimeSyncRunningTime += DeltaTime;
if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency) if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency)
{ {
ServerRequestServerTime(GetWorld()->GetTimeSeconds()); ServerRequestServerTime(GetWorld()->GetTimeSeconds());
@ -70,51 +102,257 @@ void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds)
} }
} }
void ABlasterPlayerController::ServerCheckMatchState_Implementation()
{
ABlasterGameMode* GameMode = Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this));
if (GameMode)
{
WarmupTime = GameMode->WarmupTime;
MatchTime = GameMode->MatchTime;
CooldownTime = GameMode->CooldownTime;
LevelStartingTime = GameMode->LevelStartingTime;
MatchState = GameMode->GetMatchState();
ClientJoinMidgame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime);
}
}
void ABlasterPlayerController::ClientJoinMidgame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime)
{
WarmupTime = Warmup;
MatchTime = Match;
CooldownTime = Cooldown;
LevelStartingTime = StartingTime;
MatchState = StateOfMatch;
OnMatchStateSet(MatchState);
if (BlasterHUD && MatchState == MatchState::WaitingToStart)
{
BlasterHUD->AddAnnouncementOverlay();
}
}
void ABlasterPlayerController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(InPawn);
if (BlasterCharacter)
{
SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth());
}
}
void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->HealthBar &&
BlasterHUD->CharacterOverlay->HealthText;
if (bHUDValid)
{
const float HealthPercent = Health / MaxHealth;
BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent);
FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth));
BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText));
}
else
{
bInitializeCharacterOverlay = true;
HUDHealth = Health;
HUDMaxHealth = MaxHealth;
}
}
void ABlasterPlayerController::SetHUDScore(float Score)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->ScoreValue;
if (bHUDValid)
{
FString ScoreText = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score));
BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreText));
}
else
{
bInitializeCharacterOverlay = true;
HUDScore = Score;
}
}
void ABlasterPlayerController::SetHUDDefeats(int32 Defeats)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->DefeatsValue;
if (bHUDValid)
{
FString DefeatsText = FString::Printf(TEXT("%d"), Defeats);
BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsText));
}
else
{
bInitializeCharacterOverlay = true;
HUDDefeats = Defeats;
}
}
void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->WeaponAmmoValue;
if (bHUDValid)
{
FString AmmoText = FString::Printf(TEXT("%d"), Ammo);
BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(AmmoText));
}
}
void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->CarriedAmmoValue;
if (bHUDValid)
{
FString AmmoText = FString::Printf(TEXT("%d"), Ammo);
BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(AmmoText));
}
}
void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->CharacterOverlay &&
BlasterHUD->CharacterOverlay->MatchCountdownText;
if (bHUDValid)
{
if (CountdownTime < 0.f)
{
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText());
return;
}
int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f);
int32 Seconds = CountdownTime - Minutes * 60;
FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds);
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText));
}
}
void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = BlasterHUD &&
BlasterHUD->Announcement &&
BlasterHUD->Announcement->CountdownText;
if (bHUDValid)
{
if (CountdownTime < 0.f)
{
BlasterHUD->Announcement->CountdownText->SetText(FText());
return;
}
int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f);
int32 Seconds = CountdownTime - Minutes * 60;
FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds);
BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText));
}
}
void ABlasterPlayerController::SetHUDTime()
{
float TimeLeft = 0.f;
if (MatchState == MatchState::WaitingToStart) TimeLeft = WarmupTime - GetServerTime(); // + LevelStartingTime;
else if (MatchState == MatchState::InProgress) TimeLeft = WarmupTime + MatchTime - GetServerTime(); // + LevelStartingTime;
else if (MatchState == MatchState::Cooldown) TimeLeft = WarmupTime + MatchTime + CooldownTime - GetServerTime(); // + LevelStartingTime;
uint32 SecondsLeft = FMath::CeilToInt(TimeLeft);
if (HasAuthority())
{
BlasterGameMode = BlasterGameMode == nullptr ? Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this)) : BlasterGameMode;
if (BlasterGameMode)
{
SecondsLeft = FMath::CeilToInt(BlasterGameMode->GetCountdownTime());
}
}
if (CountdownInt != SecondsLeft)
{
if (MatchState == MatchState::WaitingToStart || MatchState == MatchState::Cooldown)
{
SetHUDAnnouncementCountdown(TimeLeft);
}
if (MatchState == MatchState::InProgress)
{
SetHUDMatchCountdown(TimeLeft);
}
}
CountdownInt = SecondsLeft;
}
void ABlasterPlayerController::PollInit()
{
if (BlasterHUD && BlasterHUD->DebugWidget == nullptr)
{
BlasterHUD->AddDebugWidget();
if (BlasterHUD->DebugWidget)
{
DebugWidget = BlasterHUD->DebugWidget;
}
}
if (CharacterOverlay == nullptr)
{
if (BlasterHUD && BlasterHUD->CharacterOverlay)
{
CharacterOverlay = BlasterHUD->CharacterOverlay;
if (CharacterOverlay)
{
SetHUDHealth(HUDHealth, HUDMaxHealth);
SetHUDScore(HUDScore);
SetHUDDefeats(HUDDefeats);
}
}
}
}
void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest)
{
float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds();
ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt);
}
void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest)
{
float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest;
float CurrentServerTime = TimeServerReceivedClientRequest + 0.5f * RoundTripTime;
ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds();
}
float ABlasterPlayerController::GetServerTime() float ABlasterPlayerController::GetServerTime()
{ {
if (HasAuthority()) return GetWorld()->GetTimeSeconds(); if (HasAuthority()) return GetWorld()->GetTimeSeconds();
return GetWorld()->GetTimeSeconds() + ClientServerDelta; return GetWorld()->GetTimeSeconds() + ClientServerDelta;
} }
void ABlasterPlayerController::HandleMatchHasStarted() void ABlasterPlayerController::ReceivedPlayer()
{ {
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD; Super::ReceivedPlayer();
if (BlasterHUD) if (IsLocalController())
{ {
BlasterHUD->AddCharacterOverlay(); ServerRequestServerTime(GetWorld()->GetTimeSeconds());
if (BlasterHUD->Announcement)
{
BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden);
}
}
}
void ABlasterPlayerController::HandleCooldown()
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
if (BlasterHUD)
{
BlasterHUD->CharacterOverlay->RemoveFromParent();
bool bHUDValid =
BlasterHUD->Announcement &&
BlasterHUD->Announcement->AnnouncementText &&
BlasterHUD->Announcement->AnnouncementMessage;
if (bHUDValid)
{
const FString AnnouncementText("New match starts in:");
BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText));
BlasterHUD->Announcement->AnnouncementMessage->SetText(FText());
BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible);
}
}
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(GetPawn());
if (BlasterCharacter && BlasterCharacter->GetCombat())
{
BlasterCharacter->bDisableGameplay = true;
BlasterCharacter->GetCombat()->FireButtonPressed(false);
} }
} }
@ -144,211 +382,45 @@ void ABlasterPlayerController::OnRep_MatchState()
} }
} }
void ABlasterPlayerController::ServerCheckMatchState_Implementation() void ABlasterPlayerController::HandleMatchHasStarted()
{ {
ABlasterGameMode* GameMode = Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this)); BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
if (GameMode) if (BlasterHUD)
{ {
LevelStartingTime = GameMode->LevelStartingTime; BlasterHUD->AddCharacterOverlay();
WarmupTime = GameMode->WarmupTime; if (BlasterHUD->Announcement)
MatchTime = GameMode->MatchTime;
CooldownTime = GameMode->CooldownTime;
MatchState = GameMode->GetMatchState();
ClientJoinMidGame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime);
}
}
void ABlasterPlayerController::ClientJoinMidGame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime)
{
LevelStartingTime = StartingTime;
WarmupTime = Warmup;
MatchTime = Match;
CooldownTime = Cooldown;
MatchState = StateOfMatch;
OnMatchStateSet(MatchState);
if (BlasterHUD && MatchState == MatchState::WaitingToStart)
{
BlasterHUD->AddAnnouncementOverlay();
}
}
void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest)
{
const float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds();
ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt);
}
void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest)
{
const float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest;
const float CurrentServerTime = TimeServerReceivedClientRequest + 0.5f * RoundTripTime;
ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds();
}
void ABlasterPlayerController::SetHUDTime()
{
float TimeLeft = 0.f;
if (MatchState == MatchState::WaitingToStart) TimeLeft = WarmupTime - GetServerTime() + LevelStartingTime;
else if (MatchState == MatchState::InProgress) TimeLeft = WarmupTime + MatchTime - GetServerTime() + LevelStartingTime;
else if (MatchState == MatchState::Cooldown) TimeLeft = WarmupTime + MatchTime + CooldownTime - GetServerTime() + LevelStartingTime;
uint32 SecondsLeft = FMath::CeilToInt(TimeLeft);
if (HasAuthority())
{
BlasterGameMode = BlasterGameMode == nullptr ? Cast<ABlasterGameMode>(UGameplayStatics::GetGameMode(this)) : BlasterGameMode;
if (BlasterGameMode)
{ {
SecondsLeft = FMath::CeilToInt(BlasterGameMode->GetCountdownTime() + LevelStartingTime); BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden);
}
}
if (CountdownInt != SecondsLeft)
{
if (MatchState == MatchState::WaitingToStart || MatchState == MatchState::Cooldown) SetHUDAnnouncementCountdown(TimeLeft);
if (MatchState == MatchState::InProgress) SetHUDMatchCountdown(TimeLeft);
}
CountdownInt = SecondsLeft;
}
void ABlasterPlayerController::PollInit()
{
if (CharacterOverlay == nullptr)
{
if (BlasterHUD && BlasterHUD->CharacterOverlay)
{
CharacterOverlay = BlasterHUD->CharacterOverlay;
if (CharacterOverlay)
{
SetHUDHealth(HUDHealth, HUDMaxHealth);
SetHUDScore(HUDScore);
SetHUDDefeats(HUDDefeats);
}
} }
} }
} }
void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth) void ABlasterPlayerController::HandleCooldown()
{ {
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD; BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = CharacterOverlay && CharacterOverlay->HealthBar && CharacterOverlay->HealthText; if (BlasterHUD)
if (bHUDValid)
{ {
const float HealthPercent = Health / MaxHealth; if (BlasterHUD->CharacterOverlay)
BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent);
const FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth));
BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText));
}
else
{
bInitializeCharacterOverlay = true;
HUDHealth = Health;
HUDMaxHealth = MaxHealth;
}
}
void ABlasterPlayerController::SetHUDScore(float Score)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = CharacterOverlay && CharacterOverlay->ScoreValue;
if (bHUDValid)
{
const FString ScoreAmount = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score));
BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreAmount));
}
else
{
bInitializeCharacterOverlay = true;
HUDScore = Score;
}
}
void ABlasterPlayerController::SetHUDDefeats(int32 Defeats)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = CharacterOverlay && CharacterOverlay->DefeatsValue;
if (bHUDValid)
{
const FString DefeatsAmount = FString::Printf(TEXT("%d"), Defeats);
BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsAmount));
}
else
{
bInitializeCharacterOverlay = true;
HUDDefeats = Defeats;
}
}
void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = CharacterOverlay && CharacterOverlay->WeaponAmmoValue;
if (bHUDValid)
{
const FString WeaponAmmoAmount = FString::Printf(TEXT("%d"), Ammo);
BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(WeaponAmmoAmount));
}
}
void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = CharacterOverlay && CharacterOverlay->CarriedAmmoValue;
if (bHUDValid)
{
const FString CarriedAmmoAmount = FString::Printf(TEXT("%d"), Ammo);
BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(CarriedAmmoAmount));
}
}
void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid = CharacterOverlay && CharacterOverlay->MatchCountdownText;
if (bHUDValid)
{
if (CountdownTime < 0.f)
{ {
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText()); BlasterHUD->CharacterOverlay->RemoveFromParent();
return;
} }
const int32 Minutes = FMath::FloorToInt(CountdownTime / 60);
const int32 Seconds = CountdownTime - Minutes * 60; bool bHUDValid = BlasterHUD->Announcement &&
BlasterHUD->Announcement->AnnouncementText &&
BlasterHUD->Announcement->AnnouncementMessage;
const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); if (bHUDValid)
BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText));
}
}
void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime)
{
BlasterHUD = BlasterHUD == nullptr ? Cast<ABlasterHUD>(GetHUD()) : BlasterHUD;
bool bHUDValid =
BlasterHUD &&
BlasterHUD->Announcement &&
BlasterHUD->Announcement->AnnouncementText &&
BlasterHUD->Announcement->CountdownText;
if (bHUDValid)
{
if (CountdownTime < 0.f)
{ {
BlasterHUD->Announcement->CountdownText->SetText(FText()); BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible);
return; FString AnnouncementText("New match starts in:");
BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText));
BlasterHUD->Announcement->AnnouncementMessage->SetText(FText());
} }
const int32 Minutes = FMath::FloorToInt(CountdownTime / 60); }
const int32 Seconds = CountdownTime - Minutes * 60; ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(GetPawn());
if (BlasterCharacter && BlasterCharacter->GetCombat())
const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); {
BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText)); BlasterCharacter->bDisableGameplay = true;
BlasterCharacter->GetCombat()->FireButtonPressed(false);
} }
} }

View File

@ -16,11 +16,18 @@ class BLASTER_API ABlasterPlayerController : public APlayerController
public: public:
virtual void Tick(float DeltaSeconds) override; virtual void Tick(float DeltaTime) override;
virtual void OnPossess(APawn* InPawn) override; virtual void OnPossess(APawn* InPawn) override;
virtual void ReceivedPlayer() override; // Sync with server clock as soon as possible virtual void ReceivedPlayer() override; // Sync with server clock as soon as possible
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
void SetDebugMsg1(FString Key, FString Value);
void SetDebugMsg2(FString Key, FString Value);
void SetDebugMsg3(FString Key, FString Value);
void SetDebugMsg4(FString Key, FString Value);
void SetDebugMsg5(FString Key, FString Value);
void SetDebugMsg6(FString Key, FString Value);
void SetDebugMsg7(FString Key, FString Value);
void SetHUDHealth(float Health, float MaxHealth); void SetHUDHealth(float Health, float MaxHealth);
void SetHUDScore(float Score); void SetHUDScore(float Score);
void SetHUDDefeats(int32 Defeats); void SetHUDDefeats(int32 Defeats);
@ -38,7 +45,7 @@ public:
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
void CheckTimeSync(float DeltaSeconds); void CheckTimeSync(float DeltaTime);
void HandleMatchHasStarted(); void HandleMatchHasStarted();
void SetHUDTime(); void SetHUDTime();
void PollInit(); void PollInit();
@ -65,9 +72,12 @@ protected:
void ServerCheckMatchState(); void ServerCheckMatchState();
UFUNCTION(Client, Reliable) UFUNCTION(Client, Reliable)
void ClientJoinMidGame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime); void ClientJoinMidgame(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime);
private: private:
UPROPERTY()
class UDebugWidget* DebugWidget;
UPROPERTY() UPROPERTY()
class ABlasterHUD* BlasterHUD; class ABlasterHUD* BlasterHUD;

View File

@ -7,21 +7,6 @@
#include "Blaster/PlayerController/BlasterPlayerController.h" #include "Blaster/PlayerController/BlasterPlayerController.h"
#include "Net/UnrealNetwork.h" #include "Net/UnrealNetwork.h"
void ABlasterPlayerState::IncreaseScore(float ScoreAmount)
{
SetScore(GetScore() + ScoreAmount);
Character = GetCharacter();
if (Character)
{
Controller = GetController();
if (Controller)
{
Controller->SetHUDScore(GetScore());
}
}
}
void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{ {
Super::GetLifetimeReplicatedProps(OutLifetimeProps); Super::GetLifetimeReplicatedProps(OutLifetimeProps);
@ -29,14 +14,28 @@ void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>&
DOREPLIFETIME(ABlasterPlayerState, Defeats); DOREPLIFETIME(ABlasterPlayerState, Defeats);
} }
void ABlasterPlayerState::IncreaseScore(float ScoreAmount)
{
SetScore(GetScore() + ScoreAmount);
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
if (Character)
{
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDScore(GetScore());
}
}
}
void ABlasterPlayerState::OnRep_Score() void ABlasterPlayerState::OnRep_Score()
{ {
Super::OnRep_Score(); Super::OnRep_Score();
Character = GetCharacter(); Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
if (Character) if (Character)
{ {
Controller = GetController(); Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller) if (Controller)
{ {
Controller->SetHUDScore(GetScore()); Controller->SetHUDScore(GetScore());
@ -47,11 +46,10 @@ void ABlasterPlayerState::OnRep_Score()
void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount) void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount)
{ {
Defeats += DefeatsAmount; Defeats += DefeatsAmount;
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
Character = GetCharacter();
if (Character) if (Character)
{ {
Controller = GetController(); Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller) if (Controller)
{ {
Controller->SetHUDDefeats(Defeats); Controller->SetHUDDefeats(Defeats);
@ -61,29 +59,13 @@ void ABlasterPlayerState::IncreaseDefeats(int32 DefeatsAmount)
void ABlasterPlayerState::OnRep_Defeats() void ABlasterPlayerState::OnRep_Defeats()
{ {
Character = GetCharacter(); Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
if (Character) if (Character)
{ {
Controller = GetController(); Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller) if (Controller)
{ {
Controller->SetHUDDefeats(Defeats); Controller->SetHUDDefeats(Defeats);
} }
} }
} }
ABlasterCharacter* ABlasterPlayerState::GetCharacter() const
{
return Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
}
ABlasterPlayerController* ABlasterPlayerState::GetController() const
{
if (Character)
{
return Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
}
return nullptr;
}

View File

@ -28,8 +28,6 @@ private:
class ABlasterCharacter* Character; class ABlasterCharacter* Character;
UPROPERTY() UPROPERTY()
class ABlasterPlayerController* Controller; class ABlasterPlayerController* Controller;
ABlasterCharacter* GetCharacter() const;
ABlasterPlayerController* GetController() const;
UPROPERTY(ReplicatedUsing = OnRep_Defeats) UPROPERTY(ReplicatedUsing = OnRep_Defeats)
int32 Defeats; int32 Defeats;