Hello. I’m new to unreal engine.
I’m trying to run simple project as listen server. This project has custom game mode which spawns pawns for all player controllers:
FString AMyGameMode::InitNewPlayer(APlayerController* NewPlayerController, const TSharedPtr<const FUniqueNetId>& UniqueId, const FString& Options, const FString& Portal)
{
FString Result = Super::InitNewPlayer(NewPlayerController, UniqueId, Options, Portal);
UWorld* world = GetWorld();
AMyGameMode* gameMode = Cast<AMyGameMode>(world->GetAuthGameMode());
UClass* pawnClass = gameMode->PlayerPawnClass;
FActorSpawnParameters params;
params.Owner = NewPlayerController;
APawn* pawn = Cast<APawn>(world->SpawnActor(pawnClass, 0, 0, params));
NewPlayerController->Possess(pawn);
return Result;
}
This pawns is dummy pawns which are used as RTS camera controllers, so they have implementation of SetupPlayerInputComponent with input bindings.
When I’m trying to play in editor - all works fine, all players can control their pawns, but when I package the project and run it in listen mode, listen server host can’t control his pawn, though other players can.
I found that SetupPlayerInputComponent does not fired for host, though InitNewPlayer has fired.
So, why it happend? What I’m doing wrong?
Sorry for my english.
Update: I don’t know where InitNewPlayer is being called.
AMyGameMode.h
#pragma once
#include "MyTypes.h"
#include "GameFramework/GameMode.h"
#include "MyGameMode.generated.h"
/**
*
*/
UCLASS(config = Game)
class PROTECTTHE_API AMyGameMode : public AGameMode
{
GENERATED_BODY()
public:
AMyGameMode(const FObjectInitializer& ObjectInitializer);
UPROPERTY(EditAnywhere, Category = "Game Mode")
TSubclassOf<APawn> PlayerPawnClass;
/** Time before game returns to menu after finish. */
UPROPERTY(config)
int32 TimeBeforeReturnToMenu;
// Begin GameMode interface
/** Initialize the GameState actor. */
virtual void InitGameState() override;
virtual FString InitNewPlayer(APlayerController* NewPlayerController,
const TSharedPtr<const FUniqueNetId>& UniqueId,
const FString& Options,
const FString& Portal) override;
virtual void PostLogin(APlayerController* NewPlayerController) override;
/**
* Handle new player, skips pawn spawning.
* @param NewPlayer
*/
virtual void RestartPlayer(AController* NewPlayer) override;
/**
* Modify the damage we want to apply to an actor.
*
* @param Damage The damage
* @param DamagedActor The actor we wish to damage
* @param DamageEvent The event that caused the damage
* @param EventInstigator
* @param DamageCauser
*
* @returns The adjusted damage amount
*/
virtual float ModifyDamage(float Damage, AActor* DamagedActor, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) const;
// End GameMode interface
/**
* Finish the game with selected team as winner.
*
* @param InWinningTeam The team that has won.
*/
UFUNCTION(BlueprintCallable, Category = Game)
void FinishGame(ETeam InWinningTeam);
void ReturnToMenu();
protected:
/* Helper to return the current gameplay state. */
EGameplayState GetGameplayState() const;
/** Handle for efficient management of UpdateHealth timer */
FTimerHandle TimerHandle_ReturnToMenu;
};
AMyGameMode.cpp
#include "MyProject.h"
#include "MyGameMode.h"
#include "MyGameState.h"
#include "Player/MyPlayerController.h"
AMyGameMode::AMyGameMode(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
GameStateClass = AMyGameState::StaticClass();
PlayerControllerClass = AMyPlayerController::StaticClass();
if ((GEngine != nullptr) && (GEngine->GameViewport != nullptr)) {
GEngine->GameViewport->SetSuppressTransitionMessage(true);
}
}
// internal
EGameplayState AMyGameMode::GetGameplayState() const
{
return GetGameState<AMyGameState>()->GameplayState;
}
void AMyGameMode::InitGameState()
{
Super::InitGameState();
AMyGameState* const GameState = GetGameState<AMyGameState>();
if (GameState)
GameState->StartGameplayStateMachine();
}
FString AMyGameMode::InitNewPlayer(APlayerController* NewPlayerController, const TSharedPtr<const FUniqueNetId>& UniqueId, const FString& Options, const FString& Portal)
{
FString Result = Super::InitNewPlayer(NewPlayerController, UniqueId, Options, Portal);
UWorld* world = GetWorld();
AMyGameMode* gameMode = Cast<AMyGameMode>(world->GetAuthGameMode());
UClass* pawnClass = gameMode->PlayerPawnClass;
FActorSpawnParameters params;
params.Owner = NewPlayerController;
APawn* pawn = Cast<APawn>(world->SpawnActor(pawnClass, 0, 0, params));
NewPlayerController->Possess(pawn);
return Result;
}
void AMyGameMode::PostLogin(APlayerController* NewPlayerController)
{
Super::PostLogin(NewPlayerController);
}
void AMyGameMode::RestartPlayer(AController* NewPlayer)
{
AActor* const StartSpot = FindPlayerStart(NewPlayer);
if (StartSpot != nullptr) {
// initialize and start it up
InitStartSpot(StartSpot, NewPlayer);
//AMyPlayerController* const NewPC = Cast<AMyPlayerController>(NewPlayer);
//if (NewPC != nullptr)
// NewPC->SetInitialLocationAndRotation(StartSpot->GetActorLocation(), StartSpot->GetActorRotation());
} else {
UE_LOG(LogGame, Warning, TEXT("Player start not found, failed to restart player"));
}
}
float AMyGameMode::ModifyDamage(float Damage, AActor* DamagedActor, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) const
{
// no health changes after game is finished
if (GetGameplayState() == EGameplayState::Finished)
return 0.0f;
return Damage;
}
void AMyGameMode::FinishGame(ETeam InWinningTeam)
{
AMyGameState* CurrentGameState = GetGameState<AMyGameState>();
// If the game state is valid and we are still playing
if ((CurrentGameState != nullptr) && (CurrentGameState->GameplayState != EGameplayState::Finished) ) {
// tell the gamestate to wrap it up
CurrentGameState->FinishGame(InWinningTeam);
}
// Add a timer to return to main if one does not already exist.
if (GetWorldTimerManager().GetTimerRate(TimerHandle_ReturnToMenu) == -1.0f ) {
// set timer to return to the main menu
GetWorldTimerManager().SetTimer(TimerHandle_ReturnToMenu, this, &AMyGameMode::ReturnToMenu, TimeBeforeReturnToMenu, false);
}
}
void AMyGameMode::ReturnToMenu()
{
//GetWorld()->ServerTravel(FString("/Game/Maps/StrategyMenu"));
}
Update:
When I move spawning code from InitNewPlayer to PostLogin, the problem has gone. It looks like, that spawn pawns in InitNewPlayer is not a good idea.
FString AMyGameMode::InitNewPlayer(APlayerController* NewPlayerController, const TSharedPtr<const FUniqueNetId>& UniqueId, const FString& Options, const FString& Portal)
{
FString Result = Super::InitNewPlayer(NewPlayerController, UniqueId, Options, Portal);
return Result;
}
void AMyGameMode::PostLogin(APlayerController* NewPlayerController)
{
Super::PostLogin(NewPlayerController);
UWorld* world = GetWorld();
AMyGameMode* gameMode = Cast<AMyGameMode>(world->GetAuthGameMode());
UClass* pawnClass = gameMode->PlayerPawnClass;
FActorSpawnParameters params;
params.Owner = NewPlayerController;
APawn* pawn = Cast<APawn>(world->SpawnActor(pawnClass, 0, 0, params));
NewPlayerController->Possess(pawn);
}