Create CLre_server mod and port CLre basic functionality
This commit is contained in:
parent
5dd67a88f4
commit
14a5fc8a54
6
CLre.sln
6
CLre.sln
|
@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29609.76
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLre", "CLre\CLre.csproj", "{E0EEA15D-AB3C-4C73-A000-C49B5AE9EA66}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLre_server", "CLre_server\CLre_server.csproj", "{89B354CF-C654-4E48-8166-5E20BC6E4836}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -15,6 +17,10 @@ Global
|
|||
{E0EEA15D-AB3C-4C73-A000-C49B5AE9EA66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E0EEA15D-AB3C-4C73-A000-C49B5AE9EA66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E0EEA15D-AB3C-4C73-A000-C49B5AE9EA66}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{89B354CF-C654-4E48-8166-5E20BC6E4836}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89B354CF-C654-4E48-8166-5E20BC6E4836}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89B354CF-C654-4E48-8166-5E20BC6E4836}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89B354CF-C654-4E48-8166-5E20BC6E4836}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
10
CLre_server/API/Engines/ICLreEngine.cs
Normal file
10
CLre_server/API/Engines/ICLreEngine.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Game.DataLoader;
|
||||
using Svelto.ECS;
|
||||
|
||||
namespace CLre_server.API.Engines
|
||||
{
|
||||
public interface ICLreEngine : IQueryingEntitiesEngine, IEngine, IDataAccess
|
||||
{
|
||||
IEntityFactory entityFactory { get; set; }
|
||||
}
|
||||
}
|
61
CLre_server/API/Engines/ServerEngines.cs
Normal file
61
CLre_server/API/Engines/ServerEngines.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using Game.DataLoader;
|
||||
using HarmonyLib;
|
||||
using Svelto.DataStructures;
|
||||
using Svelto.ECS;
|
||||
|
||||
namespace CLre_server.API.Engines
|
||||
{
|
||||
public abstract class ServerEnginePreBuild : ICLreEngine
|
||||
{
|
||||
public ServerEnginePreBuild()
|
||||
{
|
||||
MainGameServer_BuildDeprecatedEngines_Patch.beforeBuildEngines.Add(this);
|
||||
}
|
||||
|
||||
public abstract void Ready();
|
||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
||||
public abstract IEntityFactory entityFactory { get; set; }
|
||||
public IDataDB dataDB { get; set; }
|
||||
}
|
||||
|
||||
public abstract class ServerEnginePostBuild : ICLreEngine
|
||||
{
|
||||
public ServerEnginePostBuild()
|
||||
{
|
||||
MainGameServer_BuildDeprecatedEngines_Patch.afterBuildEngines.Add(this);
|
||||
}
|
||||
|
||||
public abstract void Ready();
|
||||
public abstract IEntitiesDB entitiesDB { get; set; }
|
||||
public abstract IEntityFactory entityFactory { get; set; }
|
||||
public IDataDB dataDB { get; set; }
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameServer.GameFramework.MainGameServer), "BuildDeprecatedEngines")]
|
||||
class MainGameServer_BuildDeprecatedEngines_Patch
|
||||
{
|
||||
internal static FasterList<ServerEnginePreBuild> beforeBuildEngines = new FasterList<ServerEnginePreBuild>();
|
||||
|
||||
internal static FasterList<ServerEnginePostBuild> afterBuildEngines = new FasterList<ServerEnginePostBuild>();
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void BeforeMethodCall(GameServer.GameFramework.MainGameServer __instance, IEntityFactory ____entityFactory)
|
||||
{
|
||||
foreach (ICLreEngine e in beforeBuildEngines)
|
||||
{
|
||||
e.entityFactory = ____entityFactory;
|
||||
__instance.AddEngine(e);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
public static void AfterMethodCall(GameServer.GameFramework.MainGameServer __instance, IEntityFactory ____entityFactory)
|
||||
{
|
||||
foreach (ICLreEngine e in afterBuildEngines)
|
||||
{
|
||||
e.entityFactory = ____entityFactory;
|
||||
__instance.AddEngine(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
147
CLre_server/API/MainServer/Server.cs
Normal file
147
CLre_server/API/MainServer/Server.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using GameServer;
|
||||
using HarmonyLib;
|
||||
using Svelto.Context;
|
||||
|
||||
namespace CLre_server.API.MainServer
|
||||
{
|
||||
public class Server
|
||||
{
|
||||
// static
|
||||
|
||||
private static Server _instance = null;
|
||||
|
||||
public static Server Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null) _instance = new Server();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
// instance events
|
||||
public event EventHandler<StartingEventArgs> InitStart
|
||||
{
|
||||
add => MainGameServer_Constructor_Patch.preConstructor += value;
|
||||
remove => MainGameServer_Constructor_Patch.preConstructor -= value;
|
||||
}
|
||||
|
||||
public event EventHandler<StartedEventArgs> InitComplete
|
||||
{
|
||||
add => ServerReadyEngine.serverEngineReady += value;
|
||||
remove => ServerReadyEngine.serverEngineReady -= value;
|
||||
}
|
||||
|
||||
public event EventHandler<StartedEventArgs> FrameworkReady
|
||||
{
|
||||
add => ServerReadyEngine.serverFrameworkReady += value;
|
||||
remove => ServerReadyEngine.serverFrameworkReady -= value;
|
||||
}
|
||||
|
||||
public event EventHandler<StopEventArgs> FrameworkExit
|
||||
{
|
||||
add => ServerReadyEngine.serverFrameworkDestroyed += value;
|
||||
remove => ServerReadyEngine.serverFrameworkDestroyed -= value;
|
||||
}
|
||||
|
||||
// properties
|
||||
|
||||
public GameServerSettings GameServerSettings
|
||||
{
|
||||
get => MainGameServer_SetupMods_Patch._gameServerSettings;
|
||||
|
||||
set
|
||||
{
|
||||
MainGameServer_SetupMods_Patch._gameServerSettings = value;
|
||||
Traverse.Create(MainGameServer_Constructor_Patch.mgs).Field<GameServerSettings>("_gameServerSettings").Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Server()
|
||||
{
|
||||
new ServerReadyEngine();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
class MainGameServer_SetupMods_Patch
|
||||
{
|
||||
internal static GameServerSettings _gameServerSettings;
|
||||
|
||||
[HarmonyPostfix]
|
||||
public static void AfterMethodCall(GameServerSettings ____gameServerSettings)
|
||||
{
|
||||
_gameServerSettings = ____gameServerSettings;
|
||||
}
|
||||
|
||||
[HarmonyTargetMethod]
|
||||
public static MethodBase Target()
|
||||
{
|
||||
return AccessTools.Method("GameServer.GameFramework.MainGameServer:SetupMods");
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
class MainGameServer_Constructor_Patch
|
||||
{
|
||||
|
||||
internal static ICompositionRoot mgs = null;
|
||||
|
||||
internal static event EventHandler<StartingEventArgs> preConstructor;
|
||||
|
||||
internal static event EventHandler<StartingEventArgs> postConstructor;
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void BeforeMethodCall()
|
||||
{
|
||||
if (preConstructor != null) preConstructor(null, default(StartingEventArgs));
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
public static void AfterMethodCall(ICompositionRoot __instance)
|
||||
{
|
||||
mgs = __instance;
|
||||
if (postConstructor != null) postConstructor(__instance, default(StartingEventArgs));
|
||||
}
|
||||
|
||||
[HarmonyTargetMethod]
|
||||
public static MethodBase Target()
|
||||
{
|
||||
return AccessTools.Constructor(AccessTools.TypeByName("GameServer.GameFramework.MainGameServer"));
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PhotonNetwork), "ConnectUsingSettings")]
|
||||
class PhotonNetwork_ConnectUsingSettings_Patch
|
||||
{
|
||||
internal static event EventHandler<StartedEventArgs> preConnect;
|
||||
|
||||
internal static event EventHandler<StartedEventArgs> postConnect;
|
||||
|
||||
[HarmonyPostfix]
|
||||
public static void AfterMethodCall(string gameVersion)
|
||||
{
|
||||
if (postConnect != null) postConnect(null, new StartedEventArgs
|
||||
{
|
||||
photonVersion = gameVersion,
|
||||
photonRegion = PhotonNetwork.CloudRegion,
|
||||
worldName = MainGameServer_SetupMods_Patch._gameServerSettings.GetWorldName(),
|
||||
gameGuid = MainGameServer_SetupMods_Patch._gameServerSettings.GetGameGuid(),
|
||||
});
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void BeforeMethodCall(string gameVersion)
|
||||
{
|
||||
if (preConnect != null) preConnect(null, new StartedEventArgs
|
||||
{
|
||||
photonVersion = gameVersion,
|
||||
photonRegion = PhotonNetwork.CloudRegion,
|
||||
worldName = MainGameServer_SetupMods_Patch._gameServerSettings.GetWorldName(),
|
||||
gameGuid = MainGameServer_SetupMods_Patch._gameServerSettings.GetGameGuid(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
50
CLre_server/API/MainServer/ServerEngines.cs
Normal file
50
CLre_server/API/MainServer/ServerEngines.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using CLre_server.API.Engines;
|
||||
using Game.DataLoader;
|
||||
using GameServer;
|
||||
using Svelto.Context;
|
||||
using Svelto.ECS;
|
||||
|
||||
namespace CLre_server.API.MainServer
|
||||
{
|
||||
class ServerReadyEngine : ServerEnginePostBuild, IWaitForFrameworkInitialization, IWaitForFrameworkDestruction
|
||||
{
|
||||
internal static event EventHandler<StartedEventArgs> serverEngineReady;
|
||||
|
||||
internal static event EventHandler<StartedEventArgs> serverFrameworkReady;
|
||||
|
||||
internal static event EventHandler<StopEventArgs> serverFrameworkDestroyed;
|
||||
|
||||
public override void Ready()
|
||||
{
|
||||
GameServerSettings gss = Server.Instance.GameServerSettings;
|
||||
if (serverEngineReady != null) serverEngineReady(this, new StartedEventArgs
|
||||
{
|
||||
photonVersion = PhotonNetwork.gameVersion,
|
||||
photonRegion = PhotonNetwork.CloudRegion,
|
||||
gameGuid = gss.GetGameGuid(),
|
||||
worldName = gss.GetWorldName(),
|
||||
});
|
||||
}
|
||||
|
||||
public override IEntitiesDB entitiesDB { get; set; }
|
||||
public override IEntityFactory entityFactory { get; set; }
|
||||
|
||||
public void OnFrameworkInitialized()
|
||||
{
|
||||
GameServerSettings gss = Server.Instance.GameServerSettings;
|
||||
if (serverFrameworkReady != null) serverFrameworkReady(this, new StartedEventArgs
|
||||
{
|
||||
photonVersion = PhotonNetwork.gameVersion,
|
||||
photonRegion = PhotonNetwork.CloudRegion,
|
||||
gameGuid = gss.GetGameGuid(),
|
||||
worldName = gss.GetWorldName(),
|
||||
});
|
||||
}
|
||||
|
||||
public void OnFrameworkDestroyed()
|
||||
{
|
||||
if (serverFrameworkDestroyed != null) serverFrameworkDestroyed(this, new StopEventArgs{});
|
||||
}
|
||||
}
|
||||
}
|
14
CLre_server/API/MainServer/ServerEventArgs.cs
Normal file
14
CLre_server/API/MainServer/ServerEventArgs.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace CLre_server.API.MainServer
|
||||
{
|
||||
public struct StartingEventArgs{}
|
||||
|
||||
public struct StartedEventArgs
|
||||
{
|
||||
public string photonVersion;
|
||||
public CloudRegionCode photonRegion;
|
||||
public string worldName;
|
||||
public string gameGuid;
|
||||
}
|
||||
|
||||
public struct StopEventArgs{}
|
||||
}
|
55
CLre_server/API/Tools/AccessToolsWarnings.cs
Normal file
55
CLre_server/API/Tools/AccessToolsWarnings.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
|
||||
#if DEBUG
|
||||
namespace CLre_server.API.Tools
|
||||
{
|
||||
public static class AccessToolsWarnings
|
||||
{
|
||||
internal static bool isEnabled = false;
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
public static void Disable()
|
||||
{
|
||||
isEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(AccessTools), "TypeByName")]
|
||||
class AccessTools_TypeByName_Patch
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void AfterMethodCall(Type __result, string name)
|
||||
{
|
||||
if (!AccessToolsWarnings.isEnabled) return;
|
||||
if (__result == null)
|
||||
{
|
||||
var method = (new StackTrace()).GetFrame(2).GetMethod();
|
||||
Utility.Logging.LogWarning($"[{method.DeclaringType.FullName}.{method.Name}] AccessTools.TypeByName(\"{name}\") returned null result");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(AccessTools), "Method",
|
||||
new Type[] {typeof(string), typeof(Type[]), typeof(Type[])})]
|
||||
class AccessTools_Method_Patch
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void AfterMethodCall(MethodInfo __result, string typeColonMethodname)
|
||||
{
|
||||
if (!AccessToolsWarnings.isEnabled) return;
|
||||
if (__result == null)
|
||||
{
|
||||
var method = (new StackTrace()).GetFrame(2).GetMethod();
|
||||
Utility.Logging.LogWarning($"[{method.DeclaringType.FullName}.{method.Name}] AccessTools.Method(\"{typeColonMethodname}\") returned null result");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
101
CLre_server/API/Tools/NetServerListener.cs
Normal file
101
CLre_server/API/Tools/NetServerListener.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System.Reflection;
|
||||
using System.Text;
|
||||
using GameNetworkLayer.Shared;
|
||||
using HarmonyLib;
|
||||
using Svelto.DataStructures;
|
||||
using Svelto.DataStructures.Experimental;
|
||||
|
||||
namespace CLre_server.API.Tools
|
||||
{
|
||||
public class NetServerListener
|
||||
{
|
||||
internal static bool isEnabled = false;
|
||||
|
||||
private static FasterDictionary<short, FasterList<NetReceiveMessageCallback>> callbacks = new FasterDictionary<short,FasterList<NetReceiveMessageCallback>>();
|
||||
|
||||
public delegate void NetReceiveMessageCallback(NetworkDispatcherCode code, byte[] data, int playerId);
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
public static void Disable()
|
||||
{
|
||||
isEnabled = false;
|
||||
}
|
||||
|
||||
public static void DebugReceiveMessage(NetworkDispatcherCode code, NetReceiveMessageCallback callback)
|
||||
{
|
||||
short key = (short)code;
|
||||
if (callbacks.TryGetValue(key, out FasterList<NetReceiveMessageCallback> handlers))
|
||||
{
|
||||
handlers.Add(callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
FasterList<NetReceiveMessageCallback> newHandlers = new FasterList<NetReceiveMessageCallback>(new [] {callback});
|
||||
callbacks.Add(key, newHandlers);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool RunDebugCallbacks(NetworkDispatcherCode code, byte[] data, int playerId)
|
||||
{
|
||||
short key = (short)code;
|
||||
if (callbacks.TryGetValue(key, out FasterList<NetReceiveMessageCallback> handlers))
|
||||
{
|
||||
foreach (NetReceiveMessageCallback callback in handlers)
|
||||
{
|
||||
callback(code, data, playerId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Log(NetworkDispatcherCode code, byte[] data, int playerId)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("Received ");
|
||||
sb.Append(code.ToString());
|
||||
sb.Append(" for player #");
|
||||
sb.Append(playerId);
|
||||
sb.Append(": 0x");
|
||||
foreach (byte b in data)
|
||||
{
|
||||
sb.Append(b.ToString("X"));
|
||||
}
|
||||
Utility.Logging.Log(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
class NetMessageClientListener_HandleAllMessages_Patch
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void BeforeMethodCall(object ____deserializer, int playerId, object value)
|
||||
{
|
||||
if (!NetServerListener.isEnabled) return;
|
||||
// TODO optimize this to not use Traverse
|
||||
Traverse result = Traverse.Create(____deserializer).Method("Deserialize", value);
|
||||
NetworkDispatcherCode code = result.Field<NetworkDispatcherCode>("dispatcherCode").Value;
|
||||
byte[] data = result.Field<byte[]>("bytes").Value;
|
||||
if (data == null)
|
||||
{
|
||||
Utility.Logging.LogWarning("Network message data was deserialized as null");
|
||||
return;
|
||||
}
|
||||
bool isHandled = NetServerListener.RunDebugCallbacks(code, data, playerId);
|
||||
if (!isHandled) Utility.Logging.Log($"Received network message for player {playerId} (code: {code.ToString()}, len: {data.Length})");
|
||||
}
|
||||
|
||||
[HarmonyTargetMethod]
|
||||
public static MethodBase Target()
|
||||
{
|
||||
return AccessTools.Method("GameNetworkLayer.Server.NetMessageServerListener:HandleAllMessages");
|
||||
}
|
||||
}
|
||||
}
|
114
CLre_server/API/Tools/NetServerSender.cs
Normal file
114
CLre_server/API/Tools/NetServerSender.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using GameNetworkLayer.Shared;
|
||||
using HarmonyLib;
|
||||
using NetworkFramework.Shared;
|
||||
|
||||
namespace CLre_server.API.Tools
|
||||
{
|
||||
public class NetServerSender
|
||||
{
|
||||
private struct DummyNetDataStruct : ISerializedNetData
|
||||
{
|
||||
public byte[] Serialize()
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public void Deserialize(byte[] data)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly MethodInfo _genericSendMessage = AccessTools.Method("GameNetworkLayer.Server.NetMessageServerSender:SendMessage");
|
||||
|
||||
private static readonly MethodInfo _genericGetSendMessageMethod =
|
||||
AccessTools.Method(typeof(NetServerSender), "GetSendMessageMethod",parameters: new Type[0]);/*
|
||||
/*((Func<MethodInfo>) GetSendMessageMethod<DummyNetDataStruct>).Method
|
||||
.GetBaseDefinition()
|
||||
.GetGenericMethodDefinition();*/
|
||||
|
||||
private static readonly MethodInfo _genericLog =
|
||||
AccessTools.Method(typeof(NetServerSender), "Log");/*
|
||||
((Action<NetworkDispatcherCode, DummyNetDataStruct>) Log<DummyNetDataStruct>).Method
|
||||
.GetBaseDefinition()
|
||||
.GetGenericMethodDefinition();*/
|
||||
|
||||
private static readonly MethodInfo _genericGetLogMethod =
|
||||
AccessTools.Method(typeof(NetServerSender), "GetLogMethod", new Type[0]);/*
|
||||
((Func<MethodInfo>) GetLogMethod<DummyNetDataStruct>).Method
|
||||
.GetBaseDefinition()
|
||||
.GetGenericMethodDefinition();*/
|
||||
|
||||
public static MethodInfo GetSendMessageMethod(Type t)
|
||||
{
|
||||
return (MethodInfo) _genericGetSendMessageMethod.MakeGenericMethod(t)
|
||||
.Invoke(null, new object[0]);
|
||||
}
|
||||
|
||||
public static MethodInfo GetSendMessageMethod<T>() where T : struct, ISerializedNetData
|
||||
{
|
||||
return _genericSendMessage.MakeGenericMethod(typeof(T));
|
||||
}
|
||||
|
||||
public static MethodInfo DebugSendMessage<T>(Harmony instance = null, MethodInfo before = null, MethodInfo after = null, MethodInfo transpiler = null, MethodInfo finalizer = null) where T : struct, ISerializedNetData
|
||||
{
|
||||
return DebugSendMessage(typeof(T), instance, before, after, transpiler, finalizer);
|
||||
}
|
||||
|
||||
public static MethodInfo DebugSendMessage(Type generic, Harmony instance = null, MethodInfo before = null, MethodInfo after = null, MethodInfo transpiler = null, MethodInfo finalizer = null)
|
||||
{
|
||||
return DebugSendMessage(
|
||||
generic, instance,
|
||||
before == null ? null : new HarmonyMethod(before),
|
||||
after == null ? null : new HarmonyMethod(after),
|
||||
transpiler == null ? null : new HarmonyMethod(transpiler),
|
||||
finalizer == null ? null : new HarmonyMethod(finalizer));
|
||||
}
|
||||
|
||||
public static MethodInfo DebugSendMessage<T>(Harmony instance = null, HarmonyMethod before = null, HarmonyMethod after = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null) where T : struct, ISerializedNetData
|
||||
{
|
||||
return DebugSendMessage(typeof(T), instance, before, after, transpiler, finalizer);
|
||||
}
|
||||
|
||||
public static MethodInfo DebugSendMessage(Type generic, Harmony instance = null, HarmonyMethod before = null, HarmonyMethod after = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null)
|
||||
{
|
||||
if (instance == null) instance = CLre.harmonyInstance;
|
||||
MethodInfo target = GetSendMessageMethod(generic);
|
||||
return instance.Patch(target,
|
||||
before,
|
||||
after,
|
||||
transpiler,
|
||||
finalizer);
|
||||
}
|
||||
|
||||
public static MethodInfo GetLogMethod(Type t)
|
||||
{
|
||||
return (MethodInfo) _genericGetLogMethod.MakeGenericMethod(t)
|
||||
.Invoke(null, new object[0]);
|
||||
}
|
||||
|
||||
public static MethodInfo GetLogMethod<T>() where T : struct, ISerializedNetData
|
||||
{
|
||||
return _genericLog.MakeGenericMethod(typeof(T));
|
||||
}
|
||||
|
||||
private static void Log<T>(NetworkDispatcherCode code, ref T data) where T : struct, ISerializedNetData
|
||||
{
|
||||
//Utility.Logging.Log($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
||||
Traverse d = Traverse.Create(data);
|
||||
StringBuilder sb = new StringBuilder($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
||||
foreach (string fieldName in d.Fields())
|
||||
{
|
||||
Traverse field = d.Field(fieldName);
|
||||
sb.Append("\n");
|
||||
sb.Append("\"");
|
||||
sb.Append(fieldName.Substring(fieldName.IndexOf('<')+1, fieldName.LastIndexOf('>')-1));
|
||||
sb.Append("\": ");
|
||||
sb.Append(field.GetValue());
|
||||
}
|
||||
Utility.Logging.Log(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
88
CLre_server/API/Utility/Logging.cs
Normal file
88
CLre_server/API/Utility/Logging.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CLre_server.API.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class to access Cardlife's built-in logging capabilities.
|
||||
/// The log is saved to outputLog#.Log
|
||||
/// </summary>
|
||||
public static class Logging
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Log(string msg)
|
||||
{
|
||||
Svelto.Console.Log(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a regular message to Cardlife's log
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to log</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Log(object obj)
|
||||
{
|
||||
Svelto.Console.Log(obj.ToString());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void LogError(string msg, Dictionary<string, string> extraData = null)
|
||||
{
|
||||
Svelto.Console.LogError(msg, extraData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an error message to Cardlife's log
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to log</param>
|
||||
/// <param name="extraData">The extra data to pass to the ILogger</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void LogError(object obj, Dictionary<string, string> extraData = null)
|
||||
{
|
||||
Svelto.Console.LogError(obj.ToString(), extraData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an exception to Cardlife's log and to the screen and exit game
|
||||
/// </summary>
|
||||
/// <param name="e">The exception to log</param>
|
||||
/// <param name="extraData">The extra data to pass to the ILogger.
|
||||
/// This is automatically populated with "OuterException#" and "OuterStacktrace#" entries</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void LogException(Exception e, string msg = null, Dictionary<string, string> extraData = null)
|
||||
{
|
||||
Svelto.Console.LogException(msg, e, extraData);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void LogWarning(string msg)
|
||||
{
|
||||
Svelto.Console.LogWarning(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a warning message to Cardlife's log
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to log</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void LogWarning(object obj)
|
||||
{
|
||||
Svelto.Console.LogWarning(obj.ToString());
|
||||
}
|
||||
|
||||
// descriptive logging
|
||||
|
||||
/// <summary>
|
||||
/// Write a descriptive message to Cardlife's log including the calling method's name
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to log</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void MetaLog(object obj)
|
||||
{
|
||||
var method = (new StackTrace()).GetFrame(1).GetMethod();
|
||||
Log($"[{method.DeclaringType.FullName}.{method.Name}] {obj.ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
119
CLre_server/API/Utility/Reflection.cs
Normal file
119
CLre_server/API/Utility/Reflection.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using GameNetworkLayer.Shared;
|
||||
using HarmonyLib;
|
||||
using NetworkFramework.Shared;
|
||||
using Svelto.DataStructures;
|
||||
using Svelto.ECS;
|
||||
|
||||
namespace CLre_server.API.Utility
|
||||
{
|
||||
public static class Reflection
|
||||
{
|
||||
// useful function & method prototypes
|
||||
public delegate T Getter<T>();
|
||||
|
||||
public delegate bool ExistsV1(EGID egid);
|
||||
|
||||
public delegate bool ExistsV2(int id, int groupid);
|
||||
|
||||
public delegate T QueryEntityViewV1<T>(EGID egid);
|
||||
|
||||
public delegate T QueryEntityViewV2<T>(int id, ExclusiveGroup.ExclusiveGroupStruct groupid);
|
||||
|
||||
public delegate ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int group) where T : class, IEntityViewStruct;
|
||||
|
||||
public delegate T[] QueryEntitiesV2<T>(int group, out int count) where T : IEntityStruct;
|
||||
|
||||
public delegate T[] QueryEntitiesV1<T>(ExclusiveGroup.ExclusiveGroupStruct group, out int count) where T : IEntityStruct;
|
||||
|
||||
public delegate object[] SendMessage<T>(NetworkDispatcherCode dispatcherCode, ref T value) where T : struct, ISerializedNetData;
|
||||
|
||||
// useful reflection functions
|
||||
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
||||
{
|
||||
return (TFuncProto) Delegate.CreateDelegate(typeof(TFuncProto), method);
|
||||
}
|
||||
|
||||
public static Delegate BuildDelegateRaw(MethodInfo method, Type TFuncProto)
|
||||
{
|
||||
return Delegate.CreateDelegate(TFuncProto, method);
|
||||
}
|
||||
|
||||
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method, object instance) where TFuncProto : Delegate
|
||||
{
|
||||
return (TFuncProto) Delegate.CreateDelegate(typeof(TFuncProto), instance, method, true);
|
||||
}
|
||||
|
||||
public static Delegate BuildDelegateRaw(MethodInfo method, object instance, Type TFuncProto)
|
||||
{
|
||||
return Delegate.CreateDelegate(TFuncProto, instance, method, true);
|
||||
}
|
||||
|
||||
public static TFuncProto MethodAsDelegate<TFuncProto>(Type class_, string methodName, Type[] parameters = null, Type[] generics = null, object instance = null) where TFuncProto : Delegate
|
||||
{
|
||||
MethodInfo method = AccessTools.Method(class_, methodName, parameters, generics);
|
||||
if (instance != null)
|
||||
{
|
||||
return BuildDelegate<TFuncProto>(method, instance);
|
||||
}
|
||||
return BuildDelegate<TFuncProto>(method);
|
||||
}
|
||||
|
||||
public static Delegate MethodAsDelegateRaw(Type class_, Type TFuncProto, string methodName, Type[] parameters = null, Type[] generics = null, object instance = null)
|
||||
{
|
||||
MethodInfo method = AccessTools.Method(class_, methodName, parameters, generics);
|
||||
if (instance != null)
|
||||
{
|
||||
return BuildDelegateRaw(method, instance, TFuncProto);
|
||||
}
|
||||
return BuildDelegateRaw(method, TFuncProto);
|
||||
}
|
||||
|
||||
public static TFuncProto MethodAsDelegate<TFuncProto>(string typeColonName, Type[] parameters = null, Type[] generics = null, object instance = null) where TFuncProto : Delegate
|
||||
{
|
||||
MethodInfo method = AccessTools.Method(typeColonName, parameters, generics);
|
||||
if (instance != null)
|
||||
{
|
||||
return BuildDelegate<TFuncProto>(method, instance);
|
||||
}
|
||||
return BuildDelegate<TFuncProto>(method);
|
||||
}
|
||||
|
||||
public static Delegate MethodAsDelegateRaw(string typeColonName, Type TFuncProto, Type[] parameters = null, Type[] generics = null, object instance = null)
|
||||
{
|
||||
MethodInfo method = AccessTools.Method(typeColonName, parameters, generics);
|
||||
if (instance != null)
|
||||
{
|
||||
return BuildDelegateRaw(method, instance, TFuncProto);
|
||||
}
|
||||
return BuildDelegateRaw(method, TFuncProto);
|
||||
}
|
||||
|
||||
public static PropertyInfo GetIndexer(this Type type, Type[] arguments = null, BindingFlags bindingFlags = BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.SetField | BindingFlags.SetProperty | BindingFlags.Static)
|
||||
{
|
||||
foreach (PropertyInfo p in type.GetProperties(bindingFlags))
|
||||
{
|
||||
if (arguments == null && p.GetIndexParameters().Length != 0) return p;
|
||||
if (arguments != null)
|
||||
{
|
||||
uint count = 0;
|
||||
foreach (ParameterInfo param in p.GetIndexParameters())
|
||||
{
|
||||
if (param.ParameterType != arguments[count])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
if (count == arguments.Length)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
102
CLre_server/CLre_server.cs
Normal file
102
CLre_server/CLre_server.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using CLre_server.API.Tools;
|
||||
using CLre_server.WebStatus;
|
||||
using GameNetworkLayer.Shared;
|
||||
using HarmonyLib;
|
||||
using Svelto.ECS;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CLre_server
|
||||
{
|
||||
public class CLre : IllusionPlugin.IEnhancedPlugin // the Illusion Plugin Architecture (IPA) will ignore classes that don't implement IPlugin
|
||||
{
|
||||
public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
|
||||
|
||||
public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
|
||||
internal static Harmony harmonyInstance = null;
|
||||
|
||||
// called when Cardlife shuts down
|
||||
public override void OnApplicationQuit()
|
||||
{
|
||||
WebServer.Deinit();
|
||||
harmonyInstance.UnpatchAll();
|
||||
}
|
||||
|
||||
// called when Cardlife starts up
|
||||
public override void OnApplicationStart()
|
||||
{
|
||||
#if DEBUG
|
||||
FileLog.Reset();
|
||||
Harmony.DEBUG = true;
|
||||
// enable CLre debug functionality
|
||||
AccessToolsWarnings.Enable();
|
||||
NetServerListener.Enable();
|
||||
#endif
|
||||
// init all Harmony patches in project
|
||||
harmonyInstance = new Harmony(Name);
|
||||
harmonyInstance.PatchAll();
|
||||
|
||||
// patches for bugs
|
||||
Fixes.InitLogSooner.Init();
|
||||
|
||||
// misc
|
||||
LogIPAPlugins(); // log plugins again so they show up in the log, and not just stdout
|
||||
Fixes.BugfixAttributeUtility.LogBugfixes(); // log bugfixes that are applied
|
||||
|
||||
#if DEBUG
|
||||
// test CLre debug functionality
|
||||
Type netData = AccessTools.TypeByName("Game.Handhelds.DrawingStateMessage");
|
||||
NetServerSender.DebugSendMessage(netData, harmonyInstance,
|
||||
NetServerSender.GetLogMethod(netData));
|
||||
API.Utility.Logging.MetaLog("Patched SendMessage<Game.Handhelds.DrawingStateMessage>");
|
||||
|
||||
netData = AccessTools.TypeByName("Shared.Inventory.HandheldEquipmentRequest");
|
||||
NetServerSender.DebugSendMessage(netData, harmonyInstance,
|
||||
NetServerSender.GetLogMethod(netData));
|
||||
API.Utility.Logging.MetaLog("Patched SendMessage<Shared.Inventory.HandheldEquipmentRequest>");
|
||||
|
||||
NetServerListener.DebugReceiveMessage(NetworkDispatcherCode.EACMessageServerToClient,
|
||||
NetServerListener.Log);
|
||||
|
||||
// API debug and testing
|
||||
API.MainServer.Server.Instance.FrameworkReady += (_, __) => API.Utility.Logging.MetaLog("(!) Server framework ready for business");
|
||||
API.MainServer.Server.Instance.FrameworkExit += (_, __) => API.Utility.Logging.MetaLog("(!) Server framework shutting down"); // this seems to never happen
|
||||
API.MainServer.Server.Instance.InitStart += (_, __) => API.Utility.Logging.MetaLog("(!) Server initialising");
|
||||
API.MainServer.Server.Instance.InitComplete += (_, __) => API.Utility.Logging.MetaLog("(!) Server successfully initialised");
|
||||
#endif
|
||||
WebServer.Init();
|
||||
// Log info
|
||||
API.Utility.Logging.MetaLog($"{Name} init complete.");
|
||||
}
|
||||
|
||||
private static void LogIPAPlugins()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Running on Unity {0}\n", Application.unityVersion);
|
||||
sb.AppendFormat("Running on CardLife Server {0} (aka {1})\n", Game.Utilities.VersionReader.GetVersion(), Application.version);
|
||||
sb.AppendFormat("-----------------------------\n");
|
||||
sb.AppendFormat("Loading plugins from {0} and found {1}\n", System.IO.Path.Combine(Environment.CurrentDirectory, "Plugins"), IllusionInjector.PluginManager.Plugins.Count());
|
||||
sb.AppendFormat("-----------------------------\n");
|
||||
foreach (IllusionPlugin.IPlugin plugin in IllusionInjector.PluginManager.Plugins)
|
||||
{
|
||||
|
||||
sb.AppendFormat(" {0}: {1}\n", plugin.Name, plugin.Version);
|
||||
}
|
||||
sb.AppendFormat("-----------------------------\n");
|
||||
API.Utility.Logging.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public override void OnGUI()
|
||||
{
|
||||
if (GUI.Button(new Rect(10, 10, 50, 50), "QUIT"))
|
||||
{
|
||||
Application.Quit(); // yeet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
292
CLre_server/CLre_server.csproj
Normal file
292
CLre_server/CLre_server.csproj
Normal file
|
@ -0,0 +1,292 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Version>0.0.2</Version>
|
||||
<Authors>NGnius</Authors>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://git.exmods.org/NGnius/CLre</PackageProjectUrl>
|
||||
<NeutralLanguage>en-CA</NeutralLanguage>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Lib.Harmony" Version="2.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<!--Start Dependencies-->
|
||||
<ItemGroup>
|
||||
<Reference Include="Accessibility">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Accessibility.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BehaviorDesignerRuntime">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\BehaviorDesignerRuntime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DOTween">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\DOTween.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EasyAntiCheat.Client">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\EasyAntiCheat.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EasyAntiCheat.Server">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\EasyAntiCheat.Server.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Fabric.AudioSpline">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Fabric.AudioSpline.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Fabric.Core">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Fabric.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\mscorlib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Novell.Directory.Ldap">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Novell.Directory.Ldap.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Photon3Unity3D">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Photon3Unity3D.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Rewired_Core">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Rewired_Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Rewired_Windows_Lib">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Rewired_Windows_Lib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Svelto.Common">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Svelto.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Svelto.ECS">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Svelto.ECS.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Svelto.Tasks">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Svelto.Tasks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Unity.Postprocessing.Runtime">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Unity.TextMeshPro">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AccessibilityModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AIModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.AIModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ARModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ARModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AssetBundleModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AudioModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.BaselibModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.BaselibModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ClothModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ClusterInputModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ClusterRendererModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CrashReportingModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.DirectorModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.DirectorModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.FileSystemHttpModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.FileSystemHttpModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.GameCenterModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.GridModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.GridModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.HotReloadModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ImageConversionModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.InputModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.JSONSerializeModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.LocalizationModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.Networking">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.Networking.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ParticleSystemModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PerformanceReportingModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.Physics2DModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ProfilerModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.ScreenCaptureModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.SharedInternalsModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.SpatialTracking">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.SpatialTracking.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.SpriteMaskModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.SpriteShapeModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.StreamingModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.StreamingModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.StyleSheetsModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.StyleSheetsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.SubstanceModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TerrainModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TerrainModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TerrainPhysicsModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextCoreModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TilemapModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TilemapModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.Timeline">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.Timeline.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TimelineModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TimelineModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TLSModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIElementsModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UmbraModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UmbraModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UNETModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UNETModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityAnalyticsModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityConnectModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityTestProtocolModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.VehiclesModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.VFXModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.VFXModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.VideoModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.VRModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.WindModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.WindModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.XRModule">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="IllusionInjector">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\IllusionInjector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="IllusionPlugin">
|
||||
<HintPath>..\..\cl\CardlifeGameServer_Data\Managed\IllusionPlugin.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="WebStatus\Assets\index.html" />
|
||||
<EmbeddedResource Include="WebStatus\Assets\index.html" />
|
||||
<None Remove="WebStatus\Assets\error404.html" />
|
||||
<EmbeddedResource Include="WebStatus\Assets\error404.html" />
|
||||
</ItemGroup>
|
||||
<!--End Dependencies-->
|
||||
|
||||
</Project>
|
118
CLre_server/Fixes/BugfixAttribute.cs
Normal file
118
CLre_server/Fixes/BugfixAttribute.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace CLre_server.Fixes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class BugfixAttribute : Attribute
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string description { get; set; }
|
||||
public Type target { get; set; }
|
||||
public string more { get; set; }
|
||||
public uint id { get; set; }
|
||||
public BugfixType component { get; set; }
|
||||
}
|
||||
|
||||
public enum BugfixType : byte
|
||||
{
|
||||
Miscellaneous = 0x00,
|
||||
HarmonyPatch,
|
||||
Initialiser,
|
||||
Workaround,
|
||||
API,
|
||||
Debug
|
||||
}
|
||||
|
||||
internal static class BugfixAttributeUtility
|
||||
{
|
||||
public static void LogBugfixes()
|
||||
{
|
||||
List<uint> keys = new List<uint>();
|
||||
Dictionary<uint, BugfixStruct> fixes = new Dictionary<uint, BugfixStruct>();
|
||||
foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
|
||||
{
|
||||
BugfixAttribute b = t.GetCustomAttribute<BugfixAttribute>(true);
|
||||
if (b != null)
|
||||
{
|
||||
if (!fixes.ContainsKey(b.id))
|
||||
{
|
||||
BugfixStruct bugfixStruct = new BugfixStruct{id = b.id};
|
||||
bugfixStruct.Merge(b);
|
||||
fixes[b.id] = bugfixStruct;
|
||||
keys.Add(b.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BugfixStruct bugfixStruct = fixes[b.id];
|
||||
bugfixStruct.Merge(b);
|
||||
fixes[b.id] = bugfixStruct;
|
||||
}
|
||||
}
|
||||
}
|
||||
keys.Sort();
|
||||
//keys.Sort((u, u1) => u.CompareTo(u1));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Applying {0} CLre fixes\n", keys.Count);
|
||||
sb.AppendFormat("-----------------------------\n");
|
||||
foreach (uint i in keys)
|
||||
{
|
||||
sb.Append(fixes[i].ToString());
|
||||
sb.Append("\n");
|
||||
}
|
||||
sb.AppendFormat("-----------------------------\n");
|
||||
API.Utility.Logging.Log(sb.ToString());
|
||||
}
|
||||
|
||||
private struct BugfixStruct
|
||||
{
|
||||
public string name;
|
||||
public string description;
|
||||
public Type target;
|
||||
public string more;
|
||||
public uint id;
|
||||
private uint total;
|
||||
private uint[] bugfixTypeCount;
|
||||
|
||||
public void Merge(BugfixAttribute b)
|
||||
{
|
||||
if (name == null && b.name != null) name = b.name;
|
||||
if (description == null && b.description != null) description = b.description;
|
||||
if (target == null && b.target != null) target = b.target;
|
||||
if (more == null && b.more != null) more = b.more;
|
||||
total++;
|
||||
if (bugfixTypeCount == null) bugfixTypeCount = new uint[Enum.GetNames(typeof(BugfixType)).Length];
|
||||
bugfixTypeCount[(byte) b.component]++;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat(" {0}: ", name);
|
||||
if (more != null)
|
||||
{
|
||||
sb.AppendFormat("[MORE: {0}] ", more);
|
||||
}
|
||||
else if (description != null)
|
||||
{
|
||||
sb.Append(description);
|
||||
sb.Append(" ");
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
sb.AppendFormat("[TARGET: {0}] ", target.FullName);
|
||||
}
|
||||
sb.AppendFormat("[ID: {0}] ", id);
|
||||
sb.AppendFormat("({0}M/{1}P/{2}I/{3}W/{4}A/{5}D/{6}T)",
|
||||
bugfixTypeCount[(byte) BugfixType.Miscellaneous], bugfixTypeCount[(byte) BugfixType.HarmonyPatch],
|
||||
bugfixTypeCount[(byte) BugfixType.Initialiser], bugfixTypeCount[(byte) BugfixType.Workaround],
|
||||
bugfixTypeCount[(byte) BugfixType.API], bugfixTypeCount[(byte) BugfixType.Debug], total);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
84
CLre_server/Fixes/InitLogSooner.cs
Normal file
84
CLre_server/Fixes/InitLogSooner.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace CLre_server.Fixes
|
||||
{
|
||||
[Bugfix(name = "InitLogSooner",
|
||||
description = "Start the logger slightly sooner than Cardlife does",
|
||||
component = BugfixType.Initialiser, id = 0)]
|
||||
public static class InitLogSooner
|
||||
{
|
||||
public static int millisecondsTimeout = 5000;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
CustomLoggerThread_CreateGameObject_Patch.allowed = true;
|
||||
CustomLoggerThread.CreateGameObject();
|
||||
CustomLoggerThread_CreateGameObject_Patch.allowed = false;
|
||||
API.Utility.Logging.Log($"Completed early log init, hello!");
|
||||
//System.IO.File.WriteAllText("InitLogSooner.log", $"Done at " + System.DateTime.Now.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.Utility.Logging.Log($"Failed to initialise log sooner, reason:\n" + e);
|
||||
System.IO.File.WriteAllText("InitLogSooner.log", e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Bugfix(name = "InitLogSooner",
|
||||
target = typeof(CustomLoggerThread),
|
||||
component = BugfixType.HarmonyPatch, id = 0)]
|
||||
[HarmonyPatch(typeof(CustomLoggerThread), "CreateGameObject")]
|
||||
class CustomLoggerThread_CreateGameObject_Patch
|
||||
{
|
||||
internal static bool allowed = false;
|
||||
|
||||
public static bool Prefix()
|
||||
{
|
||||
return allowed;
|
||||
}
|
||||
}
|
||||
|
||||
[Bugfix(name = "InitLogSooner",
|
||||
component = BugfixType.HarmonyPatch, id = 0)]
|
||||
[HarmonyPatch(typeof(CustomLoggerThread), "StartQueue")]
|
||||
class CustomLoggerThread_StartQueue_Patch
|
||||
{
|
||||
internal static volatile bool IsLogStarted = false;
|
||||
|
||||
private delegate void Flusher();
|
||||
|
||||
public static bool Prefix()
|
||||
{
|
||||
// setup thru reflection
|
||||
FieldInfo quitThreadField = AccessTools.Field(typeof(CustomLoggerThread), "_quitThread");
|
||||
|
||||
MethodInfo flushLoggerMethod = AccessTools.Method(typeof(CustomLoggerThread), "FlushLogger");
|
||||
Flusher flushLogger = (Flusher) Delegate.CreateDelegate(typeof(Action), null, flushLoggerMethod);
|
||||
|
||||
MethodInfo forceFlushMethod = AccessTools.Method("CustomLogger:ForceFlush");
|
||||
Flusher forceFlush = (Flusher) Delegate.CreateDelegate(typeof(Action), null, forceFlushMethod);
|
||||
|
||||
Thread.MemoryBarrier();
|
||||
IsLogStarted = true;
|
||||
while (!(bool) quitThreadField.GetValue(null))
|
||||
{
|
||||
flushLogger();
|
||||
forceFlush();
|
||||
Thread.Sleep(millisecondsTimeout);
|
||||
}
|
||||
|
||||
IsLogStarted = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
74
CLre_server/WebStatus/AssetEndpoints.cs
Normal file
74
CLre_server/WebStatus/AssetEndpoints.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace CLre_server.WebStatus
|
||||
{
|
||||
public static class AssetEndpoints
|
||||
{
|
||||
[WebEndpoint("/")]
|
||||
public static void LandingPage(HttpListenerContext ctx)
|
||||
{
|
||||
ctx.Response.Headers.Add("Content-Type", "text/html");
|
||||
Asset(ctx, "CLre_server.WebStatus.Assets.index.html");
|
||||
}
|
||||
|
||||
[WebEndpoint("/asset")]
|
||||
public static void AllAssets(HttpListenerContext ctx)
|
||||
{
|
||||
ctx.Response.Headers.Add("Content-Type", "text/html");
|
||||
Asset(ctx, "");
|
||||
}
|
||||
|
||||
[WebEndpoint("/asset/404")]
|
||||
public static void Asset404(HttpListenerContext ctx)
|
||||
{
|
||||
ctx.Response.Headers.Add("Content-Type", "text/html");
|
||||
Asset(ctx, "CLre_server.WebStatus.Assets.error404.html");
|
||||
}
|
||||
|
||||
private static bool Asset(HttpListenerContext ctx, string name)
|
||||
{
|
||||
Assembly asm = Assembly.GetCallingAssembly();
|
||||
Stream resource = asm.GetManifestResourceStream(name);
|
||||
if (resource == null)
|
||||
{
|
||||
string assetStr = ListAssetsHtml(asm);
|
||||
byte[] output = Encoding.UTF8.GetBytes(assetStr);
|
||||
ctx.Response.OutputStream.Write(output, 0, output.Length);
|
||||
return false;
|
||||
}
|
||||
resource.CopyTo(ctx.Response.OutputStream);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string ListAssetsHtml(Assembly target)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'><title>Asset not found</title></head><body><h1>");
|
||||
sb.Append(target.GetName().Name);
|
||||
sb.Append(" available assets</h1>");
|
||||
foreach (string asset in target.GetManifestResourceNames())
|
||||
{
|
||||
sb.Append("<li>");
|
||||
sb.Append(asset);
|
||||
sb.Append("</li>");
|
||||
}
|
||||
|
||||
sb.Append("</ul></body></html>");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string ListAssetsText(Assembly target)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(target.FullName);
|
||||
foreach (string asset in target.GetManifestResourceNames())
|
||||
{
|
||||
sb.Append("\n\t");
|
||||
sb.Append(asset);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
13
CLre_server/WebStatus/Assets/error404.html
Normal file
13
CLre_server/WebStatus/Assets/error404.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>404 Not Found</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Page not found</h1>
|
||||
<div>
|
||||