evershade/Assets/Scripts/Managers/GameManager.cs

406 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using Data.ScriptableObjects;
using FishNet.Connection;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using Types;
using UnityEngine;
using UnityEngine.Serialization;
namespace Managers
{
public class GameManager : NetworkBehaviour
{
[SerializeField] private SaveManager saveManager;
[SerializeField] private HotkeyManager hotkeyManager;
[SerializeField] private AudioManager audioManager;
[SerializeField] private UIManager uiManager;
// person who's running the game, owner.
[FormerlySerializedAs("playerManager")] [SerializeField]
private PlayerManager ownerPlayerManager;
[SerializeField] public ItemDatabase itemDatabase;
private readonly SyncVar<int> _syncGameSeed = new(new SyncTypeSettings
{
WritePermission = WritePermission.ServerOnly,
ReadPermission = ReadPermission.Observers
});
private readonly SyncVar<GameStatus> _syncGameStatus = new(new SyncTypeSettings
{
WritePermission = WritePermission.ServerOnly,
ReadPermission = ReadPermission.Observers
});
private readonly SyncVar<GameTimeSettings> _syncGameTimeSettings = new(new SyncTypeSettings
{
WritePermission = WritePermission.ServerOnly,
ReadPermission = ReadPermission.Observers
});
private readonly SyncDictionary<int, GamePlayer> _syncPlayers = new(new SyncTypeSettings
{
WritePermission = WritePermission.ServerOnly,
ReadPermission = ReadPermission.Observers
});
private readonly SyncVar<WeatherConditions> _syncWeather = new(new SyncTypeSettings
{
WritePermission = WritePermission.ServerOnly,
ReadPermission = ReadPermission.Observers
});
public static GameManager Instance { get; set; }
private void Awake()
{
Debug.Log("Starting GameManager");
itemDatabase = Resources.Load<ItemDatabase>("GameItems/ItemDatabase");
// Players = new Dictionary<int, GamePlayer>(),
// TimeSettings = new GameTimeSettings(),
// GameStatus = GameStatus.WaitingForPlayers,
// Weather = WeatherConditions.Sunny,
_syncPlayers.OnChange += SyncPlayersChange;
_syncGameTimeSettings.OnChange += SyncGameTimeSettingsChange;
_syncGameStatus.OnChange += SyncGameStatusChange;
_syncWeather.OnChange += SyncWeatherChange;
if (Instance != null)
{
Destroy(this);
return;
}
Instance = this;
}
private void OnDestroy()
{
if (Instance == this)
Instance = null;
Debug.Log("GameManager destroyed");
}
private void SyncWeatherChange(WeatherConditions prev, WeatherConditions next, bool asserver)
{
throw new NotImplementedException();
}
private void SyncGameStatusChange(GameStatus prev, GameStatus next, bool asserver)
{
throw new NotImplementedException();
}
private void SyncGameTimeSettingsChange(GameTimeSettings prev, GameTimeSettings next, bool asserver)
{
throw new NotImplementedException();
}
private void SyncPlayersChange(SyncDictionaryOperation op, int key, GamePlayer value, bool asServer)
{
Debug.Log($"SyncPlayersChange Triggered - Operation: {op}, Key: {key}, AsServer: {asServer}");
switch (op)
{
case SyncDictionaryOperation.Add:
Debug.Log($"Player added - ID: {key}, Name: {value.PlayerName}");
// Implement logic for when a new player is added
OnPlayerAdded(key, value);
break;
case SyncDictionaryOperation.Remove:
Debug.Log($"Player removed - ID: {key}");
// Implement logic for when a player is removed
OnPlayerRemoved(key);
break;
case SyncDictionaryOperation.Clear:
Debug.Log("All players cleared");
// Implement logic for when all players are cleared
OnAllPlayersCleared();
break;
case SyncDictionaryOperation.Set:
Debug.Log($"Player updated - ID: {key}, Name: {value.PlayerName}");
// Implement logic for when a player's data is updated
OnPlayerUpdated(key, value);
break;
}
// Notify any listeners that the player list has changed
OnPlayersListChanged();
}
private void OnPlayerAdded(int playerId, GamePlayer player)
{
// Implement logic for when a new player is added
// For example, update UI, spawn player object, etc.
}
private void OnPlayerRemoved(int playerId)
{
// Implement logic for when a player is removed
// For example, remove player from UI, destroy player object, etc.
}
private void OnAllPlayersCleared()
{
// Implement logic for when all players are cleared
// For example, reset UI, clear all player objects, etc.
}
private void OnPlayerUpdated(int playerId, GamePlayer player)
{
// Implement logic for when a player's data is updated
// For example, update UI elements, update player object properties, etc.
}
private void OnPlayersListChanged()
{
// Notify any parts of your game that need to know when the player list changes
// For example, update a player list UI, recalculate game state, etc.
}
[ServerRpc(RequireOwnership = false)]
public void RegisterPlayerServerRpc(NetworkConnection conn, GamePlayer player)
{
try
{
Debug.Log(
$"Attempting to register player. Connection ID: {conn?.ClientId}, Player null?: {player == null}");
if (conn == null)
{
Debug.LogError("RegisterPlayerServerRpc: NetworkConnection is null");
return;
}
if (player == null)
{
Debug.LogError($"RegisterPlayerServerRpc: GamePlayer is null for connection {conn.ClientId}");
return;
}
if (_syncPlayers.TryAdd(conn.ClientId, player))
{
Debug.Log($"Player registered successfully: {conn.ClientId}");
OnPlayerRegisteredObserversRpc(conn.ClientId);
_syncPlayers.Dirty(conn.ClientId);
}
else
{
Debug.LogWarning($"Player with ID {conn.ClientId} is already registered");
}
}
catch (Exception e)
{
Debug.LogError($"Error in RegisterPlayerServerRpc: {e.Message}\nStack Trace: {e.StackTrace}");
}
}
[ObserversRpc]
private void OnPlayerRegisteredObserversRpc(int clientId)
{
Debug.Log($"OBS: Player with ID {clientId} has joined the game!");
// You can add any client-side logic here when a new player joins
}
public override void OnStartNetwork()
{
base.OnStartNetwork();
Debug.Log("Network started");
}
// method to handle player connections
public override void OnStartClient()
{
Debug.Log("Client connected to server");
base.OnStartClient();
if (IsServerInitialized) Instance = this;
// Server logic for new player connections
}
// get player by client id
public GamePlayer GetPlayer(int clientId)
{
// Debug.Log("Getting player: " + clientId);
if (_syncPlayers.Count == 0)
{
Debug.LogWarning("Players not yet initialized");
return null;
}
// Debug.Log("Players: " + _syncGameState.Value.Players.Count);
return _syncPlayers.GetValueOrDefault(clientId);
}
public Dictionary<int, GamePlayer> GetPlayers()
{
return (Dictionary<int, GamePlayer>)_syncPlayers.Values;
}
public override void OnStopClient()
{
base.OnStopClient();
// client specific cleanup code?
if (IsServerInitialized)
{
// server logic for disconnection
}
// client logic for disconnection
}
[ServerRpc(RequireOwnership = false)]
public void StartGameServerRpc()
{
UIManager.ShowMainMenuScreen(false);
// AudioManager.PlayMusic("MainTheme");
}
[ObserversRpc]
public void StartGameObserversRpc()
{
UIManager.ShowMainMenuScreen(false);
}
[ServerRpc(RequireOwnership = false)]
// client ot server comm? i.e client is telling the server to run this code
public void EndGameServerRpc()
{
Debug.Log("ServerRPC Game Over");
UIManager.ShowGameOverScreen(true);
// AudioManager.PlayMusic("GameOverTheme");
}
[ObserversRpc]
// server to client communication i.e server is telling the client to run this code
public void EndGameObserversRpc()
{
Debug.Log("ObserverRPC Game Over");
UIManager.ShowGameOverScreen(true);
}
public void StartGame()
{
if (IsServerInitialized)
StartGameServerRpc();
else
StartGameObserversRpc();
}
public GameTimeSettings GetTimeSettings()
{
return _syncGameTimeSettings.Value;
}
private static GameStateChange GetGameStateChanges(GameState oldState, GameState newState)
{
var changes = new GameStateChange();
// Compare players
foreach (var kvp in newState.Players)
if (!oldState.Players.TryGetValue(kvp.Key, out var oldPlayer) || !oldPlayer.Equals(kvp.Value))
changes.PlayerChanges[kvp.Key] = kvp.Value;
// Compare TimeSettings
if (!oldState.TimeSettings.Equals(newState.TimeSettings))
changes.TimeSettingsChanges = newState.TimeSettings;
// Compare GameStatus
if (oldState.GameStatus != newState.GameStatus) changes.StatusChange = newState.GameStatus;
// Compare Weather
if (oldState.Weather != newState.Weather) changes.WeatherChange = newState.Weather;
// Compare GameSeed
if (oldState.GameSeed != newState.GameSeed) changes.GameSeedChange = newState.GameSeed;
return changes;
}
[Server]
private void UpdatePlayer(int playerId, GamePlayer player)
{
Debug.Log("Updating player: " + playerId);
_syncPlayers[playerId] = player;
_syncPlayers.Dirty(playerId);
}
[Server]
private void UpdateTimeSettings(GameTimeSettings timeSettings)
{
_syncGameTimeSettings.Value = new GameTimeSettings(timeSettings);
}
[Server]
private void UpdateGameStatus(GameStatus status)
{
_syncGameStatus.Value = status;
}
[Server]
private void UpdateWeather(WeatherConditions weather)
{
_syncWeather.Value = weather;
}
[ServerRpc(RequireOwnership = false)]
public void RequestUpdatePlayerServerRpc(int playerId, GamePlayer player, NetworkConnection sender = null)
{
// Validate the request (e.g., ensure the sender is allowed to update this player)
if (sender != null && (sender.ClientId == playerId || IsServerInitialized)) UpdatePlayer(playerId, player);
}
[ServerRpc(RequireOwnership = false)]
public void RequestUpdateTimeSettingsServerRpc(GameTimeSettings timeSettings)
{
// You might want to add validation here
UpdateTimeSettings(timeSettings);
}
[ServerRpc(RequireOwnership = false)]
public void RequestUpdateGameStatusServerRpc(GameStatus status)
{
// Add validation if needed
UpdateGameStatus(status);
}
[ServerRpc(RequireOwnership = false)]
public void RequestUpdateWeatherServerRpc(WeatherConditions weather)
{
// Add validation if needed
UpdateWeather(weather);
}
public GamePlayer GetCurrentPlayer()
{
if (!IsServerInitialized && !IsClientInitialized)
{
Debug.LogError("GameManager not initialized");
return null;
}
var clientId = ClientManager.Connection.ClientId;
if (_syncPlayers.TryGetValue(clientId, out var player))
{
Debug.Log("Found player for clientId: " + clientId);
Debug.Log("Player name: " + player.PlayerName);
return player;
}
Debug.LogError("Player not found for clientId: " + clientId);
return null;
}
}
}