Skip to content

Commit 2f4cd01

Browse files
committed
feat: chat memory and squad command demo
1 parent b72b761 commit 2f4cd01

File tree

6 files changed

+81
-58
lines changed

6 files changed

+81
-58
lines changed

src/App.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {injectAPI} from "@/memory/wasmExtraction.ts";
1414
import {petalCountLoggerInit} from "@/petalCountLogger.ts";
1515
import Api from "@/Api.vue";
1616
import '@/commands/builtin';
17+
import {gameChatUtilityInit} from "@/gameChat/gameChatUtility.ts";
1718
const { t } = useI18n();
1819
1920
const webSocketServerAddress = import.meta.env.VITE_SERVER;
@@ -23,8 +24,9 @@ switch (import.meta.env.VITE_ENCRYPTION) {
2324
webSocketService.applyEncryptor(new NoneEncryptor());
2425
break;
2526
}
26-
injectAPI().then(({ inventory }) => {
27+
injectAPI().then(({ inventory, chatBase, chatOverflow }) => {
2728
petalCountLoggerInit(inventory);
29+
gameChatUtilityInit(chatBase, chatOverflow);
2830
});
2931
patchWebsocket();
3032
webSocketService.subscribeOpen(() => {

src/commands/builtin/asquad.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {dispatcher} from "@/commands/dispatcher.ts";
2+
import {literal} from "@jsprismarine/brigadier";
3+
import {addChatMessage} from "@/gameChat/gameChatUtility.ts";
4+
5+
dispatcher.register(
6+
literal('aaccept').executes(
7+
async () => {
8+
addChatMessage([
9+
{
10+
text: 'Joining squad 3v7f7v',
11+
r: 163,
12+
g: 196,
13+
b: 243
14+
}
15+
]);
16+
return '/squad-join 3v7f7v';
17+
}
18+
)
19+
)

src/commands/builtin/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
import './ahelp.ts';
1+
import './ahelp.ts';
2+
import './asquad.ts';

src/commands/dispatcher.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {CommandDispatcher} from "@jsprismarine/brigadier";
22

33
export const dispatcher = new CommandDispatcher();
44

5-
document.addEventListener("keydown", (e) => {
5+
document.addEventListener("keydown", async (e) => {
66
if (e.key !== "Enter") {
77
return;
88
}
@@ -17,13 +17,16 @@ document.addEventListener("keydown", (e) => {
1717
}
1818

1919
const value = target.value.trim();
20-
console.log(value);
2120
if (!value.startsWith("/")) {
2221
return;
2322
}
2423

2524
if (dispatcher.parse(value.slice(1), null)) {
26-
dispatcher.execute(dispatcher.parse(value.slice(1), null));
27-
target.value = "";
25+
const result = await (dispatcher.execute(dispatcher.parse(value.slice(1), null))[0]);
26+
if (typeof result === 'string') {
27+
target.value = result;
28+
} else {
29+
target.value = '';
30+
}
2831
}
2932
}, true);

src/gameChat/gameChatUtility.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// TODO refactor this file
2-
// TODO find these two value in wasm
3-
const base = 19286288;
4-
const overflow = 3563868;
1+
let base!:number;
2+
let overflow!:number;
53

64
function writeString(str: string) {
75
if (!window.Module.HEAPU8) {
@@ -94,4 +92,9 @@ export function addChatMessage(segments: {text: string, r: number, g: number, b:
9492
}
9593

9694
window.Module.HEAP32[(base - 8) / 4] = count + 1;
95+
}
96+
97+
export function gameChatUtilityInit(chatBase: number, chatOverflow: number) {
98+
base = chatBase;
99+
overflow = chatOverflow;
97100
}

src/memory/wasmExtraction.ts

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,54 @@
1-
import {matches, readLeb128} from "@/memory/utils.ts";
2-
3-
function parseInventory(bytes: Uint8Array): number {
4-
const patternPrefix = [0x41, 0x01, 0x3a, 0x00, 0x00, 0x41];
5-
const patternSuffix = [0x41, 0x05, 0x36, 0x02, 0x00];
6-
1+
import { matches, readLeb128 } from "@/memory/utils.ts";
2+
3+
function parsePattern(
4+
bytes: Uint8Array,
5+
prefix: number[],
6+
suffix: number[],
7+
transform: (value: number) => number = v => v
8+
): number {
79
for (let i = 0; i < bytes.length; i++) {
8-
if (!matches(bytes, i, patternPrefix)) continue;
10+
if (!matches(bytes, i, prefix)) continue;
911

10-
const addrStart = i + patternPrefix.length;
11-
const { value: addr, nextIndex } = readLeb128(bytes, addrStart);
12+
const addrStart = i + prefix.length;
13+
const { value, nextIndex } = readLeb128(bytes, addrStart);
1214

13-
if (!matches(bytes, nextIndex, patternSuffix)) continue;
15+
if (!matches(bytes, nextIndex, suffix)) continue;
1416

15-
return addr >> 2;
17+
return transform(value);
1618
}
1719

18-
throw new Error('Could not find the magic value for "inventory"');
20+
throw new Error(`Could not find pattern.`);
1921
}
2022

21-
async function streamToUint8Array(stream: ReadableStream<Uint8Array>): Promise<Uint8Array> {
22-
const reader = stream.getReader();
23-
const chunks: Uint8Array[] = [];
24-
25-
while (true) {
26-
const { value, done } = await reader.read();
27-
if (done) break;
28-
if (value) chunks.push(value);
29-
}
30-
31-
// Calculate total length
32-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
33-
34-
// Concatenate all chunks
35-
const result = new Uint8Array(totalLength);
36-
let offset = 0;
37-
for (const chunk of chunks) {
38-
result.set(chunk, offset);
39-
offset += chunk.length;
40-
}
41-
42-
return result;
23+
async function fetchWasmBytes(): Promise<Uint8Array> {
24+
const response = await fetch(`https://static.florr.io/${window.versionHash}/client.wasm`);
25+
const buffer = await response.arrayBuffer();
26+
return new Uint8Array(buffer);
4327
}
4428

45-
4629
export async function injectAPI(): Promise<{
47-
inventory: number
48-
}>{
49-
return new Promise((resolve => {
50-
fetch(`https://static.florr.io/${window.versionHash}/client.wasm`)
51-
.then(response => response.body)
52-
.then(async stream => {
53-
const bytes = await streamToUint8Array(stream!);
54-
resolve({
55-
inventory: parseInventory(bytes)
56-
});
57-
});
58-
}));
59-
}
30+
inventory: number;
31+
chatBase: number;
32+
chatOverflow: number;
33+
}> {
34+
const bytes = await fetchWasmBytes();
35+
36+
return {
37+
inventory: parsePattern(
38+
bytes,
39+
[0x41, 0x01, 0x3a, 0x00, 0x00, 0x41],
40+
[0x41, 0x05, 0x36, 0x02, 0x00],
41+
value => value >> 2
42+
),
43+
chatBase: parsePattern(
44+
bytes,
45+
[0x41, 0x98, 0x03, 0x6C, 0x22, 0x00, 0x41],
46+
[0x6A, 0x41, 0x00, 0x41, 0x98, 0x03]
47+
),
48+
chatOverflow: parsePattern(
49+
bytes,
50+
[0x22, 0x05, 0x41],
51+
[0x36, 0x02, 0x00, 0x20, 0x02, 0x41, 0x08, 0x6A]
52+
)
53+
};
54+
}

0 commit comments

Comments
 (0)