Merge pull request #2 from yourfriendoss/TCP
TCP Packet Splitting (fixes #1)
This commit is contained in:
commit
11700fe211
3 changed files with 86 additions and 41 deletions
|
@ -8,6 +8,7 @@ export class Player {
|
||||||
private server: Server;
|
private server: Server;
|
||||||
|
|
||||||
username: string;
|
username: string;
|
||||||
|
ip: string;
|
||||||
id: number;
|
id: number;
|
||||||
world = "main";
|
world = "main";
|
||||||
position: Position;
|
position: Position;
|
||||||
|
@ -23,15 +24,15 @@ export class Player {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
this.ip = (this.socket.remoteAddr as Deno.NetAddr).hostname;
|
||||||
|
|
||||||
let id = Math.floor(Math.random() * 255);
|
let id = Math.floor(Math.random() * server.maxUsers);
|
||||||
|
|
||||||
// reassigns ID until finds available one
|
// reassigns ID until finds available one
|
||||||
// if we reach 255 players this will loop forever
|
|
||||||
while (server.players.find((e) => e.id == id)) {
|
|
||||||
id = Math.floor(Math.random() * 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
while (server.players.find((e) => e.id == id)) {
|
||||||
|
id = Math.floor(Math.random() * server.maxUsers);
|
||||||
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ export class Player {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async toWorld(world: World) {
|
toWorld(world: World) {
|
||||||
this.server.broadcastPacket(
|
this.server.broadcastPacket(
|
||||||
(e) => PacketDefinitions.despawn(this.id, e),
|
(e) => PacketDefinitions.despawn(this.id, e),
|
||||||
this,
|
this,
|
||||||
|
@ -75,6 +76,6 @@ export class Player {
|
||||||
|
|
||||||
this.message("You have been moved.");
|
this.message("You have been moved.");
|
||||||
|
|
||||||
await world.save();
|
//await world.save(); TODO: this causes way too many issues
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,16 @@ export class Server {
|
||||||
|
|
||||||
players: Player[] = [];
|
players: Player[] = [];
|
||||||
plugins: Map<string, PluginUpdateTime> = new Map();
|
plugins: Map<string, PluginUpdateTime> = new Map();
|
||||||
lengthMap: Map<number, number> = new Map([[0, 131], [5, 9], [8, 10], [
|
|
||||||
13,
|
lengthMap: Map<number, number> = new Map([
|
||||||
66,
|
[0, 130],
|
||||||
]]);
|
[5, 8],
|
||||||
|
[8, 9],
|
||||||
|
[13, 65],
|
||||||
|
]);
|
||||||
|
|
||||||
|
maxUsers = 69
|
||||||
|
|
||||||
worlds: World[] = [new World({ x: 64, y: 64, z: 64 }, "main")];
|
worlds: World[] = [new World({ x: 64, y: 64, z: 64 }, "main")];
|
||||||
|
|
||||||
async start(port: number) {
|
async start(port: number) {
|
||||||
|
@ -60,9 +66,10 @@ export class Server {
|
||||||
await fetch(
|
await fetch(
|
||||||
"https://www.classicube.net/heartbeat.jsp" +
|
"https://www.classicube.net/heartbeat.jsp" +
|
||||||
`?port=${config.port}` +
|
`?port=${config.port}` +
|
||||||
"&max=255" +
|
`&max=${this.maxUsers}` +
|
||||||
"&name=Cla66ic" +
|
"&name=Cla66ic" +
|
||||||
"&public=True" +
|
"&public=True" +
|
||||||
|
"&software=Cla66ic" +
|
||||||
`&version=7&salt=${config.hash}` +
|
`&version=7&salt=${config.hash}` +
|
||||||
`&users=${this.players.length}`,
|
`&users=${this.players.length}`,
|
||||||
);
|
);
|
||||||
|
@ -136,8 +143,13 @@ export class Server {
|
||||||
|
|
||||||
this.players = this.players.filter((e) => e != player);
|
this.players = this.players.filter((e) => e != player);
|
||||||
|
|
||||||
|
try {
|
||||||
|
conn.close();
|
||||||
|
} catch {
|
||||||
|
// whatever
|
||||||
|
}
|
||||||
|
|
||||||
this.broadcast(`${player.username} has &cleft`);
|
this.broadcast(`${player.username} has &cleft`);
|
||||||
this.worlds.find((e) => e.name == player.world)!.save();
|
|
||||||
|
|
||||||
this.broadcastPacket(
|
this.broadcastPacket(
|
||||||
(e) => PacketDefinitions.despawn(player.id, e),
|
(e) => PacketDefinitions.despawn(player.id, e),
|
||||||
|
@ -145,14 +157,25 @@ export class Server {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handlePacket(packet: PacketReader, connection: Deno.Conn) {
|
async handlePacket(
|
||||||
const packetType = packet.readByte();
|
buffer: Uint8Array,
|
||||||
|
packetType: number,
|
||||||
|
connection: Deno.Conn,
|
||||||
|
) {
|
||||||
|
const packet = new PacketReader(buffer);
|
||||||
if (packetType == 0x00) {
|
if (packetType == 0x00) {
|
||||||
if (this.players.find((e) => e.socket == connection)) return;
|
if (this.players.find((e) => e.socket == connection)) return;
|
||||||
packet.readByte();
|
packet.readByte();
|
||||||
const username = packet.readString();
|
const username = packet.readString();
|
||||||
|
|
||||||
const verification = packet.readString();
|
const verification = packet.readString();
|
||||||
|
|
||||||
|
if(this.players.length >= this.maxUsers) {
|
||||||
|
|
||||||
|
connection.close();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
const player = new Player(
|
const player = new Player(
|
||||||
connection,
|
connection,
|
||||||
username,
|
username,
|
||||||
|
@ -281,33 +304,51 @@ export class Server {
|
||||||
player,
|
player,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.buffer.length - 1 >= packet.pos) { // TODO: This logic is wrong! Sometimes, TCP packets are still dropped. Need to rewrite this properly.
|
|
||||||
this.handlePacket(packet, connection);
|
|
||||||
|
|
||||||
packet.pos += packet.totalPacketSize;
|
|
||||||
packet.totalPacketSize = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async startSocket(connection: Deno.Conn) {
|
async startSocket(connection: Deno.Conn) {
|
||||||
const buffer = new Uint8Array(1024 * 1024 * 10);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
let count;
|
const packetID = new Uint8Array(1);
|
||||||
|
let packetIDReadAttempt;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
count = await connection.read(buffer);
|
packetIDReadAttempt = await connection.read(packetID);
|
||||||
} catch (e) {
|
} catch {
|
||||||
count = 0;
|
this.removeUser(connection); // TODO: add a reason to this
|
||||||
log.critical(e);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!count) {
|
if (packetIDReadAttempt) {
|
||||||
|
const packetLength = this.lengthMap.get(packetID[0]);
|
||||||
|
|
||||||
|
if (!packetLength) {
|
||||||
|
log.critical("Unknown Packet: " + packetID[0]);
|
||||||
|
this.removeUser(connection); // TODO: add a reason to this
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rawPacket = new Uint8Array(packetLength);
|
||||||
|
let packetReadAttempt;
|
||||||
|
|
||||||
|
try {
|
||||||
|
packetReadAttempt = await connection.read(rawPacket);
|
||||||
|
} catch {
|
||||||
|
this.removeUser(connection); // TODO: add a reason to this
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let fullRead = packetReadAttempt!;
|
||||||
|
|
||||||
|
while (fullRead < packetLength) {
|
||||||
|
const halfPacket = new Uint8Array(packetLength - fullRead);
|
||||||
|
rawPacket = new Uint8Array([...rawPacket, ...halfPacket]);
|
||||||
|
|
||||||
|
fullRead += (await connection.read(halfPacket))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handlePacket(rawPacket, packetID[0], connection);
|
||||||
|
} else {
|
||||||
this.removeUser(connection);
|
this.removeUser(connection);
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
const packet = new PacketReader(buffer.subarray(0, count));
|
|
||||||
this.handlePacket(packet, connection);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
readme.md
17
readme.md
|
@ -33,15 +33,18 @@ environment variables
|
||||||
|
|
||||||
### insipration taken from:
|
### insipration taken from:
|
||||||
|
|
||||||
1. mcgalaxy (obviuouuusly!!)
|
1. https://github.com/Patbox/Cobblestone-Classic (some protocol information and
|
||||||
2. https://github.com/Patbox/Cobblestone-Classic (some protocol information and
|
|
||||||
worldhandling)
|
worldhandling)
|
||||||
3. cla55ic (world data too)
|
2. cla55ic (world data too)
|
||||||
|
|
||||||
### issues:
|
### issues:
|
||||||
|
|
||||||
1. tcp packet splitting fails sometimes
|
|
||||||
2. no cpe support! i want to get all of the above issues fixed before
|
1. Properly queue up map saves instead of just blantantly saving whenever possible
|
||||||
|
2. massive performance issues, running more than 100 something accounts makes the server instead insane amounts of cpu (most likely multithreading needed)
|
||||||
|
3. no cpe support! i want to get all of the above issues fixed before
|
||||||
implementing CPE support
|
implementing CPE support
|
||||||
3. proper rank support (implemented as plugin)
|
4. no IP cooldown connections (no block cooldown either), no anticheat, no unique IP heartbeats
|
||||||
4. no discord bridge (implemented as plugin)
|
5. proper rank support (implemented as plugin)
|
||||||
|
6. no discord bridge (implemented as plugin)
|
||||||
|
7. no cla66ic/plugins repository
|
||||||
|
|
Loading…
Reference in a new issue