using System;
using System.Linq;
using Unity.MegaCity.Traffic;
using Unity.NetCode;
using Unity.Networking.Transport;
using UnityEngine;
namespace Unity.MegaCity.UI
{
///
/// Save bool parameters such as SkipMenu or QuitAfterFlyover,
/// These parameters are reading during the execution.
/// These parameters can be writing using command line.
///
public class ExecutionOptions
{
public bool SkipMenu { get; }
public bool QuitAfterFlyover { get; }
public bool IsThinClient => TargetThinClientWorldCount > 0;
public NetworkEndpoint UserSpecifiedEndpoint { get; }
public int TargetThinClientWorldCount { get; }
public int MaxCarCount { get; }
public ExecutionOptions(bool skipMenu, bool quitAfterFlyover, NetworkEndpoint userSpecifiedEndpoint,
int targetThinClientWorldCount, int maxCarCount)
{
Console.WriteLine($"Creating execution options: skipMenu {skipMenu}, quitAfterFlyover {quitAfterFlyover}");
SkipMenu = skipMenu;
QuitAfterFlyover = quitAfterFlyover;
UserSpecifiedEndpoint = userSpecifiedEndpoint;
TargetThinClientWorldCount = targetThinClientWorldCount;
MaxCarCount = maxCarCount;
}
}
///
/// This is a execution code to run via command line,
/// This writes if the execution should skip the menu and close the execution after flyover the scene.
///
public static class ModeBootstrap
{
private const string RunFlyoverAndExitSwitch = "--run-flyover-and-exit";
private const string ThinClientsEnabled = "--enable-thin-clients";
private const string MaxCars = "--max-cars";
private const string MultiversePort = "-port";
private const string MultiverseServerIp = "0.0.0.0";
public static ExecutionOptions Options => m_Options ??= CreateOptions();
private static ExecutionOptions m_Options;
private static ExecutionOptions CreateOptions()
{
var commandLineArgs = Environment.GetCommandLineArgs();
var isAutomatedFlyOver = commandLineArgs.Contains(RunFlyoverAndExitSwitch);
ParseThinClientArgs(commandLineArgs, out var userSpecifiedEndpoint, out var userSpecifiedNumThinClients);
ParseMaxCarCountArgs(commandLineArgs, out var maxCarCount);
ParseMultiverseEndpoint(commandLineArgs, out userSpecifiedEndpoint);
return new ExecutionOptions(isAutomatedFlyOver, isAutomatedFlyOver, userSpecifiedEndpoint,
userSpecifiedNumThinClients, maxCarCount);
}
private static void ParseThinClientArgs(string[] commandLineArgs, out NetworkEndpoint userSpecifiedEndpoint,
out int userSpecifiedNumThinClients)
{
var hardcodedFallbackAddress = NetCodeBootstrap.MegaCityServerIp;
userSpecifiedEndpoint = hardcodedFallbackAddress;
userSpecifiedNumThinClients = 0;
var indexOfThinClientCount = Array.IndexOf(commandLineArgs, ThinClientsEnabled);
var hasThinClientSpecified = indexOfThinClientCount != -1;
if (!Application.isBatchMode)
{
if (hasThinClientSpecified)
Debug.LogWarning(
$"Warning: Commandline arg {ThinClientsEnabled} specified, but not running headless!");
}
// No ThinClientsEnabled arg specified. ThinClients are disabled.
if (!hasThinClientSpecified)
return;
var indexOfEndpointString = indexOfThinClientCount + 1;
if (indexOfEndpointString < commandLineArgs.Length)
{
var endpointString = commandLineArgs[indexOfEndpointString];
var port = ClientServerBootstrap.AutoConnectPort != 0
? ClientServerBootstrap.AutoConnectPort
: hardcodedFallbackAddress.Port;
if (!NetworkEndpoint.TryParse(endpointString, port, out userSpecifiedEndpoint, NetworkFamily.Ipv4))
{
Debug.LogError(
$"Cannot parse commandline arg {indexOfEndpointString} '{endpointString}' as NetworkEndpoint (for arg '{ThinClientsEnabled}')! Using hardcoded address '{hardcodedFallbackAddress}' instead! Note that NetworkEndpoint.TryParse does not support passing in a port! The port is therefore hardcoded to '{port}'!");
userSpecifiedEndpoint = hardcodedFallbackAddress;
}
}
else
Debug.LogError(
$"Expecting an endpoint after commandline arg '{ThinClientsEnabled}' but there was none!");
var indexOfCountString = indexOfThinClientCount + 2;
if (indexOfCountString < commandLineArgs.Length)
{
var countString = commandLineArgs[indexOfCountString];
if (!int.TryParse(countString, out userSpecifiedNumThinClients))
Debug.LogError(
$"Cannot parse commandline arg {indexOfCountString} '{countString}' as int count (for arg '{ThinClientsEnabled}')!");
}
else
Debug.LogError(
$"Expecting an int after commandline arg '{ThinClientsEnabled}' (after the endpoint) but there was none!");
Debug.Log(
$"ThinClients enabled via commandline arg '{ThinClientsEnabled}': User-specified address '{userSpecifiedEndpoint}' and thin client count: '{userSpecifiedNumThinClients}'.");
}
private static void ParseMaxCarCountArgs(string[] commandLineArgs, out int maxCarCount)
{
maxCarCount = -1;
var indexOfMaxCarCount = Array.IndexOf(commandLineArgs, MaxCars);
// No MaxCars arg specified. Leaving default.
if (indexOfMaxCarCount == -1)
return;
var indexOfMaxCarInt = indexOfMaxCarCount + 1;
if (indexOfMaxCarInt >= commandLineArgs.Length)
{
Debug.LogError($"Expecting an int after commandline arg '{MaxCars}' but there was none!");
return;
}
var maxCarString = commandLineArgs[indexOfMaxCarInt];
if (!int.TryParse(maxCarString, out maxCarCount))
{
Debug.LogError(
$"Cannot parse commandline arg {indexOfMaxCarInt} '{maxCarString}' as int (for arg '{MaxCars}')! Leaving existing value.");
return;
}
Debug.Log(
$"Successfully parsed commandline arg {indexOfMaxCarCount} '{maxCarString}' as int '{maxCarCount}' (for arg '{MaxCars}')!");
}
private static void ParseMultiverseEndpoint(string[] commandlineArgs, out NetworkEndpoint multiverseEndpoint)
{
var hardcodedFallbackAddress = NetCodeBootstrap.MegaCityServerIp;
multiverseEndpoint = hardcodedFallbackAddress;
if (commandlineArgs.Length < 1)
return;
var indexOfPort = Array.IndexOf(commandlineArgs, MultiversePort);
if (indexOfPort != -1 && indexOfPort < commandlineArgs.Length)
{
var portString = commandlineArgs[indexOfPort + 1];
if (!ushort.TryParse(portString, out var portShort))
{
Debug.LogError($"Cannot parse -port arg: {portString} not a ushort!");
return;
}
if (!NetworkEndpoint.TryParse(MultiverseServerIp, portShort, out multiverseEndpoint, NetworkFamily.Ipv4))
{
Debug.LogError(
$"Cannot parse ip : port - '{MultiverseServerIp}: {portShort}' as NetworkEndpoint (for arg '{MultiversePort}')! Using hardcoded address '{hardcodedFallbackAddress}' instead!");
}
Debug.Log(
$"Using {MultiversePort} arg. Starting server in Multiverse Mode on {multiverseEndpoint.Address}");
}
else
{
#if !UNITY_EDITOR
Debug.LogWarning($"Expecting a port after commandline arg '{MultiversePort}' but there was none!");
#endif
}
}
}
}