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.
 
 
 
 
 

241 lines
6.0 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; }
/// <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
{
#if UNITY_PS4 || UNITY_PS5 || UNITY_GAMECORE
baseDir = Application.streamingAssetsPath,
userDir = Application.persistentDataPath,
#else
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
#endif
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;
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;
}
}