Skip to content

Commit 1c45fc4

Browse files
committed
feat: update source files
1 parent 0b8bf07 commit 1c45fc4

17 files changed

+1040
-69
lines changed

.npmignore

+2
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ yarn.lock
1010
*.node
1111
.yarn
1212
__test__
13+
src
14+
lib
1315
renovate.json

esm.mjs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export * from "./structures/Client";
2+
export * from "./structures/Peer";
3+
export * from "./packets/TankPacket";
4+
export * from "./packets/TextPacket";
5+
export * from "./packets/Variant";
6+
export * from "./utils/ItemsDat";
7+
export * from "./Constants";
8+
9+
const Client = (await import("./dist/structures/Client.js")).default;
10+
const Peer = (await import("./dist/structures/Peer.js")).default;
11+
const TankPacket = (await import("./dist/packets/TankPacket.js")).default;
12+
const TextPacket = (await import("./dist/packets/TextPacket.js")).default;
13+
const Variant = (await import("./dist/packets/Variant.js")).default;
14+
const ItemsDat = (await import("./dist/utils/ItemsDat.js")).default;
15+
16+
export * from "./dist/Constants.js";
17+
18+
export { Client, Peer, TankPacket, TextPacket, Variant, ItemsDat };

lib/Constants.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Types for each Argument.
3+
*/
4+
export enum VariantTypes {
5+
NONE,
6+
FLOAT_1,
7+
STRING,
8+
FLOAT_2,
9+
FLOAT_3,
10+
UNSIGNED_INT,
11+
SIGNED_INT = 0x9
12+
}
13+
14+
/**
15+
* Growtopia Packet Types
16+
*/
17+
export enum PacketTypes {
18+
UNK,
19+
HELLO,
20+
STR,
21+
ACTION,
22+
TANK,
23+
ERROR,
24+
TRACK,
25+
CLIENT_LOG_REQ,
26+
CLIENT_LOG_RES
27+
}

lib/index.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
export * from "./structures/ItemsDat";
1+
export * from "./structures/Client";
2+
export * from "./structures/Peer";
3+
export * from "./packets/TankPacket";
4+
export * from "./packets/TextPacket";
5+
export * from "./packets/Variant";
6+
export * from "./utils/ItemsDat";
7+
export * from "./Constants";
8+
9+
export * from "../native";
10+
export type * from "../types";

lib/packets/TankPacket.ts

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import type { Tank } from "../../types";
2+
3+
const TANK_HEADER_SIZE = 60;
4+
5+
/**
6+
* Represent a TankPacket.
7+
*/
8+
export class TankPacket {
9+
/**
10+
* Creates a new instance of the TankPacket class.
11+
* @param data The tankpacket header and data.
12+
*/
13+
constructor(public data?: Tank) {}
14+
15+
/**
16+
* Creates a new instance of the TankPacket class.
17+
* @param data TankPacket header and data.
18+
*/
19+
public static from(data: Tank) {
20+
return new TankPacket(data);
21+
}
22+
23+
/**
24+
* Converts a buffer to a tank packet.
25+
* @param buf The buffer to convert.
26+
*/
27+
public static fromBuffer(buf: Buffer) {
28+
const data: Tank = {
29+
packetType: buf.readUint32LE(0),
30+
type: buf.readUInt8(4),
31+
punchID: buf.readUInt8(5),
32+
buildRange: buf.readUInt8(6),
33+
punchRange: buf.readUInt8(7),
34+
netID: buf.readInt32LE(8),
35+
targetNetID: buf.readInt32LE(12),
36+
state: buf.readUInt32LE(16),
37+
info: buf.readInt32LE(24),
38+
xPos: buf.readFloatLE(28),
39+
yPos: buf.readFloatLE(32),
40+
xSpeed: buf.readFloatLE(36),
41+
ySpeed: buf.readFloatLE(40),
42+
xPunch: buf.readInt32LE(48),
43+
yPunch: buf.readInt32LE(52)
44+
};
45+
46+
const dataLength = buf.readUInt32LE(56);
47+
if (dataLength > 0) data.data = () => buf.slice(60, 60 + dataLength);
48+
49+
return new TankPacket(data);
50+
}
51+
52+
/**
53+
* Converts the TankPacket class to a Buffer
54+
*/
55+
public parse() {
56+
if (!this.data) return;
57+
let buf = Buffer.alloc(TANK_HEADER_SIZE);
58+
59+
buf.writeUInt32LE(0x4); // packetType
60+
buf.writeUint8(this.data.type ?? 0, 4);
61+
buf.writeUint8(this.data.punchID ?? 0, 5);
62+
buf.writeUint8(this.data.buildRange ?? 0, 6);
63+
buf.writeUint8(this.data.punchRange ?? 0, 7);
64+
buf.writeInt32LE(this.data.netID ?? 0, 8);
65+
buf.writeInt32LE(this.data.targetNetID ?? 0, 12);
66+
buf.writeUInt32LE(this.data.state ?? 0x8, 16);
67+
buf.writeInt32LE(this.data.info ?? 0, 24);
68+
buf.writeFloatLE(this.data.xPos ?? 0, 28);
69+
buf.writeFloatLE(this.data.yPos ?? 0, 32);
70+
buf.writeFloatLE(this.data.xSpeed ?? 0, 36);
71+
buf.writeFloatLE(this.data.ySpeed ?? 0, 40);
72+
buf.writeInt32LE(this.data.xPunch ?? 0, 48);
73+
buf.writeInt32LE(this.data.yPunch ?? 0, 52);
74+
75+
if (typeof this.data.data === "function") {
76+
const extra = this.data.data();
77+
if (!Buffer.isBuffer(extra)) return;
78+
79+
buf.writeUInt32LE(extra.length, 56);
80+
buf = Buffer.concat([buf, extra]);
81+
}
82+
83+
return buf;
84+
}
85+
}

lib/packets/TextPacket.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* TextPacket class to create text packets such as for actions or other uses.
3+
*/
4+
export class TextPacket {
5+
/**
6+
* Creates a new TextPacket class
7+
* @param type The type of the packet.
8+
* @param strings An array of strings to include, they will be joined by a newline character. (`\n`)
9+
*/
10+
constructor(public type: number, public strings: string[]) {}
11+
12+
/**
13+
* Creates a TextPacket class.
14+
* @param type The type of the packet.
15+
* @param strings Strings to include to the packet. They are not arrays, but instead they are arguments for the function.
16+
*/
17+
public static from(type: number, ...strings: string[]) {
18+
return new TextPacket(type, strings);
19+
}
20+
21+
/**
22+
* Creates a TextPacket class from a Buffer.
23+
* @param packet The buffer to convert.
24+
*/
25+
public static fromBuffer(packet: Buffer) {
26+
if (packet.length < 4) throw new Error("Invalid packet received.");
27+
const type = packet.readUInt32LE();
28+
const str = packet.toString("utf-8", 4).slice(0, -1) ?? "";
29+
30+
return new TextPacket(type, str.split("\n"));
31+
}
32+
33+
/**
34+
* Parses the TextPacket and covnerts it to a buffer.
35+
*/
36+
public parse() {
37+
const str = this.strings.join("\n");
38+
const buffer = Buffer.alloc(4 + str.length + 1); // + 1 for null terminator
39+
40+
buffer.writeUInt32LE(this.type);
41+
buffer.write(str, 4);
42+
43+
return buffer;
44+
}
45+
}

lib/packets/Variant.ts

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { TankPacket } from "./TankPacket.js";
2+
3+
// Types
4+
import type { VariantArg, VariantArray, VariantOptions } from "../../types";
5+
import { VariantTypes } from "../Constants.js";
6+
7+
/**
8+
* Represents the Variant class.
9+
*/
10+
export class Variant {
11+
public index: number = 0;
12+
13+
/**
14+
* Creates a new instance of the Variant class.
15+
* @param options The options for the variant.
16+
* @param args The arguments of the Variant.
17+
*/
18+
constructor(public options: VariantOptions = {}, public args: VariantArg[]) {}
19+
20+
/**
21+
* Creates a new Variant class.
22+
* @param opts The options for the variant.
23+
* @param args The arguments of the Variant.
24+
*/
25+
public static from(opts?: VariantOptions | VariantArg, ...args: VariantArg[]) {
26+
if (typeof opts === "string" || typeof opts === "number" || Array.isArray(opts)) {
27+
args.unshift(opts);
28+
opts = { netID: -1, delay: 0 };
29+
}
30+
31+
return new Variant(opts as VariantOptions, args);
32+
}
33+
34+
public static toArray(data: Buffer): VariantArray[] {
35+
let arr: VariantArray[] = [];
36+
37+
let pos = 60;
38+
const count = data.readUint8(60);
39+
pos += 1;
40+
41+
for (let i = 1; i <= count; i++) {
42+
const index = data.readUint8(pos);
43+
pos += 1;
44+
45+
const type = data.readUint8(pos);
46+
const typeName = VariantTypes[type];
47+
48+
pos += 1;
49+
50+
switch (type) {
51+
case VariantTypes.STRING: {
52+
const strLength = data.readUint32LE(pos);
53+
pos += 4;
54+
55+
const value = data.subarray(pos, pos + strLength).toString();
56+
pos += strLength;
57+
58+
arr.push({ index, type, typeName, value });
59+
break;
60+
}
61+
case VariantTypes.UNSIGNED_INT: {
62+
const value = data.readUint32LE(pos);
63+
pos += 4;
64+
65+
arr.push({ index, type, typeName, value });
66+
67+
break;
68+
}
69+
case VariantTypes.SIGNED_INT: {
70+
const value = data.readInt32LE(pos);
71+
pos += 4;
72+
73+
arr.push({ index, type, typeName, value });
74+
break;
75+
}
76+
case VariantTypes.FLOAT_1: {
77+
const value = [data.readFloatLE(pos)];
78+
79+
pos += 4;
80+
arr.push({ index, type, typeName, value });
81+
break;
82+
}
83+
case VariantTypes.FLOAT_2: {
84+
let value = [];
85+
86+
for (let i = 1; i <= 2; i++) {
87+
value.push(data.readFloatLE(pos));
88+
pos += 4;
89+
}
90+
arr.push({ index, type, typeName, value });
91+
break;
92+
}
93+
case VariantTypes.FLOAT_3: {
94+
let value = [];
95+
96+
for (let i = 1; i <= 3; i++) {
97+
value.push(data.readFloatLE(pos));
98+
pos += 4;
99+
}
100+
arr.push({ index, type, typeName, value });
101+
break;
102+
}
103+
}
104+
}
105+
return arr;
106+
}
107+
108+
/**
109+
* Parses the data of the Variant and returns a TankPacket from it.
110+
*/
111+
public parse() {
112+
let buf = [this.args.length];
113+
114+
this.args.forEach((arg) => {
115+
buf.push(this.index++);
116+
117+
switch (typeof arg) {
118+
case "string": {
119+
buf.push(VariantTypes.STRING);
120+
121+
const bytes = new Uint32Array(1);
122+
bytes[0] = arg.length;
123+
124+
const uint8_buf = new Uint8ClampedArray(bytes.buffer);
125+
const text_buf = new TextEncoder().encode(arg);
126+
127+
buf = [...buf, ...uint8_buf, ...text_buf];
128+
break;
129+
}
130+
131+
case "number": {
132+
let bytes;
133+
134+
if (arg < 0) {
135+
bytes = new Int32Array(1);
136+
buf.push(VariantTypes.SIGNED_INT);
137+
} else {
138+
bytes = new Uint32Array(1);
139+
buf.push(VariantTypes.UNSIGNED_INT);
140+
}
141+
142+
bytes[0] = arg;
143+
144+
const uint8_buf = new Uint8ClampedArray(bytes.buffer);
145+
buf = [...buf, ...uint8_buf];
146+
break;
147+
}
148+
149+
case "object": {
150+
if (!Array.isArray(arg)) return;
151+
152+
const type = VariantTypes[`FLOAT_${arg.length}` as "FLOAT_1" | "FLOAT_2"];
153+
if (!type) return;
154+
155+
buf.push(type);
156+
157+
arg.forEach((float) => {
158+
const bytes = new Float32Array(1);
159+
bytes[0] = float;
160+
161+
const uint8_buf = new Uint8ClampedArray(bytes.buffer);
162+
buf = [...buf, ...uint8_buf];
163+
});
164+
break;
165+
}
166+
}
167+
});
168+
169+
return TankPacket.from({
170+
type: 0x1,
171+
netID: this.options.netID ?? -1,
172+
info: this.options.delay ?? 0,
173+
data: () => Buffer.from(buf)
174+
});
175+
}
176+
}

0 commit comments

Comments
 (0)