openDecal/Managed/Decal.Adapter/Decal.Adapter.IDQueue/FairIDQueue.cs
erik d1442e3747 Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild:

Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil)
Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs
  - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters
  - Decal.Core, DecalControls, DecalRender, D3DService
Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL
Phase 4: DenAgent WinForms tray application
Phase 5: WiX installer and build script

25 C# projects building with 0 errors.
Native C++ projects require VS 2022 + Windows SDK (x86).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:27:56 +01:00

213 lines
5 KiB
C#

using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Decal.Adapter.Support;
using Decal.Adapter.Wrappers;
using Decal.Interop.Core;
namespace Decal.Adapter.IDQueue;
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IIdentifyFilter))]
[ProgId("DecalAdapter.FairIDQueue")]
[Guid("5CD85A12-3DED-48E7-B440-B41E2A1452D9")]
[CLSCompliant(true)]
public class FairIDQueue : FairRoundRobinScheduleQueue<Assembly, int>, IIdentifyFilter
{
private static int iVal = 1126270821;
private const int REQUEST_INTERVAL = 600;
private const int MAX_TRY_COUNT = 3;
private const int NULL_ACTION_ID = -1;
private Timer FireTimer = new Timer();
private DateTime LastFireTime = DateTime.MinValue;
private uint CurrentTimerFrame;
private uint LastTimerFireFrame;
private int UserRequestedID = -1;
private int UserRequestedAttempts;
private EventHandler<UserIDRequestProcessedEventArgs> mUserIDRequestProcessed;
[CLSCompliant(false)]
public event EventHandler<UserIDRequestProcessedEventArgs> UserIDRequestProcessed
{
add
{
mUserIDRequestProcessed = (EventHandler<UserIDRequestProcessedEventArgs>)Delegate.Combine(mUserIDRequestProcessed, value);
}
remove
{
mUserIDRequestProcessed = (EventHandler<UserIDRequestProcessedEventArgs>)Delegate.Remove(mUserIDRequestProcessed, value);
}
}
internal FairIDQueue()
: base(3, -1)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
FireTimer.Interval = 600;
FireTimer.Tick += FireTimer_Tick;
CoreManager.Current.Actions.Underlying.SetIDFilter(this);
CoreManager.Current.MessageProcessed += Current_MessageProcessed;
CoreManager.Current.RenderFrame += Current_RenderFrame;
}
private void Current_RenderFrame(object sender, EventArgs e)
{
CurrentTimerFrame++;
}
private void Current_MessageProcessed(object sender, MessageProcessedEventArgs e)
{
if (e.Message.Type == 63408 && e.Message.Value<int>("event") == 201)
{
int num = e.Message.Value<int>("object");
DeleteAction(num);
if (UserRequestedID == num)
{
UserRequestedID = -1;
Util.SafeFireEvent(this, mUserIDRequestProcessed, new UserIDRequestProcessedEventArgs(num));
}
}
}
internal void Start()
{
LastFireTime = DateTime.MinValue;
FireTimer.Enabled = true;
}
internal void Stop()
{
FireTimer.Enabled = false;
ClearAll();
UserRequestedID = -1;
}
private void FireTimer_Tick(object sender, EventArgs e)
{
if (FireTimer.Interval != 600)
{
FireTimer.Enabled = false;
FireTimer.Interval = 600;
FireTimer.Enabled = true;
}
if (CurrentTimerFrame != LastTimerFireFrame)
{
LastTimerFireFrame = CurrentTimerFrame;
FireNow();
}
}
private void FireNow()
{
Assembly requester = null;
int num = -1;
if (UserRequestedID != -1)
{
num = UserRequestedID;
UserRequestedAttempts++;
if (UserRequestedAttempts > 3)
{
UserRequestedID = -1;
}
}
if (num == -1)
{
num = GetNextAction(ref requester);
}
if (num != -1)
{
LastFireTime = DateTime.Now;
int num2 = num ^ iVal;
CoreManager.Current.Actions.Underlying.CallerRefInstanceInternal = num2;
iVal = (num2 << 5) ^ (num2 >> 13) ^ iVal;
}
}
protected override bool IsActionValidNow(int action)
{
WorldObject worldObject = CoreManager.Current.WorldFilter[action];
if (worldObject == null)
{
return true;
}
if (worldObject.Container == 0)
{
WorldObject worldObject2 = CoreManager.Current.WorldFilter[CoreManager.Current.CharacterFilter.Id];
if (worldObject2 != null && worldObject.Coordinates().DistanceToCoords(worldObject2.Coordinates()) > 0.375)
{
return false;
}
}
return true;
}
protected override bool IsActionPermanentlyInvalid(int action)
{
return !CoreManager.Current.Actions.IsValidObject(action);
}
public void AddToQueue(int lObjectID)
{
AddToQueue(lObjectID, DateTime.MaxValue);
}
public void AddToQueue(int lObjectID, DateTime pTimeout)
{
Assembly assembly = Assembly.GetCallingAssembly();
if (assembly == null)
{
assembly = Assembly.GetExecutingAssembly();
}
AddToQueueForCaller(lObjectID, assembly, pTimeout);
}
internal void AddToQueueForCaller(int lObjectID, Assembly pCaller, DateTime pTimeout)
{
try
{
if (FireTimer.Enabled && lObjectID != -1)
{
Enqueue(pCaller, lObjectID, DateTime.MaxValue);
if ((DateTime.Now - LastFireTime).TotalMilliseconds > 700.0)
{
FireTimer.Enabled = false;
FireTimer.Interval = 1;
FireTimer.Enabled = true;
}
}
}
catch (Exception ex)
{
Util.WriteLine("Queue exception in addtoqueue: " + ex.ToString());
}
}
[CLSCompliant(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public void ShortcircuitID(int lObjectID)
{
if (FireTimer.Enabled && lObjectID != -1)
{
UserRequestedID = lObjectID;
UserRequestedAttempts = 0;
if ((DateTime.Now - LastFireTime).TotalMilliseconds > 700.0)
{
LastFireTime = DateTime.Now;
}
}
}
}