该项目的目的是同时测试和演示来自 Unity DOTS 技术堆栈的多个新包。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

929 行
29 KiB

#define DEBUG_LOGGING
using UnityEngine;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using System;
using System.Globalization;
using SQP;
using System.Reflection;
using System.Linq;
using Unity.DebugDisplay;
using Unity.Sample.Core;
using UnityEngine.Profiling;
#if UNITY_EDITOR
using UnityEditorInternal;
using UnityEditor;
using Unity.NetCode.Editor;
#endif
public class EnumeratedArrayAttribute : PropertyAttribute
{
public readonly string[] names;
public EnumeratedArrayAttribute(Type enumtype)
{
names = Enum.GetNames(enumtype);
}
}
[ExecuteAlways]
[DisableAutoCreation]
public class ControlledEntityCameraUpdate : ManualComponentSystemGroup
{
protected override void OnUpdate()
{
Profiler.BeginSample("ControlledEntityCameraUpdate");
base.OnUpdate();
Profiler.EndSample();
}
}
[DefaultExecutionOrder(-1000)]
public class Game : MonoBehaviour
{
public delegate void UpdateDelegate();
public WeakAssetReference movableBoxPrototype;
public WeakAssetReference dotsNetCodePrefabs;
[AssetType(typeof(SoundDef))]
public WeakAssetReference soundTrackTest;
// Color scheme configurable? (cvars?)
public enum GameColor
{
Friend,
Enemy
}
[EnumeratedArray(typeof(GameColor))]
public Color[] gameColors;
public GameStatistics m_GameStatistics { get; private set; }
public interface IGameLoop
{
bool Init(string[] args);
void Shutdown();
void Update();
void FixedUpdate();
void LateUpdate();
}
public static Game game;
public event UpdateDelegate endUpdateEvent;
// Vars owned by server and replicated to clients
[ConfigVar(Name = "server.tickrate", DefaultValue = "60", Description = "Tickrate for server", Flags = ConfigVar.Flags.ServerInfo)]
public static ConfigVar serverTickRate;
// [ConfigVar(Name = "config.fov", DefaultValue = "60", Description = "Field of view", Flags = ConfigVar.Flags.Save)]
// public static ConfigVar configFov;
[ConfigVar(Name = "debug.catchloop", DefaultValue = "1", Description = "Catch exceptions in gameloop and pause game", Flags = ConfigVar.Flags.None)]
public static ConfigVar debugCatchLoop;
[ConfigVar(Name = "chartype", DefaultValue = "-1", Description = "Character to start with (-1 uses default character)")]
public static ConfigVar characterType;
[ConfigVar(Name = "allowcharchange", DefaultValue = "1", Description = "Is changing character allowed")]
public static ConfigVar allowCharChange;
[ConfigVar(Name = "debug.cpuprofile", DefaultValue = "0", Description = "Profile and dump cpu usage")]
public static ConfigVar debugCpuProfile;
[ConfigVar(Name = "net.dropevents", DefaultValue = "0", Description = "Drops a fraction of all packages containing events!!")]
public static ConfigVar netDropEvents;
[ConfigVar(Name = "show.entities", DefaultValue = "0", Description = "Entity stats")]
public static ConfigVar showEntities;
static readonly string k_UserConfigFilename = "user.cfg";
public static readonly string k_BootConfigFilename = "boot.cfg";
public UnityEngine.Audio.AudioMixer audioMixer;
public Camera bootCamera;
public LevelManager levelManager;
public SQPClient sqpClient;
public static double frameTime;
public static int frameCount;
public static bool IsHeadless()
{
return game.m_isHeadless;
}
public static int GameLoopCount
{
get { return game == null ? 0 : 1; }
}
public static T GetGameLoop<T>() where T : class
{
if (game == null)
return null;
foreach (var gameLoop in game.m_gameLoops)
{
T result = gameLoop as T;
if (result != null)
return result;
}
return null;
}
public static System.Diagnostics.Stopwatch Clock
{
get { return game.m_Clock; }
}
public string buildId
{
get { return _buildId; }
}
string _buildId = "NoBuild";
public string buildUnityVersion
{
get { return _buildUnityVersion; }
}
// Start with sensible default, but we would like to have the full build version
// which is only available in editor so we bake it into the build.
string _buildUnityVersion = Application.unityVersion;
public void RequestGameLoop(System.Type type, string[] args)
{
GameDebug.Assert(typeof(IGameLoop).IsAssignableFrom(type));
m_RequestedGameLoopTypes.Add(type);
m_RequestedGameLoopArguments.Add(args);
GameDebug.Log("Game loop " + type + " requested");
}
// Pick argument for argument(!). Given list of args return null if option is
// not found. Return argument following option if found or empty string if none given.
// Options are expected to be prefixed with + or -
public static string ArgumentForOption(List<string> args, string option)
{
var idx = args.IndexOf(option);
if (idx < 0)
return null;
if (idx < args.Count - 1)
return args[idx + 1];
return "";
}
/*
* THIS CAUSES RANDOM CRASHES
*
private static void PreLoadAnimationNodes()
{
// In Editor, convince Burst to JIT compile all Animation UNode types immediately.
#if UNITY_EDITOR
var start = UnityEngine.Time.realtimeSinceStartup;
var wasSyncCompile = Menu.GetChecked("Jobs/Burst/Synchronous Compilation");
Menu.SetChecked("Jobs/Burst/Synchronous Compilation", true);
try
{
var animAssembly = typeof(Unity.Animation.AnimationGraphSystem).Assembly;
var unodeNonGenericTypes = animAssembly.GetTypes().Where(t =>
t.IsClass && !t.IsAbstract && !t.IsGenericType &&
typeof(Unity.DataFlowGraph.INodeFunctionality).IsAssignableFrom(t));
var unodeGenericTypesReferencedInData = animAssembly.GetTypes()
.Where(t => !t.IsClass && typeof(Unity.DataFlowGraph.INodeData).IsAssignableFrom(t))
.Select(t => t
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(fi => fi.FieldType)
.Where(ft => ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Unity.DataFlowGraph.NodeHandle<>))
.Select(ft => ft.GetGenericArguments()[0])
.Where(ft => ft.IsGenericType))
.SelectMany(t => t)
.Distinct();
var nodeSet = new Unity.DataFlowGraph.NodeSet();
MethodInfo getFunctionality = nodeSet.GetType().GetMethod("GetFunctionality", new System.Type[0]);
foreach (System.Type t in unodeNonGenericTypes.Concat(unodeGenericTypesReferencedInData))
getFunctionality.MakeGenericMethod(t).Invoke(nodeSet, null);
nodeSet.Dispose();
Debug.Log($"Compilation of Animation UNode types took {UnityEngine.Time.realtimeSinceStartup - start} seconds");
}
finally
{
Menu.SetChecked("Jobs/Burst/Synchronous Compilation", wasSyncCompile);
}
#endif
}
*/
public void Awake()
{
GameDebug.Assert(game == null);
DontDestroyOnLoad(gameObject);
game = this;
GameApp.IsInitialized = true;
//PreLoadAnimationNodes();
m_StopwatchFrequency = System.Diagnostics.Stopwatch.Frequency;
m_Clock = new System.Diagnostics.Stopwatch();
m_Clock.Start();
#if UNITY_EDITOR
_buildUnityVersion = InternalEditorUtility.GetFullUnityVersion();
#endif
var buildInfo = FindObjectOfType<BuildInfo>();
if (buildInfo != null)
{
_buildId = buildInfo.buildId;
_buildUnityVersion = buildInfo.buildUnityVersion;
}
var commandLineArgs = new List<string>(System.Environment.GetCommandLineArgs());
// TODO we should only initialize this if we have a graphics device (i.e. non-headless)
Overlay.Managed.Initialize();
#if UNITY_STANDALONE_LINUX
m_isHeadless = true;
#else
m_isHeadless = commandLineArgs.Contains("-batchmode");
#endif
var noconsole = commandLineArgs.Contains("-noconsole");
var consoleRestoreFocus = commandLineArgs.Contains("-consolerestorefocus");
if (noconsole)
{
UnityEngine.Debug.Log("WARNING: starting without a console");
var consoleUI = new ConsoleNullUI();
Console.Init(buildId,buildUnityVersion, consoleUI);
}else if (m_isHeadless)
{
#if UNITY_EDITOR
Debug.LogError("ERROR: Headless mode not supported in editor");
#endif
#if UNITY_STANDALONE_WIN
string consoleTitle;
var overrideTitle = ArgumentForOption(commandLineArgs, "-title");
if (overrideTitle != null)
consoleTitle = overrideTitle;
else
consoleTitle = Application.productName + " Console";
consoleTitle += " [" + System.Diagnostics.Process.GetCurrentProcess().Id + "]";
var consoleUI = new ConsoleTextWin(consoleTitle, consoleRestoreFocus);
#elif UNITY_STANDALONE_LINUX
var consoleUI = new ConsoleTextLinux();
#else
UnityEngine.Debug.Log("WARNING: starting without a console");
var consoleUI = new ConsoleNullUI();
#endif
Console.Init(buildId,buildUnityVersion,consoleUI);
}
else
{
var consoleUI = Instantiate(Resources.Load<ConsoleGUI>("Prefabs/ConsoleGUI"));
DontDestroyOnLoad(consoleUI);
Console.Init(buildId,buildUnityVersion,consoleUI);
m_DebugOverlay = Instantiate(Resources.Load<DebugOverlay>("DebugOverlay"));
DontDestroyOnLoad(m_DebugOverlay);
m_DebugOverlay.Init();
m_GameStatistics = new GameStatistics();
}
// If -logfile was passed, we try to put our own logs next to the engine's logfile
// if -logfile was set to "-" we forward our logs to Debug.Log, so that it ends up on stdout.
var engineLogFileLocation = ".";
var logName = m_isHeadless ? "game_" + DateTime.UtcNow.ToString("yyyyMMdd_HHmmss_fff") : "game";
var logfileArgIdx = commandLineArgs.IndexOf("-logfile");
var forceForwardToDebug = false;
if (logfileArgIdx >= 0 && commandLineArgs.Count >= logfileArgIdx)
{
var logFile = commandLineArgs[logfileArgIdx + 1];
if (logFile == "-")
forceForwardToDebug = true;
else
engineLogFileLocation = System.IO.Path.GetDirectoryName(logFile);
}
GameDebug.Init(engineLogFileLocation, logName, forceForwardToDebug);
ConfigVar.Init();
// Support -port and -query_port as per Multiplay standard
var serverPort = ArgumentForOption(commandLineArgs, "-port");
if (serverPort != null)
Console.EnqueueCommandNoHistory("server.port " + serverPort);
var sqpPort = ArgumentForOption(commandLineArgs, "-query_port");
if (sqpPort != null)
Console.EnqueueCommandNoHistory("server.sqp_port " + sqpPort);
Console.EnqueueCommandNoHistory("exec -s " + k_UserConfigFilename);
// Default is to allow no frame cap, i.e. as fast as possible if vsync is disabled
Application.targetFrameRate = -1;
if (m_isHeadless)
{
Application.targetFrameRate = serverTickRate.IntValue;
QualitySettings.vSyncCount = 0; // Needed to make targetFramerate work; even in headless mode
#if !UNITY_STANDALONE_LINUX
if (!commandLineArgs.Contains("-nographics"))
GameDebug.Log("WARNING: running -batchmod without -nographics");
#endif
}
else
{
RenderSettings.Init();
}
// Out of the box game behaviour is driven by boot.cfg unless you ask it not to
if (!commandLineArgs.Contains("-noboot"))
{
Console.EnqueueCommandNoHistory("exec -s " + k_BootConfigFilename);
}
if (m_isHeadless)
{
SoundSystem.Initialize(new SoundSystemNull());
}
else
{
var soundSystem = new SoundSystemBase();
soundSystem.Init(audioMixer);
SoundSystem.Initialize(soundSystem);
GameObject go = (GameObject)GameObject.Instantiate(Resources.Load("Prefabs/ClientFrontend", typeof(GameObject)));
UnityEngine.Object.DontDestroyOnLoad(go);
clientFrontend = go.GetComponentInChildren<ClientFrontend>();
}
sqpClient = new SQP.SQPClient();
GameDebug.Log("A2 initialized");
#if UNITY_EDITOR
GameDebug.Log("Build type: editor");
#elif DEVELOPMENT_BUILD
GameDebug.Log("Build type: development");
#else
GameDebug.Log("Build type: release");
#endif
GameDebug.Log("BuildID: " + buildId);
GameDebug.Log("Unity: " + buildUnityVersion);
GameDebug.Log("Cwd: " + System.IO.Directory.GetCurrentDirectory());
levelManager = new LevelManager();
levelManager.Init();
GameDebug.Log("LevelManager initialized");
GameDebug.Log("InputSystem initialized");
// Game loops
Console.AddCommand("serve", CmdServe, "Start server listening");
Console.AddCommand("client", CmdClient, "client: Enter client mode.");
Console.AddCommand("thinclient", CmdThinClient, "client: Enter thin client mode.");
Console.AddCommand("boot", CmdBoot, "Go back to boot loop");
Console.AddCommand("connect", CmdConnect, "connect <ip>: Connect to server on ip (default: localhost)");
Console.AddCommand("menu", CmdMenu, "show the main menu");
Console.AddCommand("load", CmdLoad, "Load level");
Console.AddCommand("quit", CmdQuit, "Quits");
Console.AddCommand("screenshot", CmdScreenshot, "Capture screenshot. Optional argument is destination folder or filename.");
Console.AddCommand("crashme", (string[] args) => { GameDebug.Assert(false); }, "Crashes the game next frame ");
Console.AddCommand("saveconfig", CmdSaveConfig, "Save the user config variables");
Console.AddCommand("loadconfig", CmdLoadConfig, "Load the user config variables");
Console.AddCommand("profile", CmdProfile, "Run the profiling for a level");
#if UNITY_STANDALONE_WIN
Console.AddCommand("windowpos", CmdWindowPosition, "Position of window. e.g. windowpos 100,100");
#endif
Console.SetOpen(true);
Console.ProcessCommandLineArguments(commandLineArgs.ToArray());
#if UNITY_IOS
// (marton) This is a hack to work around command line arguments not working on iOS
if (!Application.isEditor)
Console.EnqueueCommandNoHistory("preview Level_00");
#endif
GameApp.CameraStack.OnCameraEnabledChanged += OnCameraEnabledChanged;
GameApp.CameraStack.PushCamera(bootCamera);
}
void OnDisable()
{
GameDebug.Shutdown();
Overlay.Managed.DoShutdown();
Console.Shutdown();
game = null;
GameApp.IsInitialized = false;
InputSystem.SetMousePointerLock(false);
GameDebug.Log("A2 was shutdown");
}
bool pipeSetup = false;
public void Update()
{
if (!m_isHeadless)
RenderSettings.Update();
// TODO (petera) remove this hack once we know exactly when renderer is available...
if (!pipeSetup)
{
var hdpipe = RenderPipelineManager.currentPipeline as HDRenderPipeline;
if (hdpipe != null)
{
var layer = LayerMask.NameToLayer("PostProcess Volumes");
if (layer == -1)
GameDebug.LogWarning("Unable to find layer mask for camera fader");
else
{
var gameObject = new GameObject()
{
name = "Game Quick Volume",
layer = layer,
hideFlags = HideFlags.HideAndDontSave
};
m_ExposureVolume = gameObject.AddComponent<Volume>();
m_ExposureVolume.priority = 100.0f;
m_ExposureVolume.isGlobal = true;
var profile = m_ExposureVolume.profile;
m_Exposure = profile.Add<Exposure>();
m_Exposure.active = false;
m_Exposure.mode.Override(ExposureMode.Automatic);
m_Exposure.compensation.Override(0);
}
pipeSetup = true;
}
}
if (m_ExposureReleaseCount > 0)
{
m_ExposureReleaseCount--;
if (m_ExposureReleaseCount == 0)
BlackFade(false);
}
GameApp.CameraStack.Update();
#if UNITY_EDITOR
// Ugly hack to force focus to game view when using scriptable renderloops.
if (Time.frameCount < 4)
{
try
{
var gameViewType = typeof(UnityEditor.EditorWindow).Assembly.GetType("UnityEditor.GameView");
var gameView = (EditorWindow)Resources.FindObjectsOfTypeAll(gameViewType)[0];
gameView.Focus();
}
catch (System.Exception) { /* too bad */ }
}
#endif
frameTime = (double)m_Clock.ElapsedTicks / m_StopwatchFrequency;
frameCount = Time.frameCount;
GameDebug.SetFrameCount(frameCount);
Console.SetFrameTime(frameTime);;
// Switch game loop if needed
if (m_RequestedGameLoopTypes.Count > 0)
{
// Multiple running gameloops only allowed in editor
#if !UNITY_EDITOR
ShutdownGameLoops();
#endif
bool initSucceeded = false;
for (int i = 0; i < m_RequestedGameLoopTypes.Count; i++)
{
try
{
IGameLoop gameLoop = (IGameLoop)System.Activator.CreateInstance(m_RequestedGameLoopTypes[i]);
initSucceeded = gameLoop.Init(m_RequestedGameLoopArguments[i]);
Debug.Log("Game initialization succeeded: " + initSucceeded);
if (!initSucceeded)
break;
m_gameLoops.Add(gameLoop);
}
catch (System.Exception e)
{
GameDebug.LogError(string.Format("Game loop initialization threw exception : ({0})\n{1}", e.Message, e.StackTrace));
}
}
if (!initSucceeded)
{
ShutdownGameLoops();
GameDebug.LogError("Game loop initialization failed ... reverting to boot loop");
}
m_RequestedGameLoopTypes.Clear();
m_RequestedGameLoopArguments.Clear();
}
try
{
if (!m_ErrorState)
{
foreach (var gameLoop in m_gameLoops)
{
gameLoop.Update();
}
levelManager.Update();
}
}
catch (System.Exception e)
{
HandleGameloopException(e);
throw;
}
if (SoundSystem.Instance != null)
SoundSystem.Instance.Update();
if (clientFrontend != null)
clientFrontend.UpdateGame();
Console.ConsoleUpdate();
bool menusShowing = (clientFrontend != null && clientFrontend.menuShowing != ClientFrontend.MenuShowing.None);
InputSystem.WindowFocusUpdate(menusShowing);
UpdateCPUStats();
UpdateEntityStats();
sqpClient.Update();
endUpdateEvent?.Invoke();
/* HACKY WAY TO LOOK AT MONOBEHAVIOURS LEFT
if (Time.frameCount % 1000 == 100)
{
var mbs = FindObjectsOfType(typeof(MonoBehaviour));
numMBS = mbs.Length;
var h = new HashSet<Type>();
foreach (var mb in mbs)
{
h.Add(mb.GetType());
}
foreach(var t in h)
GameDebug.Log(":" + t);
numUMBS = h.Count();
}
Overlay.Managed.Write(2, 4, "Monobehaviours left {0} ({1})", numMBS, numUMBS);
*/
}
//int numMBS = 0;
//int numUMBS = 0;
bool m_ErrorState;
public void FixedUpdate()
{
foreach (var gameLoop in m_gameLoops)
{
gameLoop.FixedUpdate();
}
}
public void LateUpdate()
{
try
{
if (!m_ErrorState)
{
foreach (var gameLoop in m_gameLoops)
{
gameLoop.LateUpdate();
}
Console.ConsoleLateUpdate();
}
}
catch (System.Exception e)
{
HandleGameloopException(e);
throw;
}
if (m_GameStatistics != null)
m_GameStatistics.TickLateUpdate();
if (m_DebugOverlay != null)
m_DebugOverlay.TickLateUpdate();
Unity.DebugDisplay.Overlay.Managed.instance.TickLateUpdate();
}
void OnApplicationQuit()
{
ShutdownGameLoops();
}
void BlackFade(bool enabled)
{
if (m_Exposure != null)
m_Exposure.active = enabled;
}
void OnCameraEnabledChanged(Camera camera, bool enabled)
{
if (enabled)
RenderSettings.UpdateCameraSettings(camera);
var audioListener = camera.GetComponent<AudioListener>();
if (audioListener != null)
{
audioListener.enabled = enabled;
if (SoundSystem.Instance != null)
SoundSystem.Instance.SetCurrentListener(enabled ? audioListener : null);
}
if(enabled)
m_ExposureReleaseCount = 10;
}
float m_NextCpuProfileTime = 0;
double m_LastCpuUsage = 0;
double m_LastCpuUsageUser = 0;
void UpdateCPUStats()
{
if (debugCpuProfile.IntValue > 0)
{
if (Time.time > m_NextCpuProfileTime)
{
const float interval = 5.0f;
m_NextCpuProfileTime = Time.time + interval;
var process = System.Diagnostics.Process.GetCurrentProcess();
var user = process.UserProcessorTime.TotalMilliseconds;
var total = process.TotalProcessorTime.TotalMilliseconds;
float userUsagePct = (float)(user - m_LastCpuUsageUser) / 10.0f / interval;
float totalUsagePct = (float)(total - m_LastCpuUsage) / 10.0f / interval;
m_LastCpuUsage = total;
m_LastCpuUsageUser = user;
GameDebug.Log(string.Format("CPU Usage {0}% (user: {1}%)", totalUsagePct, userUsagePct));
}
}
}
void UpdateEntityStats()
{
if (showEntities.IntValue <= 0)
return;
int y = 10;
var aw = World.AllWorlds;
Overlay.Managed.Write(2, y++, "Worlds: {0}", aw.Count);
foreach(var w in aw)
{
Overlay.Managed.Write(3, y++, "{0}: {1} ents {2} sys", w.Name, w.EntityManager.UniversalQuery.CalculateEntityCountWithoutFiltering(), w.Systems.Count<ComponentSystemBase>());
}
}
public void LoadLevel(string levelname)
{
if (!Game.game.levelManager.CanLoadLevel(levelname))
{
GameDebug.Log("ERROR : Cannot load level : " + levelname);
return;
}
Game.game.levelManager.LoadLevel(levelname);
}
void UnloadLevel()
{
// TODO
}
void HandleGameloopException(System.Exception e)
{
if (debugCatchLoop.IntValue > 0)
{
GameDebug.Log("EXCEPTION " + e.Message + "\n" + e.StackTrace);
Console.SetOpen(true);
m_ErrorState = true;
}
}
string FindNewFilename(string pattern)
{
for (var i = 0; i < 10000; i++)
{
var f = string.Format(pattern, i);
if (System.IO.File.Exists(string.Format(pattern, i)))
continue;
return f;
}
return null;
}
void ShutdownGameLoops()
{
foreach (var gameLoop in m_gameLoops)
gameLoop.Shutdown();
m_gameLoops.Clear();
}
void CmdServe(string[] args)
{
RequestGameLoop(typeof(ServerGameLoop) , args);
Console.s_PendingCommandsWaitForFrames = 1;
}
void CmdLoad(string[] args)
{
LoadLevel(args[0]);
Console.SetOpen(false);
}
void CmdProfile(string[] args)
{
GameDebug.Log("ProfileGameLoop not available");
return;
//RequestGameLoop(typeof(ProfileGameLoop), args);
//Console.s_PendingCommandsWaitForFrames = 1;
}
void CmdBoot(string[] args)
{
clientFrontend.ShowMenu(ClientFrontend.MenuShowing.None);
levelManager.UnloadLevel();
ShutdownGameLoops();
Console.s_PendingCommandsWaitForFrames = 1;
Console.SetOpen(true);
}
void CmdClient(string[] args)
{
RequestGameLoop(typeof(ClientGameLoop), args);
Console.s_PendingCommandsWaitForFrames = 1;
}
void CmdConnect(string[] args)
{
// Special hack to allow "connect a.b.c.d" as shorthand
if (m_gameLoops.Count == 0)
{
RequestGameLoop(typeof(ClientGameLoop), args);
Console.s_PendingCommandsWaitForFrames = 1;
return;
}
ClientGameLoop clientGameLoop = GetGameLoop<ClientGameLoop>();
ThinClientGameLoop thinClientGameLoop = GetGameLoop<ThinClientGameLoop>();
if (clientGameLoop != null)
clientGameLoop.CmdConnect(args);
else if (thinClientGameLoop != null)
thinClientGameLoop.CmdConnect(args);
else
GameDebug.Log("Cannot connect from current gamemode");
}
void CmdThinClient(string[] args)
{
RequestGameLoop(typeof(ThinClientGameLoop), args);
Console.s_PendingCommandsWaitForFrames = 1;
}
void CmdQuit(string[] args)
{
#if UNITY_EDITOR
EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
void CmdScreenshot(string[] arguments)
{
string filename = null;
var root = System.IO.Path.GetFullPath(".");
if (arguments.Length == 0)
filename = FindNewFilename(root + "/screenshot{0}.png");
else if (arguments.Length == 1)
{
var a = arguments[0];
if (System.IO.Directory.Exists(a))
filename = FindNewFilename(a + "/screenshot{0}.png");
else if (!System.IO.File.Exists(a))
filename = a;
else
{
Console.Write("File " + a + " already exists");
return;
}
}
if (filename != null)
{
GameDebug.Log("Saving screenshot to " + filename);
Console.SetOpen(false);
ScreenCapture.CaptureScreenshot(filename);
}
}
public ClientFrontend clientFrontend;
private void CmdMenu(string[] args)
{
float fadeTime = 0.0f;
ClientFrontend.MenuShowing show = ClientFrontend.MenuShowing.Main;
if (args.Length > 0)
{
if (args[0] == "0")
show = ClientFrontend.MenuShowing.None;
else if (args[0] == "2")
show = ClientFrontend.MenuShowing.Ingame;
}
if (args.Length > 1)
{
float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out fadeTime);
}
clientFrontend.ShowMenu(show, fadeTime);
Console.SetOpen(false);
}
void CmdSaveConfig(string[] arguments)
{
ConfigVar.Save(k_UserConfigFilename);
}
void CmdLoadConfig(string[] arguments)
{
Console.EnqueueCommandNoHistory("exec " + k_UserConfigFilename);
}
#if UNITY_STANDALONE_WIN
void CmdWindowPosition(string[] arguments)
{
if (arguments.Length == 1)
{
string[] cords = arguments[0].Split(',');
if (cords.Length == 2)
{
int x, y;
var xParsed = int.TryParse(cords[0], out x);
var yParsed = int.TryParse(cords[1], out y);
if (xParsed && yParsed)
{
WindowsUtil.SetWindowPosition(x, y);
return;
}
}
}
Console.Write("Usage: windowpos <x,y>");
}
#endif
List<Type> m_RequestedGameLoopTypes = new List<System.Type>();
private List<string[]> m_RequestedGameLoopArguments = new List<string[]>();
List<IGameLoop> m_gameLoops = new List<IGameLoop>();
DebugOverlay m_DebugOverlay;
bool m_isHeadless;
long m_StopwatchFrequency;
System.Diagnostics.Stopwatch m_Clock;
// Global camera handling
Exposure m_Exposure;
Volume m_ExposureVolume;
int m_ExposureReleaseCount;
}