-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
131 lines (107 loc) · 4.11 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Type reflection shim
import { Server as TCPServer } from "net";
import { Server as HTTPServer } from "http";
import * as crypto from "crypto";
import "reflect-metadata";
import { r } from "rethinkdb-ts";
import { Settings, MinecraftConfigs, ElytraConfigs } from "./src/Configuration.js";
import { State } from "./src/State.js";
import { Database } from "./src/database/Database.js";
import { Server } from "./src/protocol/Server.js";
import { Keypair } from "./src/protocol/Encryption.js";
import { World } from "./src/game/World.js";
import { Logging } from "./src/game/Logging.js";
import { PacketFactory } from "./src/protocol/PacketFactory.js";
import { WorldModel } from "./src/database/models/WorldModel.js";
import { Locale } from "./src/game/Locale.js";
import { API } from "./src/API.js";
import { Constants } from "./src/Constants.js";
/**
* Prepare the server to accept players
* @async
*/
async function bootstrap() {
// Log the server start time
const start: number = performance.now();
// Load settings from the config file
Settings.Load();
Logging.Info("Loaded database configuration");
// Connect to the database
await Database.Connect();
// Cache all settings
await Settings.Cache();
// Generate a keypair for protocol encryption
State.Keypair = await Keypair.Generate();
// Set up a packet factory
await PacketFactory.Load();
// Print out the key fingerprint for debugging purposes
const publicKey: Buffer = State.Keypair.PublicKey.export({ format: "der", type: "spki" });
const fingerprint: string = crypto.createHash("md5")
.update(publicKey)
.digest("hex")
.replace(/(\w{2})(?!$)/g, "$1:");
Logging.Info("Server public key has fingerprint", fingerprint.green);
Logging.Trace("Server public keypair:", publicKey.toString("hex").green);
// Load chat translations
await Locale.Load();
// Retrieve all existing world data
const worlds = await r.table<WorldModel>("world")
.run();
State.Worlds = new Map();
if (worlds.length > 0) {
// Convert and proxy the world objects
worlds.forEach((world: WorldModel) => {
State.Worlds.set(world.id, World.Mapper.load(world, true));
});
} else {
Logging.Info("Creating default world");
// Create a new world
const newWorld: World = new World();
// Proxy and map the world
State.Worlds.set(newWorld.Metadata.id, World.Mapper.proxy(newWorld));
}
// Log the bootstrap time
const end: number = performance.now();
Logging.Info("Server ready after", `${Math.round(end - start)}`.green, "milliseconds");
}
/**
* Start listening for connections from Minecraft clients
* @async
*/
async function startListener() {
const server = new TCPServer();
// Attach a connection handler
State.Server = new Server(server);
// Start the server
const port: number = Settings.Get(MinecraftConfigs.ServerPort);
const ip: number = Settings.Get(MinecraftConfigs.ServerIP);
server.listen(port, ip, () => {
Logging.Info("Server listening on", `${ip}:${port}`.green);
});
}
/**
* Start the REST and Websocket APIs to allow for remote management and synchronization
* @async
*/
async function startAPI() {
// Compile the GraphQL schema and build a handler
const server: HTTPServer = await API.Bootstrap();
// Start the API server
const port: number = Settings.Get(Constants.ElytraConfigNamespace, ElytraConfigs.ApiPort);
const ip: string = Settings.Get(Constants.ElytraConfigNamespace, ElytraConfigs.ApiIP);
server.listen(port, ip, () => {
Logging.Info("API server listening on", `${ip}:${port}`.green);
});
}
(async () => {
// Prepare the server to start
await bootstrap();
// Start the API
await startAPI();
const eula: boolean = Settings.Get(MinecraftConfigs.EULA);
if (eula)
// Start the Minecraft server
await startListener();
else
Logging.Error("You must accept the EULA first. Go to https://account.mojang.com/documents/minecraft_eula, then set", "eula".green, "to", "true".blue);
})();