te
This commit is contained in:
parent
01151e679b
commit
57b2f0400e
265 changed files with 22828 additions and 6 deletions
231
Unused/Decal.Adapter.IDQueue/FairIDQueue.cs
Normal file
231
Unused/Decal.Adapter.IDQueue/FairIDQueue.cs
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
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;
|
||||
|
||||
/// <summary>
|
||||
/// An IDQueue that is fair with respect to plugins and round-robin with respect to ID requests.
|
||||
/// </summary>
|
||||
[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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a request to the queue.
|
||||
/// </summary>
|
||||
/// <param name="lObjectID">The game object ID to identify.</param>
|
||||
public void AddToQueue(int lObjectID)
|
||||
{
|
||||
AddToQueue(lObjectID, DateTime.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a request to the queue with a timeout time.
|
||||
/// Note: if something else requests this ID while this request is still pending,
|
||||
/// the later of the two timeouts will prevail.
|
||||
/// </summary>
|
||||
/// <param name="lObjectID">The game object ID to identify.</param>
|
||||
/// <param name="pTimeout"></param>
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an ID request which bypasses the queue.
|
||||
/// This is used when the user manually requests an ID. Only one object
|
||||
/// at a time can be pending here.
|
||||
/// </summary>
|
||||
/// <param name="lObjectID">The game object ID to identify.</param>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
298
Unused/Decal.Adapter.IDQueue/FairRoundRobinScheduleQueue.cs
Normal file
298
Unused/Decal.Adapter.IDQueue/FairRoundRobinScheduleQueue.cs
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using CustomCollections;
|
||||
|
||||
namespace Decal.Adapter.IDQueue;
|
||||
|
||||
/// <summary>
|
||||
/// A scheduler: callers request actions. Multiple callers can request the same action.
|
||||
/// -Each caller gets one action, then the other callers get a turn.
|
||||
/// -If a new caller arrives, it is given priority in the turns list.
|
||||
/// -Everytime a caller gets a turn, it selects its next available action in round-robin fashion.
|
||||
/// -If all of a caller's actions are unavailable when it is that caller's turn, its turn is lost and it must wait in line again.
|
||||
/// -If no caller can take a turn, the null action is returned.
|
||||
/// Thus if multiple callers request the same action, it will be tried more often
|
||||
/// since the attempt will occur during the turns of multiple callers.
|
||||
/// </summary>
|
||||
/// <typeparam name="CALLERTYPE"></typeparam>
|
||||
/// <typeparam name="ACTIONTYPE"></typeparam>
|
||||
[CLSCompliant(true)]
|
||||
[ClassInterface(ClassInterfaceType.None)]
|
||||
public abstract class FairRoundRobinScheduleQueue<CALLERTYPE, ACTIONTYPE>
|
||||
{
|
||||
public class ActionRemovedEventArgs : EventArgs
|
||||
{
|
||||
private ACTIONTYPE mAction;
|
||||
|
||||
public ACTIONTYPE Action => mAction;
|
||||
|
||||
internal ActionRemovedEventArgs(ACTIONTYPE pAction)
|
||||
{
|
||||
mAction = pAction;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionInfo : IEquatable<ActionInfo>
|
||||
{
|
||||
public ACTIONTYPE Action;
|
||||
|
||||
public DateTime Expires;
|
||||
|
||||
public int TryCount;
|
||||
|
||||
public ActionInfo(ACTIONTYPE pAction, DateTime pExpires)
|
||||
{
|
||||
Action = pAction;
|
||||
Expires = pExpires;
|
||||
}
|
||||
|
||||
public bool IsExpired()
|
||||
{
|
||||
return Expires < DateTime.Now;
|
||||
}
|
||||
|
||||
public bool Equals(ActionInfo other)
|
||||
{
|
||||
ref ACTIONTYPE action = ref Action;
|
||||
object obj = other.Action;
|
||||
return action.Equals(obj);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as ActionInfo);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Action.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private HashedList<CALLERTYPE> Callers = new HashedList<CALLERTYPE>();
|
||||
|
||||
private Dictionary<ACTIONTYPE, ActionInfo> ActInfos = new Dictionary<ACTIONTYPE, ActionInfo>();
|
||||
|
||||
private Dictionary<CALLERTYPE, HashedList<ActionInfo>> CallerActions = new Dictionary<CALLERTYPE, HashedList<ActionInfo>>();
|
||||
|
||||
private Dictionary<ACTIONTYPE, HashedList<CALLERTYPE>> ActionCallers = new Dictionary<ACTIONTYPE, HashedList<CALLERTYPE>>();
|
||||
|
||||
private int MaximumTryCount;
|
||||
|
||||
private ACTIONTYPE NullAction;
|
||||
|
||||
public int CallerCount => Callers.Count;
|
||||
|
||||
public int ActionCount => ActInfos.Count;
|
||||
|
||||
public event EventHandler<ActionRemovedEventArgs> OnActionRemoved;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pMaximumTryCount">The most times an action can be attempted before it fails.</param>
|
||||
/// <param name="pNullAction">An ACTIONTYPE to return when no action is available.</param>
|
||||
protected FairRoundRobinScheduleQueue(int pMaximumTryCount, ACTIONTYPE pNullAction)
|
||||
{
|
||||
MaximumTryCount = pMaximumTryCount;
|
||||
NullAction = pNullAction;
|
||||
}
|
||||
|
||||
protected abstract bool IsActionValidNow(ACTIONTYPE action);
|
||||
|
||||
protected abstract bool IsActionPermanentlyInvalid(ACTIONTYPE action);
|
||||
|
||||
private void RotateQueue<T>(HashedList<T> q)
|
||||
{
|
||||
if (q.Count > 0)
|
||||
{
|
||||
T item = q[0];
|
||||
q.RemoveAt(0);
|
||||
q.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
Callers.Clear();
|
||||
ActInfos.Clear();
|
||||
CallerActions.Clear();
|
||||
ActionCallers.Clear();
|
||||
}
|
||||
|
||||
public void DeleteAction(ACTIONTYPE action)
|
||||
{
|
||||
if (!ActionCallers.ContainsKey(action) || !ActInfos.ContainsKey(action))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ActionInfo item = ActInfos[action];
|
||||
ActInfos.Remove(action);
|
||||
HashedList<CALLERTYPE> hashedList = ActionCallers[action];
|
||||
ActionCallers.Remove(action);
|
||||
foreach (CALLERTYPE item2 in hashedList)
|
||||
{
|
||||
CallerActions[item2].Remove(item);
|
||||
if (CallerActions[item2].Count == 0)
|
||||
{
|
||||
CallerActions.Remove(item2);
|
||||
Callers.Remove(item2);
|
||||
}
|
||||
}
|
||||
if (this.OnActionRemoved != null)
|
||||
{
|
||||
this.OnActionRemoved(this, new ActionRemovedEventArgs(action));
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteCaller(CALLERTYPE caller)
|
||||
{
|
||||
Callers.Remove(caller);
|
||||
if (!CallerActions.ContainsKey(caller))
|
||||
{
|
||||
return;
|
||||
}
|
||||
HashedList<ActionInfo> hashedList = CallerActions[caller];
|
||||
CallerActions.Remove(caller);
|
||||
HashedList<ActionInfo> hashedList2 = new HashedList<ActionInfo>();
|
||||
foreach (ActionInfo item in hashedList)
|
||||
{
|
||||
if (ActionCallers.ContainsKey(item.Action))
|
||||
{
|
||||
ActionCallers[item.Action].Remove(caller);
|
||||
if (ActionCallers[item.Action].Count == 0)
|
||||
{
|
||||
ActionCallers.Remove(item.Action);
|
||||
ActInfos.Remove(item.Action);
|
||||
hashedList2.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.OnActionRemoved == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (ActionInfo item2 in hashedList2)
|
||||
{
|
||||
this.OnActionRemoved(this, new ActionRemovedEventArgs(item2.Action));
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<ACTIONTYPE> GetActionsForCaller(CALLERTYPE caller)
|
||||
{
|
||||
List<ACTIONTYPE> list = new List<ACTIONTYPE>();
|
||||
if (CallerActions.ContainsKey(caller))
|
||||
{
|
||||
foreach (ActionInfo item in CallerActions[caller])
|
||||
{
|
||||
list.Add(item.Action);
|
||||
}
|
||||
}
|
||||
return list.AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<CALLERTYPE> GetCallersForAction(ACTIONTYPE action)
|
||||
{
|
||||
if (ActionCallers.ContainsKey(action))
|
||||
{
|
||||
return ActionCallers[action].AsReadOnly();
|
||||
}
|
||||
return new List<CALLERTYPE>().AsReadOnly();
|
||||
}
|
||||
|
||||
public void Enqueue(CALLERTYPE caller, ACTIONTYPE action, DateTime expiration)
|
||||
{
|
||||
ActionInfo actionInfo;
|
||||
if (ActInfos.ContainsKey(action))
|
||||
{
|
||||
actionInfo = ActInfos[action];
|
||||
if (actionInfo.Expires < expiration)
|
||||
{
|
||||
actionInfo.Expires = expiration;
|
||||
}
|
||||
actionInfo.TryCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
actionInfo = new ActionInfo(action, expiration);
|
||||
ActInfos[action] = actionInfo;
|
||||
}
|
||||
if (!CallerActions.ContainsKey(caller) || !CallerActions[caller].Contains(actionInfo))
|
||||
{
|
||||
if (!Callers.Contains(caller))
|
||||
{
|
||||
Callers.Insert(0, caller);
|
||||
}
|
||||
if (!CallerActions.ContainsKey(caller))
|
||||
{
|
||||
CallerActions.Add(caller, new HashedList<ActionInfo>());
|
||||
}
|
||||
CallerActions[caller].Add(actionInfo);
|
||||
if (!ActionCallers.ContainsKey(action))
|
||||
{
|
||||
ActionCallers.Add(action, new HashedList<CALLERTYPE>());
|
||||
}
|
||||
ActionCallers[action].Add(caller);
|
||||
}
|
||||
}
|
||||
|
||||
public ACTIONTYPE GetNextAction(ref CALLERTYPE requester)
|
||||
{
|
||||
HashedList<ActionInfo> hashedList = new HashedList<ActionInfo>();
|
||||
ACTIONTYPE result = NullAction;
|
||||
for (int i = 0; i < Callers.Count; i++)
|
||||
{
|
||||
CALLERTYPE val = Callers[0];
|
||||
HashedList<ActionInfo> hashedList2 = CallerActions[val];
|
||||
bool flag = false;
|
||||
for (int j = 0; j < hashedList2.Count; j++)
|
||||
{
|
||||
ActionInfo actionInfo = hashedList2[0];
|
||||
if (hashedList.Contains(actionInfo))
|
||||
{
|
||||
RotateQueue(hashedList2);
|
||||
continue;
|
||||
}
|
||||
if (actionInfo.IsExpired())
|
||||
{
|
||||
hashedList.Add(actionInfo);
|
||||
RotateQueue(hashedList2);
|
||||
continue;
|
||||
}
|
||||
if (IsActionPermanentlyInvalid(actionInfo.Action))
|
||||
{
|
||||
hashedList.Add(actionInfo);
|
||||
RotateQueue(hashedList2);
|
||||
continue;
|
||||
}
|
||||
if (!IsActionValidNow(actionInfo.Action))
|
||||
{
|
||||
RotateQueue(hashedList2);
|
||||
continue;
|
||||
}
|
||||
flag = true;
|
||||
result = actionInfo.Action;
|
||||
requester = val;
|
||||
RotateQueue(hashedList2);
|
||||
actionInfo.TryCount++;
|
||||
if (actionInfo.TryCount > MaximumTryCount)
|
||||
{
|
||||
hashedList.Add(actionInfo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
RotateQueue(Callers);
|
||||
if (flag)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (ActionInfo item in hashedList)
|
||||
{
|
||||
DeleteAction(item.Action);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace Decal.Adapter.IDQueue;
|
||||
|
||||
public class UserIDRequestProcessedEventArgs : EventArgs
|
||||
{
|
||||
private int mObjectId;
|
||||
|
||||
public int ObjectId => mObjectId;
|
||||
|
||||
internal UserIDRequestProcessedEventArgs(int ObjectId)
|
||||
{
|
||||
mObjectId = ObjectId;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue