Skip to content

Commit

Permalink
Merge pull request xiv-gear-planner#296 from xiv-gear-planner/sim-val…
Browse files Browse the repository at this point in the history
…idation

Sim validation
  • Loading branch information
xpdota authored Aug 26, 2024
2 parents c1b026c + 98382af commit 34208f8
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 17 deletions.
26 changes: 16 additions & 10 deletions packages/common-ui/styles/common.less
Original file line number Diff line number Diff line change
Expand Up @@ -1580,7 +1580,22 @@ add-sim-dialog {
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
align-items: stretch;
width: max-content;
max-width: calc(100% - 10px);
margin-left: auto;
margin-right: auto;

> .named-section {
.named-section-standard;
width: 100%;

max-width: unset;

label[for='cycle-total-time'] {
margin-right: 10px;
}
}

> * {
margin-top: 10px;
Expand Down Expand Up @@ -3207,15 +3222,6 @@ gear-set-issues-modal {
.top-level-widget;
}

#sim-config-area-inner > .named-section {
.named-section-standard;
width: 100%;

label[for='cycle-total-time'] {
margin-right: 10px;
}
}

.top-level-widget {
border-radius: 10px;
.shadow-big;
Expand Down
21 changes: 17 additions & 4 deletions packages/core/src/sims/cycle_sim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,13 @@ export class CycleProcessor {
private readonly comboTrackerMap: Map<ComboKey, ComboTracker>;
private readonly aaAbility: AutoAttack;

/**
* Tracks the number of actions used so that it can trip a circuit breaker if stuck in an infinite loop.
*
* @private
*/
private _rowCount = 0;

constructor(private settings: MultiCycleSettings) {
// TODO: set enforcement mode
this.cdTracker = new CooldownTracker(() => this.currentTime);
Expand Down Expand Up @@ -473,7 +480,7 @@ export class CycleProcessor {
}

const activeBuffs = this.getActiveBuffsData(startTime);
const matchingActiveBuffIdx = activeBuffs.findIndex(b => b.buff.statusId == buff.statusId);
const matchingActiveBuffIdx = activeBuffs.findIndex(b => b.buff.statusId == buff.statusId);
if (matchingActiveBuffIdx != -1) {
activeBuffs[matchingActiveBuffIdx].end = startTime;
activeBuffs[matchingActiveBuffIdx].forceEnd = true;
Expand Down Expand Up @@ -667,6 +674,9 @@ export class CycleProcessor {
* @param time The time of the record. Current time will be used if not specified.
*/
addSpecialRow(message: string, time?: number) {
if (this._rowCount++ > 10_000) {
throw Error("Used too many special rows");
}
this.allRecords.push({
usedAt: time ?? this.currentTime,
label: message,
Expand Down Expand Up @@ -892,7 +902,7 @@ export class CycleProcessor {
}

// Counter that makes this fail on purpose if buggy sim rotation code gets into an infinite loop
_counter: number = 0;
_canUseCdCount: number = 0;

/**
* Determines whether or not a GCD plus zero or more oGCDs can be used without violating cooldowns and
Expand All @@ -905,8 +915,8 @@ export class CycleProcessor {
* @param ogcds
*/
canUseCooldowns(gcd: GcdAbility, ogcds: OgcdAbility[]): 'yes' | 'no' | 'not-enough-time' {
if (this._counter++ > 10000) {
if (this._counter > 10005) {
if (this._canUseCdCount++ > 10000) {
if (this._canUseCdCount > 10005) {
throw Error("loop")
}
}
Expand Down Expand Up @@ -1059,6 +1069,9 @@ export class CycleProcessor {
private combatStarting: boolean = false;

protected addAbilityUse(usedAbility: AbilityUseRecordUnf) {
if (this._rowCount++ > 10_000) {
throw Error("Used too many actions");
}
this.allRecords.push(usedAbility);
// If this is a pre-pull ability, we can offset by the hardcast time and/or application delay
if (!this.combatStarted && usedAbility.ability.potency !== null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import {CycleSettings} from "@xivgear/core/sims/cycle_settings";
import {
clampValues,
FieldBoundCheckBox,
FieldBoundFloatField,
labeledCheckbox,
labelFor,
nonNegative
labelFor
} from "@xivgear/common-ui/components/util";
import {NamedSection} from "../../components/section";

export function cycleSettingsGui(cycleSettings: CycleSettings) {
const out = new NamedSection('Cycle Settings');
const timeField = new FieldBoundFloatField(cycleSettings, 'totalTime', {
inputMode: 'number',
postValidators: [nonNegative]
// 1 hour of sim time should be enough for any application
postValidators: [clampValues(0, 60 * 60)],
});
timeField.id = 'cycle-total-time';
const label = labelFor('Total Time:', timeField);
Expand Down

0 comments on commit 34208f8

Please sign in to comment.