mirror of
https://github.com/motajs/template.git
synced 2026-09-13 10:18:50 +08:00
feat(03-01): add Node-safe core state construction
- isolate legacy loading behind internal dependencies - provide memory saves and remove singleton back-edges
This commit is contained in:
parent
51d1796358
commit
a707be4856
@ -70,13 +70,18 @@ class GameLoading extends EventEmitter<GameLoadEvent> {
|
||||
}
|
||||
|
||||
export const loading = new GameLoading();
|
||||
main.loading = loading;
|
||||
if (typeof main !== 'undefined') {
|
||||
main.loading = loading;
|
||||
}
|
||||
|
||||
let clientRegistered = false;
|
||||
let dataRegistered = false;
|
||||
|
||||
function checkRegistered() {
|
||||
if (main.replayChecking || main.mode === 'editor') {
|
||||
if (
|
||||
typeof main !== 'undefined' &&
|
||||
(main.replayChecking || main.mode === 'editor')
|
||||
) {
|
||||
clientRegistered = true;
|
||||
}
|
||||
if (clientRegistered && dataRegistered) {
|
||||
@ -168,8 +173,8 @@ class GameListener extends EventEmitter<ListenerEvent> {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (main.replayChecking) return;
|
||||
if (window.core) {
|
||||
if (typeof main === 'undefined' || main.replayChecking) return;
|
||||
if (typeof window !== 'undefined' && window.core) {
|
||||
this.init();
|
||||
} else {
|
||||
loading.once('coreInit', () => {
|
||||
|
||||
@ -40,7 +40,7 @@ export class HeroMover<T extends IHeroLocation>
|
||||
readonly tile: T,
|
||||
faceHandler: IFaceHandler<FaceDirection>
|
||||
) {
|
||||
super(faceHandler, tile.getCurrentFaceDirection());
|
||||
super(faceHandler, FaceDirection.Unknown);
|
||||
this.state = tile.state;
|
||||
}
|
||||
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
export * from './system';
|
||||
export * from './memory';
|
||||
export * from './types';
|
||||
|
||||
152
packages-user/data-common/src/save/memory.ts
Normal file
152
packages-user/data-common/src/save/memory.ts
Normal file
@ -0,0 +1,152 @@
|
||||
import { Dexie, Table } from 'dexie';
|
||||
import { isNil } from 'lodash-es';
|
||||
import {
|
||||
IGlobalTrasaction,
|
||||
ISaveRead,
|
||||
ISaveSystem,
|
||||
ISaveSystemConfig,
|
||||
ISaveableContent,
|
||||
SaveCompression
|
||||
} from './types';
|
||||
|
||||
interface MemorySaveRecord {
|
||||
readonly compression: SaveCompression;
|
||||
readonly data: Map<string, unknown>;
|
||||
}
|
||||
|
||||
class MemoryGlobalTransaction implements IGlobalTrasaction {
|
||||
readonly table!: Table<unknown, string>;
|
||||
|
||||
constructor(private readonly values: Map<string, unknown>) {}
|
||||
|
||||
async get<T>(key: string): Promise<T> {
|
||||
return this.values.get(key) as T;
|
||||
}
|
||||
|
||||
async set(key: string, value: unknown): Promise<void> {
|
||||
this.values.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
export class MemorySaveSystem implements ISaveSystem {
|
||||
db!: Dexie;
|
||||
|
||||
private readonly saves: Map<number, MemorySaveRecord> = new Map();
|
||||
private readonly values: Map<string, unknown> = new Map();
|
||||
private readonly undoStack: ISaveRead[] = [];
|
||||
private readonly redoStack: ISaveRead[] = [];
|
||||
private stackSize: number = 20;
|
||||
private autosaveLevel: SaveCompression = SaveCompression.LowCompression;
|
||||
private commonSaveLevel: SaveCompression = SaveCompression.HighCompression;
|
||||
|
||||
init(): void {}
|
||||
|
||||
config(config: Readonly<Partial<ISaveSystemConfig>>): void {
|
||||
if (!isNil(config.autosaveLevel)) {
|
||||
this.autosaveLevel = config.autosaveLevel;
|
||||
}
|
||||
if (!isNil(config.commonSaveLevel)) {
|
||||
this.commonSaveLevel = config.commonSaveLevel;
|
||||
}
|
||||
if (!isNil(config.autosaveStackSize)) {
|
||||
this.stackSize = config.autosaveStackSize;
|
||||
this.trim(this.undoStack);
|
||||
this.trim(this.redoStack);
|
||||
}
|
||||
}
|
||||
|
||||
undoAutosave(
|
||||
current: Map<string, ISaveableContent<unknown>>
|
||||
): ISaveRead | null {
|
||||
if (this.undoStack.length === 0) return null;
|
||||
this.redoStack.push(this.capture(current, this.autosaveLevel));
|
||||
this.trim(this.redoStack);
|
||||
return this.undoStack.pop()!;
|
||||
}
|
||||
|
||||
redoAutosave(
|
||||
current: Map<string, ISaveableContent<unknown>>
|
||||
): ISaveRead | null {
|
||||
if (this.redoStack.length === 0) return null;
|
||||
this.undoStack.push(this.capture(current, this.autosaveLevel));
|
||||
this.trim(this.undoStack);
|
||||
return this.redoStack.pop()!;
|
||||
}
|
||||
|
||||
getUndoStack(): ISaveRead[] {
|
||||
return this.undoStack.slice();
|
||||
}
|
||||
|
||||
getRedoStack(): ISaveRead[] {
|
||||
return this.redoStack.slice();
|
||||
}
|
||||
|
||||
autosave(state: Map<string, ISaveableContent<unknown>>): void {
|
||||
this.undoStack.push(this.capture(state, this.autosaveLevel));
|
||||
this.redoStack.length = 0;
|
||||
this.trim(this.undoStack);
|
||||
}
|
||||
|
||||
async saveAutosaveToDB(): Promise<void> {}
|
||||
|
||||
async save(
|
||||
id: number,
|
||||
state: Map<string, ISaveableContent<unknown>>
|
||||
): Promise<void> {
|
||||
this.saves.set(id, this.captureRecord(state, this.commonSaveLevel));
|
||||
await this.setGlobal('lastSlot', id);
|
||||
}
|
||||
|
||||
async load(id: number): Promise<ISaveRead | null> {
|
||||
const record = this.saves.get(id);
|
||||
if (!record) return null;
|
||||
return { compression: record.compression, data: record.data };
|
||||
}
|
||||
|
||||
async deleteSave(id: number): Promise<void> {
|
||||
this.saves.delete(id);
|
||||
}
|
||||
|
||||
async getLastSlot(): Promise<number> {
|
||||
return (await this.getGlobal<number>('lastSlot')) ?? 0;
|
||||
}
|
||||
|
||||
async getGlobal<T>(key: string): Promise<T | null> {
|
||||
return this.values.has(key) ? (this.values.get(key) as T) : null;
|
||||
}
|
||||
|
||||
async setGlobal(key: string, value: unknown): Promise<void> {
|
||||
this.values.set(key, value);
|
||||
}
|
||||
|
||||
async startGlobalTransaction<R>(
|
||||
handle: (transaction: IGlobalTrasaction) => PromiseLike<R>
|
||||
): Promise<R> {
|
||||
return handle(new MemoryGlobalTransaction(this.values));
|
||||
}
|
||||
|
||||
private capture(
|
||||
state: Map<string, ISaveableContent<unknown>>,
|
||||
compression: SaveCompression
|
||||
): ISaveRead {
|
||||
const record = this.captureRecord(state, compression);
|
||||
return { compression: record.compression, data: record.data };
|
||||
}
|
||||
|
||||
private captureRecord(
|
||||
state: Map<string, ISaveableContent<unknown>>,
|
||||
compression: SaveCompression
|
||||
): MemorySaveRecord {
|
||||
const data = new Map<string, unknown>();
|
||||
for (const [key, content] of state) {
|
||||
data.set(key, content.saveState(compression));
|
||||
}
|
||||
return { compression, data };
|
||||
}
|
||||
|
||||
private trim(stack: ISaveRead[]): void {
|
||||
if (stack.length > this.stackSize) {
|
||||
stack.splice(0, stack.length - this.stackSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,6 @@ import {
|
||||
IHeroAttr,
|
||||
IEnemyAttr,
|
||||
ISaveSystem,
|
||||
SaveSystem,
|
||||
GameEventStore,
|
||||
IGameEventStore,
|
||||
IItemStore,
|
||||
@ -33,7 +32,6 @@ import {
|
||||
FlagSystem,
|
||||
IMotaDataLoader,
|
||||
MotaDataLoader,
|
||||
loading,
|
||||
IReadonlyEnemy,
|
||||
IMapState,
|
||||
MapState
|
||||
@ -68,11 +66,9 @@ import {
|
||||
TILE_WIDTH
|
||||
} from './shared';
|
||||
import {
|
||||
ItemLegacyBridge,
|
||||
LegacyItemData,
|
||||
LegacyTileData,
|
||||
TileLegacyBridge
|
||||
} from './legacy';
|
||||
createLegacyDependencies,
|
||||
ILegacyLoadData
|
||||
} from './legacy/dependencies';
|
||||
import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader';
|
||||
import { isNil } from 'lodash-es';
|
||||
import { DirectionMapper, IDirectionMapper, logger } from '@motajs/common';
|
||||
@ -83,8 +79,8 @@ export class CoreState implements ICoreState {
|
||||
readonly saveSystem: ISaveSystem;
|
||||
readonly roleFace: IRoleFaceBinder;
|
||||
readonly faceManager: IFaceManager;
|
||||
readonly tileStore: ITileStore<LegacyTileData>;
|
||||
readonly itemStore: IItemStore<IHeroAttr, LegacyItemData>;
|
||||
readonly tileStore: ITileStore;
|
||||
readonly itemStore: IItemStore<IHeroAttr, unknown>;
|
||||
readonly mapStore: IMapStore;
|
||||
readonly eventStore: IGameEventStore;
|
||||
readonly directionMapper: IDirectionMapper;
|
||||
@ -113,10 +109,12 @@ export class CoreState implements ICoreState {
|
||||
> = new Map();
|
||||
|
||||
constructor() {
|
||||
const legacy = createLegacyDependencies();
|
||||
|
||||
//#region L0 初始化
|
||||
|
||||
// 存档系统
|
||||
this.saveSystem = new SaveSystem();
|
||||
this.saveSystem = legacy.saveSystem;
|
||||
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
|
||||
this.saveSystem.config({
|
||||
autosaveLevel: SaveCompression.LowCompression,
|
||||
@ -137,12 +135,17 @@ export class CoreState implements ICoreState {
|
||||
this.faceManager.registerById('dir8', dir8);
|
||||
|
||||
// 图块
|
||||
const tileStore = new TileStore<LegacyTileData>();
|
||||
tileStore.attachLegacyConverter(new TileLegacyBridge());
|
||||
const tileStore = new TileStore();
|
||||
if (legacy.tileConverter) {
|
||||
tileStore.attachLegacyConverter(legacy.tileConverter);
|
||||
}
|
||||
this.tileStore = tileStore;
|
||||
// 道具
|
||||
const itemStore = new ItemStore<IHeroAttr, LegacyItemData>();
|
||||
itemStore.attachLegacyConverter(new ItemLegacyBridge(this));
|
||||
const itemStore = new ItemStore();
|
||||
const itemConverter = legacy.createItemConverter(this);
|
||||
if (itemConverter) {
|
||||
itemStore.attachLegacyConverter(itemConverter);
|
||||
}
|
||||
this.itemStore = itemStore;
|
||||
// 地图
|
||||
const mapStore = new MapStore();
|
||||
@ -173,7 +176,7 @@ export class CoreState implements ICoreState {
|
||||
|
||||
// 怪物管理器
|
||||
const comparer = new MainEnemyComparer();
|
||||
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
||||
const enemyManager = new EnemyManager(legacy.enemyBridge);
|
||||
enemyManager.attachEnemyComparer(comparer);
|
||||
enemyManager.setAttributeDefaults('hp', 0);
|
||||
enemyManager.setAttributeDefaults('atk', 0);
|
||||
@ -217,20 +220,9 @@ export class CoreState implements ICoreState {
|
||||
this.addSaveableContent('@system/flags', this.flags);
|
||||
this.addSaveableContent('@system/maps', this.maps);
|
||||
this.addSaveableContent('@system/enemy', this.enemyManager);
|
||||
// 初始化存档数据库,不要动
|
||||
loading.once('coreInit', () => {
|
||||
this.saveSystem.init(`@game/${core.firstData.name}`);
|
||||
});
|
||||
|
||||
// 加载初始化,先使用兼容层实现
|
||||
loading.once('loaded', () => {
|
||||
this.initTileStore(core.maps.blocksInfo);
|
||||
this.initItemStore(core.items.items);
|
||||
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
||||
this.initMapState(
|
||||
core.floorIds,
|
||||
core.floors as Record<FloorIds, ResolvedFloor>
|
||||
);
|
||||
// 旧样板初始化只能经由内部边界进入,Node 路径不会注册加载回调
|
||||
legacy.registerLoading(data => {
|
||||
this.initLegacyData(data);
|
||||
});
|
||||
|
||||
// 勇士顶层初始化
|
||||
@ -242,11 +234,18 @@ export class CoreState implements ICoreState {
|
||||
|
||||
//#region 私有方法
|
||||
|
||||
private initLegacyData(data: ILegacyLoadData): void {
|
||||
this.initTileStore(data.tiles);
|
||||
this.initItemStore(data.items);
|
||||
this.initEnemyManager(data.enemies);
|
||||
this.initMapState(data.floors, data.maps);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化图块存储对象
|
||||
* @param data 旧样板图块定义对象
|
||||
*/
|
||||
private initTileStore(data: typeof core.maps.blocksInfo) {
|
||||
private initTileStore(data: ILegacyLoadData['tiles']) {
|
||||
const entries = Object.entries(data);
|
||||
for (const [key, block] of entries) {
|
||||
this.tileStore.fromLegacy(Number(key), block);
|
||||
@ -277,7 +276,7 @@ export class CoreState implements ICoreState {
|
||||
* 初始化道具存储对象
|
||||
* @param data 旧样板道具定义对象
|
||||
*/
|
||||
private initItemStore(data: typeof core.items.items) {
|
||||
private initItemStore(data: ILegacyLoadData['items']) {
|
||||
const entries = Object.entries(data);
|
||||
for (const [id, legacy] of entries) {
|
||||
const num = this.tileStore.idToNumber(id);
|
||||
@ -293,7 +292,7 @@ export class CoreState implements ICoreState {
|
||||
* 初始化怪物管理器对象
|
||||
* @param data 旧样板怪物存储对象
|
||||
*/
|
||||
private initEnemyManager(data: Record<EnemyIds, Enemy>) {
|
||||
private initEnemyManager(data: ILegacyLoadData['enemies']) {
|
||||
const manager = this.enemyManager;
|
||||
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
|
||||
for (const [id, enemy] of Object.entries(structuredClone(data))) {
|
||||
@ -326,8 +325,8 @@ export class CoreState implements ICoreState {
|
||||
}
|
||||
|
||||
private initMapState(
|
||||
floors: FloorIds[],
|
||||
data: Record<FloorIds, ResolvedFloor>
|
||||
floors: ILegacyLoadData['floors'],
|
||||
data: ILegacyLoadData['maps']
|
||||
) {
|
||||
const reference = new Map<string, Map<number, Uint32Array>>();
|
||||
for (const id of floors) {
|
||||
@ -436,3 +435,7 @@ export class CoreState implements ICoreState {
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
export function createCoreState(): CoreState {
|
||||
return new CoreState();
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
} from '@user/data-system';
|
||||
import { IEnemyAttr, IHeroAttr } from '@user/data-common';
|
||||
import { IVampireValue } from './special';
|
||||
import { state } from '../ins';
|
||||
import { logger } from '@motajs/common';
|
||||
|
||||
export class MainDamageCalculator implements IDamageCalculator<
|
||||
@ -30,7 +29,10 @@ export class MainDamageCalculator implements IDamageCalculator<
|
||||
let monHp = enemy.getAttribute('hp');
|
||||
|
||||
// 无敌
|
||||
if (enemy.hasSpecial(20) && core.itemCount('cross') < 1) {
|
||||
if (
|
||||
enemy.hasSpecial(20) &&
|
||||
(handler.state.hero.items.getItemState('cross')?.count ?? 0) < 1
|
||||
) {
|
||||
return { damage: Infinity, turn: 0 };
|
||||
}
|
||||
|
||||
@ -147,7 +149,7 @@ export class MainDamageCalculator implements IDamageCalculator<
|
||||
|
||||
// 仇恨,无法被魔防减伤
|
||||
if (enemy.hasSpecial(17)) {
|
||||
damage += state.flags.getFieldValueDefaults('hatred', 0);
|
||||
damage += handler.state.flags.getFieldValueDefaults('hatred', 0);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
76
packages-user/data-state/src/legacy/dependencies.ts
Normal file
76
packages-user/data-state/src/legacy/dependencies.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import {
|
||||
IItemLegacyConverter,
|
||||
IHeroAttr,
|
||||
IEnemyAttr,
|
||||
ISaveSystem,
|
||||
ITileLegacyConverter,
|
||||
MemorySaveSystem,
|
||||
SaveSystem
|
||||
} from '@user/data-common';
|
||||
import { IEnemyLegacyBridge, loading } from '@user/data-base';
|
||||
import { IStateSystem } from '@user/data-system';
|
||||
import { EnemyLegacyBridge } from '../enemy/legacy';
|
||||
import { ItemLegacyBridge, LegacyItemData } from './item';
|
||||
import { LegacyTileData, TileLegacyBridge } from './tile';
|
||||
|
||||
export interface ILegacyLoadData {
|
||||
readonly tiles: typeof core.maps.blocksInfo;
|
||||
readonly items: typeof core.items.items;
|
||||
readonly enemies: Record<EnemyIds, Enemy>;
|
||||
readonly floors: FloorIds[];
|
||||
readonly maps: Record<FloorIds, ResolvedFloor>;
|
||||
}
|
||||
|
||||
export interface ILegacyDependencies {
|
||||
readonly saveSystem: ISaveSystem;
|
||||
readonly tileConverter: ITileLegacyConverter<LegacyTileData> | null;
|
||||
readonly enemyBridge: IEnemyLegacyBridge<IEnemyAttr>;
|
||||
createItemConverter(
|
||||
state: IStateSystem
|
||||
): IItemLegacyConverter<IHeroAttr, LegacyItemData> | null;
|
||||
registerLoading(onLoaded: (data: ILegacyLoadData) => void): void;
|
||||
}
|
||||
|
||||
function hasLegacyHost(): boolean {
|
||||
return (
|
||||
typeof main !== 'undefined' &&
|
||||
typeof core !== 'undefined' &&
|
||||
typeof window !== 'undefined' &&
|
||||
typeof document !== 'undefined' &&
|
||||
typeof indexedDB !== 'undefined'
|
||||
);
|
||||
}
|
||||
|
||||
export function createLegacyDependencies(): ILegacyDependencies {
|
||||
if (!hasLegacyHost()) {
|
||||
return {
|
||||
saveSystem: new MemorySaveSystem(),
|
||||
tileConverter: null,
|
||||
enemyBridge: new EnemyLegacyBridge(),
|
||||
createItemConverter: () => null,
|
||||
registerLoading: () => {}
|
||||
};
|
||||
}
|
||||
|
||||
const saveSystem = new SaveSystem();
|
||||
return {
|
||||
saveSystem,
|
||||
tileConverter: new TileLegacyBridge(),
|
||||
enemyBridge: new EnemyLegacyBridge(),
|
||||
createItemConverter: state => new ItemLegacyBridge(state),
|
||||
registerLoading: onLoaded => {
|
||||
loading.once('coreInit', () => {
|
||||
saveSystem.init(`@game/${core.firstData.name}`);
|
||||
});
|
||||
loading.once('loaded', () => {
|
||||
onLoaded({
|
||||
tiles: core.maps.blocksInfo,
|
||||
items: core.items.items,
|
||||
enemies: enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80,
|
||||
floors: core.floorIds,
|
||||
maps: core.floors as Record<FloorIds, ResolvedFloor>
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -3,9 +3,13 @@ import { backDir, toDir } from './utils';
|
||||
import { loading } from '@user/data-base';
|
||||
import type { HeroKeyMover } from '@user/client-modules';
|
||||
import { sleep } from '@motajs/common';
|
||||
import { state } from '..';
|
||||
import { fromDirectionString } from '@user/data-common';
|
||||
|
||||
function getDataStateMover() {
|
||||
if (typeof Mota === 'undefined') return null;
|
||||
return Mota.require('@user/data-state').state.hero.location.mover;
|
||||
}
|
||||
|
||||
// todo: 转身功能
|
||||
|
||||
interface MoveStepDir {
|
||||
@ -288,7 +292,7 @@ export class HeroMover extends ObjectMoverBase {
|
||||
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
||||
this.beforeMoveSpeed = this.moveSpeed;
|
||||
if (!core.isReplaying() || core.status.replay.speed <= 12) {
|
||||
state.hero.mover.startMove();
|
||||
getDataStateMover()?.start();
|
||||
}
|
||||
// 这里要检查前面那一格能不能走,不能走则不触发平滑视角,以避免撞墙上视角卡住
|
||||
if (!this.ignoreTerrain) {
|
||||
@ -310,7 +314,6 @@ export class HeroMover extends ObjectMoverBase {
|
||||
protected async onMoveEnd(controller: IMoveController): Promise<void> {
|
||||
this.moveSpeed = this.beforeMoveSpeed;
|
||||
this.onSetMoveSpeed(this.moveSpeed, controller);
|
||||
await state.hero.mover.endMove();
|
||||
// viewport.sync('endMove');
|
||||
core.clearContinueAutomaticRoute();
|
||||
core.stopAutomaticRoute();
|
||||
@ -442,22 +445,17 @@ export class HeroMover extends ObjectMoverBase {
|
||||
const replaying = core.isReplaying();
|
||||
if (replaying) {
|
||||
if (core.status.replay.speed > 12) {
|
||||
await state.hero.mover.endMove();
|
||||
await sleep(speed);
|
||||
state.hero.mover.setPosition(x, y);
|
||||
getDataStateMover()?.setPos(x, y);
|
||||
} else {
|
||||
state.hero.mover.startMove();
|
||||
await state.hero.mover.move(
|
||||
fromDirectionString(moveDir),
|
||||
this.moveSpeed / core.status.replay.speed
|
||||
);
|
||||
const mover = getDataStateMover();
|
||||
mover?.step(fromDirectionString(moveDir));
|
||||
await mover?.start()?.onEnd;
|
||||
}
|
||||
} else {
|
||||
state.hero.mover.startMove();
|
||||
await state.hero.mover.move(
|
||||
fromDirectionString(moveDir),
|
||||
this.moveSpeed
|
||||
);
|
||||
const mover = getDataStateMover();
|
||||
mover?.step(fromDirectionString(moveDir));
|
||||
await mover?.start()?.onEnd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,8 +21,13 @@ interface LoggerCatchReturns<T> {
|
||||
info: LoggerCatchInfo[];
|
||||
}
|
||||
|
||||
let logTip: HTMLSpanElement;
|
||||
if (!main.replayChecking) {
|
||||
let logTip: HTMLSpanElement | undefined;
|
||||
const hasBrowserHost =
|
||||
typeof document !== 'undefined' && typeof main !== 'undefined';
|
||||
const isReplayChecking = () =>
|
||||
typeof main !== 'undefined' && main.replayChecking;
|
||||
|
||||
if (hasBrowserHost && !isReplayChecking()) {
|
||||
const tip = document.createElement('span');
|
||||
logTip = tip;
|
||||
tip.style.position = 'fixed';
|
||||
@ -40,7 +45,7 @@ if (!main.replayChecking) {
|
||||
}
|
||||
|
||||
const hideTipText = debounce(() => {
|
||||
if (main.replayChecking) return;
|
||||
if (isReplayChecking() || !logTip) return;
|
||||
logTip.style.display = 'none';
|
||||
}, 5000);
|
||||
|
||||
@ -125,14 +130,16 @@ export class Logger {
|
||||
});
|
||||
}
|
||||
if (this.level <= LogLevel.ERROR && this.enabled) {
|
||||
if (!main.replayChecking) {
|
||||
if (!isReplayChecking() && logTip) {
|
||||
logTip.style.color = 'lightcoral';
|
||||
logTip.style.display = 'block';
|
||||
logTip.textContent = `Error thrown, please check in console.`;
|
||||
hideTipText();
|
||||
}
|
||||
const n = Math.floor(code / 50) + 1;
|
||||
const url = `${location.origin}/_docs/logger/error/error${n}.html#error-code-${code}`;
|
||||
const origin =
|
||||
typeof location === 'undefined' ? '' : location.origin;
|
||||
const url = `${origin}/_docs/logger/error/error${n}.html#error-code-${code}`;
|
||||
console.error(`[ERROR Code ${code}] ${text} See ${url}`);
|
||||
}
|
||||
}
|
||||
@ -158,14 +165,16 @@ export class Logger {
|
||||
});
|
||||
}
|
||||
if (this.level <= LogLevel.WARNING && this.enabled) {
|
||||
if (!main.replayChecking) {
|
||||
if (!isReplayChecking() && logTip) {
|
||||
logTip.style.color = 'gold';
|
||||
logTip.style.display = 'block';
|
||||
logTip.textContent = `Warning thrown, please check in console.`;
|
||||
hideTipText();
|
||||
}
|
||||
const n = Math.floor(code / 50) + 1;
|
||||
const url = `${location.origin}/_docs/logger/warn/warn${n}.html#warn-code-${code}`;
|
||||
const origin =
|
||||
typeof location === 'undefined' ? '' : location.origin;
|
||||
const url = `${origin}/_docs/logger/warn/warn${n}.html#warn-code-${code}`;
|
||||
console.warn(`[WARNING Code ${code}] ${text} See ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user