Where are you supposed to put game logic in multiplayer?

I dont understand it. GameModes dont exist in multiplayer. Im trying to create an enemy spawn actor that just spawns enemies and I thought it was GameMode to GameState because that’s what I found on google but I just dont understand. My UE_LOG’s all dont post in multiplayer either.

Ex: this is my game mode :

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

#include "FPSGameMode.h"
#include "Engine/Engine.h"
#include "FPSHUD.h"
#include "FPSCharacter.h"
#include "Zombie.h"
#include "EnemySpawner.h"
#include "UObject/ConstructorHelpers.h"
#include "FPSGameState.h"
AFPSGameMode::AFPSGameMode()
{
	// set default pawn class to our Blueprinted character
	static ConstructorHelpers::FClassFinder<APawn> PlayerPawnClassFinder(TEXT("/Game/Blueprints/BP_Player"));
	DefaultPawnClass = PlayerPawnClassFinder.Class;

	// use our custom HUD class
	HUDClass = AFPSHUD::StaticClass();
}

int32 AFPSGameMode::SetMaxEnemies(int enemies)
{
	maxEnemies += enemies;
	return maxEnemies;
}

int32 AFPSGameMode::GetMaxEnemies()
{
	return maxEnemies;
}

void AFPSGameMode::SpawnEnemy()
{
	//fix
	AEnemySpawner* ESpawner = Cast<AEnemySpawner>(EnemySpawner);
	FActorSpawnParameters SpawnParams;

	/*if (ESpawner) {
		FVector Loc = ESpawner->GetActorLocation();
		GetWorld()->SpawnActor<AZombie>(Zombie, Loc, FRotator(0, 0, 0), SpawnInfo);
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("SPAWNED")));
	}
	else {
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("SPAWNED FAILED")));
		return;

			GetWorld()->SpawnActor<AZombie>(Zombie, FVector(0, 0, 0), FRotator(0, 0, 0), SpawnParams);
	GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("SPAWNED")));
	}*/
	if (HasAuthority()) {
		if (AFPSGameState* gs = GetGameState<AFPSGameState>()) {
			GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("GS PASS")));
			gs->SpawnEnemy();
		}
	}
	
	

}

void AFPSGameMode::BeginPlay()
{
	Super::BeginPlay();

	if (!Zombie) {
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("ZOMBIE FAILED")));
	}
	else {
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("ZOMBIE SUCCESS")));
	}

	if (!EnemySpawner) {
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("ENEMY SPAWNER FAILED")));
	}
	else {
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("ENEMY SPAWNER SUCCESS")));
	}

	if (HasAuthority()) {
		SetMaxEnemies(10);

		if (CurrentZombies < GetMaxEnemies()) {
			GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("SPAWN ZOMBIE")));
			SpawnEnemy();
		}
	}
	else {
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("NO AUTH")));

	}
}

function spawn enemy is just a UE_LOG to print out its working or not. Nothing shows. As you can see i switched to GEngine but that doesnt seem right. Where can I put basic game logic?

GameMode exists only on the server/host. So all those debug messages will only show up on the server/host. If you play as listen server, you’d probably see the messages. If you’re client, then the server is hidden in its own world in the editor.

It really depends on what you’re trying to achieve. If the spawn manager needs to only exist on the server, then you can stick it in the game mode. It would spawn enemy actors that are replicated, and those show up on the player side.

If you need players to know about some values, like max count or a timer or something, then you push those values in the Gamestate and mark them as replicated. Or use RPCs in the Gamestate.

You could also stick its own actor in the world. The server would own it and it replicates values and RPCs down to the players for whatever it is you need player side, like max count or a timer or whatever. Just be sure to flag the actor as Replicating and probably “Always Relevant” so it doesn’t matter where it exists in the world physically. And any server/host logic like actually spawning enemies, you have the Authority checks all the same.

Okay thank you for responding and confirming! I had to take a break but I will try again and see what happens.