openDecal/Managed/Decal.Core/ACHooksImpl.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

281 lines
11 KiB
C#

using System;
using System.Runtime.InteropServices;
using Decal.Interop.Core;
namespace Decal.Core
{
[ComVisible(true)]
[Guid("CB8875CD-ABC2-42AD-8175-8908706EED37")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces("Decal.Interop.Core.IACHooksEvents\0\0")]
[ProgId("Decal.ACHooks")]
public class ACHooksImpl : IACHooks
{
// COM events
public event IACHooksEvents_ObjectDestroyedEventHandler ObjectDestroyed;
public event IACHooksEvents_ChatTextInterceptEventHandler ChatTextIntercept;
public event IACHooksEvents_ChatParserInterceptEventHandler ChatParserIntercept;
public event IACHooksEvents_StatusTextInterceptEventHandler StatusTextIntercept;
public event IACHooksEvents_ObjectSelectedEventHandler ObjectSelected;
public event IACHooksEvents_MessageProcessedEventHandler MessageProcessed;
public event IACHooksEvents_AC3DRegionChangedEventHandler AC3DRegionChanged;
public event IACHooksEvents_ContainerOpenedEventHandler ContainerOpened;
public event IACHooksEvents_ChatClickInterceptEventHandler ChatClickIntercept;
public event IACHooksEvents_RenderPreUIEventHandler RenderPreUI;
private DecalCoreImpl _decal;
private IIdentifyFilter _idFilter;
// State
private int _currentSelection;
private int _previousSelection;
private int _selectedStackCount;
private int _maxSelectedStackCount;
private int _combatMode;
private int _vendorId;
private int _busyState;
private int _busyStateId;
private int _pointerState;
private int _commandInterpreter;
private int _openedContainer;
private bool _chatState;
private double _headingDegrees;
private double _headingRadians;
private int _landcell;
private double _locationX, _locationY, _locationZ;
private tagRECT _ac3dRegionRect;
private tagRECT _acWindowRect;
public void SetIDFilter(IIdentifyFilter pIDFilter) => _idFilter = pIDFilter;
public void SetDecal(object pDecal)
{
_decal = pDecal as DecalCoreImpl;
}
// Hook availability
public int HooksAvail =>
(int)(eAvailableHooks.eCurrentSelect | eAvailableHooks.ePrevSelect |
eAvailableHooks.eCastSpell | eAvailableHooks.eMoveItem |
eAvailableHooks.eSelectItem | eAvailableHooks.eUseItem |
eAvailableHooks.eCombatMode | eAvailableHooks.eChatState |
eAvailableHooks.eStackCount | eAvailableHooks.eMaxStackCount |
eAvailableHooks.eVendorID | eAvailableHooks.eBusyState |
eAvailableHooks.eBusyStateID | eAvailableHooks.ePointerState |
eAvailableHooks.eMoveItemEx | eAvailableHooks.ePosition |
eAvailableHooks.eFaceHeading | eAvailableHooks.eAC3DRegion |
eAvailableHooks.eObjectDestroyed | eAvailableHooks.eSendTell |
eAvailableHooks.eSetAutorun | eAvailableHooks.eSetCombatMode |
eAvailableHooks.eGetMiscInt | eAvailableHooks.eGetAttribute |
eAvailableHooks.eGetSkill | eAvailableHooks.eGetVital |
eAvailableHooks.eHooksAvailEx);
public bool HooksAvailEx => true;
// Chat methods
public void AddChatText(string szText, int lColor, int lTarget)
{
// In the open-source version, we fire this through the chat event system
bool eat = false;
ChatTextIntercept?.Invoke(szText, lColor, lTarget, ref eat);
}
public void AddChatTextRaw(string szText, int lColor, int lTarget)
{
AddChatText(szText, lColor, lTarget);
}
public void AddStatusText(string Text)
{
bool eat = false;
StatusTextIntercept?.Invoke(Text, ref eat);
}
public void InvokeChatParser(string Text)
{
bool eat = false;
ChatParserIntercept?.Invoke(Text, ref eat);
}
public void SetIdleTime(double dIdleTimeout) { }
public void Logout() { }
// Selection
public int CurrentSelection { get => _currentSelection; set => _currentSelection = value; }
public int PreviousSelection { get => _previousSelection; set => _previousSelection = value; }
public int SelectedStackCount { get => _selectedStackCount; set => _selectedStackCount = value; }
public int MaxSelectedStackCount => _maxSelectedStackCount;
public void SetCursorPosition(int lX, int lY) { }
// Window/region info
public tagRECT AC3DRegionRect => _ac3dRegionRect;
public IntPtr AC3DRegionRectPtr => IntPtr.Zero;
public tagRECT ACWindowRect => _acWindowRect;
// State properties
public bool ChatState => _chatState;
public int BusyState => _busyState;
public int BusyStateID => _busyStateId;
public int PointerState => _pointerState;
public int VendorID => _vendorId;
// Vendor operations
public void VendorBuyListAdd(int lID, int lAmount) { }
public void VendorBuyListClear() { }
public void VendorBuyAll() { }
public void VendorSellListAdd(int lID) { }
public void VendorSellListClear() { }
public void VendorSellAll() { }
// Combat
public int CombatMode => _combatMode;
public void SetCombatMode(int pVal) { _combatMode = pVal; }
public void SetAutorun(bool bOnOff) { }
public bool FaceHeading(float fHeading, bool bUnknown) { return true; }
public int CommandInterpreter => _commandInterpreter;
// Item operations
public void SelectItem(int lObjectID)
{
_previousSelection = _currentSelection;
_currentSelection = lObjectID;
ObjectSelected?.Invoke(lObjectID);
}
public void GiveItem(int lObject, int lDestination) { }
public void ApplyItem(int UseThis, int OnThis) { }
public void UseItem(int lObjectID, int lUseState) { }
public void UseItemRaw(int lObjectID, int lUseState, int lUseMethod) { }
public void MoveItem(int lObjectID, int lPackID, int lSlot, bool bStack) { }
public void MoveItemEx(int lObjectID, int lDestinationID) { }
public void MoveItemExRaw(int lObject, int lDestination, int lMoveFlags) { }
public void DropItem(int lObjectID) { }
// Spell casting
public void CastSpell(int lSpellID, int lObjectID) { }
// Object queries
public bool IsValidObject(int lGUID) => false;
public int GetWeenieObjectPtr(int lObjectID) => 0;
public int GetPhysicsObjectPtr(int lObjectID) => 0;
// Position
public double HeadingDegrees => _headingDegrees;
public double HeadingRadians => _headingRadians;
public int Landcell => _landcell;
public double LocationX => _locationX;
public double LocationY => _locationY;
public double LocationZ => _locationZ;
// Character stats (parameterized properties — index-based access)
public eTrainLevel SkillTrainLevel => eTrainLevel.eUntrained;
public int SkillTotalXP => 0;
public int SkillFreePoints => 0;
public int SkillClicks => 0;
public int AttributeTotalXP => 0;
public int AttributeClicks => 0;
public int AttributeStart => 0;
public int VitalTotalXP => 0;
public int VitalClicks => 0;
public int Vital => 0;
public int Attribute => 0;
public int Skill => 0;
public int Misc => 0;
// ID/object operations
public void RequestID(int lObjectID) { _idFilter?.AddToQueue(lObjectID); }
public void IDQueueAdd(int lObjectID) { _idFilter?.AddToQueue(lObjectID); }
// Spell bar
public void SpellTabAdd(int lTab, int lIndex, int lSpellID) { }
public void SpellTabDelete(int lTab, int lSpellID) { }
// Trade
public void TradeAdd(int ItemID) { }
public void TradeAccept() { }
public void TradeDecline() { }
public void TradeReset() { }
public void TradeEnd() { }
// Salvage
public void SalvagePanelAdd(int lObjectID) { }
public void SalvagePanelSalvage() { }
public int OpenedContainer => _openedContainer;
// Experience
public void AddSkillExp(eSkill SkillID, int lExperience) { }
public void AddAttributeExp(eAttribute AttribID, int lExperience) { }
public void AddVitalExp(eVital VitalID, int lExperience) { }
public int SmartboxPtr() => 0;
public float ObjectHeight(int lObjectID) => 0f;
public int CallerRefInstanceInternal { set { } }
// Equipment
public void AutoWieldRaw(int lObjectID, int SlotID, int Explicit, int NotExplicit, int zeroVal1, int zeroVal2) { }
public void AutoWield(int lObjectID) { }
public void AutoWieldEx(int lObjectID, int SlotID, int Explicit, int NotExplicit) { }
// Fellowship
public void FellowshipRecruit(int lObjectID) { }
public void FellowshipGrantLeader(int lObjectID) { }
public void FellowshipSetOpen(bool IsOpen) { }
public void FellowshipQuit() { }
public void FellowshipDisband() { }
public void FellowshipDismiss(int lObjectID) { }
// UI
public void UIElementMove(int lUIElementType, int X, int Y) { }
public void UIElementResize(int lUIElementType, int Width, int Height) { }
public int UIElementLookup(int lUIElementType) => 0;
public tagRECT UIElementRegionRect(int lUIElementType) => default;
// Internal event firing methods
internal void FireObjectDestroyed(int guid) => ObjectDestroyed?.Invoke(guid);
internal void FireContainerOpened(int guid) => ContainerOpened?.Invoke(guid);
internal void FireRenderPreUI() => RenderPreUI?.Invoke();
internal void FireChatText(string text, int color, int target, ref bool eat)
{
ChatTextIntercept?.Invoke(text, color, target, ref eat);
}
internal void FireChatParser(string text, ref bool eat)
{
ChatParserIntercept?.Invoke(text, ref eat);
}
internal void FireStatusText(string text, ref bool eat)
{
StatusTextIntercept?.Invoke(text, ref eat);
}
internal void FireObjectSelected(int guid) => ObjectSelected?.Invoke(guid);
internal void FireAC3DRegionChanged(int left, int top, int right, int bottom)
{
_ac3dRegionRect = new tagRECT { left = left, top = top, right = right, bottom = bottom };
AC3DRegionChanged?.Invoke(left, top, right, bottom);
}
internal void FireChatClick(string text, int id, ref bool eat)
{
ChatClickIntercept?.Invoke(text, id, ref eat);
}
internal void UpdatePosition(double x, double y, double z, int landcell, double headDeg, double headRad)
{
_locationX = x;
_locationY = y;
_locationZ = z;
_landcell = landcell;
_headingDegrees = headDeg;
_headingRadians = headRad;
}
}
}