HAxis sos

This commit is contained in:
guus
2018-08-11 16:46:35 +02:00
commit 510654f8a1
480 changed files with 54126 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "DefaultGameInstance.h"
#include "MenuController.h"
#include "LobbySpawn.h"
#include "GameStateBase.h"
#include "PlayerStateBase.h"
#include "PlayerControllerBase.h"
#include "CharacterBase.h"
#include "LobbyCharacterSelect.h"
#include "MenuGameMode.h"
void ULobbyCharacterSelect::m_OnPlayerJoined(APlayerController* pc)
{
for(auto it = m_visualCharacters.CreateIterator(); it; ++it)
{
(it.Value()).character->SendInitialAppearance(pc);
}
}
void ULobbyCharacterSelect::NativeConstruct()
{
Super::NativeConstruct();
// Add GameMode callback
AMenuGameMode* gm = Cast<AMenuGameMode>(GetWorld()->GetAuthGameMode());
if(gm)
{
m_onPlayerJoinedDH = gm->onPlayerJoined.AddUObject(this, &ULobbyCharacterSelect::m_OnPlayerJoined);
}
UWorld* const world = GetWorld();
for (TActorIterator<ALobbySpawn> iter(world); iter; ++iter)
{
TArray<ALobbySpawn*>* find = m_spawnPoints.Find(iter->assignedTeam);
if (!find)
{
TArray<ALobbySpawn*> arr;
arr.Add(*iter);
m_spawnPoints.Add(iter->assignedTeam, arr);
}
else
find->Add(*iter);
}
m_requireUpdate = false;
m_updateInterval = 0;
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
check(gameState);
gameState->OnPlayerStateChange.AddDynamic(this, &ULobbyCharacterSelect::UpdateVisualCharacters);
}
void ULobbyCharacterSelect::NativeDestruct()
{
Super::NativeDestruct();
// Remove GameMode Callback
AMenuGameMode* gm = Cast<AMenuGameMode>(GetWorld()->GetAuthGameMode());
if(gm)
{
gm->onPlayerJoined.Remove(m_onPlayerJoinedDH);
}
UWorld* const world = GetWorld();
check(world);
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
check(gameState);
gameState->OnPlayerStateChange.RemoveAll(this);
}
void ULobbyCharacterSelect::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
// The updating is called once per frame
// This is to prevent double calls when two players leave in one cycle
// Ensure that only the server runs this
if (!GetOwningPlayer()->HasAuthority())
return;
// No need to update this frame
if (!m_requireUpdate)
return;
// Await the interval
m_updateInterval -= InDeltaTime;
if (m_updateInterval > 0)
return;
m_requireUpdate = false;
m_updateInterval = 0.3f;
UWorld* world = GetWorld();
check(world);
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
check(gameState);
TArray<int32> teamSizes = gameState->GetTeamSizes();
TArray<TArray<APlayerStateBase*>> playersPerTeam = gameState->GetPlayersByTeam();
// Check if players have left
TMap<APlayerStateBase*, VisualSlot> outdatedCharacters = m_visualCharacters;
TArray<APlayerStateBase*> players = gameState->GetPlayers();
for (int32 i = 0; i < players.Num(); i++)
{
VisualSlot* find = outdatedCharacters.Find(players[i]);
if (find)
outdatedCharacters.Remove(players[i]);
}
for (auto iter = outdatedCharacters.CreateIterator(); iter; ++iter)
{
if (IsValid(iter->Value.character))
iter->Value.character->Destroy();
m_visualCharacters.Remove(iter->Key);
}
// Check if players switched team
TMap<APlayerStateBase*, ACharacterBase*> newCharacters;
TMap<APlayerStateBase*, VisualSlot> newMap;
for (int32 i = 1; i < playersPerTeam.Num(); i++)
{
auto& set = playersPerTeam[i];
for (int32 j = 0; j < set.Num(); j++)
{
APlayerStateBase* playerState = set[j];
VisualSlot* find = m_visualCharacters.Find(playerState);
const int32 team = i - 1;
if (!find || find->team != team || find->slot != j)
{
// Fetch the spawn coordinates if the spawnpoint exists
FVector position;
FRotator rotation;
if (team < m_spawnPoints.Num() && j < m_spawnPoints[team].Num())
{
position = m_spawnPoints[team][j]->GetActorLocation();
rotation = m_spawnPoints[team][j]->GetActorRotation();
}
// Check if we need to create a new character, else we just repurpose the previous character (like when the player switched slot)
ACharacterBase* character;
if (!find || !IsValid(find->character))
{
FActorSpawnParameters params;
params.bNoFail = true;
params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
character = GetWorld()->SpawnActor<ACharacterBase>(characterBlueprint, FTransform::Identity, params);
if (!IsValid(character))
{
JERROR("Failed to spawn Actor");
return;
}
}
else
{
find->character->ClearEquipment();
character = find->character;
}
// Set and add
character->SetActorLocation(position);
character->SetActorRotation(rotation.Quaternion());
newMap.Add(playerState, VisualSlot(team, j, character));
newCharacters.Add(playerState, character);
}
else
newMap.Add(playerState, *find);
}
}
m_visualCharacters = newMap;
// Apply the customizations
TMap<APlayerControllerBase*, APlayerStateBase*> controllers = gameState->GetPlayersByController();
for (auto iter = controllers.CreateIterator(); iter; ++iter)
{
ACharacterBase** character = newCharacters.Find(iter->Value);
if (!character || !IsValid(*character)) continue;
(*character)->SetCustomizations(iter->Key->setupState.customizations);
(*character)->EquipSkillsFromSkillTreeState(iter->Key->setupState.skills);
// Set class specific equipment
if(characterClassProperties)
{
FCharacterClassProperty properties = characterClassProperties->GetCharacterClass(iter->Key->setupState.characterClass);
(*character)->EquipItems(properties.classItems);
}
}
}
void ULobbyCharacterSelect::Init()
{
UWorld* const world = GetWorld();
check(world);
UDefaultGameInstance* const instance = Cast<UDefaultGameInstance>(world->GetGameInstance());
check(instance);
UCharacterSettings* const settings = instance->GetCharacterSettings();
check(settings);
// Fetch the characters from the save
check(settings->characterSaves.Num() > 0);
m_playerCharacterSaves = settings->GetValidCharacters();
m_selection = 0;
m_ApplyCharacter();
}
void ULobbyCharacterSelect::OnNextCharacter()
{
if (m_selection == m_playerCharacterSaves.Num() - 1)
return;
m_selection++;
m_ApplyCharacter();
}
void ULobbyCharacterSelect::OnPreviousCharacter()
{
if (m_selection == 0)
return;
m_selection--;
m_ApplyCharacter();
}
void ULobbyCharacterSelect::UpdateCharacter_Implementation(FCharacterSave save)
{
// Blueprint implementation
}
void ULobbyCharacterSelect::m_ApplyCharacter()
{
UpdateCharacter(m_playerCharacterSaves[m_selection]);
// Apply the selected character to the player controller
UWorld* const world = GetWorld();
check(world);
AMenuController* const controller = Cast<AMenuController>(world->GetFirstPlayerController());
check(controller);
FPlayerSetupState state;
state.skills = m_playerCharacterSaves[m_selection].skillTreeState;
state.customizations = m_playerCharacterSaves[m_selection].characterCustomization;
state.characterClass = m_playerCharacterSaves[m_selection].characterClass;
controller->SetSetupState(state);
}
void ULobbyCharacterSelect::UpdateVisualCharacters(APlayerControllerBase* playerController)
{
if (!IsValid(characterBlueprint))
{
JERROR("Character blueprint not assigned");
return;
}
if (!IsValid(playerController) && playerController != nullptr)
return;
// Ensure that only the server runs this
if (!GetOwningPlayer()->HasAuthority())
return;
if (playerController != nullptr)
{
// Just update the visuals on the specific player
APlayerStateBase* playerState = Cast<APlayerStateBase>(playerController->PlayerState);
if (IsValid(playerState))
{
VisualSlot* slot = m_visualCharacters.Find(playerState);
if (slot && IsValid(slot->character))
{
slot->character->SetCustomizations(playerController->setupState.customizations);
slot->character->ClearEquipment();
slot->character->EquipSkillsFromSkillTreeState(playerController->setupState.skills);
// Set class specific equipment
if(characterClassProperties)
{
FCharacterClassProperty properties = characterClassProperties->GetCharacterClass(playerController->setupState.characterClass);
slot->character->EquipItems(properties.classItems);
}
}
else // Failed to find the character, refresh all
m_requireUpdate = true;
}
}
else
m_requireUpdate = true;
}

View File

@@ -0,0 +1,65 @@
// Project Lab - NHTV Igad
#pragma once
#include "GUI/Menu/SubMenu.h"
#include "CharacterSettings.h"
#include "LobbyCharacterSelect.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ULobbyCharacterSelect : public USubMenu
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
UFUNCTION(BlueprintCallable, Category = "Lobby")
void Init();
// On next/previous player character
UFUNCTION(BlueprintCallable, Category = "Lobby")
void OnNextCharacter();
UFUNCTION(BlueprintCallable, Category = "Lobby")
void OnPreviousCharacter();
// Called to set the name of the selected character
UFUNCTION(BlueprintNativeEvent, Category = "Lobby")
void UpdateCharacter(FCharacterSave save);
// Called to update all visual characters in the lobby (specify a controller if one player only requires a visual update, or nullptr if all characters need to be updated)
UFUNCTION(BlueprintCallable, Category = "Lobby")
void UpdateVisualCharacters(class APlayerControllerBase* playerController);
UPROPERTY(EditAnywhere, Category = "Lobby")
TSubclassOf<class ACharacterBase> characterBlueprint;
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Character Sub Menu")
class UCharacterClassPropertySet* characterClassProperties;
private:
void m_OnPlayerJoined(APlayerController* pc);
FDelegateHandle m_onPlayerJoinedDH;
TArray<FCharacterSave> m_playerCharacterSaves;
int32 m_selection;
TMap<int32, TArray<ALobbySpawn*>> m_spawnPoints;
struct VisualSlot
{
VisualSlot(int32 team, int32 slot, ACharacterBase* character) : team(team), slot(slot), character(character) {}
int32 team;
int32 slot;
ACharacterBase* character;
};
TMap<APlayerStateBase*, VisualSlot> m_visualCharacters;
void m_ApplyCharacter();
bool m_requireUpdate;
float m_updateInterval;
};

View File

@@ -0,0 +1,204 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "LobbyMenu.h"
#include "LobbySlot.h"
#include "DefaultPlayer.h"
#include "PlayerStateBase.h"
#include "MenuController.h"
#include "DefaultGameInstance.h"
#include "MenuGameMode.h"
#include "GameStateBase.h"
#include "SubMenu.h"
#include "SessionManager.h"
#include "Engine.h"
#include "ScreenOverlay.h"
#include "CharacterSettings.h"
ULobbyMenu::ULobbyMenu(const FObjectInitializer& init)
: Super(init)
{
}
void ULobbyMenu::NativeConstruct()
{
m_teamContainer = Cast<USubMenu>(WidgetTree->FindWidget("Container"));
Super::NativeConstruct();
}
void ULobbyMenu::NativeDestruct()
{
Super::NativeDestruct();
}
void ULobbyMenu::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
Super::NativeTick(MyGeometry, InDeltaTime);
if(!m_myState)
{
// Try to aquire my local player state, this is in Tick because player states are not guaranteed during BeginPlay
UWorld* const world = GetWorld();
check(world);
APlayerControllerBase* player = Cast<APlayerControllerBase>(world->GetGameInstance()->GetFirstLocalPlayerController());
check(player);
m_myState = Cast<APlayerStateBase>(player->PlayerState);
}
UWorld* world = GetWorld();
check(world);
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
check(gameState);
TArray<int32> teamSizes = gameState->GetTeamSizes();
TArray<TArray<APlayerStateBase*>> playersPerTeam = gameState->GetPlayersByTeam();
// Update team slots with their respective player arrays
for (int32 i = 0; i < (int32)m_numTeams; i++)
{
if((i + 1) < playersPerTeam.Num())
{
m_lobbySlots[i]->UpdatePlayers(playersPerTeam[i+1]);
}
else
m_lobbySlots[i]->UpdatePlayers(TArray<APlayerStateBase*>());
if (i > teamSizes.Num())
{
m_lobbySlots[i]->SetState(false);
}
else
{
m_lobbySlots[i]->SetState(true);
}
}
}
void ULobbyMenu::Init()
{
// Generate the selectable builds
UWorld* world = GetWorld();
check(world);
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(world->GetGameInstance());
check(instance);
UCharacterSettings* settings = instance->GetCharacterSettings();
check(settings);
m_characters = settings->characterSaves;
// Remove existing lobby slots
for(ULobbySlot* s : m_lobbySlots)
{
s->RemoveFromParent();
}
m_lobbySlots.SetNum(0);
if(!m_teamContainer)
{
GWERROR("Container not set, can't initialize lobby menu");
return;
}
UPanelWidget* panel = Cast<UPanelWidget>(m_teamContainer->WidgetTree->RootWidget);
if (!panel)
{
GWERROR(L"No UPanelWidget found");
return;
}
// Create team slots in this menu for the amount of selected teams in the game setup screen
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
check(gameState);
m_numTeams = gameState->GetMapTeamCount();
for (uint32 i = 0; i < m_numTeams; i++)
{
ULobbySlot* slot = CreateWidget<ULobbySlot>(GetWorld(), lobbySlotClass);
check(slot);
panel->AddChild(slot);
slot->SetTeamIndex(i+1);
m_lobbySlots.Add(slot);
}
m_teamContainer->RescanItems();
}
void ULobbyMenu::ToggleReadyState()
{
// Toggle my player state's ready state
if(!m_myState)
{
UWorld* const world = GetWorld();
check(world);
APlayerControllerBase* player = Cast<APlayerControllerBase>(world->GetGameInstance()->GetFirstLocalPlayerController());
check(player);
m_myState = Cast<APlayerStateBase>(player->PlayerState);
}
if(m_myState)
m_myState->SetReadyState(!m_myState->GetReadyState());
}
void ULobbyMenu::StartGame()
{
UWorld* world = GetWorld();
check(world);
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
check(gameState);
TArray<APlayerStateBase*> players = gameState->GetPlayers<APlayerStateBase>();
// Check if we're the host
AMenuGameMode* gameMode = world->GetAuthGameMode<AMenuGameMode>();
if(gameMode)
{
// Check if everyone's ready
for (size_t i = 0; i < players.Num(); i++)
{
if (!players[i]->GetReadyState())
return;
}
// Tell the game to start
GPRINT("Starting game");
if(!gameMode->StartGame())
{
GERROR("Failed to start game");
TArray<FString> options;
options.Add("OK");
Cast<APlayerControllerBase>(GetOwningPlayer())->overlay->ShowMessageBox("Error", "Failed to start game", options);
}
}
}
void ULobbyMenu::GotoTeamSelector()
{
if (m_teamContainer)
{
OpenSubMenu(m_teamContainer);
}
}
void ULobbyMenu::BackToMenu()
{
// Close active session
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetOwningPlayer()->GetGameInstance());
inst->sessionManager->DestroySession();
inst->sessionManager->CloseNetConnections();
// Goto menu
AMenuController* mc = Cast<AMenuController>(GetOwningPlayer());
mc->SwitchToMenu();
}
bool ULobbyMenu::IsHost() const
{
if (!GetOwningPlayer())
return false;
return GetOwningPlayer()->Role == ROLE_Authority;
}
void ULobbyMenu::OnLobbyEnter()
{
// Register session callbacks
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetOwningPlayer()->GetGameInstance());
Init();
}
TArray<FCharacterSave> ULobbyMenu::GetCharacterSaves()
{
return m_characters;
}

View File

@@ -0,0 +1,63 @@
// Project Lab - NHTV Igad
#pragma once
#include "MenuScreenBase.h"
#include "CharacterSettings.h"
#include "LobbyMenu.generated.h"
UCLASS()
class UNREALPROJECT_API ULobbyMenu : public UMenuScreenBase
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
// Must be called from blueprint to setup this element
void Init();
UFUNCTION(BlueprintCallable, Category = "Ready")
void ToggleReadyState();
UFUNCTION(BlueprintCallable, Category = "Ready")
void StartGame();
UFUNCTION(BlueprintCallable, Category = "Ready")
void GotoTeamSelector();
UFUNCTION(BlueprintCallable, Category = "Game")
void BackToMenu();
UFUNCTION(BlueprintCallable, Category = "Game")
bool IsHost() const;
// Called when the local player enters the lobby menu & state
void OnLobbyEnter();
// When this menu needs to be hidden
UFUNCTION(BlueprintImplementableEvent)
void OnShow();
// When this menu needs to be shown
UFUNCTION(BlueprintImplementableEvent)
void OnHide();
UPROPERTY(EditDefaultsOnly, Category = "Lobby")
TSubclassOf<class ULobbySlot> lobbySlotClass;
UFUNCTION(BlueprintCallable, Category = "Lobby")
TArray<FCharacterSave> GetCharacterSaves();
private:
ULobbyMenu(const FObjectInitializer& init);
UPROPERTY()
class APlayerStateBase* m_myState;
UPROPERTY()
TArray<class ULobbySlot*> m_lobbySlots;
UPROPERTY()
class USubMenu* m_teamContainer;
uint32 m_numTeams;
TArray<FCharacterSave> m_characters;
};

View File

@@ -0,0 +1,4 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "LobbyPlayerSlot.h"

View File

@@ -0,0 +1,16 @@
// Project Lab - NHTV Igad
#pragma once
#include "GUI/PlayerSlot.h"
#include "PlayerSlot.h"
#include "LobbyPlayerSlot.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ULobbyPlayerSlot : public UPlayerSlot
{
GENERATED_BODY()
};

View File

@@ -0,0 +1,125 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "LobbySlot.h"
#include "LobbyPlayerSlot.h"
#include "PlayerStateBase.h"
#include "PlayerControllerBase.h"
#include "SubMenu.h"
#include "MenuScreenBase.h"
#include "GameStateBase.h"
ULobbySlot::ULobbySlot(const FObjectInitializer& init)
: Super(init)
{
}
void ULobbySlot::NativeConstruct()
{
Super::NativeConstruct();
m_open = false;
}
void ULobbySlot::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
Super::NativeTick(MyGeometry, InDeltaTime);
this->bIsEnabled = m_open;
}
void ULobbySlot::SetTeamIndex(uint32 idx)
{
m_teamIndex = idx;
m_UpdateTeamTitle();
}
void ULobbySlot::m_UpdateTeamTitle()
{
// Set the title of this team slot
if (m_teamName)
{
std::wstring teamName = std::wstring() + L"Team " + m_teamIndex + L" (" + m_players.Num() + L"/2)";
SetButtonText(FString(teamName.c_str()));
}
}
void ULobbySlot::UpdatePlayers(TArray<APlayerStateBase*> players)
{
check(m_playerList);
check(m_playerSlots.Num() == 2);
UWorld* const world = GetWorld();
check(world);
APlayerControllerBase* player = Cast<APlayerControllerBase>(world->GetGameInstance()->GetFirstLocalPlayerController());
check(player);
APlayerStateBase* myState = Cast<APlayerStateBase>(player->PlayerState);
// Set all the player slots in this team to show their respective player / no player placeholder
m_players = players;
for (int32 i = 0; i < 2; i++)
{
if (i < m_players.Num())
{
APlayerStateBase* player = players[i];
m_playerSlots[i]->Init(player, player == myState);
}
else
{
m_playerSlots[i]->Init(nullptr);
}
}
m_UpdateTeamTitle();
}
bool ULobbySlot::OnSlotSelected()
{
UWorld* const world = GetWorld();
check(world);
APlayerControllerBase* player = Cast<APlayerControllerBase>(world->GetGameInstance()->GetFirstLocalPlayerController());
check(player);
APlayerStateBase* myState = Cast<APlayerStateBase>(player->PlayerState);
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
if (myState->GetReadyState())
return false;
if (gameState)
{
auto pbt = gameState->GetPlayersByTeam();
if (m_teamIndex < (uint32)pbt.Num() && pbt[m_teamIndex].Num() == 2)
{
return false;
}
}
// Try for the local player to join this team
if (myState) // Check the state cause it can be null
myState->RequestTeamEntry(m_teamIndex);
else
GWERROR(L"Player not set in " + GetName());
// Make sure this item is now selected
GetSubMenu()->SelectNewItem(this);
return true;
}
void ULobbySlot::Init(UTextBlock* teamName, UVerticalBox* playerList)
{
m_teamName = teamName;
m_playerList = playerList;
// Add fixed 2 player slots to this team
m_playerList->ClearChildren();
for (int32 i = 0; i < 2; i++)
{
ULobbyPlayerSlot* playerSlot = CreateWidget<ULobbyPlayerSlot>(GetWorld(), lobbyPlayerSlotClass);
check(playerSlot);
playerSlot->Init(nullptr);
m_playerSlots.Add(playerSlot);
m_playerList->AddChild(playerSlot);
}
}
void ULobbySlot::SetState(bool open)
{
m_open = open;
}

View File

@@ -0,0 +1,55 @@
// Project Lab - NHTV Igad
#pragma once
#include "Blueprint/UserWidget.h"
#include "MenuButton.h"
#include <set>
#include "LobbySlot.generated.h"
UCLASS()
class UNREALPROJECT_API ULobbySlot : public UMenuButton
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
void SetTeamIndex(uint32 idx);
// Must be called from blueprint to setup this element
UFUNCTION(BlueprintCallable, Category = "Lobby")
void Init(UTextBlock* teamName, UVerticalBox* playerList);
void UpdatePlayers(TArray<class APlayerStateBase*> players);
void SetState(bool open);
UFUNCTION(BlueprintCallable, Category = "Lobby")
bool OnSlotSelected();
UPROPERTY(EditDefaultsOnly, Category = "Lobby")
UFont* font;
UPROPERTY(EditDefaultsOnly, Category="Lobby")
TSubclassOf<class ULobbyPlayerSlot> lobbyPlayerSlotClass;
private:
ULobbySlot(const FObjectInitializer& init);
void m_UpdateTeamTitle();
UPROPERTY()
UTextBlock* m_teamName;
UPROPERTY()
UVerticalBox* m_playerList;
UPROPERTY()
TArray<class ULobbyPlayerSlot*> m_playerSlots;
UPROPERTY()
UButton* m_joinButton;
uint32 m_teamIndex;
UPROPERTY()
TArray<class APlayerStateBase*> m_players;
bool m_open;
};