format everything + fix plugin events
This commit is contained in:
parent
cf8772f0ed
commit
d40e90240c
|
@ -150,7 +150,6 @@ export class PacketDefinitions {
|
||||||
await PacketDefinitions.levelFinish(world.size, player);
|
await PacketDefinitions.levelFinish(world.size, player);
|
||||||
|
|
||||||
await PacketDefinitions.spawn(player, -1, player);
|
await PacketDefinitions.spawn(player, -1, player);
|
||||||
|
|
||||||
}
|
}
|
||||||
static async levelFinish(size: Position, player: Player) {
|
static async levelFinish(size: Position, player: Player) {
|
||||||
await player.writeToSocket(
|
await player.writeToSocket(
|
||||||
|
|
|
@ -28,7 +28,9 @@ export class Player {
|
||||||
|
|
||||||
// reassigns ID until finds available one
|
// reassigns ID until finds available one
|
||||||
// if we reach 255 players this will loop forever
|
// 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() * 255);
|
||||||
|
}
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
@ -63,8 +65,7 @@ export class Player {
|
||||||
PacketDefinitions.sendPackets(this, world);
|
PacketDefinitions.sendPackets(this, world);
|
||||||
|
|
||||||
this.server.broadcastPacket(
|
this.server.broadcastPacket(
|
||||||
(e) =>
|
(e) => PacketDefinitions.spawn(this, this.id, e),
|
||||||
PacketDefinitions.spawn(this, this.id, e),
|
|
||||||
this,
|
this,
|
||||||
);
|
);
|
||||||
this.server.broadcastPacket(
|
this.server.broadcastPacket(
|
||||||
|
|
|
@ -139,9 +139,12 @@ export class Server {
|
||||||
this.broadcast(`${player.username} has &cleft`);
|
this.broadcast(`${player.username} has &cleft`);
|
||||||
this.worlds.find((e) => e.name == player.world)!.save();
|
this.worlds.find((e) => e.name == player.world)!.save();
|
||||||
|
|
||||||
this.broadcastPacket((e) => PacketDefinitions.despawn(player.id, e), player);
|
this.broadcastPacket(
|
||||||
|
(e) => PacketDefinitions.despawn(player.id, e),
|
||||||
|
player,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handlePacket(packet: PacketReader, connection: Deno.Conn) {
|
async handlePacket(packet: PacketReader, connection: Deno.Conn) {
|
||||||
const packetType = packet.readByte();
|
const packetType = packet.readByte();
|
||||||
if (packetType == 0x00) {
|
if (packetType == 0x00) {
|
||||||
|
@ -258,18 +261,25 @@ export class Server {
|
||||||
|
|
||||||
const world = this.worlds.find((e) => e.name == player.world)!;
|
const world = this.worlds.find((e) => e.name == player.world)!;
|
||||||
|
|
||||||
const before = world.getBlock(position);
|
let pluginAnswer: boolean[] = [];
|
||||||
|
|
||||||
this.worlds.find((e) => e.name == player.world)!.setBlock(position, id);
|
for await (const [_k, v] of this.plugins) {
|
||||||
|
pluginAnswer = pluginAnswer.concat(
|
||||||
|
await v.plugin.emit("setblock", player, mode, id, position),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pluginAnswer.some((e) => e == true)) {
|
||||||
|
PacketDefinitions.setBlock(position, world.getBlock(position), player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
world.setBlock(position, id);
|
||||||
|
|
||||||
this.broadcastPacket(
|
this.broadcastPacket(
|
||||||
(e) => PacketDefinitions.setBlock(position, id, e),
|
(e) => PacketDefinitions.setBlock(position, id, e),
|
||||||
player,
|
player,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.plugins.forEach((value) => { // TODO: Rework this to work with proper block disabling (not resetting bullshit)
|
|
||||||
value.plugin.emit("setblock", player, mode, id, position, before);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.buffer.length - 1 >= packet.pos) { // TODO: This logic is wrong! Sometimes, TCP packets are still dropped. Need to rewrite this properly.
|
if (packet.buffer.length - 1 >= packet.pos) { // TODO: This logic is wrong! Sometimes, TCP packets are still dropped. Need to rewrite this properly.
|
||||||
|
@ -298,7 +308,6 @@ export class Server {
|
||||||
} else {
|
} else {
|
||||||
const packet = new PacketReader(buffer.subarray(0, count));
|
const packet = new PacketReader(buffer.subarray(0, count));
|
||||||
this.handlePacket(packet, connection);
|
this.handlePacket(packet, connection);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,7 @@ export abstract class Plugin extends EventEmitter<{
|
||||||
mode: number,
|
mode: number,
|
||||||
id: number,
|
id: number,
|
||||||
position: Position,
|
position: Position,
|
||||||
blockBefore: number,
|
): boolean;
|
||||||
): void;
|
|
||||||
|
|
||||||
stop(): void;
|
stop(): void;
|
||||||
}> {
|
}> {
|
||||||
|
|
4
deps.ts
4
deps.ts
|
@ -5,7 +5,7 @@ import { S3 } from "https://aws-api.deno.dev/v0.3/services/s3.ts";
|
||||||
|
|
||||||
export * as log from "https://deno.land/std@0.136.0/log/mod.ts";
|
export * as log from "https://deno.land/std@0.136.0/log/mod.ts";
|
||||||
export { crypto } from "https://deno.land/std@0.136.0/crypto/mod.ts";
|
export { crypto } from "https://deno.land/std@0.136.0/crypto/mod.ts";
|
||||||
export { EventEmitter } from "https://deno.land/x/eventemitter@1.2.1/mod.ts";
|
export { EventEmitter } from "./events.ts";
|
||||||
import "https://deno.land/x/dotenv@v3.2.0/load.ts";
|
import "https://deno.land/x/dotenv@v3.2.0/load.ts";
|
||||||
export const toHexString = (bytes: Uint8Array) =>
|
export const toHexString = (bytes: Uint8Array) =>
|
||||||
bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
|
bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
|
||||||
|
@ -23,5 +23,5 @@ export const config = {
|
||||||
ops: Deno.env.get("OPS") ? JSON.parse(Deno.env.get("OPS")!) : [],
|
ops: Deno.env.get("OPS") ? JSON.parse(Deno.env.get("OPS")!) : [],
|
||||||
port: +Deno.env.get("PORT")!,
|
port: +Deno.env.get("PORT")!,
|
||||||
hash: Deno.env.get("HASH"),
|
hash: Deno.env.get("HASH"),
|
||||||
onlineMode: Deno.env.get("ONLINEMODE") == "true"
|
onlineMode: Deno.env.get("ONLINEMODE") == "true",
|
||||||
};
|
};
|
||||||
|
|
231
events.ts
Normal file
231
events.ts
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
/** The callback type. */
|
||||||
|
type Callback = (...args: any[]) => any | Promise<any>;
|
||||||
|
|
||||||
|
/** A listener type. */
|
||||||
|
type Listener = Callback & { __once__?: true };
|
||||||
|
|
||||||
|
/** The name of an event. */
|
||||||
|
type EventName = string | number;
|
||||||
|
|
||||||
|
type EventsType =
|
||||||
|
& { [key: string]: Callback }
|
||||||
|
& { [key: number]: Callback };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event emitter.
|
||||||
|
*/
|
||||||
|
export class EventEmitter<E extends EventsType = {}> {
|
||||||
|
/**
|
||||||
|
* This is where the events and listeners are stored.
|
||||||
|
*/
|
||||||
|
private _events_: Map<keyof E, Set<Listener>> = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for a typed event.
|
||||||
|
* @param event The typed event name to listen for.
|
||||||
|
* @param listener The typed listener function.
|
||||||
|
*/
|
||||||
|
public on<K extends keyof E>(event: K, listener: E[K]): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for an event.
|
||||||
|
* @param event The event name to listen for.
|
||||||
|
* @param listener The listener function.
|
||||||
|
*/
|
||||||
|
public on(event: EventName, listener: Callback): this {
|
||||||
|
if (!this._events_.has(event)) this._events_.set(event, new Set());
|
||||||
|
this._events_.get(event)!.add(listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for a typed event once.
|
||||||
|
* @param event The typed event name to listen for.
|
||||||
|
* @param listener The typed listener function.
|
||||||
|
*/
|
||||||
|
public once<K extends keyof E>(event: K, listener: E[K]): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for an event once.
|
||||||
|
* @param event The event name to listen for.
|
||||||
|
* @param listener The listener function.
|
||||||
|
*/
|
||||||
|
public once(event: EventName, listener: Callback): this {
|
||||||
|
const l: Listener = listener;
|
||||||
|
l.__once__ = true;
|
||||||
|
return this.on(event, l as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific listener in the event emitter on a specific
|
||||||
|
* typed event.
|
||||||
|
* @param event The typed event name.
|
||||||
|
* @param listener The typed event listener function.
|
||||||
|
*/
|
||||||
|
public off<K extends keyof E>(event: K, listener: E[K]): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all listeners on a specific typed event.
|
||||||
|
* @param event The typed event name.
|
||||||
|
*/
|
||||||
|
public off<K extends keyof E>(event: K): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all events from the event listener.
|
||||||
|
*/
|
||||||
|
public off(): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific listener on a specific event if both `event`
|
||||||
|
* and `listener` is defined, or remove all listeners on a
|
||||||
|
* specific event if only `event` is defined, or lastly remove
|
||||||
|
* all listeners on every event if `event` is not defined.
|
||||||
|
* @param event The event name.
|
||||||
|
* @param listener The event listener function.
|
||||||
|
*/
|
||||||
|
public off(event?: EventName, listener?: Callback): this {
|
||||||
|
if (!event && listener) {
|
||||||
|
throw new Error("Why is there a listener defined here?");
|
||||||
|
} else if (!event && !listener) {
|
||||||
|
this._events_.clear();
|
||||||
|
} else if (event && !listener) {
|
||||||
|
this._events_.delete(event);
|
||||||
|
} else if (event && listener && this._events_.has(event)) {
|
||||||
|
const _ = this._events_.get(event)!;
|
||||||
|
_.delete(listener);
|
||||||
|
if (_.size === 0) this._events_.delete(event);
|
||||||
|
} else {
|
||||||
|
throw new Error("Unknown action!");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a typed event without waiting for each listener to
|
||||||
|
* return.
|
||||||
|
* @param event The typed event name to emit.
|
||||||
|
* @param args The arguments to pass to the typed listeners.
|
||||||
|
*/
|
||||||
|
public emitSync<K extends keyof E>(event: K, ...args: Parameters<E[K]>): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an event without waiting for each listener to return.
|
||||||
|
* @param event The event name to emit.
|
||||||
|
* @param args The arguments to pass to the listeners.
|
||||||
|
*/
|
||||||
|
public emitSync(event: EventName, ...args: Parameters<Callback>): this {
|
||||||
|
if (!this._events_.has(event)) return this;
|
||||||
|
const _ = this._events_.get(event)!;
|
||||||
|
for (let [, listener] of _.entries()) {
|
||||||
|
const r = listener(...args);
|
||||||
|
if (r instanceof Promise) r.catch(console.error);
|
||||||
|
if (listener.__once__) {
|
||||||
|
delete listener.__once__;
|
||||||
|
_.delete(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.size === 0) this._events_.delete(event);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a typed event and wait for each typed listener to return.
|
||||||
|
* @param event The typed event name to emit.
|
||||||
|
* @param args The arguments to pass to the typed listeners.
|
||||||
|
*/
|
||||||
|
public async emit<K extends keyof E>(
|
||||||
|
event: K,
|
||||||
|
...args: Parameters<E[K]>
|
||||||
|
): Promise<any[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an event and wait for each listener to return.
|
||||||
|
* @param event The event name to emit.
|
||||||
|
* @param args The arguments to pass to the listeners.
|
||||||
|
*/
|
||||||
|
public async emit(
|
||||||
|
event: EventName,
|
||||||
|
...args: Parameters<Callback>
|
||||||
|
): Promise<any[]> {
|
||||||
|
let returns: any[] = [];
|
||||||
|
|
||||||
|
if (!this._events_.has(event)) return returns;
|
||||||
|
const _ = this._events_.get(event)!;
|
||||||
|
for (let [, listener] of _.entries()) {
|
||||||
|
try {
|
||||||
|
returns.push(await listener(...args));
|
||||||
|
if (listener.__once__) {
|
||||||
|
delete listener.__once__;
|
||||||
|
_.delete(listener);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.size === 0) this._events_.delete(event);
|
||||||
|
return returns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The same as emitSync, but wait for each typed listener to
|
||||||
|
* return before calling the next typed listener.
|
||||||
|
* @param event The typed event name.
|
||||||
|
* @param args The arguments to pass to the typed listeners.
|
||||||
|
*/
|
||||||
|
public queue<K extends keyof E>(event: K, ...args: Parameters<E[K]>): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The same as emitSync, but wait for each listener to return
|
||||||
|
* before calling the next listener.
|
||||||
|
* @param event The event name.
|
||||||
|
* @param args The arguments to pass to the listeners.
|
||||||
|
*/
|
||||||
|
public queue(event: EventName, ...args: Parameters<Callback>): this {
|
||||||
|
(async () => await this.emit(event, ...args as any))().catch(console.error);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a typed event to be emitted and return the arguments.
|
||||||
|
* @param event The typed event name to wait for.
|
||||||
|
* @param timeout An optional amount of milliseconds to wait
|
||||||
|
* before throwing.
|
||||||
|
*/
|
||||||
|
public pull<K extends keyof E>(
|
||||||
|
event: K,
|
||||||
|
timeout?: number,
|
||||||
|
): Promise<Parameters<E[K]>>;
|
||||||
|
/**
|
||||||
|
* Wait for an event to be emitted and return the arguments.
|
||||||
|
* @param event The event name to wait for.
|
||||||
|
* @param timeout An optional amount of milliseconds to wait
|
||||||
|
* before throwing.
|
||||||
|
*/
|
||||||
|
public pull(
|
||||||
|
event: EventName,
|
||||||
|
timeout?: number,
|
||||||
|
): Promise<Parameters<Callback>> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let timeoutId: number | null;
|
||||||
|
|
||||||
|
let listener = (...args: any[]) => {
|
||||||
|
if (timeoutId !== null) clearTimeout(timeoutId);
|
||||||
|
resolve(args);
|
||||||
|
};
|
||||||
|
|
||||||
|
timeoutId = typeof timeout !== "number"
|
||||||
|
? null
|
||||||
|
: setTimeout(() => (this.off(event, listener as any),
|
||||||
|
reject(
|
||||||
|
new Error("Timed out!"),
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
this.once(event, listener as any);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EventEmitter;
|
|
@ -13,7 +13,7 @@ export default class CommandPlugin extends Plugin {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
|
||||||
this.on("command", async (command, player) => {
|
this.on("command", async (command, player) => {
|
||||||
if (command == "help") {
|
if (command == "help") {
|
||||||
let allComamnds = "";
|
let allComamnds = "";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PacketDefinitions, Plugin, World } from "../classes/classes.ts";
|
import { Plugin, World } from "../classes/classes.ts";
|
||||||
import { Server } from "../classes/Server.ts";
|
import { Server } from "../classes/Server.ts";
|
||||||
import { config } from "../deps.ts";
|
import { config } from "../deps.ts";
|
||||||
|
|
||||||
|
@ -13,20 +13,16 @@ export default class CommandPlugin extends Plugin {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.on("setblock", (player, _mode, _id, position, blockBefore) => {
|
this.on("setblock", (player, _mode, _id) => {
|
||||||
const world = server.worlds.find((e) => e.name == player.world)!;
|
const world = server.worlds.find((e) => e.name == player.world)!;
|
||||||
if (!world.optionalJson?.builders?.includes("*")) {
|
if (!world.optionalJson?.builders?.includes("*")) {
|
||||||
if (!world.optionalJson?.builders?.includes(player.username)) {
|
if (!world.optionalJson?.builders?.includes(player.username)) {
|
||||||
player.message("You are %cnot allowed &fto build in this world!");
|
player.message("You are %cnot allowed &fto build in this world!");
|
||||||
world.setBlock(position, blockBefore);
|
return true;
|
||||||
|
|
||||||
server.players.forEach(async (e) => {
|
|
||||||
if (e.world == player.world) {
|
|
||||||
await PacketDefinitions.setBlock(position, blockBefore, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
this.on("command", async (command, player, args) => {
|
this.on("command", async (command, player, args) => {
|
||||||
if (command == "g") {
|
if (command == "g") {
|
||||||
|
|
28
readme.md
28
readme.md
|
@ -1,8 +1,9 @@
|
||||||
# cla66ic
|
# cla66ic
|
||||||
|
|
||||||
## sucessor of cla55ic
|
## sucessor of cla55ic
|
||||||
|
|
||||||
### features:
|
### features:
|
||||||
|
|
||||||
1. written in typescript (types and shit)
|
1. written in typescript (types and shit)
|
||||||
2. entierly cloud based (meaning you can host it anywhere)
|
2. entierly cloud based (meaning you can host it anywhere)
|
||||||
3. extremely extensive plugin system
|
3. extremely extensive plugin system
|
||||||
|
@ -10,8 +11,10 @@
|
||||||
5. DENO!! It's not node, and a classic server.
|
5. DENO!! It's not node, and a classic server.
|
||||||
|
|
||||||
### setup tutorial (be warned it's not the easiest)
|
### setup tutorial (be warned it's not the easiest)
|
||||||
|
|
||||||
1. make a backblaze b2 account, make a bucket, and get your keys from the bucket
|
1. make a backblaze b2 account, make a bucket, and get your keys from the bucket
|
||||||
2. configure .env file to look something like
|
2. configure .env file to look something like
|
||||||
|
|
||||||
```
|
```
|
||||||
PORT=6969
|
PORT=6969
|
||||||
HASH=RandomHashIlIke
|
HASH=RandomHashIlIke
|
||||||
|
@ -21,19 +24,24 @@ ONLINEMODE=true
|
||||||
S3_ACCESS_KEY_ID="MyAccessKey"
|
S3_ACCESS_KEY_ID="MyAccessKey"
|
||||||
S3_SECRET_KEY="SecretKey"
|
S3_SECRET_KEY="SecretKey"
|
||||||
```
|
```
|
||||||
NOTE: if you are running inside of a cloud provider, just set these as
|
|
||||||
your environment variables
|
|
||||||
|
|
||||||
3. install deno
|
NOTE: if you are running inside of a cloud provider, just set these as your
|
||||||
|
environment variables
|
||||||
|
|
||||||
|
3. install deno
|
||||||
4. run `deno run --allow-env --allow-net --allow-read index.ts`
|
4. run `deno run --allow-env --allow-net --allow-read index.ts`
|
||||||
|
|
||||||
### insipration taken from:
|
### insipration taken from:
|
||||||
|
|
||||||
1. mcgalaxy (obviuouuusly!!)
|
1. mcgalaxy (obviuouuusly!!)
|
||||||
2. https://github.com/Patbox/Cobblestone-Classic (some protocol information and worldhandling)
|
2. https://github.com/Patbox/Cobblestone-Classic (some protocol information and
|
||||||
|
worldhandling)
|
||||||
3. cla55ic (world data too)
|
3. cla55ic (world data too)
|
||||||
|
|
||||||
### issues:
|
### issues:
|
||||||
1. plugin system event handling is lackluster in some palces
|
|
||||||
2. tcp packet splitting fails sometimes
|
1. tcp packet splitting fails sometimes
|
||||||
3. no cpe support! i want to get all of the above issues fixed before implementing CPE support
|
2. no cpe support! i want to get all of the above issues fixed before
|
||||||
4. proper rank support (implemented as plugin)
|
implementing CPE support
|
||||||
5. no discord bridge (implemented as plugin)
|
3. proper rank support (implemented as plugin)
|
||||||
|
4. no discord bridge (implemented as plugin)
|
||||||
|
|
Loading…
Reference in a new issue