omegga 1.2.8 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -1
- package/dist/brickadia/config.js +26 -90
- package/dist/brickadia/config.js.map +1 -1
- package/dist/brickadia/server.js +294 -293
- package/dist/brickadia/server.js.map +1 -1
- package/dist/cli/auth.js +149 -177
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/config.js +64 -66
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +14 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/installer.js +37 -43
- package/dist/cli/installer.js.map +1 -1
- package/dist/cli/plugin.js +651 -682
- package/dist/cli/plugin.js.map +1 -1
- package/dist/cli/terminal.js +811 -733
- package/dist/cli/terminal.js.map +1 -1
- package/dist/config/formats/format_js.js +6 -6
- package/dist/config/formats/format_js.js.map +1 -1
- package/dist/config/formats/format_yml.js +7 -10
- package/dist/config/formats/format_yml.js.map +1 -1
- package/dist/config/index.js +46 -68
- package/dist/config/index.js.map +1 -1
- package/dist/config/reader.js +16 -27
- package/dist/config/reader.js.map +1 -1
- package/dist/config/validator.js +23 -25
- package/dist/config/validator.js.map +1 -1
- package/dist/config/writer.js +11 -21
- package/dist/config/writer.js.map +1 -1
- package/dist/index.js +18 -64
- package/dist/index.js.map +1 -1
- package/dist/info/default_commands.json.js +39 -0
- package/dist/info/default_commands.json.js.map +1 -0
- package/dist/logger.js +61 -60
- package/dist/logger.js.map +1 -1
- package/dist/main.js +424 -471
- package/dist/main.js.map +1 -1
- package/dist/omegga/auth.js +101 -148
- package/dist/omegga/auth.js.map +1 -1
- package/dist/omegga/commandInjector.js +261 -251
- package/dist/omegga/commandInjector.js.map +1 -1
- package/dist/omegga/index.js +14 -52
- package/dist/omegga/index.js.map +1 -1
- package/dist/omegga/logWrangler.js +224 -275
- package/dist/omegga/logWrangler.js.map +1 -1
- package/dist/omegga/matchers/auth.js +36 -50
- package/dist/omegga/matchers/auth.js.map +1 -1
- package/dist/omegga/matchers/chat.js +49 -71
- package/dist/omegga/matchers/chat.js.map +1 -1
- package/dist/omegga/matchers/command.js +25 -36
- package/dist/omegga/matchers/command.js.map +1 -1
- package/dist/omegga/matchers/exit.js +15 -18
- package/dist/omegga/matchers/exit.js.map +1 -1
- package/dist/omegga/matchers/index.js +26 -40
- package/dist/omegga/matchers/index.js.map +1 -1
- package/dist/omegga/matchers/init.js +20 -23
- package/dist/omegga/matchers/init.js.map +1 -1
- package/dist/omegga/matchers/interact.js +58 -64
- package/dist/omegga/matchers/interact.js.map +1 -1
- package/dist/omegga/matchers/join.js +74 -95
- package/dist/omegga/matchers/join.js.map +1 -1
- package/dist/omegga/matchers/leave.js +43 -56
- package/dist/omegga/matchers/leave.js.map +1 -1
- package/dist/omegga/matchers/mapChange.js +26 -35
- package/dist/omegga/matchers/mapChange.js.map +1 -1
- package/dist/omegga/matchers/minigameJoin.js +24 -31
- package/dist/omegga/matchers/minigameJoin.js.map +1 -1
- package/dist/omegga/matchers/version.js +42 -49
- package/dist/omegga/matchers/version.js.map +1 -1
- package/dist/omegga/player.js +527 -527
- package/dist/omegga/player.js.map +1 -1
- package/dist/omegga/plugin/interface.js +91 -98
- package/dist/omegga/plugin/interface.js.map +1 -1
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.js +524 -429
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js +282 -294
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_safe.js +365 -393
- package/dist/omegga/plugin/plugin_node_safe.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_unsafe.js +119 -179
- package/dist/omegga/plugin/plugin_node_unsafe.js.map +1 -1
- package/dist/omegga/plugin.js +402 -347
- package/dist/omegga/plugin.js.map +1 -1
- package/dist/omegga/server.js +742 -774
- package/dist/omegga/server.js.map +1 -1
- package/dist/omegga/wrapper.js +64 -91
- package/dist/omegga/wrapper.js.map +1 -1
- package/dist/plugin.js +11 -31
- package/dist/plugin.js.map +1 -1
- package/dist/softconfig.js +121 -100
- package/dist/softconfig.js.map +1 -1
- package/dist/updater/steam.js +97 -112
- package/dist/updater/steam.js.map +1 -1
- package/dist/util/brdb.js +496 -528
- package/dist/util/brdb.js.map +1 -1
- package/dist/util/brick/checkBounds.js +11 -15
- package/dist/util/brick/checkBounds.js.map +1 -1
- package/dist/util/brick/constants.js +723 -174
- package/dist/util/brick/constants.js.map +1 -1
- package/dist/util/brick/displayName.js +204 -211
- package/dist/util/brick/displayName.js.map +1 -1
- package/dist/util/brick/getBounds.js +29 -41
- package/dist/util/brick/getBounds.js.map +1 -1
- package/dist/util/brick/getBrickSize.js +6 -7
- package/dist/util/brick/getBrickSize.js.map +1 -1
- package/dist/util/brick/getScaleAxis.js +24 -30
- package/dist/util/brick/getScaleAxis.js.map +1 -1
- package/dist/util/brick/index.js +8 -29
- package/dist/util/brick/index.js.map +1 -1
- package/dist/util/brick/rotate.js +29 -34
- package/dist/util/brick/rotate.js.map +1 -1
- package/dist/util/brick/setOwnership.js +13 -19
- package/dist/util/brick/setOwnership.js.map +1 -1
- package/dist/util/chat.js +53 -44
- package/dist/util/chat.js.map +1 -1
- package/dist/util/color.js +112 -124
- package/dist/util/color.js.map +1 -1
- package/dist/util/file.js +54 -98
- package/dist/util/file.js.map +1 -1
- package/dist/util/index.js +84 -106
- package/dist/util/index.js.map +1 -1
- package/dist/util/map.js +18 -20
- package/dist/util/map.js.map +1 -1
- package/dist/util/pattern.js +6 -9
- package/dist/util/pattern.js.map +1 -1
- package/dist/util/time.js +31 -34
- package/dist/util/time.js.map +1 -1
- package/dist/util/uuid.js +10 -8
- package/dist/util/uuid.js.map +1 -1
- package/dist/util/wsl.js +19 -25
- package/dist/util/wsl.js.map +1 -1
- package/dist/version.js +7 -9
- package/dist/version.js.map +1 -1
- package/dist/webserver/backend/api.js +784 -874
- package/dist/webserver/backend/api.js.map +1 -1
- package/dist/webserver/backend/calendar.js +14 -17
- package/dist/webserver/backend/calendar.js.map +1 -1
- package/dist/webserver/backend/database.js +563 -613
- package/dist/webserver/backend/database.js.map +1 -1
- package/dist/webserver/backend/index.js +153 -191
- package/dist/webserver/backend/index.js.map +1 -1
- package/dist/webserver/backend/metrics.js +219 -248
- package/dist/webserver/backend/metrics.js.map +1 -1
- package/dist/webserver/backend/util.js +47 -68
- package/dist/webserver/backend/util.js.map +1 -1
- package/dist/worker.js +322 -0
- package/dist/worker.js.map +1 -0
- package/package.json +14 -10
- package/templates/safe-ts/omegga.d.ts +2 -2
- package/vite.backend.config.mts +46 -0
- package/vite.frontend.config.mts +58 -0
- package/vitest.backend.config.mts +7 -0
- package/dist/brickadia/config.d.ts +0 -3
- package/dist/brickadia/presets.d.ts +0 -65
- package/dist/brickadia/presets.js +0 -3
- package/dist/brickadia/presets.js.map +0 -1
- package/dist/brickadia/server.d.ts +0 -36
- package/dist/brickadia/types.d.ts +0 -45
- package/dist/brickadia/types.js +0 -3
- package/dist/brickadia/types.js.map +0 -1
- package/dist/cli/auth.d.ts +0 -26
- package/dist/cli/config.d.ts +0 -10
- package/dist/cli/index.d.ts +0 -30
- package/dist/cli/installer.d.ts +0 -1
- package/dist/cli/plugin.d.ts +0 -22
- package/dist/cli/terminal.d.ts +0 -25
- package/dist/config/authorizer.d.ts +0 -2
- package/dist/config/authorizer.js +0 -38
- package/dist/config/authorizer.js.map +0 -1
- package/dist/config/formats/format_js.d.ts +0 -3
- package/dist/config/formats/format_yml.d.ts +0 -3
- package/dist/config/index.d.ts +0 -18
- package/dist/config/reader.d.ts +0 -3
- package/dist/config/types.d.ts +0 -50
- package/dist/config/types.js +0 -3
- package/dist/config/types.js.map +0 -1
- package/dist/config/validator.d.ts +0 -6
- package/dist/config/writer.d.ts +0 -3
- package/dist/index.d.ts +0 -22
- package/dist/info/default_commands.json +0 -29
- package/dist/logger.d.ts +0 -41
- package/dist/main.d.ts +0 -1
- package/dist/omegga/auth.d.ts +0 -9
- package/dist/omegga/commandInjector.d.ts +0 -35
- package/dist/omegga/index.d.ts +0 -7
- package/dist/omegga/logWrangler.d.ts +0 -32
- package/dist/omegga/matchers/auth.d.ts +0 -10
- package/dist/omegga/matchers/chat.d.ts +0 -10
- package/dist/omegga/matchers/command.d.ts +0 -7
- package/dist/omegga/matchers/exit.d.ts +0 -3
- package/dist/omegga/matchers/index.d.ts +0 -3
- package/dist/omegga/matchers/init.d.ts +0 -3
- package/dist/omegga/matchers/interact.d.ts +0 -4
- package/dist/omegga/matchers/join.d.ts +0 -4
- package/dist/omegga/matchers/leave.d.ts +0 -4
- package/dist/omegga/matchers/mapChange.d.ts +0 -3
- package/dist/omegga/matchers/minigameJoin.d.ts +0 -9
- package/dist/omegga/matchers/types.d.ts +0 -5
- package/dist/omegga/matchers/types.js +0 -3
- package/dist/omegga/matchers/types.js.map +0 -1
- package/dist/omegga/matchers/version.d.ts +0 -3
- package/dist/omegga/player.d.ts +0 -81
- package/dist/omegga/plugin/interface.d.ts +0 -30
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.d.ts +0 -23
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.d.ts +0 -145
- package/dist/omegga/plugin/plugin_node_safe/worker.d.ts +0 -1
- package/dist/omegga/plugin/plugin_node_safe/worker.js +0 -367
- package/dist/omegga/plugin/plugin_node_safe/worker.js.map +0 -1
- package/dist/omegga/plugin/plugin_node_safe.d.ts +0 -23
- package/dist/omegga/plugin/plugin_node_unsafe.d.ts +0 -13
- package/dist/omegga/plugin.d.ts +0 -63
- package/dist/omegga/server.d.ts +0 -166
- package/dist/omegga/types.d.ts +0 -49
- package/dist/omegga/types.js +0 -3
- package/dist/omegga/types.js.map +0 -1
- package/dist/omegga/wrapper.d.ts +0 -32
- package/dist/plugin.d.ts +0 -916
- package/dist/softconfig.d.ts +0 -67
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/updater/index.d.ts +0 -1
- package/dist/updater/index.js +0 -10
- package/dist/updater/index.js.map +0 -1
- package/dist/updater/steam.d.ts +0 -52
- package/dist/util/brdb.d.ts +0 -31
- package/dist/util/brick/checkBounds.d.ts +0 -8
- package/dist/util/brick/constants.d.ts +0 -18
- package/dist/util/brick/displayName.d.ts +0 -7
- package/dist/util/brick/getBounds.d.ts +0 -5
- package/dist/util/brick/getBrickSize.d.ts +0 -3
- package/dist/util/brick/getScaleAxis.d.ts +0 -3
- package/dist/util/brick/index.d.ts +0 -14
- package/dist/util/brick/rotate.d.ts +0 -16
- package/dist/util/brick/setOwnership.d.ts +0 -12
- package/dist/util/chat.d.ts +0 -23
- package/dist/util/color.d.ts +0 -13
- package/dist/util/file.d.ts +0 -5
- package/dist/util/index.d.ts +0 -183
- package/dist/util/map.d.ts +0 -6
- package/dist/util/pattern.d.ts +0 -1
- package/dist/util/time.d.ts +0 -39
- package/dist/util/uuid.d.ts +0 -3
- package/dist/util/wsl.d.ts +0 -2
- package/dist/version.d.ts +0 -2
- package/dist/webserver/backend/api.d.ts +0 -115
- package/dist/webserver/backend/calendar.d.ts +0 -5
- package/dist/webserver/backend/database.d.ts +0 -150
- package/dist/webserver/backend/index.d.ts +0 -30
- package/dist/webserver/backend/metrics.d.ts +0 -3
- package/dist/webserver/backend/types.d.ts +0 -114
- package/dist/webserver/backend/types.js +0 -3
- package/dist/webserver/backend/types.js.map +0 -1
- package/dist/webserver/backend/util.d.ts +0 -2
- package/dist/webserver/index.d.ts +0 -2
- package/dist/webserver/index.js +0 -9
- package/dist/webserver/index.js.map +0 -1
|
@@ -1,635 +1,585 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const nedb_promises_1 = __importDefault(require("nedb-promises"));
|
|
13
|
-
const path_1 = __importDefault(require("path"));
|
|
14
|
-
const calendar_1 = __importDefault(require("./calendar"));
|
|
15
|
-
// TODO: online users graph
|
|
16
|
-
// TODO: player online times
|
|
17
|
-
// TODO: bricks over time graph
|
|
18
|
-
// TODO: minute server status for metrics
|
|
19
|
-
// TODO: chat messages per min/hour/day check
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const softconfig = require("../../softconfig.js");
|
|
4
|
+
const pattern = require("../../util/pattern.js");
|
|
5
|
+
const time = require("../../util/time.js");
|
|
6
|
+
const bcrypt = require("bcryptjs");
|
|
7
|
+
const chokidar = require("chokidar");
|
|
8
|
+
const EventEmitter = require("events");
|
|
9
|
+
const Datastore = require("nedb-promises");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const calendar = require("./calendar.js");
|
|
20
12
|
let serverInstance;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Database extends
|
|
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
|
-
upgrade: async (_store) => { }, // upgrade function (does not include updating version)
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
};
|
|
87
|
-
// loop through all stores to find if any need version upgrades
|
|
88
|
-
await Promise.all(Object.entries(this.stores).map(async ([name, store]) => {
|
|
89
|
-
const versionEntry = await store.findOne({
|
|
90
|
-
type: 'storeVersion',
|
|
91
|
-
});
|
|
92
|
-
const expected = storeVersions[name];
|
|
93
|
-
// if the version was not found, insert it
|
|
94
|
-
if (!versionEntry) {
|
|
95
|
-
store.insert({ type: 'storeVersion', version: expected });
|
|
96
|
-
// if the version was not what was expected
|
|
97
|
-
}
|
|
98
|
-
else if (expected !== versionEntry.version) {
|
|
99
|
-
// while the version is below the expected version
|
|
100
|
-
let { version } = versionEntry;
|
|
101
|
-
for (; version < expected; version++) {
|
|
102
|
-
// find an available migration
|
|
103
|
-
const migration = migrations[name].find(v => v.version === version);
|
|
104
|
-
// no migration found, ignore
|
|
105
|
-
if (!migration)
|
|
106
|
-
break;
|
|
107
|
-
// run the upgrade
|
|
108
|
-
migration.upgrade(store);
|
|
109
|
-
}
|
|
110
|
-
// update the stored version
|
|
111
|
-
await store.update({ _id: versionEntry._id }, { version });
|
|
112
|
-
}
|
|
113
|
-
}));
|
|
114
|
-
}
|
|
115
|
-
// get the running instance id of this omegga
|
|
116
|
-
async getInstanceId() {
|
|
117
|
-
if (serverInstance)
|
|
118
|
-
return serverInstance._id;
|
|
119
|
-
const doc = await this.stores.server.insert({
|
|
120
|
-
type: 'app:start',
|
|
121
|
-
date: Date.now(),
|
|
122
|
-
});
|
|
123
|
-
serverInstance = doc;
|
|
124
|
-
// create a calendar of all previous chat messages
|
|
125
|
-
const dates = (await this.stores.chat.find({ type: 'chat' })).map(c => c.created);
|
|
126
|
-
for (const d of dates) {
|
|
127
|
-
this.calendar.addDate(d);
|
|
13
|
+
const createPunchcard = () => Array.from({ length: 7 }).map(
|
|
14
|
+
() => Array.from({ length: 24 }).fill(0)
|
|
15
|
+
);
|
|
16
|
+
class Database extends EventEmitter {
|
|
17
|
+
constructor(options, omegga) {
|
|
18
|
+
super();
|
|
19
|
+
this.options = options;
|
|
20
|
+
this.omegga = omegga;
|
|
21
|
+
this.calendar = new calendar.default();
|
|
22
|
+
const dbOpts = {
|
|
23
|
+
autoload: true,
|
|
24
|
+
// case insensitive string comparison
|
|
25
|
+
compareStrings: (a, b) => a.localeCompare(b, "en", { ignorePunctuation: true })
|
|
26
|
+
};
|
|
27
|
+
this.stores = {
|
|
28
|
+
users: Datastore.create({
|
|
29
|
+
filename: path.join(omegga.dataPath, softconfig.default.USER_STORE),
|
|
30
|
+
...dbOpts
|
|
31
|
+
}),
|
|
32
|
+
chat: Datastore.create({
|
|
33
|
+
filename: path.join(omegga.dataPath, softconfig.default.CHAT_STORE),
|
|
34
|
+
...dbOpts
|
|
35
|
+
}),
|
|
36
|
+
players: Datastore.create({
|
|
37
|
+
filename: path.join(omegga.dataPath, softconfig.default.PLAYER_STORE),
|
|
38
|
+
...dbOpts
|
|
39
|
+
}),
|
|
40
|
+
status: Datastore.create({
|
|
41
|
+
filename: path.join(omegga.dataPath, softconfig.default.STATUS_STORE),
|
|
42
|
+
...dbOpts
|
|
43
|
+
}),
|
|
44
|
+
server: Datastore.create({
|
|
45
|
+
filename: path.join(omegga.dataPath, softconfig.default.SERVER_STORE),
|
|
46
|
+
...dbOpts
|
|
47
|
+
})
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// make sure all the databases have valid store versions
|
|
51
|
+
async doMigrations() {
|
|
52
|
+
const storeVersions = {
|
|
53
|
+
users: 1,
|
|
54
|
+
chat: 1,
|
|
55
|
+
players: 1,
|
|
56
|
+
status: 1,
|
|
57
|
+
server: 1,
|
|
58
|
+
// example version
|
|
59
|
+
dummy: 10
|
|
60
|
+
};
|
|
61
|
+
const migrations = {
|
|
62
|
+
users: [],
|
|
63
|
+
chat: [],
|
|
64
|
+
players: [],
|
|
65
|
+
status: [],
|
|
66
|
+
server: [],
|
|
67
|
+
// example migration list (all version upgrades go up by 1)
|
|
68
|
+
dummy: [
|
|
69
|
+
{
|
|
70
|
+
version: 1,
|
|
71
|
+
// target version
|
|
72
|
+
upgrade: async (_store) => {
|
|
73
|
+
}
|
|
74
|
+
// upgrade function (does not include updating version)
|
|
128
75
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}, 500));
|
|
136
|
-
setTimeout(this.syncBanList.bind(this), 500);
|
|
137
|
-
const handleKick = (kicked, kicker, reason) => {
|
|
138
|
-
// time the event listener should expire
|
|
139
|
-
const eventExpire = Date.now() + 100;
|
|
140
|
-
// detect a single leave
|
|
141
|
-
this.omegga.once('leave', async (leavingPlayer) => {
|
|
142
|
-
const now = Date.now();
|
|
143
|
-
// if a player leaves more than 100ms from the kick command, it's bugged
|
|
144
|
-
if (now > eventExpire)
|
|
145
|
-
return;
|
|
146
|
-
if (leavingPlayer.id === kicked.id) {
|
|
147
|
-
const entry = {
|
|
148
|
-
type: 'kickHistory',
|
|
149
|
-
kicked: kicked.id,
|
|
150
|
-
kickerId: kicker.id,
|
|
151
|
-
created: now,
|
|
152
|
-
reason,
|
|
153
|
-
};
|
|
154
|
-
// depending on implementation, this could potentially be a kick event
|
|
155
|
-
await this.stores.players.update(entry, { $set: entry }, { upsert: true });
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
// for a5 is based on the chat event
|
|
160
|
-
this.omegga.on('kick', (kicked, kicker, reason) => {
|
|
161
|
-
const kickedPlayer = this.omegga.findPlayerByName(kicked);
|
|
162
|
-
const kickerPlayer = this.omegga.findPlayerByName(kicker);
|
|
163
|
-
// couldn't find kicked or kicker player
|
|
164
|
-
if (!kickedPlayer || !kickerPlayer)
|
|
165
|
-
return;
|
|
166
|
-
handleKick(kickedPlayer, kickerPlayer, reason);
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
await Promise.all(
|
|
79
|
+
Object.entries(this.stores).map(async ([name, store]) => {
|
|
80
|
+
const versionEntry = await store.findOne({
|
|
81
|
+
type: "storeVersion"
|
|
167
82
|
});
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
type: 'banHistory',
|
|
180
|
-
banned,
|
|
181
|
-
bannerId: banList[banned].bannerId,
|
|
182
|
-
created: (0, time_1.parseBrickadiaTime)(banList[banned].created),
|
|
183
|
-
expires: (0, time_1.parseBrickadiaTime)(banList[banned].expires),
|
|
184
|
-
reason: banList[banned].reason,
|
|
185
|
-
};
|
|
186
|
-
this.stores.players.update(entry, { $set: entry }, { upsert: true });
|
|
83
|
+
const expected = storeVersions[name];
|
|
84
|
+
if (!versionEntry) {
|
|
85
|
+
store.insert({ type: "storeVersion", version: expected });
|
|
86
|
+
} else if (expected !== versionEntry.version) {
|
|
87
|
+
let { version } = versionEntry;
|
|
88
|
+
for (; version < expected; version++) {
|
|
89
|
+
const migration = migrations[name].find((v) => v.version === version);
|
|
90
|
+
if (!migration) break;
|
|
91
|
+
migration.upgrade(store);
|
|
92
|
+
}
|
|
93
|
+
await store.update({ _id: versionEntry._id }, { version });
|
|
187
94
|
}
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
// get the running instance id of this omegga
|
|
99
|
+
async getInstanceId() {
|
|
100
|
+
if (serverInstance) return serverInstance._id;
|
|
101
|
+
const doc = await this.stores.server.insert({
|
|
102
|
+
type: "app:start",
|
|
103
|
+
date: Date.now()
|
|
104
|
+
});
|
|
105
|
+
serverInstance = doc;
|
|
106
|
+
const dates = (await this.stores.chat.find({ type: "chat" })).map((c) => c.created);
|
|
107
|
+
for (const d of dates) {
|
|
108
|
+
this.calendar.addDate(d);
|
|
188
109
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return (await this.stores.users.count({ type: 'user', username })) > 0;
|
|
220
|
-
}
|
|
221
|
-
// create a regular user account
|
|
222
|
-
async createUser(username, password) {
|
|
223
|
-
if (await this.userExists(username))
|
|
224
|
-
throw new Error('user already exists');
|
|
225
|
-
const hash = await this.hash(password);
|
|
226
|
-
// create an owner user
|
|
227
|
-
const user = this.stores.users.insert({
|
|
228
|
-
// this is a user
|
|
229
|
-
type: 'user',
|
|
230
|
-
created: Date.now(),
|
|
231
|
-
lastOnline: 0,
|
|
232
|
-
// credentials
|
|
233
|
-
username,
|
|
234
|
-
hash,
|
|
235
|
-
// permissions
|
|
236
|
-
isOwner: false,
|
|
237
|
-
roles: [],
|
|
238
|
-
// brickadia player uuid
|
|
239
|
-
playerId: '',
|
|
240
|
-
});
|
|
241
|
-
return user;
|
|
242
|
-
}
|
|
243
|
-
// set a user's password
|
|
244
|
-
async userPasswd(username, password) {
|
|
245
|
-
const hash = await this.hash(password);
|
|
246
|
-
if (!this.userExists(username))
|
|
247
|
-
throw new Error('user does not exist');
|
|
248
|
-
await this.stores.users.update({ type: 'user', username }, { $set: { hash } });
|
|
249
|
-
}
|
|
250
|
-
// get a user from credentials
|
|
251
|
-
async authUser(username, password) {
|
|
252
|
-
const user = await this.stores.users.findOne({ username });
|
|
253
|
-
// user not found
|
|
254
|
-
if (!user || user.isBanned)
|
|
255
|
-
return null;
|
|
256
|
-
// make sure the user's password hash is valid
|
|
257
|
-
if (await bcryptjs_1.default.compare(password, user.hash)) {
|
|
258
|
-
// update last online status
|
|
259
|
-
await this.stores.users.update({ _id: user._id }, { $set: { lastOnline: Date.now() } });
|
|
260
|
-
return user;
|
|
110
|
+
const watcher = chokidar.watch(
|
|
111
|
+
path.join(this.omegga.configPath, "BanList.json"),
|
|
112
|
+
{ persistent: false }
|
|
113
|
+
);
|
|
114
|
+
watcher.on("add", () => setTimeout(this.syncBanList.bind(this), 500)).on(
|
|
115
|
+
"change",
|
|
116
|
+
() => setTimeout(() => {
|
|
117
|
+
this.syncBanList();
|
|
118
|
+
this.emit("update.bans");
|
|
119
|
+
}, 500)
|
|
120
|
+
);
|
|
121
|
+
setTimeout(this.syncBanList.bind(this), 500);
|
|
122
|
+
const handleKick = (kicked, kicker, reason) => {
|
|
123
|
+
const eventExpire = Date.now() + 100;
|
|
124
|
+
this.omegga.once("leave", async (leavingPlayer) => {
|
|
125
|
+
const now = Date.now();
|
|
126
|
+
if (now > eventExpire) return;
|
|
127
|
+
if (leavingPlayer.id === kicked.id) {
|
|
128
|
+
const entry = {
|
|
129
|
+
type: "kickHistory",
|
|
130
|
+
kicked: kicked.id,
|
|
131
|
+
kickerId: kicker.id,
|
|
132
|
+
created: now,
|
|
133
|
+
reason
|
|
134
|
+
};
|
|
135
|
+
await this.stores.players.update(
|
|
136
|
+
entry,
|
|
137
|
+
{ $set: entry },
|
|
138
|
+
{ upsert: true }
|
|
139
|
+
);
|
|
261
140
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
this.omegga.on("kick", (kicked, kicker, reason) => {
|
|
144
|
+
const kickedPlayer = this.omegga.findPlayerByName(kicked);
|
|
145
|
+
const kickerPlayer = this.omegga.findPlayerByName(kicker);
|
|
146
|
+
if (!kickedPlayer || !kickerPlayer) return;
|
|
147
|
+
handleKick(kickedPlayer, kickerPlayer, reason);
|
|
148
|
+
});
|
|
149
|
+
return doc._id;
|
|
150
|
+
}
|
|
151
|
+
// synchronize the ban list with the one in the database
|
|
152
|
+
syncBanList() {
|
|
153
|
+
const banList = this.omegga.getBanList()?.banList;
|
|
154
|
+
if (!banList) return;
|
|
155
|
+
for (const banned in banList) {
|
|
156
|
+
const entry = {
|
|
157
|
+
type: "banHistory",
|
|
158
|
+
banned,
|
|
159
|
+
bannerId: banList[banned].bannerId,
|
|
160
|
+
created: time.parseBrickadiaTime(banList[banned].created),
|
|
161
|
+
expires: time.parseBrickadiaTime(banList[banned].expires),
|
|
162
|
+
reason: banList[banned].reason
|
|
163
|
+
};
|
|
164
|
+
this.stores.players.update(entry, { $set: entry }, { upsert: true });
|
|
275
165
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
166
|
+
}
|
|
167
|
+
// determine if this user would be the first user (admin user)
|
|
168
|
+
async isFirstUser() {
|
|
169
|
+
return await this.stores.users.count({ type: "user" }) === 0;
|
|
170
|
+
}
|
|
171
|
+
// hash a password
|
|
172
|
+
async hash(password) {
|
|
173
|
+
return await bcrypt.hash(password, 10);
|
|
174
|
+
}
|
|
175
|
+
// create an admin user account, username can be blank (no password)
|
|
176
|
+
async createAdminUser(username, password) {
|
|
177
|
+
const hash = await this.hash(password);
|
|
178
|
+
const user = this.stores.users.insert({
|
|
179
|
+
// this is a user
|
|
180
|
+
type: "user",
|
|
181
|
+
created: Date.now(),
|
|
182
|
+
lastOnline: Date.now(),
|
|
183
|
+
// credentials
|
|
184
|
+
username,
|
|
185
|
+
hash,
|
|
186
|
+
// permissions
|
|
187
|
+
isOwner: true,
|
|
188
|
+
roles: [],
|
|
189
|
+
// brickadia player uuid
|
|
190
|
+
playerId: ""
|
|
191
|
+
});
|
|
192
|
+
return user;
|
|
193
|
+
}
|
|
194
|
+
// determine if a user with this name exists
|
|
195
|
+
async userExists(username) {
|
|
196
|
+
return await this.stores.users.count({ type: "user", username }) > 0;
|
|
197
|
+
}
|
|
198
|
+
// create a regular user account
|
|
199
|
+
async createUser(username, password) {
|
|
200
|
+
if (await this.userExists(username)) throw new Error("user already exists");
|
|
201
|
+
const hash = await this.hash(password);
|
|
202
|
+
const user = this.stores.users.insert({
|
|
203
|
+
// this is a user
|
|
204
|
+
type: "user",
|
|
205
|
+
created: Date.now(),
|
|
206
|
+
lastOnline: 0,
|
|
207
|
+
// credentials
|
|
208
|
+
username,
|
|
209
|
+
hash,
|
|
210
|
+
// permissions
|
|
211
|
+
isOwner: false,
|
|
212
|
+
roles: [],
|
|
213
|
+
// brickadia player uuid
|
|
214
|
+
playerId: ""
|
|
215
|
+
});
|
|
216
|
+
return user;
|
|
217
|
+
}
|
|
218
|
+
// set a user's password
|
|
219
|
+
async userPasswd(username, password) {
|
|
220
|
+
const hash = await this.hash(password);
|
|
221
|
+
if (!this.userExists(username)) throw new Error("user does not exist");
|
|
222
|
+
await this.stores.users.update(
|
|
223
|
+
{ type: "user", username },
|
|
224
|
+
{ $set: { hash } }
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
// get a user from credentials
|
|
228
|
+
async authUser(username, password) {
|
|
229
|
+
const user = await this.stores.users.findOne({ username });
|
|
230
|
+
if (!user || user.isBanned) return null;
|
|
231
|
+
if (await bcrypt.compare(password, user.hash)) {
|
|
232
|
+
await this.stores.users.update(
|
|
233
|
+
{ _id: user._id },
|
|
234
|
+
{ $set: { lastOnline: Date.now() } }
|
|
235
|
+
);
|
|
236
|
+
return user;
|
|
280
237
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
};
|
|
344
|
-
// the query used for finding a specific player
|
|
345
|
-
const exactQuery = {
|
|
346
|
-
type: 'userHistory',
|
|
347
|
-
// only filter if there's a query
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
// find a user by object id
|
|
241
|
+
async findUserById(id) {
|
|
242
|
+
return await this.stores.users.findOne({
|
|
243
|
+
$or: [
|
|
244
|
+
// the owner has no username, so everyone is the owner
|
|
245
|
+
{ type: "user", username: "", isOwner: true },
|
|
246
|
+
// the user exists and has an id
|
|
247
|
+
{ type: "user", _id: id }
|
|
248
|
+
]
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
// get a list of roles
|
|
252
|
+
// TODO: actually implement roles
|
|
253
|
+
getRoles() {
|
|
254
|
+
return this.stores.server.find({ type: "role" });
|
|
255
|
+
}
|
|
256
|
+
// add a chat message to the chat log store
|
|
257
|
+
async addChatLog(action, user, message) {
|
|
258
|
+
this.calendar.addDate(Date.now());
|
|
259
|
+
return await this.stores.chat.insert({
|
|
260
|
+
type: "chat",
|
|
261
|
+
created: Date.now(),
|
|
262
|
+
instanceId: await this.getInstanceId(),
|
|
263
|
+
action,
|
|
264
|
+
user,
|
|
265
|
+
...message ? { message } : {}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
// get recent chat activity
|
|
269
|
+
async getChats({
|
|
270
|
+
count = 50,
|
|
271
|
+
sameServer,
|
|
272
|
+
before,
|
|
273
|
+
after
|
|
274
|
+
} = {}) {
|
|
275
|
+
return await this.stores.chat.find({
|
|
276
|
+
type: "chat",
|
|
277
|
+
...sameServer ? { instanceId: await this.getInstanceId() } : {},
|
|
278
|
+
created: before ? { $lt: before } : after ? { $gt: after } : { $lt: Date.now() }
|
|
279
|
+
}).sort({ created: !before && after ? 1 : -1 }).limit(count).exec();
|
|
280
|
+
}
|
|
281
|
+
// get paginated players
|
|
282
|
+
async getPlayers({
|
|
283
|
+
count = 50,
|
|
284
|
+
search = "",
|
|
285
|
+
page = 0,
|
|
286
|
+
sort = "name",
|
|
287
|
+
direction = "1",
|
|
288
|
+
limitId = void 0
|
|
289
|
+
} = {}) {
|
|
290
|
+
const pattern$1 = pattern.explode(search);
|
|
291
|
+
const query = {
|
|
292
|
+
type: "userHistory",
|
|
293
|
+
// only filter if there's a query
|
|
294
|
+
$and: [
|
|
295
|
+
// if a limitId is passed in, the id must be in it
|
|
296
|
+
...limitId ? [{ id: { $in: limitId } }] : [],
|
|
297
|
+
// if there's a search, the search matches...
|
|
298
|
+
...search.length > 0 ? [
|
|
299
|
+
{
|
|
348
300
|
$or: [
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
.find(query)
|
|
362
|
-
// TODO: add other sorts and sort directions
|
|
363
|
-
.sort({ [sort]: direction })
|
|
364
|
-
.skip(count * page)
|
|
365
|
-
.limit(count)
|
|
366
|
-
.exec(),
|
|
367
|
-
// exact match detection
|
|
368
|
-
search.length > 0 && page === 0
|
|
369
|
-
? this.stores.players.find(exactQuery)
|
|
370
|
-
: [],
|
|
371
|
-
]);
|
|
372
|
-
// add exact matches to the beginning
|
|
373
|
-
if (exactResult.length > 0) {
|
|
374
|
-
// remove duplicates
|
|
375
|
-
for (const res of exactResult) {
|
|
376
|
-
const index = players.findIndex(p => p._id === res._id);
|
|
377
|
-
players.splice(index, 1);
|
|
378
|
-
}
|
|
379
|
-
// add results to the beginning
|
|
380
|
-
players.splice(0, 0, ...exactResult);
|
|
381
|
-
}
|
|
382
|
-
return {
|
|
383
|
-
pages: Math.ceil(total / count),
|
|
384
|
-
total,
|
|
385
|
-
players,
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
// get paginated users
|
|
389
|
-
async getUsers({ count = 50, search = '', page = 0, sort = 'name', direction = '1', } = {}) {
|
|
390
|
-
const pattern = (0, pattern_1.explode)(search);
|
|
391
|
-
// the query used for finding which players are available
|
|
392
|
-
const query = {
|
|
393
|
-
type: 'user',
|
|
394
|
-
// only filter if there's a query
|
|
395
|
-
...(search.length > 0
|
|
396
|
-
? {
|
|
397
|
-
$or: [
|
|
398
|
-
// id was pasted in
|
|
399
|
-
{ playerId: search },
|
|
400
|
-
// user's current name
|
|
401
|
-
{ name: { $regex: pattern } },
|
|
402
|
-
],
|
|
301
|
+
// id was pasted in
|
|
302
|
+
{ id: search },
|
|
303
|
+
// user's current name
|
|
304
|
+
{ name: { $regex: pattern$1 } },
|
|
305
|
+
{ displayName: { $regex: pattern$1 } },
|
|
306
|
+
// user's past name
|
|
307
|
+
{
|
|
308
|
+
nameHistory: { $elemMatch: { name: { $regex: pattern$1 } } }
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
nameHistory: {
|
|
312
|
+
$elemMatch: { displayName: { $regex: pattern$1 } }
|
|
403
313
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
.sort({ created: -1 })
|
|
435
|
-
.limit(25)
|
|
436
|
-
.exec(),
|
|
437
|
-
this.stores.players
|
|
438
|
-
.find({ type: 'note', id })
|
|
439
|
-
.sort({ created: -1 })
|
|
440
|
-
.limit(25)
|
|
441
|
-
.exec(),
|
|
442
|
-
]);
|
|
443
|
-
if (!player)
|
|
444
|
-
return null;
|
|
445
|
-
return { ...player, banHistory, kickHistory, notes };
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
] : []
|
|
318
|
+
]
|
|
319
|
+
};
|
|
320
|
+
const exactQuery = {
|
|
321
|
+
type: "userHistory",
|
|
322
|
+
// only filter if there's a query
|
|
323
|
+
$or: [
|
|
324
|
+
// id was pasted in
|
|
325
|
+
{ id: search },
|
|
326
|
+
// user's current name
|
|
327
|
+
{ name: search },
|
|
328
|
+
// user's current display name
|
|
329
|
+
{ displayName: search }
|
|
330
|
+
]
|
|
331
|
+
};
|
|
332
|
+
const [total, players, exactResult] = await Promise.all([
|
|
333
|
+
this.stores.players.count(query),
|
|
334
|
+
this.stores.players.find(query).sort({ [sort]: direction }).skip(count * page).limit(count).exec(),
|
|
335
|
+
// exact match detection
|
|
336
|
+
search.length > 0 && page === 0 ? this.stores.players.find(exactQuery) : []
|
|
337
|
+
]);
|
|
338
|
+
if (exactResult.length > 0) {
|
|
339
|
+
for (const res of exactResult) {
|
|
340
|
+
const index = players.findIndex((p) => p._id === res._id);
|
|
341
|
+
players.splice(index, 1);
|
|
342
|
+
}
|
|
343
|
+
players.splice(0, 0, ...exactResult);
|
|
446
344
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
345
|
+
return {
|
|
346
|
+
pages: Math.ceil(total / count),
|
|
347
|
+
total,
|
|
348
|
+
players
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
// get paginated users
|
|
352
|
+
async getUsers({
|
|
353
|
+
count = 50,
|
|
354
|
+
search = "",
|
|
355
|
+
page = 0,
|
|
356
|
+
sort = "name",
|
|
357
|
+
direction = "1"
|
|
358
|
+
} = {}) {
|
|
359
|
+
const pattern$1 = pattern.explode(search);
|
|
360
|
+
const query = {
|
|
361
|
+
type: "user",
|
|
362
|
+
// only filter if there's a query
|
|
363
|
+
...search.length > 0 ? {
|
|
364
|
+
$or: [
|
|
365
|
+
// id was pasted in
|
|
366
|
+
{ playerId: search },
|
|
367
|
+
// user's current name
|
|
368
|
+
{ name: { $regex: pattern$1 } }
|
|
369
|
+
]
|
|
370
|
+
} : {}
|
|
371
|
+
};
|
|
372
|
+
const [total, users] = await Promise.all([
|
|
373
|
+
this.stores.users.count(query),
|
|
374
|
+
this.stores.users.find(query).sort({ [sort]: direction }).skip(count * page).limit(count).exec()
|
|
375
|
+
]);
|
|
376
|
+
return {
|
|
377
|
+
pages: Math.ceil(total / count),
|
|
378
|
+
total,
|
|
379
|
+
users
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
// get an individual player, ban and kick history, and notes
|
|
383
|
+
async getPlayer(id) {
|
|
384
|
+
const [player, banHistory, kickHistory, notes] = await Promise.all([
|
|
385
|
+
this.stores.players.findOne({ type: "userHistory", id }),
|
|
386
|
+
this.stores.players.find({ type: "banHistory", banned: id }).sort({ created: -1 }).limit(25).exec(),
|
|
387
|
+
this.stores.players.find({ type: "kickHistory", kicked: id }).sort({ created: -1 }).limit(25).exec(),
|
|
388
|
+
this.stores.players.find({ type: "note", id }).sort({ created: -1 }).limit(25).exec()
|
|
389
|
+
]);
|
|
390
|
+
if (!player) return null;
|
|
391
|
+
return { ...player, banHistory, kickHistory, notes };
|
|
392
|
+
}
|
|
393
|
+
// add a user to the visit history, returns true if this is a first visit
|
|
394
|
+
async addVisit(user) {
|
|
395
|
+
const existing = await this.stores.players.findOne({
|
|
396
|
+
type: "userHistory",
|
|
397
|
+
id: user.id
|
|
398
|
+
});
|
|
399
|
+
const now = Date.now();
|
|
400
|
+
const instanceId = await this.getInstanceId();
|
|
401
|
+
if (!existing) {
|
|
402
|
+
await this.stores.players.insert({
|
|
403
|
+
type: "userHistory",
|
|
404
|
+
// base brickadia user info
|
|
405
|
+
id: user.id,
|
|
406
|
+
name: user.name,
|
|
407
|
+
displayName: user.displayName,
|
|
408
|
+
// list of names and when they were first used
|
|
409
|
+
nameHistory: [
|
|
410
|
+
{ name: user.name, displayName: user.displayName, date: now }
|
|
411
|
+
],
|
|
412
|
+
// list of ips this player has been on
|
|
413
|
+
ips: [],
|
|
414
|
+
// first time player was seen
|
|
415
|
+
created: now,
|
|
416
|
+
// last time player was seen
|
|
417
|
+
lastSeen: now,
|
|
418
|
+
// last server this player has been on
|
|
419
|
+
lastInstanceId: instanceId,
|
|
420
|
+
// number of status checks this player has observed
|
|
421
|
+
heartbeats: 0,
|
|
422
|
+
// number of sessions (at least an hour apart) this player has had
|
|
423
|
+
sessions: 1,
|
|
424
|
+
// number of instances (times omegga was started) this player has joined
|
|
425
|
+
instances: 1
|
|
426
|
+
});
|
|
427
|
+
return true;
|
|
428
|
+
} else {
|
|
429
|
+
await this.stores.players.update(
|
|
430
|
+
{ _id: existing._id },
|
|
431
|
+
{
|
|
432
|
+
$inc: {
|
|
433
|
+
// increment number of sessions if the player hasn't been seen for an hour
|
|
434
|
+
sessions: existing.lastSeen < now - 60 * 60 * 1e3 ? 1 : 0,
|
|
435
|
+
// increment the number of instances this player has joined
|
|
436
|
+
instances: existing.lastInstanceId === instanceId ? 1 : 0
|
|
437
|
+
},
|
|
438
|
+
$set: {
|
|
439
|
+
// update last seen time and user name
|
|
440
|
+
lastSeen: now,
|
|
441
|
+
name: user.name,
|
|
442
|
+
displayName: user.displayName,
|
|
443
|
+
// set the last joined instance
|
|
444
|
+
lastInstanceId: instanceId
|
|
445
|
+
},
|
|
446
|
+
// add the name to the history if it was not already in it
|
|
447
|
+
...existing.nameHistory.some(
|
|
448
|
+
(h) => h.name === user.name && h.displayName === user.displayName
|
|
449
|
+
) ? {} : {
|
|
450
|
+
$addToSet: {
|
|
451
|
+
nameHistory: {
|
|
463
452
|
name: user.name,
|
|
464
453
|
displayName: user.displayName,
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
// list of ips this player has been on
|
|
470
|
-
ips: [],
|
|
471
|
-
// first time player was seen
|
|
472
|
-
created: now,
|
|
473
|
-
// last time player was seen
|
|
474
|
-
lastSeen: now,
|
|
475
|
-
// last server this player has been on
|
|
476
|
-
lastInstanceId: instanceId,
|
|
477
|
-
// number of status checks this player has observed
|
|
478
|
-
heartbeats: 0,
|
|
479
|
-
// number of sessions (at least an hour apart) this player has had
|
|
480
|
-
sessions: 1,
|
|
481
|
-
// number of instances (times omegga was started) this player has joined
|
|
482
|
-
instances: 1,
|
|
483
|
-
});
|
|
484
|
-
return true;
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
await this.stores.players.update({ _id: existing._id }, {
|
|
488
|
-
$inc: {
|
|
489
|
-
// increment number of sessions if the player hasn't been seen for an hour
|
|
490
|
-
sessions: existing.lastSeen < now - 60 * 60 * 1000 ? 1 : 0,
|
|
491
|
-
// increment the number of instances this player has joined
|
|
492
|
-
instances: existing.lastInstanceId === instanceId ? 1 : 0,
|
|
493
|
-
},
|
|
494
|
-
$set: {
|
|
495
|
-
// update last seen time and user name
|
|
496
|
-
lastSeen: now,
|
|
497
|
-
name: user.name,
|
|
498
|
-
displayName: user.displayName,
|
|
499
|
-
// set the last joined instance
|
|
500
|
-
lastInstanceId: instanceId,
|
|
501
|
-
},
|
|
502
|
-
// add the name to the history if it was not already in it
|
|
503
|
-
...(existing.nameHistory.some(h => h.name === user.name && h.displayName === user.displayName)
|
|
504
|
-
? {}
|
|
505
|
-
: {
|
|
506
|
-
$addToSet: {
|
|
507
|
-
nameHistory: {
|
|
508
|
-
name: user.name,
|
|
509
|
-
displayName: user.displayName,
|
|
510
|
-
date: now,
|
|
511
|
-
},
|
|
512
|
-
},
|
|
513
|
-
}),
|
|
514
|
-
});
|
|
515
|
-
return false;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
// use data from minutely heartbeats to fuel metrics
|
|
519
|
-
async addHeartbeat(data) {
|
|
520
|
-
const now = Date.now();
|
|
521
|
-
// add the heartbeat to the server status store
|
|
522
|
-
await this.stores.status.insert({
|
|
523
|
-
type: 'heartbeat',
|
|
524
|
-
created: now,
|
|
525
|
-
bricks: data.bricks,
|
|
526
|
-
players: data.players,
|
|
527
|
-
});
|
|
528
|
-
// update player heartbeats and last seens
|
|
529
|
-
await this.stores.players.update({
|
|
530
|
-
// all players in the status update
|
|
531
|
-
id: { $in: data.players },
|
|
532
|
-
}, {
|
|
533
|
-
// update last seen
|
|
534
|
-
$set: { lastSeen: now },
|
|
535
|
-
// increment heartbeats
|
|
536
|
-
$inc: { heartbeats: 1 },
|
|
537
|
-
}, { multi: true });
|
|
538
|
-
// get all players in the status update
|
|
539
|
-
const players = await this.stores.players.find({
|
|
540
|
-
id: { $in: data.players },
|
|
541
|
-
});
|
|
542
|
-
await Promise.all(players
|
|
543
|
-
// find players without the discovered ip
|
|
544
|
-
.filter(p => !(p.ips || []).includes(data.ips[p.id]))
|
|
545
|
-
// insert the IP into the player's ip list
|
|
546
|
-
.map(p => this.stores.players.update({ _id: p._id }, {
|
|
547
|
-
$addToSet: { ips: data.ips[p.id] },
|
|
548
|
-
})));
|
|
549
|
-
}
|
|
550
|
-
async getAutoRestartConfig() {
|
|
551
|
-
var _a, _b, _c;
|
|
552
|
-
let config = await this.stores.server.findOne({
|
|
553
|
-
type: 'autoRestartConfig',
|
|
554
|
-
});
|
|
555
|
-
if (!config) {
|
|
556
|
-
config = await this.stores.server.insert({
|
|
557
|
-
type: 'autoRestartConfig',
|
|
558
|
-
maxUptime: 48,
|
|
559
|
-
maxUptimeEnabled: false,
|
|
560
|
-
emptyUptime: 24,
|
|
561
|
-
emptyUptimeEnabled: false,
|
|
562
|
-
dailyHour: 2,
|
|
563
|
-
dailyHourEnabled: false,
|
|
564
|
-
autoUpdateEnabled: true,
|
|
565
|
-
autoUpdateIntervalMins: 60,
|
|
566
|
-
announcementEnabled: true,
|
|
567
|
-
playersEnabled: true,
|
|
568
|
-
saveWorld: true,
|
|
569
|
-
});
|
|
454
|
+
date: now
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
570
458
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
(_c = config.saveWorld) !== null && _c !== void 0 ? _c : (config.saveWorld = true);
|
|
574
|
-
return config;
|
|
459
|
+
);
|
|
460
|
+
return false;
|
|
575
461
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
462
|
+
}
|
|
463
|
+
// use data from minutely heartbeats to fuel metrics
|
|
464
|
+
async addHeartbeat(data) {
|
|
465
|
+
const now = Date.now();
|
|
466
|
+
await this.stores.status.insert({
|
|
467
|
+
type: "heartbeat",
|
|
468
|
+
created: now,
|
|
469
|
+
bricks: data.bricks,
|
|
470
|
+
players: data.players
|
|
471
|
+
});
|
|
472
|
+
await this.stores.players.update(
|
|
473
|
+
{
|
|
474
|
+
// all players in the status update
|
|
475
|
+
id: { $in: data.players }
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
// update last seen
|
|
479
|
+
$set: { lastSeen: now },
|
|
480
|
+
// increment heartbeats
|
|
481
|
+
$inc: { heartbeats: 1 }
|
|
482
|
+
},
|
|
483
|
+
{ multi: true }
|
|
484
|
+
);
|
|
485
|
+
const players = await this.stores.players.find({
|
|
486
|
+
id: { $in: data.players }
|
|
487
|
+
});
|
|
488
|
+
await Promise.all(
|
|
489
|
+
players.filter((p) => !(p.ips || []).includes(data.ips[p.id])).map(
|
|
490
|
+
(p) => this.stores.players.update(
|
|
491
|
+
{ _id: p._id },
|
|
492
|
+
{
|
|
493
|
+
$addToSet: { ips: data.ips[p.id] }
|
|
494
|
+
}
|
|
495
|
+
)
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
async getAutoRestartConfig() {
|
|
500
|
+
let config = await this.stores.server.findOne({
|
|
501
|
+
type: "autoRestartConfig"
|
|
502
|
+
});
|
|
503
|
+
if (!config) {
|
|
504
|
+
config = await this.stores.server.insert({
|
|
505
|
+
type: "autoRestartConfig",
|
|
506
|
+
maxUptime: 48,
|
|
507
|
+
maxUptimeEnabled: false,
|
|
508
|
+
emptyUptime: 24,
|
|
509
|
+
emptyUptimeEnabled: false,
|
|
510
|
+
dailyHour: 2,
|
|
511
|
+
dailyHourEnabled: false,
|
|
512
|
+
autoUpdateEnabled: true,
|
|
513
|
+
autoUpdateIntervalMins: 60,
|
|
514
|
+
announcementEnabled: true,
|
|
515
|
+
playersEnabled: true,
|
|
516
|
+
saveWorld: true
|
|
517
|
+
});
|
|
588
518
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
// insert it
|
|
610
|
-
await this.stores.status.insert({
|
|
611
|
-
type: 'punchcard',
|
|
612
|
-
kind: 'playerCount',
|
|
613
|
-
created: time,
|
|
614
|
-
updated: time,
|
|
615
|
-
month,
|
|
616
|
-
year,
|
|
617
|
-
punchcard,
|
|
618
|
-
});
|
|
619
|
-
// if the card exists, check if it was already updated this hour
|
|
519
|
+
config.autoUpdateEnabled ??= true;
|
|
520
|
+
config.autoUpdateIntervalMins ??= 60;
|
|
521
|
+
config.saveWorld ??= true;
|
|
522
|
+
return config;
|
|
523
|
+
}
|
|
524
|
+
async setAutoRestartConfig(config) {
|
|
525
|
+
config.maxUptime = Math.round(Math.max(1, Math.min(config.maxUptime, 168)));
|
|
526
|
+
config.emptyUptime = Math.round(
|
|
527
|
+
Math.max(1, Math.min(config.emptyUptime, 168))
|
|
528
|
+
);
|
|
529
|
+
config.dailyHour = Math.round(Math.max(0, Math.min(config.dailyHour, 23)));
|
|
530
|
+
config.autoUpdateIntervalMins = Math.round(
|
|
531
|
+
Math.max(10, Math.min(config.autoUpdateIntervalMins ?? 60, Infinity))
|
|
532
|
+
);
|
|
533
|
+
config.autoUpdateEnabled ??= true;
|
|
534
|
+
await this.stores.server.update(
|
|
535
|
+
{ type: "autoRestartConfig" },
|
|
536
|
+
{
|
|
537
|
+
$set: {
|
|
538
|
+
...config
|
|
620
539
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
540
|
+
},
|
|
541
|
+
{ upsert: false }
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
// update player online-time punchcard
|
|
545
|
+
async updatePlayerPunchcard(numNewPlayers) {
|
|
546
|
+
const now = /* @__PURE__ */ new Date();
|
|
547
|
+
const time2 = now.getTime();
|
|
548
|
+
const hour = now.getUTCHours();
|
|
549
|
+
const day = now.getUTCDay();
|
|
550
|
+
const month = now.getUTCMonth();
|
|
551
|
+
const year = now.getUTCFullYear();
|
|
552
|
+
const card = await this.stores.status.findOne({
|
|
553
|
+
type: "punchcard",
|
|
554
|
+
kind: "playerCount",
|
|
555
|
+
month,
|
|
556
|
+
year
|
|
557
|
+
});
|
|
558
|
+
if (!card) {
|
|
559
|
+
const punchcard = createPunchcard();
|
|
560
|
+
punchcard[day][hour] = numNewPlayers;
|
|
561
|
+
await this.stores.status.insert({
|
|
562
|
+
type: "punchcard",
|
|
563
|
+
kind: "playerCount",
|
|
564
|
+
created: time2,
|
|
565
|
+
updated: time2,
|
|
566
|
+
month,
|
|
567
|
+
year,
|
|
568
|
+
punchcard
|
|
569
|
+
});
|
|
570
|
+
} else {
|
|
571
|
+
card.punchcard[day][hour] += numNewPlayers;
|
|
572
|
+
await this.stores.status.update(
|
|
573
|
+
{ _id: card._id },
|
|
574
|
+
{
|
|
575
|
+
$set: {
|
|
576
|
+
punchcard: card.punchcard,
|
|
577
|
+
updated: time2
|
|
578
|
+
}
|
|
631
579
|
}
|
|
580
|
+
);
|
|
632
581
|
}
|
|
582
|
+
}
|
|
633
583
|
}
|
|
634
584
|
exports.default = Database;
|
|
635
|
-
//# sourceMappingURL=database.js.map
|
|
585
|
+
//# sourceMappingURL=database.js.map
|