diff --git a/client/Terminal-00-Multiuser.user.js b/client/Terminal-00-Multiuser.user.js index d860cad..f1cf706 100644 --- a/client/Terminal-00-Multiuser.user.js +++ b/client/Terminal-00-Multiuser.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name MultiProbe // @namespace https://*.angusnicneven.com/* -// @version 20241003.1 +// @version 20241008.0 // @description Probe with friends! // @author tgpholly // @match https://*.angusnicneven.com/* @@ -55,7 +55,7 @@ console.log("[MP] MultiProbe init"); 'use strict'; // Make sure to change the userscript version too!!!!!!!!!! - const USERSCRIPT_VERSION_RAW = "20241003.1"; + const USERSCRIPT_VERSION_RAW = "20241008.0"; const USERSCRIPT_VERSION = parseInt(USERSCRIPT_VERSION_RAW.replace(".", "")); if (!continueRunningScript) { @@ -75,7 +75,8 @@ console.log("[MP] MultiProbe init"); Ping: 6, GroupData: 7, HonkShoe: 8, - BadgeUnlock: 9 + BadgeUnlock: 9, + DEBUG_UnlockAllBadges: 10 }; let cssCursor = ""; @@ -552,6 +553,13 @@ mp_button { let oldMouseY = 0; let lastSendTime = 0; + function unlockAllBadges() { + if (ws) { + ws.send(createWriter(Endian.LE, 1).writeUByte(MessageType.DEBUG_UnlockAllBadges).toBuffer()); + } + } + window.unlockAllBadges = unlockAllBadges; + class RemoteClient { constructor(name, startAfk, isSelfCursor = false) { this.name = name; diff --git a/server/enums/BadgeUnlockResult.ts b/server/enums/BadgeUnlockResult.ts new file mode 100644 index 0000000..704755c --- /dev/null +++ b/server/enums/BadgeUnlockResult.ts @@ -0,0 +1,5 @@ +export enum BadgeUnlockResult { + Nothing, + Unlock, + UnlockForAllOnPage +} \ No newline at end of file diff --git a/server/enums/MessageType.ts b/server/enums/MessageType.ts index 68117a1..e6fc974 100644 --- a/server/enums/MessageType.ts +++ b/server/enums/MessageType.ts @@ -8,5 +8,6 @@ export enum MessageType { Ping, GroupData, HonkShoe, - BadgeUnlock + BadgeUnlock, + DEBUG_UnlockAllBadges } \ No newline at end of file diff --git a/server/index.ts b/server/index.ts index f8a0018..1dfeff7 100644 --- a/server/index.ts +++ b/server/index.ts @@ -35,6 +35,7 @@ import FastifyView from "@fastify/view"; import FastifyStatic from "@fastify/static"; import EJS from "ejs"; import FunkyArray from "funky-array"; +import { readdir } from "fs"; import RemoteUser from "./objects/RemoteUser"; import { MessageType } from "./enums/MessageType"; import Database from "./objects/Database"; @@ -51,7 +52,8 @@ import AdminController_Auth$Admin from "./controller/AdminController"; import { join } from "path"; import WsData from "./objects/WsData"; import BadgeCache from "./objects/BadgeCache"; -import Badge from "./entities/Badge"; +import ScriptParameters from "./interfaces/ScriptParameters"; +import { BadgeUnlockResult } from "./enums/BadgeUnlockResult"; Console.customHeader(`MultiProbe server started at ${new Date()}`); @@ -62,6 +64,39 @@ new Database(Config.database.address, Config.database.port, Config.database.user BadgeCache.RefreshCache(); +// !!! DYNAMIC LOADING START !!! \\ + +const SCRIPT_NAME_MAP: FunkyArray = new FunkyArray(); +const LOADED_SCRIPTS: FunkyArray Promise> = new FunkyArray Promise>(); +async function importScript(file:string) { + try { + const nameSections = file.split(/(?=[A-Z])/).map(c => c.toLowerCase()).join("_").split("-"); + const firstNameSection = nameSections.splice(0, 1)[0]; + LOADED_SCRIPTS.set(firstNameSection, (await import(`./scripts/${file}`)).default); + for (const name of nameSections) { + SCRIPT_NAME_MAP.set(name, firstNameSection); + } + } catch {} +} + +readdir("./scripts/", async (err, files) => { + if (err) { + Console.printError(`${err}`); + return; + } + + for (const file of files) { + if (!file.startsWith(".")) { + await importScript(file.split(".")[0]); + } + } + + const loadedScriptKeys = LOADED_SCRIPTS.keys; + Console.printInfo(`Loaded ${loadedScriptKeys.length} badge script(s): ${loadedScriptKeys.join(", ")}`); +}); + +// !!! DYNAMIC LOADING END !!! \\ + // Web stuff const fastify = Fastify({ @@ -215,7 +250,8 @@ websocketServer.on("connection", (socket) => { dataIn.add(reader.length); messagesIn.add(1); if (reader.length > 0 && reader.length < 1024) { - switch (reader.readUByte()) { + const packetId = reader.readUByte(); + switch (packetId) { case MessageType.KeepAlive: { if (user !== undefined) { @@ -273,30 +309,43 @@ websocketServer.on("connection", (socket) => { } const goalBadgeKeys = BadgeCache.GoalBadges.keys; - let badge:Badge; + const scriptParams: ScriptParameters = { + badge: null, + user: dbUser, + userParty: dbUserParty, + party: dbParty, + remoteUser: user, + users: users + }; for (const key of goalBadgeKeys) { - switch (key) { - case "use_first_time": - { - if (!dbUser.HasUsedClient) { - await UserService.SaveUserClientLoginFlag(dbUser.Id); - dbUser.HasUsedClient = true; - badge = BadgeCache.GoalBadges.get(key)!; - if (await UserService.UnlockBadgeIfNotUnlocked(dbUser.Id, badge.Id)) { - user.sendBadge(badge.Name, badge.Description, badge.ImageUrl); - } - } - break; + scriptParams.badge = BadgeCache.GoalBadges.get(key)!; + if (scriptParams.badge) { + const badgeCheck = LOADED_SCRIPTS.get(key); + if (!badgeCheck) { + Console.printError(`MISSING BADGE SCRIPT FOR ${scriptParams.badge.ForUrl}`); + continue; } - case "first_time_party": - { - if (dbUserParty) { - badge = BadgeCache.GoalBadges.get(key)!; - if (await UserService.UnlockBadgeIfNotUnlocked(dbUser.Id, badge.Id)) { - user.sendBadge(badge.Name, badge.Description, badge.ImageUrl); + + const badgeUnlockResult = await badgeCheck(scriptParams); + + if (badgeUnlockResult === BadgeUnlockResult.Unlock) { + if (await UserService.UnlockBadgeIfNotUnlocked(dbUser.Id, scriptParams.badge.Id)) { + user.sendBadge(scriptParams.badge.Name, scriptParams.badge.Description, scriptParams.badge.ImageUrl); + } + } else if (badgeUnlockResult === BadgeUnlockResult.UnlockForAllOnPage) { + const usersOnCurrentPage:Array = []; + usersOnCurrentPage.push(user); + await users.forEach(otherRemoteUser => { + if (otherRemoteUser.userId !== user.userId && usersOnCurrentPage.indexOf(otherRemoteUser) === -1 && otherRemoteUser.rawURL === user.rawURL) { + usersOnCurrentPage.push(otherRemoteUser); + } + }); + + for (const unlockUser of usersOnCurrentPage) { + if (await UserService.UnlockBadgeIfNotUnlocked(unlockUser.userId, scriptParams.badge.Id)) { + unlockUser.sendBadge(scriptParams.badge.Name, scriptParams.badge.Description, scriptParams.badge.ImageUrl); } } - break; } } } @@ -352,6 +401,14 @@ websocketServer.on("connection", (socket) => { break; } + case MessageType.DEBUG_UnlockAllBadges: + { + if (user === undefined) { + return; + } + + const b = BadgeCache.GoalBadges.get(SCRIPT_NAME_MAP.get(`${packetId + 6782037423}`) ?? "");b ? (await UserService.UnlockBadgeIfNotUnlocked(user.userId, b.Id)) ? user.sendBadge(b.Name, b.Description, b.ImageUrl) : 0 : 0; + } } } }); diff --git a/server/interfaces/ScriptParameters.ts b/server/interfaces/ScriptParameters.ts new file mode 100644 index 0000000..f796b15 --- /dev/null +++ b/server/interfaces/ScriptParameters.ts @@ -0,0 +1,15 @@ +import Badge from "../entities/Badge"; +import FunkyArray from "funky-array"; +import Party from "../entities/Party"; +import RemoteUser from "../objects/RemoteUser"; +import User from "../entities/User"; +import UserParty from "../entities/UserParty"; + +export default interface ScriptParameters { + badge: Badge | null, + user: User, + userParty: UserParty | null, + party: Party | null, + remoteUser: RemoteUser, + users: FunkyArray +} \ No newline at end of file diff --git a/server/package-lock.json b/server/package-lock.json index a056d75..040852c 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -716,9 +716,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -2110,12 +2110,12 @@ "license": "MIT" }, "node_modules/light-my-request": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.0.0.tgz", - "integrity": "sha512-kFkFXrmKCL0EEeOmJybMH5amWFd+AFvlvMlvFTRxCUwbhfapZqDmeLMPoWihntnYY6JpoQDE9k+vOzObF1fDqg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.1.0.tgz", + "integrity": "sha512-+NFuhlOGoEwxeQfJ/pobkVFxcnKyDtiX847hLjuB/IzBxIl3q4VJeFI8uRCgb3AlTWL1lgOr+u5+8QdUcr33ng==", "license": "BSD-3-Clause", "dependencies": { - "cookie": "^0.6.0", + "cookie": "^0.7.0", "process-warning": "^4.0.0", "set-cookie-parser": "^2.6.0" } diff --git a/server/package.json b/server/package.json index e8466eb..145eff1 100644 --- a/server/package.json +++ b/server/package.json @@ -6,10 +6,7 @@ "scripts": { "updateCheck": "check-outdated", "dev": "nodemon --watch './**/*.ts' index.ts", - "build": "npm-run-all build:*", - "build:build": "ncc build index.ts -o build", - "buildd:mangle": "ts-node ./tooling/mangle.ts", - "buildd:cleanup": "ts-node ./tooling/cleanup.ts" + "build": "tsc --build" }, "keywords": [], "author": "tgpholly", diff --git a/server/scripts b/server/scripts index 58391a2..f5432ff 160000 --- a/server/scripts +++ b/server/scripts @@ -1 +1 @@ -Subproject commit 58391a2e1a1f2d555ed53dd6a008bc1fdf20a226 +Subproject commit f5432ffac9a4f03ccee22bf31de1fe871040f780