using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Addon
{
// ***** Uncomment if using .NET Framework 2.0 .NET Framework 3.0, or .NET Framework 3.5 *****
// ***** Yes, all of it, seriously. *****
/*
public delegate TResult Func<TResult>();
public delegate void Action();
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate void Action<T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
public delegate void Action<T1, T2, T3, T4, T5, T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
public delegate void Action<T1, T2, T3, T4, T5, T6, T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
public delegate void Action<T1, T2, T3, T4, T5, T6, T7, T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
public delegate void Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
*/
enum ParameterType
{
Entity = 1,
String = 2,
Vector = 4,
Float = 5,
Integer = 6
}
class Parameter
{
private static readonly IntPtr EntityAddress = (IntPtr)0x01918900;
private static readonly IntPtr ClientAddress = (IntPtr)0x4A0FE90;
private readonly object _value;
private readonly ParameterType _type;
internal Parameter(object value, ParameterType type)
{
_value = value;
_type = type;
}
public ParameterType Type
{
get { return _type; }
}
public object Value
{
get { return _value; }
}
public bool IsPlayer
{
get { return _type == ParameterType.Entity && (int)_value < 18; }
}
public bool IsEntity
{
get { return _type == ParameterType.Entity && (int)_value >= 18; }
}
public T As<T>()
{
if (typeof(T) == typeof(Entity))
return (T)(object)GetEntity();
if (typeof(T) == typeof(ServerClient))
return (T)(object)GetClient();
if (typeof(T) == typeof(bool) && _type == ParameterType.Integer)
return (T)(object)((int)_value != 0);
return (T)Convert.ChangeType(_value, typeof(T));
}
public static implicit operator Parameter(string value)
{
return new Parameter(value, ParameterType.String);
}
public static implicit operator Parameter(int value)
{
return new Parameter(value, ParameterType.Integer);
}
public static implicit operator Parameter(float value)
{
return new Parameter(value, ParameterType.Float);
}
public static implicit operator Parameter(Vector value)
{
return new Parameter(value, ParameterType.Vector);
}
public static implicit operator Parameter(ServerClient client)
{
return new Parameter(client.ClientNum, ParameterType.Entity);
}
public static implicit operator Parameter(Entity entity)
{
return new Parameter(entity.EntityNum, ParameterType.Entity);
}
private Entity GetEntity()
{
// Get the constructor for the Entity class.
var entityConstructors = typeof(Entity).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
// Invoke the constructor with no arguments.
var entity = (Entity)entityConstructors[0].Invoke(null);
// Call the internal SetInformation method with a pointer to the Entity.
typeof(Entity).GetMethod("SetInformation", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(entity, new object[] { GetEntityFromNum((int)_value) });
return entity;
}
private ServerClient GetClient()
{
// Get the constructor for the Client class.
var clientConstructors = typeof(ServerClient).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
// Invoke the constructor with no arguments.
var client = (ServerClient)clientConstructors[0].Invoke(null);
// Call the internal SetInformation method with a pointer to the Entity.
typeof(ServerClient).GetMethod("SetInformation", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(client, new object[] { GetClientFromNum((int)_value) });
return client;
}
private static IntPtr GetEntityFromNum(int entityNum)
{
return (IntPtr)(EntityAddress.ToInt32() + entityNum * 0x274);
}
private static IntPtr GetClientFromNum(int clientNum)
{
return (IntPtr)(ClientAddress.ToInt32() + clientNum * 0x78690);
}
}
static class Timing
{
class ServerTimer
{
public int Interval { get; set; }
public long Time { get; set; }
public ServerClient Target { get; set; }
public Delegate Function { get; set; }
}
class ServerNotify
{
public int TargetNum { get; set; }
public bool HasTarget { get; set; }
public Delegate Function { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
struct Vec3
{
public float X;
public float Y;
public float Z;
public static implicit operator Vec3(Vector vector)
{
return new Vec3 { X = vector.X, Y = vector.Y, Z = vector.Z };
}
public static implicit operator Vector(Vec3 vector)
{
return new Vector(vector.X, vector.Y, vector.Z);
}
}
private static readonly byte[] ScrAddStringStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x51, // push ecx
0x57, // push edi
0xC7, 0x45, 0xFC, 0xD0, 0x11, 0x4F, 0x00, // mov dword ptr [ebp-4], 4F11D0
0x8B, 0x7D, 0x08, // mov edi, [ebp+8]
0xFF, 0x55, 0xFC, // call [ebp-4]
0x5F, // pop edi
0x8B, 0xE5, // mov esp, ebp
0x5D, // pop ebp
0xC3 // retn
};
private static readonly byte[] ScrAddObjectStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x51, // push ecx
0x56, // push esi
0xC7, 0x45, 0xFC, 0x50, 0x11, 0x4F, 0x00, // mov dword ptr [ebp-4], 4F1150
0x8B, 0x75, 0x08, // mov esi, [ebp+8]
0xFF, 0x55, 0xFC, // call [ebp-4]
0x5E, // pop esi
0x8B, 0xE5, // mov esp, ebp
0x5D, // pop ebp
0xC3 // retn
};
private static readonly byte[] ScrAddVectorStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x51, // push ecx
0x57, // push edi
0xC7, 0x45, 0xFC, 0xF0, 0x12, 0x4F, 0x00, // mov dword ptr [ebp-4], 4F12F0
0x8B, 0x7D, 0x08, // mov edi, [ebp+8]
0xFF, 0x55, 0xFC, // call [ebp-4]
0x5F, // pop edi
0x8B, 0xE5, // mov esp, ebp
0x5D, // pop ebp
0xC3 // retn
};
private static readonly byte[] ScrNotifyNumStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x51, // push ecx
0xC7, 0x45, 0xFC, 0x00, 0xFD, 0x4E, 0x00, // mov dword ptr [ebp-4], 4EFD00
0x8B, 0x45, 0x0C, // mov eax, [ebp+C]
0xFF, 0x75, 0x14, // push [ebp+14]
0xFF, 0x75, 0x10, // push [ebp+10]
0xFF, 0x75, 0x08, // push [ebp+8]
0xFF, 0x55, 0xFC, // call [ebp-4]
0x83, 0xC4, 0x0C, // add esp, C
0x8B, 0xE5, // mov esp, ebp
0x5D, // pop ebp
0xC3 // retn
};
private static byte[] VmExecuteHookStub = new byte[]
{
0x8B, 0x44, 0x24, 0x0C, // mov eax, [esp+0Ch]
0x50, // push eax
0x8B, 0x44, 0x24, 0x0C, // mov eax, [esp+0Ch]
0x50, // push eax
0x8B, 0x44, 0x24, 0x0C, // mov eax, [esp+0Ch]
0x50, // push eax
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <handler>
0xFF, 0xD0, // call eax
0x83, 0xC4, 0x0C, // add esp, 0Ch
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x83, 0xE4, 0xF8, // and esp, 0FFFFFFF8h
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <dest>
0xFF, 0xE0, // jmp eax
};
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
private const uint MEM_COMMIT = 0x1000;
private const uint MEM_RESERVE = 0x2000;
private const uint PAGE_EXECUTE_READWRITE = 0x40;
private const uint MB_ICONERROR = 0x10;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void GameScriptNotifyHandlerDelegate(int entity, uint type, IntPtr variableStack);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int ScrAddFloatDelegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int ScrAddIntegerDelegate(int value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate void ScrAddStringDelegate(string value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int ScrGetEntityIdDelegate(int entityNum, int entityShift);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ScrAddObjectDelegate(int num);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ScrAddVectorDelegate(ref Vec3 vector);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate int ScrPrepareNotifyDelegate(string message, int zero, int messageLength);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ScrNotifyNumDelegate(int entNum, int entShift, int prepareResult, int paramCount);
private static readonly IntPtr VirtualMachineExecuteAddress = (IntPtr)0x4EF610;
private static readonly IntPtr GameScriptStringTablePointer = (IntPtr)0x1C122A4;
private static readonly IntPtr GameScriptObjectTypeArray = (IntPtr)0x1D39804;
private static readonly IntPtr GameScriptObjectToEntityLo = (IntPtr)0x1D39802;
private static readonly IntPtr ScrAddFloatAddress = (IntPtr)0x4F1070;
private static readonly IntPtr ScrAddIntegerAddress = (IntPtr)0x4F1020;
private static readonly IntPtr ScrGetEntityIdAddress = (IntPtr)0x4EA450;
private static readonly IntPtr ScrPrepareNotifyAddress = (IntPtr)0x4E7650;
private static readonly List<ServerTimer> Timers = new List<ServerTimer>();
private static readonly Stopwatch Stopwatch = new Stopwatch();
private static readonly Dictionary<string, List<ServerNotify>> NotifyHandlers = new Dictionary<string, List<ServerNotify>>();
private static ScrAddFloatDelegate _scrAddFloatFunc;
private static ScrAddIntegerDelegate _scrAddIntegerFunc;
private static ScrAddStringDelegate _scrAddStringFunc;
private static ScrGetEntityIdDelegate _scrGetEntityIdFunc;
private static ScrAddObjectDelegate _scrAddObjectFunc;
private static ScrAddVectorDelegate _scrAddVectorFunc;
private static ScrPrepareNotifyDelegate _scrPrepareNotifyFunc;
private static ScrNotifyNumDelegate _scrNotifyNumFunc;
private static GCHandle _gch;
private static IntPtr _scrNotifyStack = IntPtr.Zero;
private static IntPtr _scrAddStringFuncAddress = IntPtr.Zero;
private static IntPtr _scrAddObjectFuncAddress = IntPtr.Zero;
private static IntPtr _scrAddVectorFuncAddress = IntPtr.Zero;
private static IntPtr _scrNotifyNumFuncAddress = IntPtr.Zero;
static Timing()
{
HookGameScriptNotifyHandler();
Stopwatch.Start();
}
private static void PushFloat(float value)
{
if (_scrAddFloatFunc == null)
_scrAddFloatFunc = (ScrAddFloatDelegate)Marshal.GetDelegateForFunctionPointer(ScrAddFloatAddress, typeof(ScrAddFloatDelegate));
_scrAddFloatFunc(value);
}
private static void PushInteger(int value)
{
if (_scrAddIntegerFunc == null)
_scrAddIntegerFunc = (ScrAddIntegerDelegate)Marshal.GetDelegateForFunctionPointer(ScrAddIntegerAddress, typeof(ScrAddIntegerDelegate));
_scrAddIntegerFunc(value);
}
private static void PushString(string value)
{
if (_scrAddStringFuncAddress == IntPtr.Zero)
{
_scrAddStringFuncAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)ScrAddStringStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (_scrAddStringFuncAddress == IntPtr.Zero)
return;
Marshal.Copy(ScrAddStringStub, 0, _scrAddStringFuncAddress, ScrAddStringStub.Length);
_scrAddStringFunc = (ScrAddStringDelegate)Marshal.GetDelegateForFunctionPointer(_scrAddStringFuncAddress, typeof(ScrAddStringDelegate));
}
_scrAddStringFunc(value);
}
private static void PushEntity(int entityNum)
{
if (_scrGetEntityIdFunc == null)
_scrGetEntityIdFunc = (ScrGetEntityIdDelegate)Marshal.GetDelegateForFunctionPointer(ScrGetEntityIdAddress, typeof(ScrGetEntityIdDelegate));
if (_scrAddObjectFuncAddress == IntPtr.Zero)
{
_scrAddObjectFuncAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)ScrAddObjectStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (_scrAddObjectFuncAddress == IntPtr.Zero)
return;
Marshal.Copy(ScrAddObjectStub, 0, _scrAddObjectFuncAddress, ScrAddObjectStub.Length);
_scrAddObjectFunc = (ScrAddObjectDelegate)Marshal.GetDelegateForFunctionPointer(_scrAddObjectFuncAddress, typeof(ScrAddObjectDelegate));
}
int result = _scrGetEntityIdFunc(entityNum, entityNum >> 16);
_scrAddObjectFunc(result);
}
private static void PushVector(Vector vector)
{
if (_scrAddVectorFuncAddress == IntPtr.Zero)
{
_scrAddVectorFuncAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)ScrAddVectorStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (_scrAddVectorFuncAddress == IntPtr.Zero)
return;
Marshal.Copy(ScrAddVectorStub, 0, _scrAddVectorFuncAddress, ScrAddVectorStub.Length);
_scrAddVectorFunc = (ScrAddVectorDelegate)Marshal.GetDelegateForFunctionPointer(_scrAddVectorFuncAddress, typeof(ScrAddVectorDelegate));
}
Vec3 vec = vector;
_scrAddVectorFunc(ref vec);
}
public static void Notify(Entity entity, string message, params Parameter[] parameters)
{
Notify(entity.EntityNum, message, parameters);
}
public static void Notify(ServerClient client, string message, params Parameter[] parameters)
{
Notify(client.ClientNum, message, parameters);
}
private static void Notify(int entNum, string message, params Parameter[] parameters)
{
if (_scrPrepareNotifyFunc == null)
_scrPrepareNotifyFunc = (ScrPrepareNotifyDelegate)Marshal.GetDelegateForFunctionPointer(ScrPrepareNotifyAddress, typeof(ScrPrepareNotifyDelegate));
if (_scrNotifyNumFuncAddress == IntPtr.Zero)
{
_scrNotifyNumFuncAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)ScrNotifyNumStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (_scrNotifyNumFuncAddress == IntPtr.Zero)
return;
Marshal.Copy(ScrNotifyNumStub, 0, _scrNotifyNumFuncAddress, ScrNotifyNumStub.Length);
_scrNotifyNumFunc = (ScrNotifyNumDelegate)Marshal.GetDelegateForFunctionPointer(_scrNotifyNumFuncAddress, typeof(ScrNotifyNumDelegate));
}
Array.Reverse(parameters);
foreach (var param in parameters)
{
switch (param.Type)
{
case ParameterType.Float:
PushFloat(Convert.ToSingle(param.Value));
break;
case ParameterType.Integer:
PushInteger(Convert.ToInt32(param.Value));
break;
case ParameterType.String:
PushString(Convert.ToString(param.Value));
break;
case ParameterType.Entity:
PushEntity(Convert.ToInt32(param.Value));
break;
case ParameterType.Vector:
PushVector((Vector)param.Value);
break;
}
}
int result = _scrPrepareNotifyFunc(message, 0, message.Length + 1);
_scrNotifyNumFunc(entNum, entNum >> 16, result, parameters.Length);
}
private static void HookGameScriptNotifyHandler()
{
var handler = new GameScriptNotifyHandlerDelegate(GameScriptNotifyHandlerHook);
_gch = GCHandle.Alloc(handler); // Prevent GC from relocating/freeing function.
var handlerAddress = Marshal.GetFunctionPointerForDelegate(handler);
var hookStub = VirtualAlloc(IntPtr.Zero, (UIntPtr)VmExecuteHookStub.Length, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
BitConverter.GetBytes(handlerAddress.ToInt32()).CopyTo(VmExecuteHookStub, 16);
BitConverter.GetBytes(VirtualMachineExecuteAddress.ToInt32() + 6).CopyTo(VmExecuteHookStub, 32);
Marshal.Copy(VmExecuteHookStub, 0, hookStub, VmExecuteHookStub.Length);
SetJmpHook(VirtualMachineExecuteAddress, hookStub);
}
private static void SetJmpHook(IntPtr original, IntPtr destination)
{
uint oldProtect;
VirtualProtect(original, (UIntPtr)5, PAGE_EXECUTE_READWRITE, out oldProtect);
var hook = new byte[5];
hook[0] = 0xE9;
BitConverter.GetBytes((destination.ToInt32() - original.ToInt32()) - 5).CopyTo(hook, 1);
Marshal.Copy(hook, 0, original, hook.Length);
VirtualProtect(original, (UIntPtr)5, oldProtect, out oldProtect);
}
private static int GetObjectType(int @object)
{
return Marshal.ReadInt32(GameScriptObjectTypeArray, 8 * @object);
}
private static IntPtr GetVariableStackValueFromIndex(int index)
{
return (IntPtr)(_scrNotifyStack.ToInt32() + -8 * index);
}
private static object[] GetParameters(int argumentCount)
{
var param = new object[argumentCount];
for (int i = 0; i < argumentCount; i++)
{
var paramType = (ParameterType)Marshal.ReadInt32(GetVariableStackValueFromIndex(i), 4);
object value = null;
switch (paramType)
{
case ParameterType.Integer:
value = Marshal.ReadInt32(GetVariableStackValueFromIndex(i));
break;
case ParameterType.String:
int stringIndex = Marshal.ReadInt16(GetVariableStackValueFromIndex(i));
value = Marshal.PtrToStringAnsi((IntPtr)(Marshal.ReadInt32(GameScriptStringTablePointer) + 12 * stringIndex + 4));
break;
case ParameterType.Float:
value = Marshal.PtrToStructure(GetVariableStackValueFromIndex(i), typeof(float));
break;
case ParameterType.Entity:
int entityObjectId = Marshal.ReadInt32(GetVariableStackValueFromIndex(i));
value = ScriptObjectIDToEntityNum(entityObjectId);
break;
case ParameterType.Vector:
value = (Vector)(Vec3)Marshal.PtrToStructure(Marshal.ReadIntPtr(GetVariableStackValueFromIndex(i)), typeof(Vec3));
break;
}
param[i] = new Parameter(value, paramType);
}
return param;
}
private static int ScriptObjectIDToEntityNum(int scriptObjectId)
{
var loword = (uint)(Marshal.ReadInt16(GameScriptObjectToEntityLo, 8 * scriptObjectId));
var hiword = (uint)(Marshal.ReadInt32(GameScriptObjectTypeArray, 8 * scriptObjectId) >> 8);
return (int)((hiword << 16) | (loword & 0xFFFF));
}
private static int GetNotifyArgumentCount()
{
int argumentCount = 0;
if (Marshal.ReadInt32(_scrNotifyStack, 4) != 8)
{
for (int i = _scrNotifyStack.ToInt32(); Marshal.ReadInt32((IntPtr)i, 4) != 8; i -= 8)
argumentCount++;
}
return argumentCount;
}
private static void DispatchMessage(int targetEntityNum, string message)
{
foreach (var handler in NotifyHandlers[message])
{
// Check if the handler specified a client or entity, if so, check the client num.
if (handler.HasTarget && handler.TargetNum != targetEntityNum)
continue;
var handlerParams = handler.Function.Method.GetParameters();
// Check if the handler function has parameters.
if (handlerParams.Length > 0)
{
// Calculate the number of arguments.
int argumentCount = GetNotifyArgumentCount();
// Get the parameters.
object[] parameters = GetParameters(argumentCount);
// Fix the parameters if the user omitted some of them.
var fixedParameters = new object[handlerParams.Length];
Array.Copy(parameters, fixedParameters, fixedParameters.Length);
// Dynamically invoke the function.
handler.Function.DynamicInvoke(fixedParameters);
}
else
{
// Perform a dynamic invoke with no arguments.
handler.Function.DynamicInvoke();
}
}
}
private static void HandleNotifyEvent(int entity, uint type)
{
if (type == 0)
return;
// Get the current message address.
var messageAddress = (IntPtr)(Marshal.ReadInt32(GameScriptStringTablePointer) + 12 * type + 4);
if (messageAddress == IntPtr.Zero)
return;
int targetEntityNum = -1;
// Check if the script object type is an entity/client.
if (GetObjectType(entity) == 21)
{
// Convert the script object ID to an entity/client num.
targetEntityNum = ScriptObjectIDToEntityNum(entity);
}
// Get the current message.
string message = Marshal.PtrToStringAnsi(messageAddress);
// Check the message is valid and notify the handlers.
if (string.IsNullOrEmpty(message) || !NotifyHandlers.ContainsKey(message))
return;
try
{
DispatchMessage(targetEntityNum, message);
}
catch (Exception ex)
{
// Catch any errors and display it as a message box since there's no way to
// log it without a plugin instance.
MessageBox(IntPtr.Zero, ex.ToString(), "HandleNotifyEvent failed.", MB_ICONERROR);
}
}
private static void GameScriptNotifyHandlerHook(int entity, uint type, IntPtr variableStack)
{
_scrNotifyStack = variableStack;
HandleNotifyEvent(entity, type);
}
public static void OnInterval(int interval, ServerClient target, Func<bool> function)
{
Timers.Add(new ServerTimer { Interval = interval, Function = function, Target = target });
}
public static void OnInterval(int interval, Func<bool> function)
{
Timers.Add(new ServerTimer { Interval = interval, Function = function });
}
public static void AfterDelay(int delay, ServerClient target, Action action)
{
Timers.Add(new ServerTimer { Interval = -1, Time = Stopwatch.ElapsedMilliseconds + delay, Function = action, Target = target });
}
public static void AfterDelay(int delay, Action action)
{
Timers.Add(new ServerTimer { Interval = -1, Time = Stopwatch.ElapsedMilliseconds + delay, Function = action });
}
public static void ProcessFrame(List<ServerClient> clients)
{
var currentTime = Stopwatch.ElapsedMilliseconds;
foreach (var timer in Timers.ToArray())
{
if (currentTime < timer.Time)
continue;
if (timer.Target != null && clients.FindIndex(sc => sc.XUID == timer.Target.XUID) == -1)
{
Timers.Remove(timer);
continue;
}
object returnValue = timer.Function.DynamicInvoke();
if (timer.Interval == -1 || timer.Function.Method.ReturnType == typeof(bool) && !(bool)returnValue)
{
Timers.Remove(timer);
}
else
{
timer.Time = currentTime + timer.Interval;
}
}
}
private static void OnNotify(string type, Delegate action, bool hasTarget, int targetNum)
{
var serverNotify = new ServerNotify { Function = action, HasTarget = hasTarget, TargetNum = targetNum };
if (NotifyHandlers.ContainsKey(type))
NotifyHandlers[type].Add(serverNotify);
else
NotifyHandlers.Add(type, new List<ServerNotify>(new[] { serverNotify }));
}
public static void OnNotify(string type, Action action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, false, -1);
}
public static void OnNotify(string type, ServerClient client, Action action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, ServerClient client, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, client.ClientNum);
}
public static void OnNotify(string type, Entity entity, Action action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
public static void OnNotify(string type, Entity entity, Action<Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter, Parameter> action)
{
OnNotify(type, action, true, entity.EntityNum);
}
}
}