Skip to content

Commit

Permalink
feat: Simple start to client hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
tyler27 committed Jan 27, 2025
1 parent 9323fb8 commit 2686e82
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 65 deletions.
5 changes: 3 additions & 2 deletions src/js/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ export abstract class Client extends GameShell {
static oplogic8: number = 0;
static oplogic9: number = 0;

public onLoginScreenLoaded: () => void = (): void => {};
public onLoginScreenLoaded: () => Promise<void> = async (): Promise<void> => {};
public onWorldLoaded: () => Promise<void> = async (): Promise<void> => {};
public onTick: () => Promise<void> = async (): Promise<void> => {};
public onClientTick: () => Promise<void> = async (): Promise<void> => {};
public onUpdateStat: (stat: number, xp: number, level: number) => void = (): void => {};
public onLogout: () => Promise<void> = async (): Promise<void> => {};

static setHighMemory = (): void => {
Expand Down
5 changes: 3 additions & 2 deletions src/js/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export class Game extends Client {
World3D.init(512, 334, 500, 800, distance);
WordFilter.unpack(wordenc);
this.initializeLevelExperience();
this?.onLoginScreenLoaded();
await this?.onLoginScreenLoaded();
// try {
// Renderer.renderer = await RendererWebGPU.init(canvasContainer, this.width, this.height);
// } catch (e) {
Expand All @@ -347,7 +347,7 @@ export class Game extends Client {
return;
}
this.loopCycle++;
await this.onTick();
await this.onClientTick();
if (this.ingame) {
await this.updateGame();
} else {
Expand Down Expand Up @@ -6006,6 +6006,7 @@ export class Game extends Client {
this.skillBaseLevel[stat] = i + 2;
}
}
this.onUpdateStat(stat, xp, level);
this.packetType = -1;
return true;
}
Expand Down
57 changes: 31 additions & 26 deletions src/js/jagex2/renderer/webgpu/RendererWebGPU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ interface QueuedRenderPixMapCommand {

export class RendererWebGPU extends Renderer {
device: GPUDevice;
context: GPUCanvasContext;
context: GPUCanvasContext | RenderingContext;

defaultSampler!: GPUSampler;
samplerTextureGroupLayout!: GPUBindGroupLayout;
Expand Down Expand Up @@ -129,22 +129,23 @@ export class RendererWebGPU extends Renderer {
canvas.style.height = '100%';
container.appendChild(canvas);

const context: GPUCanvasContext | null = canvas.getContext('webgpu');
const context: GPUCanvasContext | RenderingContext | null = canvas.getContext('webgpu');
if (!context) {
canvas.remove();
throw new Error('Could not create WebGPU context');
}
const presentationFormat: GPUTextureFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device,
format: presentationFormat,
alphaMode: 'opaque'
});

if (context instanceof GPUCanvasContext && 'configure' in context) {
context.configure({
device,
format: presentationFormat,
alphaMode: 'opaque'
});
}
return new RendererWebGPU(canvas, device, context);
}

constructor(canvas: HTMLCanvasElement, device: GPUDevice, context: GPUCanvasContext) {
constructor(canvas: HTMLCanvasElement, device: GPUDevice, context: GPUCanvasContext | RenderingContext) {
super(canvas);
this.device = device;
this.context = context;
Expand Down Expand Up @@ -413,22 +414,24 @@ export class RendererWebGPU extends Renderer {
]
});

this.frameRenderPassDescriptor = {
label: 'frame render pass',
colorAttachments: [
{
view: this.context.getCurrentTexture().createView(),
clearValue: {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0
},
loadOp: 'load',
storeOp: 'store'
}
]
};
if ('getCurrentTexture' in this.context) {
this.frameRenderPassDescriptor = {
label: 'frame render pass',
colorAttachments: [
{
view: this.context.getCurrentTexture().createView(),
clearValue: {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0
},
loadOp: 'load',
storeOp: 'store'
}
]
};
}
this.renderPassDescriptor = {
label: 'main render pass',
colorAttachments: [
Expand Down Expand Up @@ -476,7 +479,9 @@ export class RendererWebGPU extends Renderer {
this.mainPass.end();

for (const colorAttachment of this.frameRenderPassDescriptor.colorAttachments) {
colorAttachment!.view = this.context.getCurrentTexture().createView();
if ('getCurrentTexture' in this.context) {
colorAttachment!.view = this.context.getCurrentTexture().createView();
}
}

const framePass: GPURenderPassEncoder = this.encoder.beginRenderPass(this.frameRenderPassDescriptor);
Expand Down
82 changes: 47 additions & 35 deletions src/js/lostlite/LostLite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Game} from '../game';
import {Renderer} from '../jagex2/renderer/Renderer';
import {RendererWebGPU} from '../jagex2/renderer/webgpu/RendererWebGPU';
import {canvasContainer} from '../jagex2/graphics/Canvas';
import Plugins from '../plugin/Plugins';
import Plugins, {usePluginRegistry, PluginRegistryType} from '../plugin/Plugins';

declare global {
interface Window {
Expand Down Expand Up @@ -258,7 +258,7 @@ class UIManager {
const lootTrackerHeader = document.querySelector('.section-header[data-section="loot"]');
lootTrackerSection?.classList.remove('expanded');
lootTrackerHeader?.classList.remove('active');

// Update visibility of content wrapper
const contentWrapper = document.querySelector('.section-content-wrapper');
const listContainer = document.querySelector('.list-container');
Expand Down Expand Up @@ -286,7 +286,7 @@ class UIManager {
const xpTrackerHeader = document.querySelector('.section-header[data-section="xp"]');
xpTrackerSection?.classList.remove('expanded');
xpTrackerHeader?.classList.remove('active');

// Update visibility of content wrapper
const contentWrapper = document.querySelector('.section-content-wrapper');
const listContainer = document.querySelector('.list-container');
Expand Down Expand Up @@ -339,11 +339,7 @@ class UIManager {
const pluginItem = this.nodragToggle.closest('.plugin-item');
pluginItem?.classList.toggle('active', this.nodragToggle.checked);
localStorage.setItem('nodragEnabled', this.nodragToggle.checked.toString());

if (this.game.ingame) {
this.game.chatTyped = '::nodrag';
this.game.onkeydown(new KeyboardEvent('keydown', {key: 'Enter', code: 'Enter'}));
}
this.sendCommand('nodrag');
});

// Tile markers toggle
Expand Down Expand Up @@ -411,6 +407,14 @@ class UIManager {
}
}

private sendCommand(command: string): void {
if (!this.game.ingame) {
return;
}
this.game.chatTyped = `::${command}`;
this.game.onkeydown(new KeyboardEvent('keydown', {key: 'Enter', code: 'Enter'}));
}

private async onGpuChange(): Promise<void> {
const pluginItem = this.gpuToggle.closest('.plugin-item');
pluginItem?.classList.toggle('active', this.gpuToggle.checked);
Expand Down Expand Up @@ -488,7 +492,7 @@ class UIManager {
const lootTrackerHeader = document.querySelector('.section-header[data-section="loot"]');
lootTrackerSection?.classList.remove('expanded');
lootTrackerHeader?.classList.remove('active');

// Update visibility of content wrapper
const contentWrapper = document.querySelector('.section-content-wrapper');
const listContainer = document.querySelector('.list-container');
Expand Down Expand Up @@ -517,7 +521,7 @@ class UIManager {
const xpTrackerHeader = document.querySelector('.section-header[data-section="xp"]');
xpTrackerSection?.classList.remove('expanded');
xpTrackerHeader?.classList.remove('active');

// Update visibility of content wrapper
const contentWrapper = document.querySelector('.section-content-wrapper');
const listContainer = document.querySelector('.list-container');
Expand Down Expand Up @@ -579,7 +583,7 @@ class UIManager {
// Close all other sections first
const allSectionContents = document.querySelectorAll('.section-content');
const allSectionHeaders = document.querySelectorAll('.section-header');
allSectionContents.forEach((otherContent) => {
allSectionContents.forEach(otherContent => {
if (otherContent !== content) {
otherContent.classList.remove('expanded');
const otherSectionId = otherContent.getAttribute('data-section');
Expand All @@ -588,7 +592,7 @@ class UIManager {
}
}
});
allSectionHeaders.forEach((otherHeader) => {
allSectionHeaders.forEach(otherHeader => {
if (otherHeader !== header) {
otherHeader.classList.remove('active');
}
Expand Down Expand Up @@ -618,7 +622,7 @@ class UIManager {
// Close all other sections first
const allSectionContents = document.querySelectorAll('.section-content');
const allSectionHeaders = document.querySelectorAll('.section-header');
allSectionContents.forEach((otherContent) => {
allSectionContents.forEach(otherContent => {
if (otherContent !== content) {
otherContent.classList.remove('expanded');
const otherSectionId = otherContent.getAttribute('data-section');
Expand All @@ -627,7 +631,7 @@ class UIManager {
}
}
});
allSectionHeaders.forEach((otherHeader) => {
allSectionHeaders.forEach(otherHeader => {
if (otherHeader !== header) {
otherHeader.classList.remove('active');
}
Expand Down Expand Up @@ -677,13 +681,14 @@ class UIManager {

export const LostLite = async (): Promise<void> => {
console.log(`Lost Lite Launching w/ user client - release #${Client.clientversion}`);

// Initialize loading UI
const loadingOverlay = document.querySelector('.loading-overlay') as HTMLElement;
const loadingProgressBar = document.getElementById('loading-progress-bar') as HTMLElement;
const loadingText = document.querySelector('.loading-text') as HTMLElement;
let progress = 0;

const { loadedPlugins, loadPlugins }: PluginRegistryType = usePluginRegistry();

const updateLoadingProgress = (text: string, newProgress: number) => {
progress = newProgress;
loadingProgressBar.style.width = `${progress}%`;
Expand All @@ -694,21 +699,22 @@ export const LostLite = async (): Promise<void> => {
try {
// Setup configuration (33%)
updateLoadingProgress('Setting up configuration...', 0);
await setupConfiguration();
await setupConfiguration();
updateLoadingProgress('Configuration loaded', 33);
console.log('Configuration has been setup. Launching game.');
console.log('Configuration has been setup. Launching game.');

// Initialize game (66%)
updateLoadingProgress('Initializing game engine...', 33);
const game: Game = new Game();
const game: Game = new Game();
updateLoadingProgress('Game engine initialized', 66);

let uiManager: UIManager | null = null;
let uiManager: UIManager | null = null;

// Setup login screen (100%)
game.onLoginScreenLoaded = (): void => {
game.onLoginScreenLoaded = async (): Promise<void> => {
updateLoadingProgress('Loading interface...', 66);
uiManager = new UIManager(game);
uiManager = new UIManager(game);
updateLoadingProgress('Loading plugins...', 75);
await loadPlugins(game);
updateLoadingProgress('LostLite Loaded!', 100);

// Hide loading overlay
Expand All @@ -719,21 +725,27 @@ export const LostLite = async (): Promise<void> => {
};

// World loading doesn't affect loading screen since it happens after login
game.onWorldLoaded = async (): Promise<void> => {
await uiManager?.initializeToggles2();
uiManager?.test();
};
game.onWorldLoaded = async (): Promise<void> => {
await uiManager?.initializeToggles2();
uiManager?.test();
};

game.onTick = async (): Promise<void> => {
const polled: (() => Promise<void>) | undefined = uiManager?.commands?.pop();
if (polled) {
await polled();
}
};
game.onClientTick = async (): Promise<void> => {
const polled: (() => Promise<void>) | undefined = uiManager?.commands?.pop();
if (polled) {
await polled();
}

game.onLogout = async (): Promise<void> => {
uiManager?.onLogout();
};
loadedPlugins.forEach((plugin): void => plugin.onClientTick())
};

game.onLogout = async (): Promise<void> => {
uiManager?.onLogout();
};

game.onUpdateStat = (stat: number, xp: number, level: number): void => {
loadedPlugins.forEach((plugin): void => plugin.onUpdateStat(stat, xp, level))
}

await game.run();
console.log('Finished.');
Expand Down
15 changes: 15 additions & 0 deletions src/js/plugin/LostLitePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Client} from '../client';

export abstract class LostLitePlugin implements ClientHook {
private client: Client;

public constructor(client: Client) {
this.client = client;
}

onClientTick(): void {}
onUpdateStat(stat: number, xp: number, level: number): void {}

abstract getName(): string;

}
23 changes: 23 additions & 0 deletions src/js/plugin/Plugins.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {LostLitePlugin} from './LostLitePlugin';
import {DebugPlugin} from './plugins/DebugPlugin';
import {Client} from '../client';

export default class Plugins {
static DRAW_DISTANCE: number = 50; // default 25
static ZOOM: number = 3; // default 3
Expand All @@ -12,3 +16,22 @@ export default class Plugins {
static LOOT_TRACKER: boolean = false; // default false
static XP_TRACKER: boolean = false; // default false
}

export type PluginRegistryType = {
loadPlugins: (client: Client) => Promise<Map<string, LostLitePlugin>>;
loadedPlugins: Map<string, LostLitePlugin>
}

export const usePluginRegistry = (): PluginRegistryType => {
const loadedPlugins: Map<string, LostLitePlugin> = new Map<string, LostLitePlugin>();

const loadPlugins = async (client: Client): Promise<Map<string, LostLitePlugin>> => {
loadedPlugins.set('debug_plugin', new DebugPlugin(client));
return Promise.resolve(loadedPlugins);
}

return {
loadPlugins,
loadedPlugins
}
}
4 changes: 4 additions & 0 deletions src/js/plugin/hooks/ClientHook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface ClientHook {
onClientTick(): void;
onUpdateStat(stat: number, xp: number, level: number): void;
}
11 changes: 11 additions & 0 deletions src/js/plugin/plugins/DebugPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {LostLitePlugin} from '../LostLitePlugin';

export class DebugPlugin extends LostLitePlugin {
onUpdateStat(stat: number, xp: number, level: number): void {
console.log(`Stat updated: Stat=${stat} XP=${xp} Level=${level}`)
}

getName(): string {
return 'DebugPlugin';
}
}

0 comments on commit 2686e82

Please sign in to comment.