Skip to content

Commit

Permalink
Rotation module explicit ordering.
Browse files Browse the repository at this point in the history
  • Loading branch information
awgil committed Jan 19, 2025
1 parent e9400d8 commit 91b861c
Show file tree
Hide file tree
Showing 11 changed files with 247 additions and 171 deletions.
30 changes: 15 additions & 15 deletions BossMod/Autorotation/Plan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,30 @@ public record struct Entry(StrategyValue Value)
public StrategyValue Value = Value;
}

public readonly record struct Module(Type Type, List<List<Entry>> Tracks) : IRotationModuleData
{
public readonly Module MakeClone() => this with { Tracks = [.. Tracks.Select(t => new List<Entry>([.. t]))] };
}

public string Guid = "";
public string Name = Name;
public Type Encounter = Encounter;
public Class Class;
public int Level;
public List<float> PhaseDurations = [];
public Dictionary<Type, List<List<Entry>>> Modules = []; // [RM][track] = entries
public List<Module> Modules = [];
public List<Entry> Targeting = []; // note that Value.Option & Value.Priority are (currently?) ignored

public Plan MakeClone()
{
var res = this with { PhaseDurations = [.. PhaseDurations], Modules = [], Targeting = [.. Targeting] };
foreach (var kv in Modules)
res.Modules[kv.Key] = [.. kv.Value.Select(t => new List<Entry>([.. t]))];
return res;
}
public Plan MakeClone() => this with { PhaseDurations = [.. PhaseDurations], Modules = [.. Modules.Select(m => m.MakeClone())], Targeting = [.. Targeting] };

// this maintains the invariant that each module has entry list per track
public List<List<Entry>> AddModule(Type t)
{
var m = Modules[t] = [];
List<List<Entry>> tracks = [];
foreach (var _ in RotationModuleRegistry.Modules[t].Definition.Configs)
m.Add([]);
return m;
tracks.Add([]);
Modules.Add(new(t, tracks));
return tracks;
}
}

Expand Down Expand Up @@ -126,11 +126,11 @@ public override void Write(Utf8JsonWriter writer, Plan value, JsonSerializerOpti
writer.WriteStartObject(nameof(Plan.Modules));
foreach (var m in value.Modules)
{
var md = RotationModuleRegistry.Modules[m.Key].Definition;
writer.WriteStartObject(m.Key.FullName!);
for (int iTrack = 0; iTrack < m.Value.Count; ++iTrack)
var md = RotationModuleRegistry.Modules[m.Type].Definition;
writer.WriteStartObject(m.Type.FullName!);
for (int iTrack = 0; iTrack < m.Tracks.Count; ++iTrack)
{
var track = m.Value[iTrack];
var track = m.Tracks[iTrack];
if (track.Count == 0)
continue;

Expand Down
19 changes: 9 additions & 10 deletions BossMod/Autorotation/PlanExecution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ public record class EntryData(float WindowStart, float WindowEnd, int BranchID,
public bool IsActive(float t, StateData s) => t >= WindowStart && t <= WindowEnd && IntersectBranchRange(s.BranchID, s.NumBranches);
}

public readonly record struct ModuleData(Type Type, List<List<EntryData>> Tracks);

public readonly BossModule Module;
public readonly Plan? Plan;
private readonly StateData Pull;
private readonly Dictionary<uint, StateData> States = [];
private readonly Dictionary<Type, List<List<EntryData>>> Strategies = [];
private readonly List<ModuleData> Strategies = [];
private readonly List<EntryData> ForcedTargets = [];

public PlanExecution(BossModule module, Plan? plan)
Expand All @@ -46,10 +48,7 @@ public PlanExecution(BossModule module, Plan? plan)

if (plan != null)
{
foreach (var (moduleType, moduleStrats) in plan.Modules)
{
Strategies[moduleType] = [.. moduleStrats.Select(BuildEntries)];
}
Strategies = [.. plan.Modules.Select(m => new ModuleData(m.Type, [.. m.Tracks.Select(BuildEntries)]))];
ForcedTargets = BuildEntries(plan.Targeting);
}
}
Expand Down Expand Up @@ -81,15 +80,15 @@ public float GetVirtualTime(StateData currentState) => currentState != Pull
return (s.Vulnerable.Active, s.Vulnerable.TransitionIn - Math.Min(Module.StateMachine.TimeSinceTransition, s.Duration));
}

public StrategyValues ActiveStrategyOverrides(Type module)
public StrategyValues ActiveStrategyOverrides(int moduleIndex)
{
var s = FindCurrentStateData();
var t = GetVirtualTime(s);
var data = Strategies[module];
var res = new StrategyValues(RotationModuleRegistry.Modules[module].Definition.Configs);
for (int i = 0; i < data.Count; ++i)
var data = Strategies[moduleIndex];
var res = new StrategyValues(RotationModuleRegistry.Modules[data.Type].Definition.Configs);
for (int i = 0; i < data.Tracks.Count; ++i)
{
var entry = GetEntryAt(data[i], t, s);
var entry = GetEntryAt(data.Tracks[i], t, s);
if (entry != null)
res.Values[i] = entry.Value with { ExpireIn = entry.WindowEnd - t };
}
Expand Down
29 changes: 16 additions & 13 deletions BossMod/Autorotation/Preset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,38 @@ public record struct ModuleSetting(Modifier Mod, int Track, StrategyValue Value)
public StrategyValue Value = Value;
}

public record class ModuleSettings
public record class ModuleSettings(Type Type) : IRotationModuleData
{
public readonly List<ModuleSetting> Settings = [];
public int NumSerialized; // entries above this are transient and are not serialized
}

public string Name = Name;
public Dictionary<Type, ModuleSettings> Modules = [];
public List<ModuleSettings> Modules = [];

public Preset MakeClone(bool includeTransient)
{
var res = new Preset(Name);
foreach (var kv in Modules)
foreach (var m in Modules)
{
var ms = res.Modules[kv.Key] = new() { NumSerialized = kv.Value.NumSerialized };
ms.Settings.AddRange(includeTransient ? kv.Value.Settings : kv.Value.Settings.Take(kv.Value.NumSerialized));
var ms = new ModuleSettings(m.Type) { NumSerialized = m.NumSerialized };
ms.Settings.AddRange(includeTransient ? m.Settings : m.Settings.Take(m.NumSerialized));
res.Modules.Add(ms);
}
return res;
}

public StrategyValues ActiveStrategyOverrides(Type type, Modifier mods)
public StrategyValues ActiveStrategyOverrides(int moduleIndex, Modifier mods)
{
var res = new StrategyValues(RotationModuleRegistry.Modules[type].Definition.Configs);
foreach (ref var s in Modules[type].Settings.AsSpan())
var m = Modules[moduleIndex];
var res = new StrategyValues(RotationModuleRegistry.Modules[m.Type].Definition.Configs);
foreach (ref var s in m.Settings.AsSpan())
if ((s.Mod & mods) == s.Mod)
res.Values[s.Track] = s.Value;
return res;
}

public StrategyValues ActiveStrategyOverrides(Type type) => ActiveStrategyOverrides(type, CurrentModifiers());
public StrategyValues ActiveStrategyOverrides(int moduleIndex) => ActiveStrategyOverrides(moduleIndex, CurrentModifiers());

public static Modifier CurrentModifiers()
{
Expand Down Expand Up @@ -83,7 +85,7 @@ public class JsonPresetConverter : JsonConverter<Preset>
continue;
}

var m = res.Modules[mt] = new();
var m = new Preset.ModuleSettings(mt);
foreach (var js in jm.Value.EnumerateArray())
{
var s = new Preset.ModuleSetting() { Value = new() };
Expand Down Expand Up @@ -122,6 +124,7 @@ public class JsonPresetConverter : JsonConverter<Preset>
m.Settings.Add(s);
++m.NumSerialized;
}
res.Modules.Add(m);
}
return res;
}
Expand All @@ -133,9 +136,9 @@ public override void Write(Utf8JsonWriter writer, Preset value, JsonSerializerOp
writer.WriteStartObject(nameof(Preset.Modules));
foreach (var m in value.Modules)
{
writer.WriteStartArray(m.Key.FullName!);
var md = RotationModuleRegistry.Modules[m.Key].Definition;
foreach (ref var s in m.Value.Settings.AsSpan()[..m.Value.NumSerialized])
writer.WriteStartArray(m.Type.FullName!);
var md = RotationModuleRegistry.Modules[m.Type].Definition;
foreach (ref var s in m.Settings.AsSpan()[..m.NumSerialized])
{
writer.WriteStartObject();
writer.WriteString(nameof(Preset.ModuleSetting.Track), md.Configs[s.Track].InternalName);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/PresetDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public void Save()
}
}

public IEnumerable<Preset> PresetsForClass(Class c) => VisiblePresets.Where(p => p.Modules.Any(m => RotationModuleRegistry.Modules[m.Key].Definition.Classes[(int)c]));
public IEnumerable<Preset> PresetsForClass(Class c) => VisiblePresets.Where(p => p.Modules.Any(m => RotationModuleRegistry.Modules[m.Type].Definition.Classes[(int)c]));

public Preset? FindPresetByName(ReadOnlySpan<char> name, StringComparison cmp = StringComparison.CurrentCultureIgnoreCase)
{
Expand Down
24 changes: 15 additions & 9 deletions BossMod/Autorotation/RotationModuleManager.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
namespace BossMod.Autorotation;

public interface IRotationModuleData
{
public Type Type { get; }
}

// the manager contains a set of rotation module instances corresponding to the selected preset/plan
public sealed class RotationModuleManager : IDisposable
{
private readonly record struct ActiveModule(int DataIndex, RotationModuleDefinition Definition, RotationModule Module);

private Preset? _preset; // if non-null, this preset overrides the configuration
public Preset? Preset
{
Expand All @@ -22,7 +29,7 @@ public Preset? Preset
public PlanExecution? Planner { get; private set; }
private readonly PartyRolesConfig _prc = Service.Config.Get<PartyRolesConfig>();
private readonly EventSubscriptions _subscriptions;
private List<(RotationModuleDefinition Definition, RotationModule Module)>? _activeModules;
private List<ActiveModule>? _activeModules;

public static readonly Preset ForceDisable = new(""); // empty preset, so if it's activated, rotation is force disabled

Expand Down Expand Up @@ -86,7 +93,7 @@ public void Update(float estimatedAnimLockDelay, bool isMoving)
}

// rebuild modules if needed
_activeModules ??= Preset != null ? RebuildActiveModules(Preset.Modules.Keys) : Planner?.Plan != null ? RebuildActiveModules(Planner.Plan.Modules.Keys) : [];
_activeModules ??= Preset != null ? RebuildActiveModules(Preset.Modules) : Planner?.Plan != null ? RebuildActiveModules(Planner.Plan.Modules) : [];

// forced target update
if (Hints.ForcedTarget == null && Preset == null && Planner?.ActiveForcedTarget() is var forced && forced != null)
Expand All @@ -100,8 +107,7 @@ public void Update(float estimatedAnimLockDelay, bool isMoving)
var target = Hints.ForcedTarget ?? WorldState.Actors.Find(Player?.TargetID ?? 0);
foreach (var m in _activeModules)
{
var mt = m.Module.GetType();
var values = Preset?.ActiveStrategyOverrides(mt) ?? Planner?.ActiveStrategyOverrides(mt) ?? throw new InvalidOperationException("Both preset and plan are null, but there are active modules");
var values = Preset?.ActiveStrategyOverrides(m.DataIndex) ?? Planner?.ActiveStrategyOverrides(m.DataIndex) ?? throw new InvalidOperationException("Both preset and plan are null, but there are active modules");
m.Module.Execute(values, target, estimatedAnimLockDelay, isMoving);
}
}
Expand Down Expand Up @@ -137,22 +143,22 @@ public void Update(float estimatedAnimLockDelay, bool isMoving)
public override string ToString() => string.Join(", ", _activeModules?.Select(m => m.Module.GetType().Name) ?? []);

// TODO: consider not recreating modules that were active and continue to be active?
private List<(RotationModuleDefinition Definition, RotationModule Module)> RebuildActiveModules(IEnumerable<Type> types)
private List<ActiveModule> RebuildActiveModules<T>(List<T> modules) where T : IRotationModuleData
{
List<(RotationModuleDefinition Definition, RotationModule Module)> res = [];
List<ActiveModule> res = [];
var player = Player;
if (player != null)
{
var isRPMode = player.Statuses.Any(IsTransformStatus);
foreach (var m in types)
for (int i = 0; i < modules.Count; ++i)
{
if (!RotationModuleRegistry.Modules.TryGetValue(m, out var def))
if (!RotationModuleRegistry.Modules.TryGetValue(modules[i].Type, out var def))
continue;
if (!def.Definition.Classes[(int)player.Class] || player.Level < def.Definition.MinLevel || player.Level > def.Definition.MaxLevel)
continue;
if (!def.Definition.CanUseWhileRoleplaying && isRPMode)
continue;
res.Add((def.Definition, def.Builder(this, player)));
res.Add(new(i, def.Definition, def.Builder(this, player)));
}
}
return res;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/UIPresetDatabaseEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void Draw()
if (_selectedPreset != null)
{
_selectedPreset.Draw();
_selectedModuleType = _selectedPreset.SelectedModuleType;
_selectedModuleType = _selectedPreset.SelectedModuleType ?? _selectedModuleType;
}
else
{
Expand Down
Loading

0 comments on commit 91b861c

Please sign in to comment.