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.
Files changed (255) hide show
  1. package/README.md +20 -1
  2. package/dist/brickadia/config.js +26 -90
  3. package/dist/brickadia/config.js.map +1 -1
  4. package/dist/brickadia/server.js +294 -293
  5. package/dist/brickadia/server.js.map +1 -1
  6. package/dist/cli/auth.js +149 -177
  7. package/dist/cli/auth.js.map +1 -1
  8. package/dist/cli/config.js +64 -66
  9. package/dist/cli/config.js.map +1 -1
  10. package/dist/cli/index.js +14 -14
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/cli/installer.js +37 -43
  13. package/dist/cli/installer.js.map +1 -1
  14. package/dist/cli/plugin.js +651 -682
  15. package/dist/cli/plugin.js.map +1 -1
  16. package/dist/cli/terminal.js +811 -733
  17. package/dist/cli/terminal.js.map +1 -1
  18. package/dist/config/formats/format_js.js +6 -6
  19. package/dist/config/formats/format_js.js.map +1 -1
  20. package/dist/config/formats/format_yml.js +7 -10
  21. package/dist/config/formats/format_yml.js.map +1 -1
  22. package/dist/config/index.js +46 -68
  23. package/dist/config/index.js.map +1 -1
  24. package/dist/config/reader.js +16 -27
  25. package/dist/config/reader.js.map +1 -1
  26. package/dist/config/validator.js +23 -25
  27. package/dist/config/validator.js.map +1 -1
  28. package/dist/config/writer.js +11 -21
  29. package/dist/config/writer.js.map +1 -1
  30. package/dist/index.js +18 -64
  31. package/dist/index.js.map +1 -1
  32. package/dist/info/default_commands.json.js +39 -0
  33. package/dist/info/default_commands.json.js.map +1 -0
  34. package/dist/logger.js +61 -60
  35. package/dist/logger.js.map +1 -1
  36. package/dist/main.js +424 -471
  37. package/dist/main.js.map +1 -1
  38. package/dist/omegga/auth.js +101 -148
  39. package/dist/omegga/auth.js.map +1 -1
  40. package/dist/omegga/commandInjector.js +261 -251
  41. package/dist/omegga/commandInjector.js.map +1 -1
  42. package/dist/omegga/index.js +14 -52
  43. package/dist/omegga/index.js.map +1 -1
  44. package/dist/omegga/logWrangler.js +224 -275
  45. package/dist/omegga/logWrangler.js.map +1 -1
  46. package/dist/omegga/matchers/auth.js +36 -50
  47. package/dist/omegga/matchers/auth.js.map +1 -1
  48. package/dist/omegga/matchers/chat.js +49 -71
  49. package/dist/omegga/matchers/chat.js.map +1 -1
  50. package/dist/omegga/matchers/command.js +25 -36
  51. package/dist/omegga/matchers/command.js.map +1 -1
  52. package/dist/omegga/matchers/exit.js +15 -18
  53. package/dist/omegga/matchers/exit.js.map +1 -1
  54. package/dist/omegga/matchers/index.js +26 -40
  55. package/dist/omegga/matchers/index.js.map +1 -1
  56. package/dist/omegga/matchers/init.js +20 -23
  57. package/dist/omegga/matchers/init.js.map +1 -1
  58. package/dist/omegga/matchers/interact.js +58 -64
  59. package/dist/omegga/matchers/interact.js.map +1 -1
  60. package/dist/omegga/matchers/join.js +74 -95
  61. package/dist/omegga/matchers/join.js.map +1 -1
  62. package/dist/omegga/matchers/leave.js +43 -56
  63. package/dist/omegga/matchers/leave.js.map +1 -1
  64. package/dist/omegga/matchers/mapChange.js +26 -35
  65. package/dist/omegga/matchers/mapChange.js.map +1 -1
  66. package/dist/omegga/matchers/minigameJoin.js +24 -31
  67. package/dist/omegga/matchers/minigameJoin.js.map +1 -1
  68. package/dist/omegga/matchers/version.js +42 -49
  69. package/dist/omegga/matchers/version.js.map +1 -1
  70. package/dist/omegga/player.js +527 -527
  71. package/dist/omegga/player.js.map +1 -1
  72. package/dist/omegga/plugin/interface.js +91 -98
  73. package/dist/omegga/plugin/interface.js.map +1 -1
  74. package/dist/omegga/plugin/plugin_jsonrpc_stdio.js +524 -429
  75. package/dist/omegga/plugin/plugin_jsonrpc_stdio.js.map +1 -1
  76. package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js +282 -294
  77. package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js.map +1 -1
  78. package/dist/omegga/plugin/plugin_node_safe.js +365 -393
  79. package/dist/omegga/plugin/plugin_node_safe.js.map +1 -1
  80. package/dist/omegga/plugin/plugin_node_unsafe.js +119 -179
  81. package/dist/omegga/plugin/plugin_node_unsafe.js.map +1 -1
  82. package/dist/omegga/plugin.js +402 -347
  83. package/dist/omegga/plugin.js.map +1 -1
  84. package/dist/omegga/server.js +742 -774
  85. package/dist/omegga/server.js.map +1 -1
  86. package/dist/omegga/wrapper.js +64 -91
  87. package/dist/omegga/wrapper.js.map +1 -1
  88. package/dist/plugin.js +11 -31
  89. package/dist/plugin.js.map +1 -1
  90. package/dist/softconfig.js +121 -100
  91. package/dist/softconfig.js.map +1 -1
  92. package/dist/updater/steam.js +97 -112
  93. package/dist/updater/steam.js.map +1 -1
  94. package/dist/util/brdb.js +496 -528
  95. package/dist/util/brdb.js.map +1 -1
  96. package/dist/util/brick/checkBounds.js +11 -15
  97. package/dist/util/brick/checkBounds.js.map +1 -1
  98. package/dist/util/brick/constants.js +723 -174
  99. package/dist/util/brick/constants.js.map +1 -1
  100. package/dist/util/brick/displayName.js +204 -211
  101. package/dist/util/brick/displayName.js.map +1 -1
  102. package/dist/util/brick/getBounds.js +29 -41
  103. package/dist/util/brick/getBounds.js.map +1 -1
  104. package/dist/util/brick/getBrickSize.js +6 -7
  105. package/dist/util/brick/getBrickSize.js.map +1 -1
  106. package/dist/util/brick/getScaleAxis.js +24 -30
  107. package/dist/util/brick/getScaleAxis.js.map +1 -1
  108. package/dist/util/brick/index.js +8 -29
  109. package/dist/util/brick/index.js.map +1 -1
  110. package/dist/util/brick/rotate.js +29 -34
  111. package/dist/util/brick/rotate.js.map +1 -1
  112. package/dist/util/brick/setOwnership.js +13 -19
  113. package/dist/util/brick/setOwnership.js.map +1 -1
  114. package/dist/util/chat.js +53 -44
  115. package/dist/util/chat.js.map +1 -1
  116. package/dist/util/color.js +112 -124
  117. package/dist/util/color.js.map +1 -1
  118. package/dist/util/file.js +54 -98
  119. package/dist/util/file.js.map +1 -1
  120. package/dist/util/index.js +84 -106
  121. package/dist/util/index.js.map +1 -1
  122. package/dist/util/map.js +18 -20
  123. package/dist/util/map.js.map +1 -1
  124. package/dist/util/pattern.js +6 -9
  125. package/dist/util/pattern.js.map +1 -1
  126. package/dist/util/time.js +31 -34
  127. package/dist/util/time.js.map +1 -1
  128. package/dist/util/uuid.js +10 -8
  129. package/dist/util/uuid.js.map +1 -1
  130. package/dist/util/wsl.js +19 -25
  131. package/dist/util/wsl.js.map +1 -1
  132. package/dist/version.js +7 -9
  133. package/dist/version.js.map +1 -1
  134. package/dist/webserver/backend/api.js +784 -874
  135. package/dist/webserver/backend/api.js.map +1 -1
  136. package/dist/webserver/backend/calendar.js +14 -17
  137. package/dist/webserver/backend/calendar.js.map +1 -1
  138. package/dist/webserver/backend/database.js +563 -613
  139. package/dist/webserver/backend/database.js.map +1 -1
  140. package/dist/webserver/backend/index.js +153 -191
  141. package/dist/webserver/backend/index.js.map +1 -1
  142. package/dist/webserver/backend/metrics.js +219 -248
  143. package/dist/webserver/backend/metrics.js.map +1 -1
  144. package/dist/webserver/backend/util.js +47 -68
  145. package/dist/webserver/backend/util.js.map +1 -1
  146. package/dist/worker.js +322 -0
  147. package/dist/worker.js.map +1 -0
  148. package/package.json +14 -10
  149. package/templates/safe-ts/omegga.d.ts +2 -2
  150. package/vite.backend.config.mts +46 -0
  151. package/vite.frontend.config.mts +58 -0
  152. package/vitest.backend.config.mts +7 -0
  153. package/dist/brickadia/config.d.ts +0 -3
  154. package/dist/brickadia/presets.d.ts +0 -65
  155. package/dist/brickadia/presets.js +0 -3
  156. package/dist/brickadia/presets.js.map +0 -1
  157. package/dist/brickadia/server.d.ts +0 -36
  158. package/dist/brickadia/types.d.ts +0 -45
  159. package/dist/brickadia/types.js +0 -3
  160. package/dist/brickadia/types.js.map +0 -1
  161. package/dist/cli/auth.d.ts +0 -26
  162. package/dist/cli/config.d.ts +0 -10
  163. package/dist/cli/index.d.ts +0 -30
  164. package/dist/cli/installer.d.ts +0 -1
  165. package/dist/cli/plugin.d.ts +0 -22
  166. package/dist/cli/terminal.d.ts +0 -25
  167. package/dist/config/authorizer.d.ts +0 -2
  168. package/dist/config/authorizer.js +0 -38
  169. package/dist/config/authorizer.js.map +0 -1
  170. package/dist/config/formats/format_js.d.ts +0 -3
  171. package/dist/config/formats/format_yml.d.ts +0 -3
  172. package/dist/config/index.d.ts +0 -18
  173. package/dist/config/reader.d.ts +0 -3
  174. package/dist/config/types.d.ts +0 -50
  175. package/dist/config/types.js +0 -3
  176. package/dist/config/types.js.map +0 -1
  177. package/dist/config/validator.d.ts +0 -6
  178. package/dist/config/writer.d.ts +0 -3
  179. package/dist/index.d.ts +0 -22
  180. package/dist/info/default_commands.json +0 -29
  181. package/dist/logger.d.ts +0 -41
  182. package/dist/main.d.ts +0 -1
  183. package/dist/omegga/auth.d.ts +0 -9
  184. package/dist/omegga/commandInjector.d.ts +0 -35
  185. package/dist/omegga/index.d.ts +0 -7
  186. package/dist/omegga/logWrangler.d.ts +0 -32
  187. package/dist/omegga/matchers/auth.d.ts +0 -10
  188. package/dist/omegga/matchers/chat.d.ts +0 -10
  189. package/dist/omegga/matchers/command.d.ts +0 -7
  190. package/dist/omegga/matchers/exit.d.ts +0 -3
  191. package/dist/omegga/matchers/index.d.ts +0 -3
  192. package/dist/omegga/matchers/init.d.ts +0 -3
  193. package/dist/omegga/matchers/interact.d.ts +0 -4
  194. package/dist/omegga/matchers/join.d.ts +0 -4
  195. package/dist/omegga/matchers/leave.d.ts +0 -4
  196. package/dist/omegga/matchers/mapChange.d.ts +0 -3
  197. package/dist/omegga/matchers/minigameJoin.d.ts +0 -9
  198. package/dist/omegga/matchers/types.d.ts +0 -5
  199. package/dist/omegga/matchers/types.js +0 -3
  200. package/dist/omegga/matchers/types.js.map +0 -1
  201. package/dist/omegga/matchers/version.d.ts +0 -3
  202. package/dist/omegga/player.d.ts +0 -81
  203. package/dist/omegga/plugin/interface.d.ts +0 -30
  204. package/dist/omegga/plugin/plugin_jsonrpc_stdio.d.ts +0 -23
  205. package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.d.ts +0 -145
  206. package/dist/omegga/plugin/plugin_node_safe/worker.d.ts +0 -1
  207. package/dist/omegga/plugin/plugin_node_safe/worker.js +0 -367
  208. package/dist/omegga/plugin/plugin_node_safe/worker.js.map +0 -1
  209. package/dist/omegga/plugin/plugin_node_safe.d.ts +0 -23
  210. package/dist/omegga/plugin/plugin_node_unsafe.d.ts +0 -13
  211. package/dist/omegga/plugin.d.ts +0 -63
  212. package/dist/omegga/server.d.ts +0 -166
  213. package/dist/omegga/types.d.ts +0 -49
  214. package/dist/omegga/types.js +0 -3
  215. package/dist/omegga/types.js.map +0 -1
  216. package/dist/omegga/wrapper.d.ts +0 -32
  217. package/dist/plugin.d.ts +0 -916
  218. package/dist/softconfig.d.ts +0 -67
  219. package/dist/tsconfig.tsbuildinfo +0 -1
  220. package/dist/updater/index.d.ts +0 -1
  221. package/dist/updater/index.js +0 -10
  222. package/dist/updater/index.js.map +0 -1
  223. package/dist/updater/steam.d.ts +0 -52
  224. package/dist/util/brdb.d.ts +0 -31
  225. package/dist/util/brick/checkBounds.d.ts +0 -8
  226. package/dist/util/brick/constants.d.ts +0 -18
  227. package/dist/util/brick/displayName.d.ts +0 -7
  228. package/dist/util/brick/getBounds.d.ts +0 -5
  229. package/dist/util/brick/getBrickSize.d.ts +0 -3
  230. package/dist/util/brick/getScaleAxis.d.ts +0 -3
  231. package/dist/util/brick/index.d.ts +0 -14
  232. package/dist/util/brick/rotate.d.ts +0 -16
  233. package/dist/util/brick/setOwnership.d.ts +0 -12
  234. package/dist/util/chat.d.ts +0 -23
  235. package/dist/util/color.d.ts +0 -13
  236. package/dist/util/file.d.ts +0 -5
  237. package/dist/util/index.d.ts +0 -183
  238. package/dist/util/map.d.ts +0 -6
  239. package/dist/util/pattern.d.ts +0 -1
  240. package/dist/util/time.d.ts +0 -39
  241. package/dist/util/uuid.d.ts +0 -3
  242. package/dist/util/wsl.d.ts +0 -2
  243. package/dist/version.d.ts +0 -2
  244. package/dist/webserver/backend/api.d.ts +0 -115
  245. package/dist/webserver/backend/calendar.d.ts +0 -5
  246. package/dist/webserver/backend/database.d.ts +0 -150
  247. package/dist/webserver/backend/index.d.ts +0 -30
  248. package/dist/webserver/backend/metrics.d.ts +0 -3
  249. package/dist/webserver/backend/types.d.ts +0 -114
  250. package/dist/webserver/backend/types.js +0 -3
  251. package/dist/webserver/backend/types.js.map +0 -1
  252. package/dist/webserver/backend/util.d.ts +0 -2
  253. package/dist/webserver/index.d.ts +0 -2
  254. package/dist/webserver/index.js +0 -9
  255. package/dist/webserver/index.js.map +0 -1
@@ -1,635 +1,585 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const softconfig_1 = __importDefault(require("../../softconfig"));
7
- const pattern_1 = require("../../util/pattern");
8
- const time_1 = require("../../util/time");
9
- const bcryptjs_1 = __importDefault(require("bcryptjs"));
10
- const chokidar_1 = __importDefault(require("chokidar"));
11
- const events_1 = __importDefault(require("events"));
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
- // generate a punchcard (days x week)
22
- const createPunchcard = () => Array.from({ length: 7 }).map(() => Array.from({ length: 24 }).fill(0));
23
- // the database keeps track of metrics for omegga
24
- class Database extends events_1.default {
25
- constructor(options, omegga) {
26
- super();
27
- this.options = options;
28
- this.omegga = omegga;
29
- this.calendar = new calendar_1.default();
30
- // database
31
- const dbOpts = {
32
- autoload: true,
33
- // case insensitive string comparison
34
- compareStrings: (a, b) => a.localeCompare(b, 'en', { ignorePunctuation: true }),
35
- };
36
- // create all the stores
37
- this.stores = {
38
- users: nedb_promises_1.default.create({
39
- filename: path_1.default.join(omegga.dataPath, softconfig_1.default.USER_STORE),
40
- ...dbOpts,
41
- }),
42
- chat: nedb_promises_1.default.create({
43
- filename: path_1.default.join(omegga.dataPath, softconfig_1.default.CHAT_STORE),
44
- ...dbOpts,
45
- }),
46
- players: nedb_promises_1.default.create({
47
- filename: path_1.default.join(omegga.dataPath, softconfig_1.default.PLAYER_STORE),
48
- ...dbOpts,
49
- }),
50
- status: nedb_promises_1.default.create({
51
- filename: path_1.default.join(omegga.dataPath, softconfig_1.default.STATUS_STORE),
52
- ...dbOpts,
53
- }),
54
- server: nedb_promises_1.default.create({
55
- filename: path_1.default.join(omegga.dataPath, softconfig_1.default.SERVER_STORE),
56
- ...dbOpts,
57
- }),
58
- };
59
- }
60
- // make sure all the databases have valid store versions
61
- async doMigrations() {
62
- // current store versions
63
- const storeVersions = {
64
- users: 1,
65
- chat: 1,
66
- players: 1,
67
- status: 1,
68
- server: 1,
69
- // example version
70
- dummy: 10,
71
- };
72
- // migrations to/from certain store versions
73
- const migrations = {
74
- users: [],
75
- chat: [],
76
- players: [],
77
- status: [],
78
- server: [],
79
- // example migration list (all version upgrades go up by 1)
80
- dummy: [
81
- {
82
- version: 1, // target version
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
- const watcher = chokidar_1.default.watch(path_1.default.join(this.omegga.configPath, 'BanList.json'), { persistent: false });
130
- watcher
131
- .on('add', () => setTimeout(this.syncBanList.bind(this), 500))
132
- .on('change', () => setTimeout(() => {
133
- this.syncBanList();
134
- this.emit('update.bans');
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
- return doc._id;
169
- }
170
- // synchronize the ban list with the one in the database
171
- syncBanList() {
172
- var _a;
173
- const banList = (_a = this.omegga.getBanList()) === null || _a === void 0 ? void 0 : _a.banList;
174
- if (!banList)
175
- return;
176
- // upsert all bans
177
- for (const banned in banList) {
178
- const entry = {
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
- // determine if this user would be the first user (admin user)
190
- async isFirstUser() {
191
- return (await this.stores.users.count({ type: 'user' })) === 0;
192
- }
193
- // hash a password
194
- async hash(password) {
195
- return await bcryptjs_1.default.hash(password, 10);
196
- }
197
- // create an admin user account, username can be blank (no password)
198
- async createAdminUser(username, password) {
199
- const hash = await this.hash(password);
200
- // create an owner user
201
- const user = this.stores.users.insert({
202
- // this is a user
203
- type: 'user',
204
- created: Date.now(),
205
- lastOnline: Date.now(),
206
- // credentials
207
- username,
208
- hash,
209
- // permissions
210
- isOwner: true,
211
- roles: [],
212
- // brickadia player uuid
213
- playerId: '',
214
- });
215
- return user;
216
- }
217
- // determine if a user with this name exists
218
- async userExists(username) {
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
- // wrong password
263
- return null;
264
- }
265
- // find a user by object id
266
- async findUserById(id) {
267
- return await this.stores.users.findOne({
268
- $or: [
269
- // the owner has no username, so everyone is the owner
270
- { type: 'user', username: '', isOwner: true },
271
- // the user exists and has an id
272
- { type: 'user', _id: id },
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
- // get a list of roles
277
- // TODO: actually implement roles
278
- getRoles() {
279
- return this.stores.server.find({ type: 'role' });
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
- // add a chat message to the chat log store
282
- async addChatLog(action, user, message) {
283
- this.calendar.addDate(Date.now());
284
- return await this.stores.chat.insert({
285
- type: 'chat',
286
- created: Date.now(),
287
- instanceId: await this.getInstanceId(),
288
- action,
289
- user,
290
- ...(message ? { message } : {}),
291
- });
292
- }
293
- // get recent chat activity
294
- async getChats({ count = 50, sameServer, before, after, } = {}) {
295
- return await this.stores.chat
296
- .find({
297
- type: 'chat',
298
- ...(sameServer ? { instanceId: await this.getInstanceId() } : {}),
299
- created: before
300
- ? { $lt: before }
301
- : after
302
- ? { $gt: after }
303
- : { $lt: Date.now() },
304
- })
305
- .sort({ created: !before && after ? 1 : -1 })
306
- .limit(count)
307
- .exec();
308
- }
309
- // get paginated players
310
- async getPlayers({ count = 50, search = '', page = 0, sort = 'name', direction = '1', limitId = undefined, } = {}) {
311
- const pattern = (0, pattern_1.explode)(search);
312
- // the query used for finding which players are available
313
- const query = {
314
- type: 'userHistory',
315
- // only filter if there's a query
316
- $and: [
317
- // if a limitId is passed in, the id must be in it
318
- ...(limitId ? [{ id: { $in: limitId } }] : []),
319
- // if there's a search, the search matches...
320
- ...(search.length > 0
321
- ? [
322
- {
323
- $or: [
324
- // id was pasted in
325
- { id: search },
326
- // user's current name
327
- { name: { $regex: pattern } },
328
- { displayName: { $regex: pattern } },
329
- // user's past name
330
- {
331
- nameHistory: { $elemMatch: { name: { $regex: pattern } } },
332
- },
333
- {
334
- nameHistory: {
335
- $elemMatch: { displayName: { $regex: pattern } },
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
- // id was pasted in
350
- { id: search },
351
- // user's current name
352
- { name: search },
353
- // user's current display name
354
- { displayName: search },
355
- ],
356
- };
357
- // count players and query players
358
- const [total, players, exactResult] = await Promise.all([
359
- this.stores.players.count(query),
360
- this.stores.players
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
- // count players and query players
407
- const [total, users] = await Promise.all([
408
- this.stores.users.count(query),
409
- this.stores.users
410
- .find(query)
411
- // TODO: add other sorts and sort directions
412
- .sort({ [sort]: direction })
413
- .skip(count * page)
414
- .limit(count)
415
- .exec(),
416
- ]);
417
- return {
418
- pages: Math.ceil(total / count),
419
- total,
420
- users,
421
- };
422
- }
423
- // get an individual player, ban and kick history, and notes
424
- async getPlayer(id) {
425
- const [player, banHistory, kickHistory, notes] = await Promise.all([
426
- this.stores.players.findOne({ type: 'userHistory', id }),
427
- this.stores.players
428
- .find({ type: 'banHistory', banned: id })
429
- .sort({ created: -1 })
430
- .limit(25)
431
- .exec(),
432
- this.stores.players
433
- .find({ type: 'kickHistory', kicked: id })
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
- // add a user to the visit history, returns true if this is a first visit
448
- async addVisit(user) {
449
- const existing = await this.stores.players.findOne({
450
- type: 'userHistory',
451
- id: user.id,
452
- });
453
- const now = Date.now();
454
- const instanceId = await this.getInstanceId();
455
- if (!existing) {
456
- // create the player
457
- // TODO: add some form of admin note tool for moderators to leave notes
458
- // on troublesome players + warnings
459
- await this.stores.players.insert({
460
- type: 'userHistory',
461
- // base brickadia user info
462
- id: user.id,
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
- // list of names and when they were first used
466
- nameHistory: [
467
- { name: user.name, displayName: user.displayName, date: now },
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
- (_a = config.autoUpdateEnabled) !== null && _a !== void 0 ? _a : (config.autoUpdateEnabled = true);
572
- (_b = config.autoUpdateIntervalMins) !== null && _b !== void 0 ? _b : (config.autoUpdateIntervalMins = 60);
573
- (_c = config.saveWorld) !== null && _c !== void 0 ? _c : (config.saveWorld = true);
574
- return config;
459
+ );
460
+ return false;
575
461
  }
576
- async setAutoRestartConfig(config) {
577
- var _a, _b;
578
- config.maxUptime = Math.round(Math.max(1, Math.min(config.maxUptime, 168)));
579
- config.emptyUptime = Math.round(Math.max(1, Math.min(config.emptyUptime, 168)));
580
- config.dailyHour = Math.round(Math.max(0, Math.min(config.dailyHour, 23)));
581
- config.autoUpdateIntervalMins = Math.round(Math.max(10, Math.min((_a = config.autoUpdateIntervalMins) !== null && _a !== void 0 ? _a : 60, Infinity)));
582
- (_b = config.autoUpdateEnabled) !== null && _b !== void 0 ? _b : (config.autoUpdateEnabled = true);
583
- await this.stores.server.update({ type: 'autoRestartConfig' }, {
584
- $set: {
585
- ...config,
586
- },
587
- }, { upsert: false });
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
- // update player online-time punchcard
590
- async updatePlayerPunchcard(numNewPlayers) {
591
- // get date, utc hour, and utc day
592
- const now = new Date();
593
- const time = now.getTime();
594
- const hour = now.getUTCHours();
595
- const day = now.getUTCDay();
596
- const month = now.getUTCMonth();
597
- const year = now.getUTCFullYear();
598
- // find the punchcard
599
- const card = await this.stores.status.findOne({
600
- type: 'punchcard',
601
- kind: 'playerCount',
602
- month,
603
- year,
604
- });
605
- // create a new punchcard if one does not exist for this month
606
- if (!card) {
607
- const punchcard = createPunchcard();
608
- punchcard[day][hour] = numNewPlayers;
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
- else {
622
- // add the players to this slot
623
- card.punchcard[day][hour] += numNewPlayers;
624
- // update the punchcard
625
- await this.stores.status.update({ _id: card._id }, {
626
- $set: {
627
- punchcard: card.punchcard,
628
- updated: time,
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