Skip to content

Commit 21aa7b3

Browse files
committed
Use a queue for menus
1 parent f8b2ea9 commit 21aa7b3

File tree

4 files changed

+65
-60
lines changed

4 files changed

+65
-60
lines changed

build/scripts/menus.js

Lines changed: 42 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/scripts/players.js

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/menus.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@ This file contains the menu system.
66
import { CommandError, fail } from "./commands";
77
import { FishPlayer } from "./players";
88
import { outputFail } from "./utils";
9-
import { crash, parseError } from './funcs';
9+
import { parseError } from './funcs';
1010
import { to2DArray } from './funcs';
1111
import { Promise } from "./promise";
1212

13+
/** Used to change the behavior of adding another menu when being run in a menu callback. */
14+
let isInMenuCallback = false;
1315
/** Stores a mapping from name to the numeric id of a listener that has been registered. */
1416
const registeredListeners: Record<string, number> = {};
1517
/** Stores all listeners in use by fish-commands. */
1618
const listeners = {
1719
generic(player, option){
1820
const fishSender = FishPlayer.get(player);
1921

20-
//TODO replace with queue
21-
const prevCallback = fishSender.activeMenu.callback;
22-
fishSender.activeMenu.callback?.(fishSender, option);
23-
//if the callback wasn't modified, then clear it
24-
if(fishSender.activeMenu.callback === prevCallback)
25-
fishSender.activeMenu.callback = undefined;
26-
//otherwise, the menu spawned another menu that needs to be handled
22+
const prevCallback = fishSender.activeMenus.shift();
23+
if(!prevCallback) return; //No menu to process, do nothing
24+
isInMenuCallback = true;
25+
prevCallback.callback(option);
26+
isInMenuCallback = false;
2727
},
2828
none(player, option){
2929
//do nothing
@@ -82,15 +82,17 @@ export const Menu = {
8282
}
8383

8484
//The target fishPlayer has a property called activeMenu, which stores information about the last menu triggered.
85-
target.activeMenu.callback = (fishSender, option) => {
85+
//If menu() is being called from a menu calback, add it to the front of the queue so it is processed before any other menus.
86+
//Otherwise, two multi-step menus queued together would alternate, which would confuse the player.
87+
target.activeMenus[isInMenuCallback ? "unshift" : "push"]({ callback(option){
8688
//Additional permission validation could be done here, but the only way that callback() can be called is if the above statement executed,
8789
//and on sensitive menus such as the stop menu, the only way to reach that is if menu() was called by the /stop command,
8890
//which already checks permissions.
8991
//Additionally, the callback is cleared by the generic menu listener after it is executed.
9092

9193
try {
9294
//We do need to validate option though, as it can be any number.
93-
if(option === -1 || option === fishSender.activeMenu.cancelOptionId || !(option in options)){
95+
if(option === -1 || option === cancelOptionId || !(option in options)){
9496
//Consider any invalid option to be a cancellation
9597
if(onCancel == "null") resolve(null as never);
9698
else if(onCancel == "reject") reject("cancel" as never);
@@ -109,7 +111,7 @@ export const Menu = {
109111
Log.err(err as Error);
110112
}
111113
}
112-
};
114+
}});
113115

114116
Call.menu(target.con, registeredListeners.generic, title, description, arrangedOptions);
115117
return promise;

src/players.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ export class FishPlayer {
5353
player:mindustryPlayer | null = null;
5454
pet:string = "";
5555
watch:boolean = false;
56-
activeMenu: {
57-
cancelOptionId: number;
58-
callback?: (sender:FishPlayer, option:number) => void;
59-
} = {cancelOptionId: -1};
56+
/** Front-to-back queue of menus to show. */
57+
activeMenus: {
58+
callback: (option:number) => void;
59+
}[] = [];
6060
tileId = false;
6161
tilelog:null | "once" | "persist" = null;
6262
trail: {
@@ -382,7 +382,7 @@ export class FishPlayer {
382382
}
383383
}
384384
//Clear temporary states such as menu and taphandler
385-
fishP.activeMenu.callback = undefined;
385+
fishP.activeMenus = [];
386386
fishP.tapInfo.commandName = null;
387387
fishP.stats.timeInGame += (Date.now() - fishP.lastJoined); //Time between joining and leaving
388388
fishP.lastJoined = Date.now();
@@ -454,7 +454,7 @@ export class FishPlayer {
454454
static onGameOver(winningTeam:Team){
455455
this.forEachPlayer((fishPlayer) => {
456456
//Clear temporary states such as menu and taphandler
457-
fishPlayer.activeMenu.callback = undefined;
457+
fishPlayer.activeMenus = [];
458458
fishPlayer.tapInfo.commandName = null;
459459
//Update stats
460460
if(!this.ignoreGameOver && fishPlayer.team() != Team.derelict && winningTeam != Team.derelict){

0 commit comments

Comments
 (0)