您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

938 行
28 KiB

#define DEBUG_LOGGING
using UnityEngine;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.HDPipeline;
using System;
using System.Globalization;
using UnityEngine.Rendering.PostProcessing;
#if UNITY_EDITOR
using UnityEditor;
#endif
public struct GameTime
{
/// <summary>Number of ticks per second.</summary>
public int tickRate
{
get { return m_tickRate; }
set
{
m_tickRate = value;
tickInterval = 1.0f / m_tickRate;
}
}
/// <summary>Length of each world tick at current tickrate, e.g. 0.0166s if ticking at 60fps.</summary>
public float tickInterval { get; private set; } // Time between ticks
public int tick; // Current tick
public float tickDuration; // Duration of current tick
public GameTime(int tickRate)
{
this.m_tickRate = tickRate;
this.tickInterval = 1.0f / m_tickRate;
this.tick = 1;
this.tickDuration = 0;
}
public float TickDurationAsFraction
{
get { return tickDuration / tickInterval; }
}
public void SetTime(int tick, float tickDuration)
{
this.tick = tick;
this.tickDuration = tickDuration;
}
public float DurationSinceTick(int tick)
{
return (this.tick - tick) * tickInterval + tickDuration;
}
public void AddDuration(float duration)
{
tickDuration += duration;
int deltaTicks = Mathf.FloorToInt(tickDuration * (float)tickRate);
tick += deltaTicks;
tickDuration = tickDuration % tickInterval;
}
public static float GetDuration(GameTime start, GameTime end)
{
if(start.tickRate != end.tickRate)
{
GameDebug.LogError("Trying to compare time with different tick rates (" + start.tickRate + " and " + end.tickRate + ")");
return 0;
}
float result = (end.tick - start.tick) * start.tickInterval + end.tickDuration - start.tickDuration;
return result;
}
int m_tickRate;
}
public class EnumeratedArrayAttribute : PropertyAttribute
{
public readonly string[] names;
public EnumeratedArrayAttribute(Type enumtype)
{
names = Enum.GetNames(enumtype);
}
}
[DefaultExecutionOrder(-1000)]
public class Game : MonoBehaviour
{
public delegate void UpdateDelegate();
public WeakAssetReference movableBoxPrototype;
// Color scheme configurable? (cvars?)
public enum GameColor
{
Friend,
Enemy
}
[EnumeratedArray(typeof(GameColor))]
public Color[] gameColors;
public GameStatistics m_GameStatistics { get; private set; }
public static class Input
{
[Flags]
public enum Blocker
{
None = 0,
Console = 1,
Chat = 2,
Debug = 4,
}
static Blocker blocks;
public static void SetBlock(Blocker b, bool value)
{
if (value)
blocks |= b;
else
blocks &= ~b;
}
internal static float GetAxisRaw(string axis)
{
return blocks != Blocker.None ? 0.0f : UnityEngine.Input.GetAxisRaw(axis);
}
internal static bool GetKey(KeyCode key)
{
return blocks != Blocker.None ? false : UnityEngine.Input.GetKey(key);
}
internal static bool GetKeyDown(KeyCode key)
{
return blocks != Blocker.None ? false : UnityEngine.Input.GetKeyDown(key);
}
internal static bool GetMouseButton(int button)
{
return blocks != Blocker.None ? false : UnityEngine.Input.GetMouseButton(button);
}
internal static bool GetKeyUp(KeyCode key)
{
return blocks != Blocker.None ? false : UnityEngine.Input.GetKeyUp(key);
}
}
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 = "config.mousesensitivity", DefaultValue = "1.5", Description = "Mouse sensitivity", Flags = ConfigVar.Flags.Save)]
public static ConfigVar configMouseSensitivity;
[ConfigVar(Name = "config.inverty", DefaultValue = "0", Description = "Invert y mouse axis", Flags = ConfigVar.Flags.Save)]
public static ConfigVar configInvertY;
[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 charaacter 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;
static readonly string k_UserConfigFilename = "user.cfg";
static readonly string k_GameConfigFilename = "game.cfg";
public static GameConfiguration config;
public static InputSystem inputSystem;
public UnityEngine.Audio.AudioMixer audioMixer;
public SoundBank defaultBank;
public Camera bootCamera;
public LevelManager levelManager;
public static double frameTime;
public static bool IsHeadless()
{
return game.m_isHeadless;
}
public static SoundSystem SoundSystem
{
get { return game.m_SoundSystem; }
}
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 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 "";
}
public void Awake()
{
GameDebug.Assert(game == null);
DontDestroyOnLoad(gameObject);
game = this;
m_StopwatchFrequency = System.Diagnostics.Stopwatch.Frequency;
m_Clock = new System.Diagnostics.Stopwatch();
m_Clock.Start();
#if UNITY_EDITOR
StateHistory.Initialize();
#endif
var buildInfo = FindObjectOfType<BuildInfo>();
if (buildInfo != null)
_buildId = buildInfo.buildId;
var commandLineArgs = new List<string>(System.Environment.GetCommandLineArgs());
m_isHeadless = commandLineArgs.Contains("-batchmode");
var consoleRestoreFocus = commandLineArgs.Contains("-consolerestorefocus");
if (m_isHeadless)
{
#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(consoleUI);
}
else
{
var consoleUI = Instantiate(Resources.Load<ConsoleGUI>("Prefabs/ConsoleGUI"));
DontDestroyOnLoad(consoleUI);
Console.Init(consoleUI);
m_DebugOverlay = Instantiate(Resources.Load<DebugOverlay>("DebugOverlay"));
DontDestroyOnLoad(m_DebugOverlay);
m_DebugOverlay.Init();
var hdpipe = RenderPipelineManager.currentPipeline as HDRenderPipeline;
if (hdpipe != null)
{
hdpipe.DebugLayer2DCallback = DebugOverlay.Render;
hdpipe.DebugLayer3DCallback = DebugOverlay.Render3D;
}
m_GameStatistics = new GameStatistics();
}
// If -logfile was passed, we try to put our own logs next to the engine's logfile
var engineLogFileLocation = ".";
var logfileArgIdx = commandLineArgs.IndexOf("-logfile");
if(logfileArgIdx >= 0 && commandLineArgs.Count >= logfileArgIdx)
{
engineLogFileLocation = System.IO.Path.GetDirectoryName(commandLineArgs[logfileArgIdx + 1]);
}
var logName = m_isHeadless ? "game_"+DateTime.UtcNow.ToString("yyyyMMdd_HHmmss_fff") : "game";
GameDebug.Init(engineLogFileLocation, logName);
ConfigVar.Init();
Console.EnqueueCommandNoHistory("exec " + 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 (!commandLineArgs.Contains("-nographics"))
GameDebug.Log("WARNING: running -batchmod without -nographics");
}
else
{
RenderSettings.Init();
// Determine if we are a 'normal' game build. If so we run game.cfg to get started
//bool menuBoot = (buildInfo != null && buildInfo.buildId != "AutoBuild" && !commandLineArgs.Contains("-nogame")) || commandLineArgs.Contains("-game");
if(!commandLineArgs.Contains("-nogame"))
{
Console.EnqueueCommandNoHistory("exec " + k_GameConfigFilename);
}
}
var forceClientSystem = commandLineArgs.Contains("-forceclientsystems");
if (!m_isHeadless || forceClientSystem)
{
m_SoundSystem = new SoundSystem();
m_SoundSystem.Init(audioMixer);
m_SoundSystem.MountBank(defaultBank);
GameObject go = (GameObject)GameObject.Instantiate(Resources.Load("Prefabs/ClientFrontend", typeof(GameObject)));
UnityEngine.Object.DontDestroyOnLoad(go);
clientFrontend = go.GetComponentInChildren<ClientFrontend>();
}
GameDebug.Log("fps.sample 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("Cwd: " + System.IO.Directory.GetCurrentDirectory());
SimpleBundleManager.Init();
GameDebug.Log("SimpleBundleManager initialized");
levelManager = new LevelManager();
levelManager.Init();
GameDebug.Log("LevelManager initialized");
inputSystem = new InputSystem();
GameDebug.Log("InputSystem initialized");
// TODO (petera) added Instantiate here to avoid making changes to asset file.
// Feels like maybe SO is not really the right tool here.
config = Instantiate((GameConfiguration)Resources.Load("GameConfiguration"));
GameDebug.Log("Loaded game config");
// Game loops
Console.AddCommand("preview", CmdPreview, "Start preview mode");
Console.AddCommand("serve", CmdServe, "Start server listening");
Console.AddCommand("client", CmdClient, "client: Enter client mode. Looking for servers");
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");
#if UNITY_STANDALONE_WIN
Console.AddCommand("windowpos", CmdWindowPosition, "Position of window. e.g. windowpos 100,100");
#endif
Console.SetOpen(true);
Console.ProcessCommandLineArguments(commandLineArgs.ToArray());
PushCamera(bootCamera);
}
public Camera TopCamera()
{
var c = m_CameraStack.Count;
return c == 0 ? null : m_CameraStack[c - 1];
}
public void PushCamera(Camera cam)
{
if (m_CameraStack.Count > 0)
SetCameraEnabled(m_CameraStack[m_CameraStack.Count - 1],false);
m_CameraStack.Add(cam);
SetCameraEnabled(cam,true);
m_ExposureReleaseCount = 10;
}
public void BlackFade(bool enabled)
{
if(m_Exposure != null)
m_Exposure.active = enabled;
}
public void PopCamera(Camera cam)
{
GameDebug.Assert(m_CameraStack.Count > 1, "Trying to pop last camera off stack!");
GameDebug.Assert(cam == m_CameraStack[m_CameraStack.Count - 1]);
if(cam != null)
SetCameraEnabled(cam,false);
m_CameraStack.RemoveAt(m_CameraStack.Count - 1);
SetCameraEnabled(m_CameraStack[m_CameraStack.Count - 1],true);
}
void SetCameraEnabled(Camera cam, bool enabled)
{
if (enabled)
RenderSettings.UpdateCameraSettings(cam);
cam.enabled = enabled;
var audioListener = cam.GetComponent<AudioListener>();
if(audioListener != null)
{
audioListener.enabled = enabled;
if(SoundSystem != null)
SoundSystem.SetCurrentListener(enabled ? audioListener : null);
}
}
void OnDestroy()
{
GameDebug.Shutdown();
Console.Shutdown();
if (m_DebugOverlay != null)
m_DebugOverlay.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)
{
hdpipe.DebugLayer2DCallback = DebugOverlay.Render;
hdpipe.DebugLayer3DCallback = DebugOverlay.Render3D;
var layer = LayerMask.NameToLayer("PostProcess Volumes");
if (layer == -1)
GameDebug.LogWarning("Unable to find layer mask for camera fader");
else
{
m_Exposure = ScriptableObject.CreateInstance<AutoExposure>();
m_Exposure.active = false;
m_Exposure.enabled.Override(true);
m_Exposure.keyValue.Override(0);
m_ExposureVolume = PostProcessManager.instance.QuickVolume(layer, 100.0f, m_Exposure);
}
pipeSetup = true;
}
}
if(m_ExposureReleaseCount > 0)
{
m_ExposureReleaseCount--;
if (m_ExposureReleaseCount == 0)
BlackFade(false);
}
// Verify if camera was somehow destroyed and pop it
if(m_CameraStack.Count > 1 && m_CameraStack[m_CameraStack.Count-1] == null)
{
PopCamera(null);
}
#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;
// 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]);
if (!initSucceeded)
break;
m_gameLoops.Add(gameLoop);
}
catch (System.Exception e)
{
GameDebug.Log(string.Format("Game loop initialization threw exception : ({0})\n{1}", e.Message, e.StackTrace));
}
}
if (!initSucceeded)
{
ShutdownGameLoops();
GameDebug.Log("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 (m_SoundSystem != null)
m_SoundSystem.Update();
if (clientFrontend != null)
clientFrontend.UpdateGame();
Console.ConsoleUpdate();
WindowFocusUpdate();
UpdateCPUStats();
endUpdateEvent?.Invoke();
}
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();
}
void OnApplicationQuit()
{
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
GameDebug.Log("Farewell, cruel world...");
System.Diagnostics.Process.GetCurrentProcess().Kill();
#endif
ShutdownGameLoops();
}
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));
}
}
}
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 CmdPreview(string[] args)
{
RequestGameLoop(typeof(PreviewGameLoop), args);
Console.s_PendingCommandsWaitForFrames = 1;
}
void CmdServe(string[] args)
{
RequestGameLoop( typeof(ServerGameLoop) , args);
Console.s_PendingCommandsWaitForFrames = 1;
}
void CmdLoad(string[] args)
{
LoadLevel(args[0]);
Console.SetOpen(false);
}
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>();
if(clientGameLoop != null)
clientGameLoop.CmdConnect(args);
else
GameDebug.Log("Cannot connect from current gamemode");
}
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
public static void RequestMousePointerLock()
{
s_bMouseLockFrameNo = Time.frameCount + 1;
}
public static void SetMousePointerLock(bool locked)
{
Cursor.lockState = locked ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = !locked;
s_bMouseLockFrameNo = Time.frameCount; // prevent default handling in WindowFocusUpdate overriding requests
}
public static bool GetMousePointerLock()
{
return Cursor.lockState == CursorLockMode.Locked;
}
void WindowFocusUpdate()
{
bool menusShowing = (clientFrontend != null && clientFrontend.menuShowing != ClientFrontend.MenuShowing.None);
bool lockWhenClicked = !menusShowing && !Console.IsOpen();
if(s_bMouseLockFrameNo == Time.frameCount)
{
SetMousePointerLock(true);
return;
}
if (lockWhenClicked)
{
// Default behaviour when no menus or anything. Catch mouse on click, release on escape.
if (UnityEngine.Input.GetMouseButtonUp(0) && !GetMousePointerLock())
SetMousePointerLock(true);
if (UnityEngine.Input.GetKeyUp(KeyCode.Escape) && GetMousePointerLock())
SetMousePointerLock(false);
}
else
{
// When menu or console open, release lock
if (GetMousePointerLock())
{
SetMousePointerLock(false);
}
}
}
List<Type> m_RequestedGameLoopTypes = new List<System.Type>();
private List<string[]> m_RequestedGameLoopArguments = new List<string[]>();
// Global camera handling
List<Camera> m_CameraStack = new List<Camera>();
AutoExposure m_Exposure;
PostProcessVolume m_ExposureVolume;
int m_ExposureReleaseCount;
List<IGameLoop> m_gameLoops = new List<IGameLoop>();
DebugOverlay m_DebugOverlay;
SoundSystem m_SoundSystem;
bool m_isHeadless;
long m_StopwatchFrequency;
System.Diagnostics.Stopwatch m_Clock;
static int s_bMouseLockFrameNo;
}