Skip to content

Commit

Permalink
util: Add basic network log seal support in timeline tools (#5947)
Browse files Browse the repository at this point in the history
This wasn't as simple as I had hoped, but it does seem to work as it is.
There's still a bit of fragility in `make_timeline` with this
implementation, since it still relies on the seal name being present in
game log form. We could change this to make "name from game log"
optional in the `assembleTimelineStrings()` function, but that would
involve some complex conditions to allow for use of either the network
seal or the game log seal.
  • Loading branch information
JLGarber authored Nov 30, 2023
1 parent 6540fa3 commit fa8a97d
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 31 deletions.
97 changes: 69 additions & 28 deletions util/logtools/encounter_tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type FightEncInfo = ZoneEncInfo & {
fightName?: string;
endType?: string;
sealName?: string;
sealId?: string;
logLines?: string[];
};

Expand All @@ -38,6 +39,8 @@ export class EncounterFinder {

regex: {
changeZone: CactbotBaseRegExp<'ChangeZone'>;
netSeal: CactbotBaseRegExp<'SystemLogMessage'>;
netUnseal: CactbotBaseRegExp<'SystemLogMessage'>;
cactbotWipe: CactbotBaseRegExp<'GameLog'>;
win: CactbotBaseRegExp<'ActorControl'>;
wipe: CactbotBaseRegExp<'ActorControl'>;
Expand All @@ -61,6 +64,8 @@ export class EncounterFinder {
constructor() {
this.regex = {
changeZone: NetRegexes.changeZone(),
netSeal: NetRegexes.systemLogMessage({ id: '7DC' }),
netUnseal: NetRegexes.systemLogMessage({ id: '7DE' }),
cactbotWipe: commonNetRegex.cactbotWipeEcho,
win: NetRegexes.network6d({ command: '4000000[23]' }),
wipe: commonNetRegex.wipe,
Expand Down Expand Up @@ -110,6 +115,12 @@ export class EncounterFinder {
return !keepTypes.includes(content);
}

storeStartLine(line: string, store: boolean): void {
const previouslyStarted = this.currentFight.startTime !== undefined;
if (store && !previouslyStarted)
(this.currentFight.logLines ??= []).push(line);
}

process(line: string, store: boolean): void {
// Irrespective of any processing that occurs, we want to store every line of an encounter.
// This allows us to save a pass when making timelines.
Expand Down Expand Up @@ -173,18 +184,31 @@ export class EncounterFinder {
}

// Once we see a seal, we know that we will be falling through to here throughout the zone.
const netSeal = this.regex.netSeal.exec(line)?.groups;
if (netSeal) {
this.onNetSeal(line, netSeal.param1, netSeal);
this.storeStartLine(line, store);
return;
}

for (const regex of this.sealRegexes) {
const s = regex.exec(line)?.groups;
if (s) {
const seal = s.seal ?? 'UNKNOWN';
const previouslyStarted = this.currentFight.startTime !== undefined;
this.onSeal(line, seal, s);
if (store && !previouslyStarted && this.currentFight.startTime !== undefined)
(this.currentFight.logLines ??= []).push(line);
this.onSeal(seal);
this.storeStartLine(line, store);
return;
}
}

// Unseal messages will almost always be picked up here.
// TODO: Determine whether we need to keep game log unseal functionality.
const netUnseal = this.regex.netUnseal.exec(line)?.groups;
if (netUnseal) {
this.onUnseal(line, netUnseal);
return;
}

for (const regex of this.unsealRegexes) {
const u = regex.exec(line)?.groups;
if (u) {
Expand All @@ -201,10 +225,8 @@ export class EncounterFinder {
// TODO: This regex catches faerie healing and could potentially give false positives!
a = this.regex.mobAttackingPlayer.exec(line);
if (a?.groups) {
const previouslyStarted = this.currentFight.startTime !== undefined;
this.onStartFight(line, this.currentZone.zoneName, a.groups);
if (store && !previouslyStarted && this.currentFight.startTime !== undefined)
(this.currentFight.logLines ??= []).push(line);
this.onStartFight(line, a.groups, this.currentZone.zoneName);
this.storeStartLine(line, store);
return;
}
}
Expand All @@ -222,12 +244,19 @@ export class EncounterFinder {
startTime: TLFuncs.dateFromMatches(matches),
};
}
onStartFight(line: string, fightName: string, matches: NetMatches['Ability' | 'GameLog']): void {
onStartFight(
line: string,
matches: NetMatches['Ability' | 'GameLog' | 'SystemLogMessage'],
fightName?: string,
sealId?: string,
): void {
this.currentFight = {
fightName: fightName,
zoneName: this.currentZone.zoneName, // Sometimes the same as the fight name, but that's fine.
sealId: sealId,
zoneName: this.currentZone.zoneName,
startLine: line,
startTime: TLFuncs.dateFromMatches(matches),
zoneId: this.currentZone.zoneId,
};
}

Expand All @@ -236,16 +265,22 @@ export class EncounterFinder {
}

onEndFight(_line: string, _matches: NetAnyMatches, _endType: string): void {
this.initializeFight();
if (this.currentFight.startTime !== undefined)
this.initializeFight();
}

onSeal(line: string, sealName: string, matches: NetMatches['GameLog']): void {
this.onStartFight(line, sealName, matches);
onNetSeal(line: string, sealId: string, matches: NetMatches['SystemLogMessage']): void {
this.onStartFight(line, matches, undefined, sealId);
this.haveSeenSeals = true;
}

onSeal(sealName: string): void {
this.currentFight.sealName = sealName;
this.currentSeal = sealName;
this.haveSeenSeals = true;
}

onUnseal(line: string, matches: NetMatches['GameLog']): void {
onUnseal(line: string, matches: NetMatches['GameLog' | 'SystemLogMessage']): void {
this.onEndFight(line, matches, 'Unseal');
this.currentSeal = undefined;
}
Expand All @@ -254,7 +289,6 @@ export class EncounterFinder {
class EncounterCollector extends EncounterFinder {
zones: Array<ZoneEncInfo> = [];
fights: Array<FightEncInfo> = [];
lastSeal?: string;
constructor() {
super();
}
Expand All @@ -268,11 +302,13 @@ class EncounterCollector extends EncounterFinder {

override onStartFight(
line: string,
fightName: string,
matches: NetMatches['Ability' | 'GameLog'],
matches: NetMatches['Ability' | 'GameLog' | 'SystemLogMessage'],
fightName?: string,
sealId?: string,
): void {
this.currentFight = {
fightName: fightName,
sealId: sealId,
zoneName: this.currentZone.zoneName,
startLine: line,
startTime: TLFuncs.dateFromMatches(matches),
Expand All @@ -281,23 +317,28 @@ class EncounterCollector extends EncounterFinder {
}

override onEndFight(line: string, matches: NetAnyMatches, endType: string): void {
this.currentFight.endLine = line;
this.currentFight.endTime = TLFuncs.dateFromMatches(matches);
this.currentFight.endType = endType;
this.fights.push(this.currentFight);
this.initializeFight();
// This needs to be conditional. Otherwise a game log unseal line could
// insert spurious unknown encounters if it occurs after a network unseal line.
if (this.currentFight.startTime !== undefined) {
this.currentFight.endLine = line;
this.currentFight.endTime = TLFuncs.dateFromMatches(matches);
this.currentFight.endType = endType;
this.fights.push(this.currentFight);
this.initializeFight();
}
}

override onSeal(line: string, sealName: string, matches: NetMatches['GameLog']): void {
this.onStartFight(line, sealName, matches);
override onNetSeal(line: string, sealId: string, matches: NetMatches['SystemLogMessage']): void {
this.onStartFight(line, matches, undefined, sealId);
this.haveSeenSeals = true;
this.lastSeal = sealName;
this.currentFight.sealName = this.lastSeal;
}

override onUnseal(line: string, matches: NetMatches['GameLog']): void {
override onSeal(sealName: string): void {
this.currentFight.sealName = sealName;
}

override onUnseal(line: string, matches: NetAnyMatches): void {
this.onEndFight(line, matches, 'Unseal');
this.lastSeal = undefined;
}
}

Expand Down
14 changes: 11 additions & 3 deletions util/logtools/make_timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,17 @@ const assembleTimelineStrings = (
let timelinePosition = 0;
let lastEntry: TimelineEntry = { time: lastAbilityTime.toString(), lineType: 'None' };
if (fight !== undefined && fight.sealName !== undefined) {
const zoneMessage = SFuncs.toProperCase(fight.sealName);
const tlString = `0.0 "--sync--" sync / 00:0839::${zoneMessage} will be sealed off/ window 0,1`;
assembled.push(tlString);
const sealMessage = SFuncs.toProperCase(fight.sealName);
if (fight.sealId !== undefined) {
const sealComment = `# ${sealMessage} will be sealed off`;
const netLogSeal = `0.0 "--sync--" sync / 29:[^:]*:7DC:[^:]*:${fight.sealId}/ window 0,1`;
assembled.push(sealComment);
assembled.push(netLogSeal);
} else {
const tlString =
`0.0 "--sync--" sync / 00:0839::${sealMessage} will be sealed off/ window 0,1`;
assembled.push(tlString);
}
} else {
assembled.push('0.0 "--sync--" sync / 104:[^:]*:1($|:)/ window 0,1');
}
Expand Down

0 comments on commit fa8a97d

Please sign in to comment.