fix: queue actor actions

This commit is contained in:
Anna 2024-07-22 02:22:54 -04:00
parent 460261d830
commit ed679ae141
Signed by: anna
GPG Key ID: D0943384CD9F87D1

View File

@ -7,13 +7,7 @@ namespace OrangeGuidanceTomestone.Util;
internal class ActorManager : IDisposable {
private Plugin Plugin { get; }
private uint? _idx;
private readonly Queue<Mode> _tasks = [];
private enum Mode {
Enable,
Disable,
Delete,
}
private readonly Queue<BaseActorAction> _tasks = [];
internal ActorManager(Plugin plugin) {
this.Plugin = plugin;
@ -31,49 +25,28 @@ internal class ActorManager : IDisposable {
return;
}
if (!this._tasks.TryPeek(out var mode)) {
if (!this._tasks.TryPeek(out var actorAction)) {
return;
}
var success = false;
var objMan = ClientObjectManager.Instance();
var obj = objMan->GetObjectByIndex((ushort) idx);
if (obj == null) {
Plugin.Log.Warning("actor by index was null");
return;
var success = false;
if (actorAction.Tries < 10) {
try {
actorAction.Tries += 1;
success = actorAction.Run(this, objMan);
} catch (Exception ex) {
Plugin.Log.Error(ex, "Error in actor action queue");
}
} else {
Plugin.Log.Warning("too many retries, skipping");
success = true;
}
switch (mode) {
case Mode.Disable: {
Plugin.Log.Debug("disabling actor");
obj->DisableDraw();
success = true;
break;
}
case Mode.Enable: {
if (!obj->IsReadyToDraw()) {
Plugin.Log.Debug("not ready to draw");
break;
}
Plugin.Log.Debug("drawing actor");
obj->EnableDraw();
success = true;
break;
}
case Mode.Delete: {
Plugin.Log.Debug("deleting actor");
objMan->DeleteObjectByIndex((ushort) idx, 0);
this._idx = null;
success = true;
break;
}
}
if (success) {
var res = this._tasks.Dequeue();
Plugin.Log.Debug($"deq {Enum.GetName(res)}");
this._tasks.Dequeue();
}
}
@ -95,28 +68,7 @@ internal class ActorManager : IDisposable {
Plugin.Log.Debug("spawning actor");
var objMan = ClientObjectManager.Instance();
var idx = objMan->CreateBattleCharacter();
if (idx == 0xFFFFFFFF) {
Plugin.Log.Debug("actor could not be spawned");
return;
}
this._idx = idx;
var chara = (BattleChara*) objMan->GetObjectByIndex((ushort) idx);
chara->ObjectKind = ObjectKind.BattleNpc;
chara->Position = message.Position;
chara->Rotation = message.Yaw;
var drawData = &chara->DrawData;
drawData->CustomizeData = new CustomizeData();
chara->Alpha = 0.25f;
chara->SetMode(CharacterModes.AnimLock, 0);
chara->Timeline.BaseOverride = 4818;
this._tasks.Enqueue(Mode.Enable);
}
internal void Despawn() {
@ -124,7 +76,114 @@ internal class ActorManager : IDisposable {
return;
}
this._tasks.Enqueue(Mode.Disable);
this._tasks.Enqueue(Mode.Delete);
this._tasks.Enqueue(new DisableAction());
this._tasks.Enqueue(new DeleteAction());
}
private unsafe abstract class BaseActorAction {
/// <summary>
/// Run this action.
/// </summary>
/// <returns>true if the action is finished, false if it should be run again</returns>
public abstract bool Run(ActorManager manager, ClientObjectManager* objMan);
public int Tries { get; set; }
protected bool TryGetBattleChara(
ActorManager manager,
ClientObjectManager* objMan,
out BattleChara* chara
) {
chara = null;
if (manager._idx is not { } idx) {
Plugin.Log.Warning("tried to get battlechara but idx was null");
return false;
}
var obj = objMan->GetObjectByIndex((ushort) idx);
if (obj == null) {
Plugin.Log.Warning("tried to get battlechara but it was null");
return false;
}
chara = (BattleChara*) obj;
return true;
}
}
private unsafe class SpawnAction(Message message) : BaseActorAction {
public override bool Run(ActorManager manager, ClientObjectManager* objMan) {
if (manager._idx != null) {
Plugin.Log.Warning("refusing to spawn a second actor");
return true;
}
var idx = objMan->CreateBattleCharacter();
if (idx == 0xFFFFFFFF) {
Plugin.Log.Debug("actor could not be spawned");
return true;
}
manager._idx = idx;
var chara = (BattleChara*) objMan->GetObjectByIndex((ushort) idx);
chara->ObjectKind = ObjectKind.BattleNpc;
chara->Position = message.Position;
chara->Rotation = message.Yaw;
var drawData = &chara->DrawData;
drawData->CustomizeData = new CustomizeData();
chara->Alpha = 0.25f;
chara->SetMode(CharacterModes.AnimLock, 0);
chara->Timeline.BaseOverride = 4818;
manager._tasks.Enqueue(new EnableAction());
return true;
}
}
private unsafe class EnableAction : BaseActorAction {
public override bool Run(ActorManager manager, ClientObjectManager* objMan) {
if (!this.TryGetBattleChara(manager, objMan, out var chara)) {
return true;
}
if (!chara->IsReadyToDraw()) {
return false;
}
chara->EnableDraw();
return true;
}
}
private unsafe class DisableAction : BaseActorAction {
public override bool Run(ActorManager manager, ClientObjectManager* objMan) {
if (!this.TryGetBattleChara(manager, objMan, out var chara)) {
return true;
}
chara->DisableDraw();
return true;
}
}
private unsafe class DeleteAction : BaseActorAction {
public override bool Run(ActorManager manager, ClientObjectManager* objMan) {
if (manager._idx is not { } idx) {
Plugin.Log.Warning("delete action but idx was null");
return true;
}
if (objMan->GetObjectByIndex((ushort) idx) == null) {
Plugin.Log.Warning("delete action but object at idx was null");
return true;
}
objMan->DeleteObjectByIndex((ushort) idx, 0);
return true;
}
}
}