Files
Ultimate-Fishing-Simulator-…/Assets/Scripts/Assembly-CSharp/MultiplayerManager.cs
2026-03-04 09:37:33 +08:00

400 lines
11 KiB
C#

using System;
using System.Linq;
using FishNet.Managing;
using FishNet.Object;
using FishNet.Transporting;
using FishNet.Transporting.Tugboat;
using FishySteamworks;
using Michsky.LSS;
using Michsky.UI.Heat;
using Obvious.Soap;
using QFSW.QC;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MultiplayerManager : MonoBehaviour
{
public enum State
{
Offline = 0,
EnteringMap = 1,
EnteringSession = 2,
InSession = 3,
HostChange = 4,
LeavingSession = 5
}
[SerializeField]
private ScriptableLobbyDataVariable scriptable_variable_LobbyData;
[SerializeField]
private ScriptableEventNoParam onLobbyReadyClick;
[SerializeField]
private ScriptableEventNoParam onServerDisconnectClick;
[SerializeField]
private ScriptableEventNoParam OnConnectionLost;
[SerializeField]
private ScriptableEventNoParam OnConnectionTimeout;
[SerializeField]
private ScriptableEventNoParam OnLeavingServer;
[Tooltip("Time (in seconds) allowed for connection attempts before showing a warning popup")]
[SerializeField]
private float connectAttemptWarning = 10f;
[Tooltip("Time (in seconds) allowed for connection attempts before closing multiplayer and kicking the player")]
[SerializeField]
private float connectAttemptKick = 15f;
private State state;
private LocalConnectionState serverConnectionState;
private LocalConnectionState clientConnectionState;
private float connectAttemptTimer;
private bool connectAttemptWarningDisplayed;
private bool isDebugHostRunning;
private bool isDebugClientRunning;
private NetworkManager NetworkManager => NetworkManager.Instances[0];
public static event Action OnOffline;
public static event Action OnEnteringMap;
public static event Action OnEnteringSession;
public static event Action OnInSession;
public static event Action OnHostChange;
public static event Action OnLeaveingSession;
private void OnLobbyReadyClick_OnRaised()
{
if (state != State.Offline || !scriptable_variable_LobbyData.Value.IsValid)
{
return;
}
ChapterManager chapterManager = UnityEngine.Object.FindFirstObjectByType<ChapterManager>(FindObjectsInactive.Include);
if (!chapterManager)
{
return;
}
if (scriptable_variable_LobbyData.Value.GetMetadata().TryGetValue("Map", out var mapName) && !string.IsNullOrEmpty(mapName))
{
ChangeState(State.EnteringMap);
chapterManager.chapters.FirstOrDefault((ChapterManager.ChapterItem c) => c.chapterID == mapName)?.onPlay?.Invoke();
}
}
private void OnServerDisconnectClick_OnRaised()
{
if (state != State.Offline && state != State.LeavingSession)
{
if (scriptable_variable_LobbyData.Value.IsValid)
{
scriptable_variable_LobbyData.Value.Leave();
}
OnLeavingServer.Raise();
ChangeState(State.LeavingSession);
}
}
private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs state)
{
serverConnectionState = state.ConnectionState;
}
private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs state)
{
clientConnectionState = state.ConnectionState;
}
private void OnEnable()
{
onLobbyReadyClick.OnRaised += OnLobbyReadyClick_OnRaised;
onServerDisconnectClick.OnRaised += OnServerDisconnectClick_OnRaised;
NetworkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState;
NetworkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState;
}
private void OnDisable()
{
onLobbyReadyClick.OnRaised -= OnLobbyReadyClick_OnRaised;
onServerDisconnectClick.OnRaised -= OnServerDisconnectClick_OnRaised;
NetworkManager.ServerManager.OnServerConnectionState -= ServerManager_OnServerConnectionState;
NetworkManager.ClientManager.OnClientConnectionState -= ClientManager_OnClientConnectionState;
}
private void Update()
{
TransitionTo_Offline();
TransitionTo_EnteringSession();
SetHostAndClientConnection();
TransitionTo_InSession();
TransitionTo_HostChange();
TransitionTo_LeavingSession();
}
[Command("start-host", "Used to test multiplayer in two editor instances on the same machine.", Platform.AllPlatforms, MonoTargetType.Single)]
public void StartHost()
{
if (state == State.Offline && IsMapSceneLoaded() && IsServerFullyDisconnected() && IsClientFullyDisconnected() && !isDebugHostRunning && !isDebugClientRunning)
{
isDebugHostRunning = true;
global::FishySteamworks.FishySteamworks component = NetworkManager.GetComponent<global::FishySteamworks.FishySteamworks>();
Tugboat component2 = NetworkManager.GetComponent<Tugboat>();
component.enabled = false;
component2.enabled = true;
NetworkManager.TransportManager.Transport = component2;
NetworkManager.ServerManager.StartConnection();
NetworkManager.ClientManager.StartConnection();
ChangeState(State.EnteringSession);
}
}
[Command("start-client", "Used to test multiplayer in two editor instances on the same machine.", Platform.AllPlatforms, MonoTargetType.Single)]
public void StartClient()
{
if (state == State.Offline && IsMapSceneLoaded() && IsServerFullyDisconnected() && IsClientFullyDisconnected() && !isDebugHostRunning && !isDebugClientRunning)
{
isDebugClientRunning = true;
global::FishySteamworks.FishySteamworks component = NetworkManager.GetComponent<global::FishySteamworks.FishySteamworks>();
Tugboat component2 = NetworkManager.GetComponent<Tugboat>();
component.enabled = false;
component2.enabled = true;
NetworkManager.TransportManager.Transport = component2;
NetworkManager.ClientManager.StartConnection();
ChangeState(State.EnteringSession);
}
}
[Command("stop-host-client", "Used to test multiplayer in two editor instances on the same machine.", Platform.AllPlatforms, MonoTargetType.Single)]
public void StopHostClient()
{
if (state == State.InSession && (isDebugHostRunning || isDebugClientRunning))
{
isDebugHostRunning = false;
isDebugClientRunning = false;
if (NetworkManager.IsServerStarted)
{
NetworkManager.ServerManager.StopConnection(sendDisconnectMessage: true);
}
if (NetworkManager.IsClientStarted)
{
NetworkManager.ClientManager.StopConnection();
}
ChangeState(State.Offline);
}
}
private void TransitionTo_Offline()
{
if (state == State.LeavingSession)
{
StopFishNet();
if (scriptable_variable_LobbyData.Value.IsValid)
{
scriptable_variable_LobbyData.Value.Leave();
}
connectAttemptTimer = 0f;
connectAttemptWarningDisplayed = false;
ChangeState(State.Offline);
}
}
private void TransitionTo_EnteringSession()
{
if (state == State.EnteringMap && IsMapSceneLoaded())
{
ChangeState(State.EnteringSession);
}
}
private void SetHostAndClientConnection()
{
if ((state == State.EnteringSession || state == State.HostChange) && IsMapSceneLoaded() && scriptable_variable_LobbyData.Value.IsValid && IsServerFullyDisconnected() && IsClientFullyDisconnected())
{
NetworkManager.GetComponent<global::FishySteamworks.FishySteamworks>().SetClientAddress(scriptable_variable_LobbyData.Value.Owner.user.id.ToString());
Debug.Log("(MultiplayerManager) Starting connection to host ID: " + scriptable_variable_LobbyData.Value.Owner.user.id.ToString());
if (scriptable_variable_LobbyData.Value.IsOwner)
{
NetworkManager.ServerManager.StartConnection();
NetworkManager.ClientManager.StartConnection();
}
else
{
NetworkManager.ClientManager.StartConnection();
}
}
}
private void TransitionTo_InSession()
{
if ((state != State.EnteringSession && state != State.HostChange) || !IsMapSceneLoaded())
{
return;
}
bool num = NetworkManager.IsClientStarted && IsClientFullyConnected();
bool flag = !NetworkManager.IsServerStarted || IsServerFullyConnected();
if (num && flag)
{
NetworkObject firstObject = NetworkManager.ClientManager.Connection.FirstObject;
if (firstObject != null && firstObject.TryGetComponent<FishNetSpawnerProxy>(out var component) && component.ClientStarted)
{
ChangeState(State.InSession);
}
}
}
private void TransitionTo_HostChange()
{
if (state == State.InSession && !IsClientFullyConnected())
{
StopFishNet();
ChangeState(State.HostChange);
}
}
private void TransitionTo_LeavingSession()
{
if (state == State.EnteringSession || state == State.HostChange)
{
connectAttemptTimer += Time.deltaTime;
}
else
{
connectAttemptTimer = 0f;
}
if (state == State.EnteringSession || state == State.InSession || state == State.HostChange)
{
if (connectAttemptTimer >= connectAttemptWarning && !connectAttemptWarningDisplayed)
{
OnConnectionTimeout.Raise();
connectAttemptWarningDisplayed = true;
}
else if (connectAttemptTimer >= connectAttemptKick)
{
OnConnectionLost.Raise();
ChangeState(State.LeavingSession);
}
else if (!IsMapSceneLoaded() || IsLobbyInvalid())
{
OnConnectionLost.Raise();
ChangeState(State.LeavingSession);
}
}
bool IsLobbyInvalid()
{
if (!scriptable_variable_LobbyData.Value.IsValid && !isDebugHostRunning)
{
return !isDebugClientRunning;
}
return false;
}
}
private bool IsMapSceneLoaded()
{
bool result = false;
Scene activeScene = SceneManager.GetActiveScene();
if (LSS_LoadingScreen.instance == null && activeScene.isLoaded && !activeScene.name.Equals("Main Menu") && !activeScene.name.Equals("Gameplay"))
{
result = true;
}
return result;
}
private bool IsServerFullyDisconnected()
{
if (!NetworkManager.IsServerStarted)
{
if (serverConnectionState != 0)
{
return serverConnectionState == LocalConnectionState.Stopped;
}
return true;
}
return false;
}
private bool IsServerFullyConnected()
{
if (NetworkManager.IsServerStarted)
{
return serverConnectionState == LocalConnectionState.Started;
}
return false;
}
private bool IsClientFullyDisconnected()
{
if (!NetworkManager.IsClientStarted)
{
if (clientConnectionState != 0)
{
return clientConnectionState == LocalConnectionState.Stopped;
}
return true;
}
return false;
}
private bool IsClientFullyConnected()
{
if (NetworkManager.IsClientStarted)
{
return clientConnectionState == LocalConnectionState.Started;
}
return false;
}
private void StopFishNet()
{
if (NetworkManager.IsClientStarted)
{
NetworkManager.ClientManager.StopConnection();
}
if (NetworkManager.IsServerStarted)
{
NetworkManager.ServerManager.StopConnection(sendDisconnectMessage: true);
}
}
private void ChangeState(State newState)
{
Debug.Log($"(MultiplayerManager) Change state to {newState}");
state = newState;
switch (state)
{
case State.Offline:
MultiplayerManager.OnOffline?.Invoke();
break;
case State.EnteringMap:
MultiplayerManager.OnEnteringMap?.Invoke();
break;
case State.EnteringSession:
MultiplayerManager.OnEnteringSession?.Invoke();
break;
case State.InSession:
MultiplayerManager.OnInSession?.Invoke();
break;
case State.HostChange:
MultiplayerManager.OnHostChange?.Invoke();
break;
case State.LeavingSession:
MultiplayerManager.OnLeaveingSession?.Invoke();
break;
}
}
}