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.
 
 
 
 
 

192 lines
4.4 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 bool initialized = false;
private double startTime;
public MissionPack BaseGame { get; set; }
public string ModDirectory { get; set; }
/// <summary>
/// Time since startup for this particular instance of Quake
/// </summary>
public double CurrentTime => Time.timeAsDouble - startTime;
private Action<string> logHandler;
private 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);
LoadLibrary();
List<string> arguments = new List<string>
{
"",
"-window",
"-width", "1440",
"-height", "1080",
};
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" });
}
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.timeAsDouble;
try
{
UniQuake_SetFmodSystem(AudioManager.Instance.FmodSystem.handle);
UniQuake_Init(quakeParms.ToNativePtr(), systemModule.CallbacksPtr, renderModule.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();
}
private void Shutdown()
{
initialized = false;
UniQuake_Shutdown();
Destroy(this);
}
private void OnDestroy()
{
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 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;
}
}