Compare commits

...

4 Commits

Author SHA1 Message Date
Opaque02
59ff4e9941
Admin panel beta (#3846)
* feat: Add hasAdminRole property to UserInfo interface and update initLoggedInUser and updateUserInfo functions

This commit adds the hasAdminRole property to the UserInfo interface in the account.ts file. The initLoggedInUser function is updated to set the hasAdminRole property to false by default. The updateUserInfo function is also updated to set the hasAdminRole property to false when bypassLogin is true. This change allows for better management of user roles and permissions.

Co-authored-by: frutescens <info@laptop>
Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt>

* Updated UI for admin panel and menu

* Remove random blank line from merge

* Fix imports in `src/ui/ui.ts`

---------

Co-authored-by: Frederico Santos <frederico.f.santos@tecnico.ulisboa.pt>
Co-authored-by: frutescens <info@laptop>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2024-08-29 10:22:01 +01:00
Blitzy
d86c47a39f
[Sprite] Update Rose Sprite (#3890) 2024-08-29 01:57:22 -07:00
Blitzy
8f2699e6ea
[Enhancement] Update Team Skull Sprites (#3886)
* Update Team Skull Sprites

* Add files via upload

* Update skull_grunt_f.json

* Update skull_grunt_m.json

* Fix eol

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2024-08-28 23:38:21 -07:00
Mumble
781e25848d
fixed infinite loop (#3887)
Co-authored-by: frutescens <info@laptop>
2024-08-28 22:44:26 -07:00
12 changed files with 146 additions and 38 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -4,8 +4,8 @@
"image": "skull_grunt_f.png", "image": "skull_grunt_f.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 69, "w": 74,
"h": 69 "h": 74
}, },
"scale": 1, "scale": 1,
"frames": [ "frames": [
@ -14,20 +14,20 @@
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"sourceSize": { "sourceSize": {
"w": 80, "w": 31,
"h": 80 "h": 74
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 27, "x": 0,
"y": 9, "y": 0,
"w": 29, "w": 31,
"h": 69 "h": 74
}, },
"frame": { "frame": {
"x": 0, "x": 0,
"y": 0, "y": 0,
"w": 29, "w": 31,
"h": 69 "h": 74
} }
} }
] ]
@ -36,6 +36,6 @@
"meta": { "meta": {
"app": "https://www.codeandweb.com/texturepacker", "app": "https://www.codeandweb.com/texturepacker",
"version": "3.0", "version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:2e44c39efe8e78ec75d9119731b9b1cb:4923b5197ea74a9ed0b861e2408f595b:9035f560a0ab0d45bcc084aba7172990$" "smartupdate": "$TexturePacker:SmartUpdate:71a1f5b1981674c6e81163ac8ea576c3:a5e612d58e5f0a1489e111212baea09d:dd369353af16e4c5eb6547e129dfac18$"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 B

After

Width:  |  Height:  |  Size: 905 B

View File

@ -4,8 +4,8 @@
"image": "skull_grunt_m.png", "image": "skull_grunt_m.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 67, "w": 72,
"h": 67 "h": 72
}, },
"scale": 1, "scale": 1,
"frames": [ "frames": [
@ -14,20 +14,20 @@
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": false,
"sourceSize": { "sourceSize": {
"w": 80, "w": 51,
"h": 80 "h": 72
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 28, "x": 0,
"y": 11, "y": 0,
"w": 26, "w": 51,
"h": 67 "h": 72
}, },
"frame": { "frame": {
"x": 0, "x": 0,
"y": 0, "y": 0,
"w": 26, "w": 51,
"h": 67 "h": 72
} }
} }
] ]
@ -36,6 +36,6 @@
"meta": { "meta": {
"app": "https://www.codeandweb.com/texturepacker", "app": "https://www.codeandweb.com/texturepacker",
"version": "3.0", "version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:688a83ff13a77c6923f038db8c7e5e84:d0ece3ab82602eb0c5003bacc26dbd9f:1ff10b395daf6ebfa377680a6404f816$" "smartupdate": "$TexturePacker:SmartUpdate:4deb2a68e4d168bb1a40cb5d190a7d1f:be3d7b29f4b544ba51cf907691fef51d:df57ca2c9bf5f80d930306e15a851d4d$"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 966 B

View File

@ -6,6 +6,7 @@ export interface UserInfo {
lastSessionSlot: integer; lastSessionSlot: integer;
discordId: string; discordId: string;
googleId: string; googleId: string;
hasAdminRole: boolean;
} }
export let loggedInUser: UserInfo | null = null; export let loggedInUser: UserInfo | null = null;
@ -13,13 +14,13 @@ export let loggedInUser: UserInfo | null = null;
export const clientSessionId = Utils.randomString(32); export const clientSessionId = Utils.randomString(32);
export function initLoggedInUser(): void { export function initLoggedInUser(): void {
loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: ""}; loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "", hasAdminRole: false };
} }
export function updateUserInfo(): Promise<[boolean, integer]> { export function updateUserInfo(): Promise<[boolean, integer]> {
return new Promise<[boolean, integer]>(resolve => { return new Promise<[boolean, integer]>(resolve => {
if (bypassLogin) { if (bypassLogin) {
loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "" }; loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "", hasAdminRole: false};
let lastSessionSlot = -1; let lastSessionSlot = -1;
for (let s = 0; s < 5; s++) { for (let s = 0; s < 5; s++) {
if (localStorage.getItem(`sessionData${s ? s : ""}_${loggedInUser.username}`)) { if (localStorage.getItem(`sessionData${s ? s : ""}_${loggedInUser.username}`)) {

View File

@ -635,13 +635,13 @@ export class GameData {
async saveRunHistory(scene: BattleScene, runEntry : SessionSaveData, isVictory: boolean): Promise<boolean> { async saveRunHistory(scene: BattleScene, runEntry : SessionSaveData, isVictory: boolean): Promise<boolean> {
const runHistoryData = await this.getRunHistoryData(scene); const runHistoryData = await this.getRunHistoryData(scene);
// runHistoryData should always return run history or {} empty object // runHistoryData should always return run history or {} empty object
const timestamps = Object.keys(runHistoryData); let timestamps = Object.keys(runHistoryData).map(Number);
const timestampsNo = timestamps.map(Number);
// Arbitrary limit of 25 entries per user --> Can increase or decrease // Arbitrary limit of 25 entries per user --> Can increase or decrease
while (timestamps.length >= RUN_HISTORY_LIMIT ) { while (timestamps.length >= RUN_HISTORY_LIMIT ) {
const oldestTimestamp = Math.min.apply(Math, timestampsNo); const oldestTimestamp = (Math.min.apply(Math, timestamps)).toString();
delete runHistoryData[oldestTimestamp]; delete runHistoryData[oldestTimestamp];
timestamps = Object.keys(runHistoryData).map(Number);
} }
const timestamp = (runEntry.timestamp).toString(); const timestamp = (runEntry.timestamp).toString();

View File

@ -0,0 +1,85 @@
import BattleScene from "#app/battle-scene.js";
import { ModalConfig } from "./modal-ui-handler";
import { Mode } from "./ui";
import * as Utils from "../utils";
import { FormModalUiHandler } from "./form-modal-ui-handler";
import { Button } from "#app/enums/buttons.js";
export default class AdminUiHandler extends FormModalUiHandler {
constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode);
}
setup(): void {
super.setup();
}
getModalTitle(config?: ModalConfig): string {
return "Admin panel";
}
getFields(config?: ModalConfig): string[] {
return ["Username", "Discord ID"];
}
getWidth(config?: ModalConfig): number {
return 160;
}
getMargin(config?: ModalConfig): [number, number, number, number] {
return [0, 0, 48, 0];
}
getButtonLabels(config?: ModalConfig): string[] {
return ["Link account", "Cancel"];
}
processInput(button: Button): boolean {
if (button === Button.SUBMIT && this.submitAction) {
this.submitAction();
return true;
}
return false;
}
show(args: any[]): boolean {
if (super.show(args)) {
const config = args[0] as ModalConfig;
const originalSubmitAction = this.submitAction;
this.submitAction = (_) => {
this.submitAction = originalSubmitAction;
this.scene.ui.setMode(Mode.LOADING, { buttonActions: [] });
const onFail = error => {
this.scene.ui.setMode(Mode.ADMIN, Object.assign(config, { errorMessage: error?.trim() }));
this.scene.ui.playError();
};
if (!this.inputs[0].text) {
return onFail("Username is required");
}
if (!this.inputs[1].text) {
return onFail("Discord Id is required");
}
Utils.apiPost("admin/account/discord-link", `username=${encodeURIComponent(this.inputs[0].text)}&discordId=${encodeURIComponent(this.inputs[1].text)}`, "application/x-www-form-urlencoded", true)
.then(response => {
if (!response.ok) {
return response.text();
}
return response.json();
})
.then(response => {
this.scene.ui.setMode(Mode.ADMIN, config);
});
return false;
};
return true;
}
return false;
}
clear(): void {
super.clear();
}
}

View File

@ -6,7 +6,7 @@ import { WindowVariant, addWindow } from "./ui-theme";
import InputText from "phaser3-rex-plugins/plugins/inputtext"; import InputText from "phaser3-rex-plugins/plugins/inputtext";
import * as Utils from "../utils"; import * as Utils from "../utils";
import i18next from "i18next"; import i18next from "i18next";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
export interface FormModalConfig extends ModalConfig { export interface FormModalConfig extends ModalConfig {
errorMessage?: string; errorMessage?: string;
@ -60,7 +60,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
const inputBg = addWindow(this.scene, 0, 0, 80, 16, false, false, 0, 0, WindowVariant.XTHIN); const inputBg = addWindow(this.scene, 0, 0, 80, 16, false, false, 0, 0, WindowVariant.XTHIN);
const isPassword = field.includes(i18next.t("menu:password")) || field.includes(i18next.t("menu:confirmPassword")); const isPassword = field.includes(i18next.t("menu:password")) || field.includes(i18next.t("menu:confirmPassword"));
const input = addTextInputObject(this.scene, 4, -2, 440, 116, TextStyle.TOOLTIP_CONTENT, { type: isPassword ? "password" : "text", maxLength: isPassword ? 64 : 16 }); const input = addTextInputObject(this.scene, 4, -2, 440, 116, TextStyle.TOOLTIP_CONTENT, { type: isPassword ? "password" : "text", maxLength: isPassword ? 64 : 18 });
input.setOrigin(0, 0); input.setOrigin(0, 0);
inputContainer.add(inputBg); inputContainer.add(inputBg);

View File

@ -306,16 +306,34 @@ export default class MenuUiHandler extends MessageUiHandler {
return true; return true;
}, },
keepOpen: true keepOpen: true
}, }];
{ if (!bypassLogin && loggedInUser?.hasAdminRole) {
label: i18next.t("menuUiHandler:cancel"), communityOptions.push({
label: "Admin",
handler: () => { handler: () => {
this.scene.ui.revertMode(); ui.playSelect();
ui.setOverlayMode(Mode.ADMIN, {
buttonActions: [
() => {
ui.revertMode();
},
() => {
ui.revertMode();
}
]
});
return true; return true;
} },
keepOpen: true
});
}
communityOptions.push({
label: i18next.t("menuUiHandler:cancel"),
handler: () => {
this.scene.ui.revertMode();
return true;
} }
]; });
this.communityConfig = { this.communityConfig = {
xOffset: 98, xOffset: 98,
options: communityOptions options: communityOptions

View File

@ -23,7 +23,7 @@ import OptionSelectUiHandler from "./settings/option-select-ui-handler";
import EggHatchSceneHandler from "./egg-hatch-scene-handler"; import EggHatchSceneHandler from "./egg-hatch-scene-handler";
import EggListUiHandler from "./egg-list-ui-handler"; import EggListUiHandler from "./egg-list-ui-handler";
import EggGachaUiHandler from "./egg-gacha-ui-handler"; import EggGachaUiHandler from "./egg-gacha-ui-handler";
import {addWindow} from "./ui-theme"; import { addWindow } from "./ui-theme";
import LoginFormUiHandler from "./login-form-ui-handler"; import LoginFormUiHandler from "./login-form-ui-handler";
import RegistrationFormUiHandler from "./registration-form-ui-handler"; import RegistrationFormUiHandler from "./registration-form-ui-handler";
import LoadingModalUiHandler from "./loading-modal-ui-handler"; import LoadingModalUiHandler from "./loading-modal-ui-handler";
@ -46,6 +46,7 @@ import SettingsAudioUiHandler from "./settings/settings-audio-ui-handler";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import BgmBar from "#app/ui/bgm-bar"; import BgmBar from "#app/ui/bgm-bar";
import RenameFormUiHandler from "./rename-form-ui-handler"; import RenameFormUiHandler from "./rename-form-ui-handler";
import AdminUiHandler from "./admin-ui-handler";
import RunHistoryUiHandler from "./run-history-ui-handler"; import RunHistoryUiHandler from "./run-history-ui-handler";
import RunInfoUiHandler from "./run-info-ui-handler"; import RunInfoUiHandler from "./run-info-ui-handler";
@ -86,6 +87,7 @@ export enum Mode {
OUTDATED, OUTDATED,
CHALLENGE_SELECT, CHALLENGE_SELECT,
RENAME_POKEMON, RENAME_POKEMON,
ADMIN,
RUN_HISTORY, RUN_HISTORY,
RUN_INFO, RUN_INFO,
} }
@ -124,7 +126,8 @@ const noTransitionModes = [
Mode.SESSION_RELOAD, Mode.SESSION_RELOAD,
Mode.UNAVAILABLE, Mode.UNAVAILABLE,
Mode.OUTDATED, Mode.OUTDATED,
Mode.RENAME_POKEMON Mode.RENAME_POKEMON,
Mode.ADMIN,
]; ];
export default class UI extends Phaser.GameObjects.Container { export default class UI extends Phaser.GameObjects.Container {
@ -188,6 +191,7 @@ export default class UI extends Phaser.GameObjects.Container {
new RenameFormUiHandler(scene), new RenameFormUiHandler(scene),
new RunHistoryUiHandler(scene), new RunHistoryUiHandler(scene),
new RunInfoUiHandler(scene), new RunInfoUiHandler(scene),
new AdminUiHandler(scene),
]; ];
} }