[Optimization] Destroy LoadingScene when done (after beta rebase) (#3215)

* destroy loading-scene when done

- unused event listeners are shut off
- children are removed
- `loading_bg` will be removed after transition is finished
- Added some simple types for `rex` plugins

* fix tests

* fix pokemonSprite.test.ts

on local runs it would include hidden dirs like `.DS_store`. Any files starting with `.` is now excluded

* add `mockGameObjectCreator` and use in `gameWrapper`

* add battle-scene.test.ts

add test to verify that LoadingScene is being removed on `BatleScene.create()` call

* update types usage for phaser3-rex-plugins

* remove phaser-extensions.d.ts

fk you typedoc...
This commit is contained in:
flx-sta 2024-07-29 21:28:43 -07:00 committed by GitHub
parent e9c48ef865
commit 29aa1a68e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 95 additions and 25 deletions

View File

@ -69,6 +69,7 @@ import { TimedEventManager } from "#app/timed-event-manager.js";
import i18next from "i18next"; import i18next from "i18next";
import {TrainerType} from "#enums/trainer-type"; import {TrainerType} from "#enums/trainer-type";
import { battleSpecDialogue } from "./data/dialogue"; import { battleSpecDialogue } from "./data/dialogue";
import { LoadingScene } from "./loading-scene";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -320,6 +321,7 @@ export default class BattleScene extends SceneBase {
} }
create() { create() {
this.scene.remove(LoadingScene.KEY);
initGameSpeed.apply(this); initGameSpeed.apply(this);
this.inputController = new InputsController(this); this.inputController = new InputsController(this);
this.uiInputs = new UiInputs(this, this.inputController); this.uiInputs = new UiInputs(this, this.inputController);
@ -370,7 +372,7 @@ export default class BattleScene extends SceneBase {
this.fieldUI = fieldUI; this.fieldUI = fieldUI;
const transition = (this.make as any).rexTransitionImagePack({ const transition = this.make.rexTransitionImagePack({
x: 0, x: 0,
y: 0, y: 0,
scale: 6, scale: 6,
@ -378,11 +380,15 @@ export default class BattleScene extends SceneBase {
origin: { x: 0, y: 0 } origin: { x: 0, y: 0 }
}, true); }, true);
//@ts-ignore (the defined types in the package are incromplete...)
transition.transit({ transition.transit({
mode: "blinds", mode: "blinds",
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
duration: 1250, duration: 1250,
oncomplete: () => transition.destroy() });
transition.once("complete", () => {
this.textures.remove("loading_bg");
transition.destroy();
}); });
this.add.existing(transition); this.add.existing(transition);

View File

@ -24,10 +24,12 @@ import { Biome } from "#enums/biome";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
export class LoadingScene extends SceneBase { export class LoadingScene extends SceneBase {
public static readonly KEY = "loading";
readonly LOAD_EVENTS = Phaser.Loader.Events; readonly LOAD_EVENTS = Phaser.Loader.Events;
constructor() { constructor() {
super("loading"); super(LoadingScene.KEY);
Phaser.Plugins.PluginCache.register("Loader", CacheBustedLoaderPlugin, "load"); Phaser.Plugins.PluginCache.register("Loader", CacheBustedLoaderPlugin, "load");
initI18n(); initI18n();
@ -434,7 +436,7 @@ export class LoadingScene extends SceneBase {
} }
const intro = this.add.video(0, 0); const intro = this.add.video(0, 0);
intro.on(Phaser.GameObjects.Events.VIDEO_COMPLETE, (video: Phaser.GameObjects.Video) => { intro.once(Phaser.GameObjects.Events.VIDEO_COMPLETE, (video: Phaser.GameObjects.Video) => {
this.tweens.add({ this.tweens.add({
targets: intro, targets: intro,
duration: 500, duration: 500,
@ -482,7 +484,10 @@ export class LoadingScene extends SceneBase {
} }
}); });
this.load.on(this.LOAD_EVENTS.COMPLETE, () => loadingGraphics.forEach(go => go.destroy())); this.load.on(this.LOAD_EVENTS.COMPLETE, () => {
loadingGraphics.forEach(go => go.destroy());
intro.destroy();
});
} }
get gameHeight() { get gameHeight() {
@ -494,6 +499,17 @@ export class LoadingScene extends SceneBase {
} }
async create() { async create() {
this.events.once(Phaser.Scenes.Events.DESTROY, () => this.handleDestroy());
this.scene.start("battle"); this.scene.start("battle");
} }
handleDestroy() {
console.debug(`Destroying ${LoadingScene.KEY} scene`);
this.load.off(this.LOAD_EVENTS.PROGRESS);
this.load.off(this.LOAD_EVENTS.FILE_COMPLETE);
this.load.off(this.LOAD_EVENTS.COMPLETE);
// this.textures.remove("loading_bg"); is removed in BattleScene.launchBattle()
this.children.removeAll(true);
console.debug(`Destroyed ${LoadingScene.KEY} scene`);
}
} }

View File

@ -0,0 +1,27 @@
import { LoadingScene } from "#app/loading-scene.js";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "./utils/gameManager";
describe("BattleScene", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
beforeEach(() => {
game = new GameManager(phaserGame);
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
it("should remove LoadingScene on create", () => {
// `BattleScene.create()` is called during the `new GameManager()` call
expect(game.scene.scene.remove).toHaveBeenCalledWith(LoadingScene.KEY);
});
});

View File

@ -1,20 +1,21 @@
import {beforeAll, describe, expect, it} from "vitest"; import { beforeAll, describe, expect, it } from "vitest";
import _masterlist from "../../../public/images/pokemon/variant/_masterlist.json"; import _masterlist from "../../../public/images/pokemon/variant/_masterlist.json";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import {getAppRootDir} from "#app/test/sprites/spritesUtils"; import { getAppRootDir } from "#app/test/sprites/spritesUtils";
const deepCopy = (data) => { type PokemonVariantMasterlist = typeof _masterlist;
const deepCopy = (data: any) => {
return JSON.parse(JSON.stringify(data)); return JSON.parse(JSON.stringify(data));
}; };
describe("check if every variant's sprite are correctly set", () => { describe("check if every variant's sprite are correctly set", () => {
let masterlist; let masterlist: PokemonVariantMasterlist;
let expVariant; let expVariant: PokemonVariantMasterlist["exp"];
let femaleVariant; let femaleVariant: PokemonVariantMasterlist["female"];
let backVariant; let backVariant: PokemonVariantMasterlist["back"];
let rootDir; let rootDir: string;
beforeAll(() => { beforeAll(() => {
rootDir = `${getAppRootDir()}${path.sep}public${path.sep}images${path.sep}pokemon${path.sep}variant${path.sep}`; rootDir = `${getAppRootDir()}${path.sep}public${path.sep}images${path.sep}pokemon${path.sep}variant${path.sep}`;
@ -34,11 +35,11 @@ describe("check if every variant's sprite are correctly set", () => {
expect(backVariant).not.toBeUndefined(); expect(backVariant).not.toBeUndefined();
}); });
function getMissingMasterlist(mlist, dirpath, excludes = []) { function getMissingMasterlist(mlist: any, dirpath: string, excludes: string[] = []): string[] {
const errors = []; const errors: string[] = [];
const trimmedDirpath = `variant${path.sep}${dirpath.split(rootDir)[1]}`; const trimmedDirpath = `variant${path.sep}${dirpath.split(rootDir)[1]}`;
if (fs.existsSync(dirpath)) { if (fs.existsSync(dirpath)) {
const files = fs.readdirSync(dirpath).filter(filename => !filename.startsWith(".")); const files = fs.readdirSync(dirpath).filter((filename) => !/^\..*/.test(filename));
for (const filename of files) { for (const filename of files) {
const filePath = `${dirpath}${filename}`; const filePath = `${dirpath}${filename}`;
const trimmedFilePath = `${trimmedDirpath}${filename}`; const trimmedFilePath = `${trimmedDirpath}${filename}`;
@ -101,12 +102,12 @@ describe("check if every variant's sprite are correctly set", () => {
return errors; return errors;
} }
function getMissingFiles(keys, dirPath) { function getMissingFiles(keys: Record<string, any>, dirPath: string): string[] {
const errors = []; const errors = [];
for (const key of Object.keys(keys)) { for (const key of Object.keys(keys)) {
const row = keys[key]; const row = keys[key];
for (const [index, elm] of row.entries()) { for (const [index, elm] of row.entries()) {
let url; let url: string;
if (elm === 0) { if (elm === 0) {
continue; continue;
} else if (elm === 1) { } else if (elm === 1) {

View File

@ -25,6 +25,7 @@ import {MoveAnim} from "#app/data/battle-anims";
import Pokemon from "#app/field/pokemon"; import Pokemon from "#app/field/pokemon";
import * as battleScene from "#app/battle-scene"; import * as battleScene from "#app/battle-scene";
import MockImage from "#app/test/utils/mocks/mocksContainer/mockImage.js"; import MockImage from "#app/test/utils/mocks/mocksContainer/mockImage.js";
import { MockGameObjectCreator } from "./mocks/mockGameObjectCreator";
Object.defineProperty(window, "localStorage", { Object.defineProperty(window, "localStorage", {
value: mockLocalStorage(), value: mockLocalStorage(),
@ -223,13 +224,9 @@ export default class GameWrapper {
return resolve(response); return resolve(response);
}); });
}; };
this.scene.make = { this.scene.make = new MockGameObjectCreator(mockTextureManager);
graphics: (config) => new MockGraphics(mockTextureManager, config),
rexTransitionImagePack: () => ({
transit: () => null,
}),
};
this.scene.time = new MockClock(this.scene); this.scene.time = new MockClock(this.scene);
this.scene.remove = vi.fn();
} }
} }

View File

@ -0,0 +1,23 @@
import { vi } from "vitest";
import MockGraphics from "./mocksContainer/mockGraphics";
import MockTextureManager from "./mockTextureManager";
export class MockGameObjectCreator {
private readonly textureManager: MockTextureManager;
constructor(textureManager: MockTextureManager) {
console.log("Mocking Phaser.GameObjects.GameObjectCreator;");
this.textureManager = textureManager;
}
graphics(config: any) {
return new MockGraphics(this.textureManager, config);
}
rexTransitionImagePack() {
return {
transit: vi.fn(),
once: vi.fn(),
};
}
}