285 lines
8.2 KiB
C#
285 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.Fate;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.InstanceContent;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.WKS;
|
|
|
|
namespace LLib.GameData;
|
|
|
|
public sealed class PublicEventHelper
|
|
{
|
|
public unsafe IReadOnlyList<PublicEvent> GetActiveFates()
|
|
{
|
|
FateManager* ptr = FateManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return Array.Empty<PublicEvent>();
|
|
}
|
|
List<PublicEvent> list = new List<PublicEvent>();
|
|
for (int i = 0; i < ptr->Fates.Count; i++)
|
|
{
|
|
FateContext* value = ptr->Fates[i].Value;
|
|
if (value != null)
|
|
{
|
|
FateState state = value->State;
|
|
if (state - 3 <= FateState.Unk1)
|
|
{
|
|
list.Add(ToPublicEvent(value));
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public unsafe IReadOnlyList<PublicEvent> GetActiveDynamicEvents()
|
|
{
|
|
DynamicEventContainer* instance = DynamicEventContainer.GetInstance();
|
|
if (instance == null)
|
|
{
|
|
return Array.Empty<PublicEvent>();
|
|
}
|
|
List<PublicEvent> list = new List<PublicEvent>();
|
|
Span<DynamicEvent> events = instance->Events;
|
|
for (int i = 0; i < events.Length; i++)
|
|
{
|
|
ref DynamicEvent reference = ref events[i];
|
|
if (reference.State != DynamicEventState.Inactive)
|
|
{
|
|
list.Add(ToPublicEvent(ref reference));
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public unsafe IReadOnlyList<PublicEvent> GetActiveMechaEvents()
|
|
{
|
|
WKSManager* ptr = WKSManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return Array.Empty<PublicEvent>();
|
|
}
|
|
WKSMechaEventModule* mechaEventModule = ptr->MechaEventModule;
|
|
if (mechaEventModule == null)
|
|
{
|
|
return Array.Empty<PublicEvent>();
|
|
}
|
|
List<PublicEvent> list = new List<PublicEvent>();
|
|
Span<WKSMechaEvent> events = mechaEventModule->Events;
|
|
for (int i = 0; i < events.Length; i++)
|
|
{
|
|
ref WKSMechaEvent reference = ref events[i];
|
|
if ((reference.Flags & WKSMechaEventFlag.IsEventActive) != 0)
|
|
{
|
|
list.Add(ToPublicEvent(ref reference));
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public IReadOnlyList<PublicEvent> GetAllActiveEvents()
|
|
{
|
|
List<PublicEvent> list = new List<PublicEvent>();
|
|
list.AddRange(GetActiveFates());
|
|
list.AddRange(GetActiveDynamicEvents());
|
|
list.AddRange(GetActiveMechaEvents());
|
|
return list;
|
|
}
|
|
|
|
public PublicEvent? GetEventById(EPublicEventType type, uint id)
|
|
{
|
|
return type switch
|
|
{
|
|
EPublicEventType.Fate => GetFateById((ushort)id),
|
|
EPublicEventType.DynamicEvent => GetDynamicEventById((ushort)id),
|
|
EPublicEventType.MechaEvent => GetMechaEventById(id),
|
|
_ => null,
|
|
};
|
|
}
|
|
|
|
public unsafe PublicEvent? GetCurrentPlayerEvent()
|
|
{
|
|
FateManager* ptr = FateManager.Instance();
|
|
if (ptr == null || ptr->CurrentFate == null)
|
|
{
|
|
return null;
|
|
}
|
|
return ToPublicEvent(ptr->CurrentFate);
|
|
}
|
|
|
|
public unsafe PublicEvent? GetCurrentDynamicEvent()
|
|
{
|
|
DynamicEventContainer* instance = DynamicEventContainer.GetInstance();
|
|
if (instance == null)
|
|
{
|
|
return null;
|
|
}
|
|
DynamicEvent* currentEvent = instance->GetCurrentEvent();
|
|
if (currentEvent == null || currentEvent->State == DynamicEventState.Inactive)
|
|
{
|
|
return null;
|
|
}
|
|
return ToPublicEvent(ref *currentEvent);
|
|
}
|
|
|
|
public unsafe PublicEvent? GetCurrentMechaEvent()
|
|
{
|
|
WKSManager* ptr = WKSManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return null;
|
|
}
|
|
WKSMechaEventModule* mechaEventModule = ptr->MechaEventModule;
|
|
if (mechaEventModule == null)
|
|
{
|
|
return null;
|
|
}
|
|
WKSMechaEvent* currentEvent = mechaEventModule->CurrentEvent;
|
|
if (currentEvent == null || (currentEvent->Flags & WKSMechaEventFlag.IsEventActive) == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return ToPublicEvent(ref *currentEvent);
|
|
}
|
|
|
|
public unsafe bool IsFateActive(ushort fateId)
|
|
{
|
|
if (fateId == 0)
|
|
{
|
|
return false;
|
|
}
|
|
FateManager* ptr = FateManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return false;
|
|
}
|
|
FateContext* fateById = ptr->GetFateById(fateId);
|
|
if (fateById == null)
|
|
{
|
|
return false;
|
|
}
|
|
return fateById->State == FateState.Running;
|
|
}
|
|
|
|
private unsafe PublicEvent? GetFateById(ushort fateId)
|
|
{
|
|
if (fateId == 0)
|
|
{
|
|
return null;
|
|
}
|
|
FateManager* ptr = FateManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return null;
|
|
}
|
|
FateContext* fateById = ptr->GetFateById(fateId);
|
|
if (fateById == null)
|
|
{
|
|
return null;
|
|
}
|
|
return ToPublicEvent(fateById);
|
|
}
|
|
|
|
private unsafe PublicEvent? GetDynamicEventById(ushort dynamicEventId)
|
|
{
|
|
if (dynamicEventId == 0)
|
|
{
|
|
return null;
|
|
}
|
|
DynamicEventContainer* instance = DynamicEventContainer.GetInstance();
|
|
if (instance == null)
|
|
{
|
|
return null;
|
|
}
|
|
Span<DynamicEvent> events = instance->Events;
|
|
for (int i = 0; i < events.Length; i++)
|
|
{
|
|
ref DynamicEvent reference = ref events[i];
|
|
if (reference.DynamicEventId == dynamicEventId && reference.State != DynamicEventState.Inactive)
|
|
{
|
|
return ToPublicEvent(ref reference);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private unsafe PublicEvent? GetMechaEventById(uint mechaEventDataRowId)
|
|
{
|
|
if (mechaEventDataRowId == 0)
|
|
{
|
|
return null;
|
|
}
|
|
WKSManager* ptr = WKSManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return null;
|
|
}
|
|
WKSMechaEventModule* mechaEventModule = ptr->MechaEventModule;
|
|
if (mechaEventModule == null)
|
|
{
|
|
return null;
|
|
}
|
|
Span<WKSMechaEvent> events = mechaEventModule->Events;
|
|
for (int i = 0; i < events.Length; i++)
|
|
{
|
|
ref WKSMechaEvent reference = ref events[i];
|
|
if (reference.WKSMechaEventDataRowId == mechaEventDataRowId && (reference.Flags & WKSMechaEventFlag.IsEventActive) != 0)
|
|
{
|
|
return ToPublicEvent(ref reference);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private unsafe static PublicEvent ToPublicEvent(FateContext* fate)
|
|
{
|
|
float num = fate->Duration;
|
|
float timeRemaining = 0f;
|
|
if (num > 0f && fate->StartTimeEpoch > 0)
|
|
{
|
|
float num2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - fate->StartTimeEpoch;
|
|
timeRemaining = Math.Max(0f, num - num2);
|
|
}
|
|
return new PublicEvent(EPublicEventType.Fate, fate->FateId, fate->Name.ToString(), fate->Location, fate->Radius, fate->Level, fate->MaxLevel, (int)fate->Progress, num, timeRemaining, fate->State == FateState.Running, fate->State == FateState.Preparing, fate->IsBonus, fate->Rule, fate->MotivationNpc, fate->FATEChain);
|
|
}
|
|
|
|
private static PublicEvent ToPublicEvent(ref DynamicEvent dynamicEvent)
|
|
{
|
|
float num = dynamicEvent.SecondsDuration;
|
|
float num2 = dynamicEvent.SecondsLeft;
|
|
uint dynamicEventId = dynamicEvent.DynamicEventId;
|
|
string name = dynamicEvent.Name.ToString();
|
|
Vector3 position = dynamicEvent.MapMarker.Position;
|
|
float radius = dynamicEvent.MapMarker.Radius;
|
|
float progress = (int)dynamicEvent.Progress;
|
|
float duration = num;
|
|
float timeRemaining = num2;
|
|
bool isActive = dynamicEvent.State == DynamicEventState.Battle;
|
|
DynamicEventState state = dynamicEvent.State;
|
|
bool isPending = state - 1 <= DynamicEventState.Register;
|
|
return new PublicEvent(EPublicEventType.DynamicEvent, dynamicEventId, name, position, radius, 0, 0, progress, duration, timeRemaining, isActive, isPending, HasBonus: false, 0, 0u, 0);
|
|
}
|
|
|
|
private unsafe static PublicEvent ToPublicEvent(ref WKSMechaEvent mechaEvent)
|
|
{
|
|
long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
float duration = ((mechaEvent.EventEndTimestamp > mechaEvent.EventStartTimestamp) ? ((float)(mechaEvent.EventEndTimestamp - mechaEvent.EventStartTimestamp)) : 0f);
|
|
float timeRemaining = ((mechaEvent.EventEndTimestamp > num) ? ((float)(mechaEvent.EventEndTimestamp - num)) : 0f);
|
|
Vector3 position = Vector3.Zero;
|
|
float radius = 0f;
|
|
string name = string.Empty;
|
|
if (mechaEvent.MapMarkerPtrs.Count > 0)
|
|
{
|
|
WKSMechaEventMapMarker* value = mechaEvent.MapMarkerPtrs[0].Value;
|
|
if (value != null)
|
|
{
|
|
name = value->Name.ToString();
|
|
position = value->MapMarkerData.Position;
|
|
radius = value->MapMarkerData.Radius;
|
|
}
|
|
}
|
|
float progress = ((mechaEvent.EventProgressMax > 0) ? ((float)mechaEvent.EventProgress / (float)mechaEvent.EventProgressMax * 100f) : 0f);
|
|
bool isPending = (mechaEvent.Flags & WKSMechaEventFlag.PilotRegistrationOpen) != 0 && (mechaEvent.Flags & WKSMechaEventFlag.IsEventActive) != 0 && mechaEvent.EventProgress == 0;
|
|
return new PublicEvent(EPublicEventType.MechaEvent, mechaEvent.WKSMechaEventDataRowId, name, position, radius, 0, 0, progress, duration, timeRemaining, (mechaEvent.Flags & WKSMechaEventFlag.IsEventActive) != 0, isPending, HasBonus: false, 0, 0u, 0);
|
|
}
|
|
}
|