Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New run comparison API and set from leaderboard entry #156

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions scripts/common/timer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
type Gamemode = import('common/web').Gamemode;

/* eslint-disable @typescript-eslint/naming-convention */
export enum TimerEvent_OLD {
STARTED = 0,
Expand Down Expand Up @@ -104,6 +106,18 @@ export interface RunSplits {
segments: RunSegment[];
}

export interface RunMetadata {
filePath: string;
timestamp: number;
gameMode: Gamemode;
tickInterval: float;
playerSteamId: number;
playerName: string;
trackId: TrackID;
runTime: double;
runSplits: RunSplits | null;
}

/** Enum for why end of run is being shown */
export enum EndOfRunShowReason {
PLAYER_FINISHED_RUN = 0,
Expand Down
137 changes: 20 additions & 117 deletions scripts/hud/comparisons.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { PanelHandler } from 'util/module-helpers';
import { TimerEvent_OLD, TimerState_OLD } from 'common/timer';
import { Comparison_OLD, RunStats_OLD, Split_OLD } from 'common/timer';
import { RunMetadata } from 'common/timer';

@PanelHandler()
class HudComparisonsHandler {
runFinished = false;
currentZone = 0;
runStatsZoneIndex = 0;
comparison: RunMetadata = null;

readonly maxActiveSplits = 12;
readonly newSplitTransitionDuration = 2;
Expand All @@ -17,129 +14,35 @@
};

constructor() {
$.RegisterEventHandler('HudCompare_Update', $.GetContextPanel(), () => this.updateComparisons());
$.RegisterForUnhandledEvent('OnMomentumTimerStateChange', (arg, arg2) => this.onTimerEvent(arg, arg2));
$.RegisterForUnhandledEvent('ComparisonRunUpdated', () => this.onComparisonRunUpdated());
$.RegisterForUnhandledEvent('OnObservedTimerStateChange', () => this.updateComparisons());
$.RegisterForUnhandledEvent('OnObservedTimerCheckpointProgressed', () => this.updateComparisons());
$.RegisterForUnhandledEvent('OnObservedTimerReplaced', () => this.updateComparisons());
}

clearComparisons() {
// this.panels.compare.RemoveAndDeleteChildren();
this.panels.splits.RemoveAndDeleteChildren();
this.runFinished = false;
this.currentZone = 0;
this.runStatsZoneIndex = 0;
}
onComparisonRunUpdated() {
this.comparison = RunComparisonsAPI.GetComparisonRun();

$.Msg(`Got comparison run ${this.comparison?.filePath ?? 'NONE'}`);

onTimerEvent(_ent: any, eventType: any) {
if (eventType === TimerEvent_OLD.STARTED) {
this.clearComparisons();
if (this.comparison) {
$.Msg(`jumps: ${this.comparison.runSplits.trackStats.jumps}`);
}

this.updateComparisons();
}

updateComparisons() {
/* TODO
const currentData = $.GetContextPanel<HudComparisons>().currentRunData;
const currentStats = $.GetContextPanel<HudComparisons>().currentRunStats;
const comparisonRun = RunComparisonsAPI.GetLoadedComparison();

const hasCompare = !!comparisonRun.compareRun;
const timerStatus = MomentumTimerAPI.GetObservedTimerStatus();
const runSplits = MomentumTimerAPI.GetObservedTimerRunSplits();

if (
!currentData ||
!currentData.isInZone ||
!currentStats ||
currentData.currentZone === 1 ||
currentData.timerState === TimerState_OLD.PRACTICE
timerStatus.trackId.type === this.comparison.trackId.type &&
timerStatus.trackId.number === this.comparison.trackId.number
) {

Check failure on line 42 in scripts/hud/comparisons.ts

View workflow job for this annotation

GitHub Actions / build

Empty block statement
return;
}

// Here, this.currentZone tracks how far into the run we are, so we can compare against currentData.currentZone,
// so we don't fire on stage we've already hit.
// this.runStatsZoneIndex tracks the correct index into the runStats array

if (currentData.timerState === TimerState_OLD.NOT_RUNNING) {
// The only time we care about comparisons when timer is not running is if you just
// hit the end zone *for the first time*
if (!this.runFinished && currentData.currentZone === 0) {
// We're at the last zone, set index to last in the RunStats zone array
this.runStatsZoneIndex = currentStats.numZones - 1;
this.currentZone = 0;

// Track that we've finished so this never runs again
this.runFinished = true;
} else {
return;
}
} else {
// Return out if you went back a zone
if (currentData.currentZone <= this.currentZone) {
return;
} else {
// This is the first time you hit this zone
this.currentZone = currentData.currentZone;
this.runStatsZoneIndex = currentData.currentZone - 2; // -2 but currentZone is offset by the end and start zones
}
// Track differs -- could maybe do a best-effort comparison if one is a stage and one is the main track,
// otherwise make sure the comparison HUD is cleared
}

const splitPanels = this.panels.splits.Children().reverse();
if (splitPanels.length > this.maxActiveSplits) {
for (const panel of splitPanels.filter((_, i) => splitPanels.length - i > this.maxActiveSplits))
panel.RemoveAndDeleteChildren();
}

const data = hasCompare
? Comparison_OLD.generateSplits(
new RunStats_OLD(currentStats, currentData.tickRate),
new RunStats_OLD(comparisonRun.compareRun.stats, currentData.tickRate)
// this.runStatsZoneIndex + 1 TODO: this was being passed to generateSplits, but that only takes two args. What was this for?
)[this.runStatsZoneIndex]
: new RunStats_OLD(currentStats, currentData.tickRate, this.runStatsZoneIndex + 1).zones[
this.runStatsZoneIndex
];

const wrapper = $.CreatePanel('Panel', this.panels.splits, `Split${data.name}`, {
class: 'hud-comparisons__split'
});

if (this.runStatsZoneIndex > 0) {
const lastSplit = this.panels.splits.GetFirstChild().GetFirstChild();
lastSplit?.RemoveClass('split--latest');
}

this.panels.splits.MoveChildBefore(wrapper, this.panels.splits.Children()[0]);

const panel = $.CreatePanel('Split', wrapper, '', { class: 'split--hud split--latest' });

// Animation code I might try in 0.9.2

// Avoids hardcoding a height value. Waits for one split to spawn and have correct height, then tracks it.
// Means first one won't animate height but that's fine as there's nothing for it to push upwards
// $.Schedule(0.05, () => (this.latestSplitHeight ??= panel.actuallayoutheight / panel.actualuiscale_y));

// if (!this.latestSplitHeight) return;

// panel.style.height = `${this.latestSplitHeight}px`;
// wrapper.style.transitionDuration = '0s';
// wrapper.style.height = '0px';
// wrapper.style.transitionDuration = `${NEW_SPLIT_TRANSITION_DURATION}s`;
// wrapper.style.height = `${this.latestSplitHeight}px`;

Object.assign(
panel,
hasCompare
? {
name: data.name,
time: data.accumulateTime,
isFirst: false,
diff: (data as Split_OLD).diff,
delta: (data as Split_OLD).delta
}
: {
name: data.name,
time: data.accumulateTime,
isFirst: true
}
);
*/
}
}
6 changes: 3 additions & 3 deletions scripts/pages/end-of-run/end-of-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class EndOfRunHandler {
selectedSplit: Split_OLD;

constructor() {
$.RegisterForUnhandledEvent('EndOfRun_CompareRuns', (baseRun, compareRun) =>
this.setComparison(baseRun, compareRun)
);
// $.RegisterForUnhandledEvent('EndOfRun_CompareRuns', (baseRun, compareRun) =>
// this.setComparison(baseRun, compareRun)
// );
$.RegisterForUnhandledEvent('EndOfRun_Show', (reason) => this.showNewEndOfRun(reason));
$.RegisterForUnhandledEvent('EndOfRun_Result_RunUpload', (uploaded, cosXP, rankXP, lvlGain) =>
this.updateRunUploadStatus(uploaded, cosXP, rankXP, lvlGain)
Expand Down
9 changes: 9 additions & 0 deletions scripts/pages/leaderboards/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@
$.DispatchEvent('LeaderboardEntry_PlayReplay', index);
}
});

items.push({

Check failure on line 57 in scripts/pages/leaderboards/entry.ts

View workflow job for this annotation

GitHub Actions / build

Do not call `Array#push()` multiple times
label: $.Localize('#Action_SetComparisonRun'),
icon: 'file://{images}/chart-timeline.svg',
style: 'icon-color-light-blue',
jsCallback: () => {
$.DispatchEvent('LeaderboardEntry_SetComparisonRun', index);
}
});
}

if (timeData.type === LeaderboardEntryType.ONLINE || timeData.type === LeaderboardEntryType.ONLINE_CACHED) {
Expand Down
7 changes: 2 additions & 5 deletions scripts/types-mom/apis.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
type RunMetadata = import('common/timer').RunMetadata;
type Gamemode = import('common/web').Gamemode;

declare namespace MomentumAPI {
Expand Down Expand Up @@ -280,12 +281,8 @@ declare namespace SpectatorAPI {
function GetSpecList(): steamID[];
}

/** Probably changing soon, doing weak types. */
declare namespace RunComparisonsAPI {
function GetLoadedComparison(): any;
function IsComparisonLoaded(): any;
function GetLoadedComparisonSpeed(...args: any[]): any;
function GetLoadedComparisonOverallDiff(arg: any): any;
function GetComparisonRun(): RunMetadata;
}

declare namespace ZonesAPI {
Expand Down
11 changes: 3 additions & 8 deletions scripts/types-mom/events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ interface GlobalEventNameMap {

OnNewChatEntry: (panel: GenericPanel & { message: string; author_name: string; author_xuid: string }) => void;

/** Fired when the JS panel should update what it's showing */
HudCompare_Update: () => void;
ComparisonRunUpdated: () => void;

// TODO: Old, remove after rio stuff is in
OnMomentumTimerStateChange: (arg1: any, arg2: any) => any;
Expand Down Expand Up @@ -271,12 +270,6 @@ interface GlobalEventNameMap {
/** Fired when the end of run panel should be hidden */
EndOfRun_Hide: () => void;

/** Fired when the end of run panel should set the two runs to compare. baseRun is compared to compareRun */
EndOfRun_CompareRuns: (
baseRun: import('common/timer').CPPRun_OLD,
compareRun: import('common/timer').CPPRun_OLD
) => void;

/** Fired when the replay recording finishes and passes whether writing the file was successful */
EndOfRun_Result_RunSave: (saved: boolean) => void;

Expand Down Expand Up @@ -322,6 +315,8 @@ interface GlobalEventNameMap {

LeaderboardEntry_PlayReplay: (itemIndex: int32) => void;

LeaderboardEntry_SetComparisonRun: (itemIndex: int32) => void;

LeaderboardEntry_DeleteReplay: (itemIndex: int32) => void;

/**
Expand Down
Loading