You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
5.9 KiB
239 lines
5.9 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
public partial class UniQuake: MonoBehaviour
|
|
{
|
|
private const int DefaultMemSize = 0x8000000; // 128 MB of heap space
|
|
|
|
public int memorySize = DefaultMemSize;
|
|
|
|
private QuakeParms quakeParms;
|
|
private SystemModule systemModule;
|
|
private RenderModule renderModule;
|
|
private GameModule gameModule;
|
|
|
|
private bool initialized = false;
|
|
private double startTime;
|
|
|
|
/// <summary>
|
|
/// Camera and viewport that this instance of Quake will be rendering to
|
|
/// </summary>
|
|
public Camera Camera { get; set; }
|
|
public Layers GameLayer { get; set; }
|
|
public Layers ViewModelLayer { get; set; }
|
|
|
|
public MissionPack BaseGame { get; set; }
|
|
public string ModDirectory { get; set; }
|
|
public string[] AdditionalArguments { get; set; }
|
|
|
|
public string LibraryOverride { get; set; }
|
|
|
|
/// <summary>
|
|
/// Time since startup for this particular instance of Quake
|
|
/// </summary>
|
|
public double CurrentTime => Time.realtimeSinceStartupAsDouble - startTime;
|
|
|
|
public GameAssets GameAssets { get; private set; } // TODO: Game assets could be shared by multiple UniQuake instances
|
|
public GameState GameState { get; private set; }
|
|
public VisualStyle CurrentStyle { get; private set; }
|
|
private VisualStyle nextStyle;
|
|
|
|
private Action<string> logHandler;
|
|
private readonly StringBuilder logBuffer = new StringBuilder();
|
|
|
|
void Start()
|
|
{
|
|
logHandler = PrintLog; // Send each log statement to Unity immediately during startup
|
|
|
|
systemModule = new SystemModule(this);
|
|
renderModule = new RenderModule(this);
|
|
gameModule = new GameModule(this);
|
|
|
|
GameAssets = new GameAssets(this);
|
|
GameState = new GameState(this);
|
|
|
|
LoadLibrary();
|
|
|
|
List<string> arguments = new List<string>
|
|
{
|
|
"",
|
|
//"-fullscreen", "-width", "1920", "-height", "1080",
|
|
"-window", "-width", "1440", "-height", "1080",
|
|
//"-window", "-width", "2240", "-height", "1260",
|
|
};
|
|
|
|
switch (BaseGame)
|
|
{
|
|
case MissionPack.Hipnotic:
|
|
arguments.Add("-hipnotic");
|
|
break;
|
|
case MissionPack.Rogue:
|
|
arguments.Add("-rogue");
|
|
break;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(ModDirectory))
|
|
{
|
|
arguments.AddRange(new[] { "-game", ModDirectory });
|
|
}
|
|
|
|
if (Debug.isDebugBuild)
|
|
{
|
|
arguments.AddRange(new[] { "+developer", "1" });
|
|
}
|
|
|
|
if (AdditionalArguments != null)
|
|
arguments.AddRange(AdditionalArguments);
|
|
|
|
quakeParms = new QuakeParms
|
|
{
|
|
baseDir = Application.persistentDataPath,
|
|
userDir = null, // TODO set this if user prefs need to be stored somewhere specific, otherwise this will be the same as baseDir
|
|
numCpus = SystemInfo.processorCount,
|
|
errState = 0,
|
|
};
|
|
quakeParms.SetArguments(arguments.ToArray());
|
|
quakeParms.AllocateMemory(memorySize);
|
|
|
|
startTime = Time.realtimeSinceStartupAsDouble;
|
|
|
|
try
|
|
{
|
|
UniQuake_SetFmodSystem(AudioManager.Instance.FmodSystem.handle);
|
|
UniQuake_Init(quakeParms.ToNativePtr(),
|
|
systemModule.CallbacksPtr, renderModule.CallbacksPtr, gameModule.CallbacksPtr);
|
|
|
|
initialized = true;
|
|
}
|
|
catch (QuakeException ex)
|
|
{
|
|
if (ex.ExitCode == 0)
|
|
Debug.Log(ex.Message);
|
|
else
|
|
Debug.LogException(ex);
|
|
|
|
Shutdown();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogException(ex);
|
|
Shutdown();
|
|
}
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (!initialized)
|
|
return;
|
|
|
|
logHandler = CollectLog; // Collect and dump logs to Unity once per frame
|
|
|
|
try
|
|
{
|
|
UniQuake_Update(Time.deltaTime);
|
|
}
|
|
catch (QuakeException ex)
|
|
{
|
|
if (ex.ExitCode == 0)
|
|
Debug.Log(ex.Message);
|
|
else
|
|
Debug.LogException(ex);
|
|
|
|
Shutdown();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogException(ex);
|
|
Shutdown();
|
|
}
|
|
|
|
FlushLog();
|
|
}
|
|
|
|
public void Shutdown()
|
|
{
|
|
initialized = false;
|
|
UniQuake_Shutdown();
|
|
Destroy(this);
|
|
}
|
|
|
|
private void OnApplicationQuit()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
GameState.Destroy();
|
|
GameAssets.Destroy();
|
|
|
|
gameModule.Destroy();
|
|
renderModule.Destroy();
|
|
systemModule.Destroy();
|
|
|
|
if (quakeParms != null)
|
|
{
|
|
quakeParms.Destroy();
|
|
quakeParms = null;
|
|
}
|
|
|
|
FreeLibrary();
|
|
}
|
|
|
|
public void AddLog(string log)
|
|
{
|
|
logHandler?.Invoke(log);
|
|
}
|
|
|
|
private void PrintLog(string log)
|
|
{
|
|
Debug.Log(log);
|
|
}
|
|
|
|
private void CollectLog(string log)
|
|
{
|
|
logBuffer.Append(log);
|
|
}
|
|
|
|
private void FlushLog()
|
|
{
|
|
if (logBuffer.Length > 0)
|
|
{
|
|
Debug.Log(logBuffer.ToString());
|
|
logBuffer.Clear();
|
|
}
|
|
}
|
|
|
|
public void SetVisualStyle(VisualStyle style)
|
|
{
|
|
if (CurrentStyle == null)
|
|
{
|
|
CurrentStyle = style;
|
|
CurrentStyle.Activate();
|
|
return;
|
|
}
|
|
|
|
// Wait to swap styles until next map load
|
|
nextStyle = style;
|
|
}
|
|
}
|
|
|
|
public enum MissionPack
|
|
{
|
|
Quake, // Vanilla Quake
|
|
Hipnotic, // Scourge of Armagon
|
|
Rogue, // Dissolution of Eternity
|
|
}
|
|
|
|
public class QuakeException: Exception
|
|
{
|
|
public int ExitCode { get; }
|
|
|
|
public QuakeException(string message, int exitCode = 0)
|
|
: base(message)
|
|
{
|
|
ExitCode = exitCode;
|
|
}
|
|
}
|