From 6b3f2e03fe56774875e7832fd8680028bea99a48 Mon Sep 17 00:00:00 2001 From: Alyxia Sother Date: Mon, 28 Jul 2025 03:02:46 +0200 Subject: [PATCH 1/4] Add compatability with CCLoader2 & Simplify globals --- packages/core/src/modloader.ts | 6 +- packages/runtime/src/_main.ts | 3 + .../runtime/src/fixes/ccloader2-polyfill.ts | 101 ++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 packages/runtime/src/fixes/ccloader2-polyfill.ts diff --git a/packages/core/src/modloader.ts b/packages/core/src/modloader.ts index 58fc1b4..c2047df 100644 --- a/packages/core/src/modloader.ts +++ b/packages/core/src/modloader.ts @@ -56,7 +56,8 @@ export async function boot(): Promise { let virtualPackages = new Map() .set('crosscode', gameVersion) - .set('ccloader', modloaderMetadata.version); + .set('ccloader', modloaderMetadata.version) + .set('Simplify', new semver.SemVer('2.14.2')); if (typeof process !== 'undefined') { virtualPackages.set('nw', new semver.SemVer(process.versions.nw!)); } @@ -178,6 +179,9 @@ export async function boot(): Promise { console.log("stage 'poststart' reached!"); await executeStage(loadedMods, 'poststart'); + // NOTE: LEGACY CCLOADER2 EVENT + document.body.dispatchEvent(new Event('modsLoaded', { bubbles: true })); + activeDelegateFn(); console.log('crosscode with mods is now fully loaded!'); } diff --git a/packages/runtime/src/_main.ts b/packages/runtime/src/_main.ts index ae9e781..f8f2b17 100644 --- a/packages/runtime/src/_main.ts +++ b/packages/runtime/src/_main.ts @@ -33,6 +33,9 @@ export default class RuntimeModMainClass implements modloader.Mod.PluginClass { moduleCache, resources, }); + + // There's probably an issue with this being a non-awaited import. + import('./fixes/ccloader2-polyfill.js'); } public onImpactInit(): void { diff --git a/packages/runtime/src/fixes/ccloader2-polyfill.ts b/packages/runtime/src/fixes/ccloader2-polyfill.ts new file mode 100644 index 0000000..6dc659b --- /dev/null +++ b/packages/runtime/src/fixes/ccloader2-polyfill.ts @@ -0,0 +1,101 @@ +/* eslint-disable consistent-return */ +// This may be one of the worst pieces of this codebase. Please don't judge too heavily! + +import type { LocalizedString } from 'ultimate-crosscode-typedefs/file-types/mod-manifest'; + +interface LegacyMod { + baseDirectory: string; + name: LocalizedString; + displayName: LocalizedString; +} + +const Plugin = class Plugin { + public preload(): void {} + public postload(): void {} + public prestart(): void {} + public main(): void {} +}; + +// The de-facto Simplify Compat Layer +// +const _simplify = { + version: '2.14.2', + updateHandlers: [] as Array<() => void>, + + registerUpdate(handler?: () => void) { + if (handler && typeof handler === 'function') { + this.updateHandlers.push(handler); + } + }, + // technically never called by us, but let's keep it in just to be sure. + fireUpdate() { + for (const handler of this.updateHandlers) { + handler(); + } + }, + + getMod(name: string): LegacyMod | undefined { + const mod = modloader.loadedMods.get(name); + if (!mod) return; + + return { + baseDirectory: mod.baseDirectory, + name: mod.id, + displayName: mod.manifest.title || mod.id, + }; + }, + + // seriously? :harold: + jumpHigh() { + ig.game.playerEntity.doJump(185, 16, 100); + }, +}; + +// For some reason this was just an alias to `window`???? +const cc = window; +const simplify = new Proxy(_simplify, { + get(target, p) { + // This is honestly just vile + const prop = target[p as keyof typeof _simplify]; + p = String(p); + + // Should it ever occur that I've forgotten something in the compat layer, let the user know. + if (!prop) { + console.warn(new Error(`Couldn't find '${p}' in Simplify compat layer. Please report!`)); + return; + } + + console.debug(new Error(`Simplify property '${p}' requested. This is no longer supported.`)); + if (prop) return prop; + }, +}); + +Object.assign(window, { + cc, + simplify, + Plugin, + + versions: Array.from(modloader.installedMods.values()).reduce>( + (acc, mod) => { + if (!mod.version) { + console.debug('Mod without a version detected in construction of window.versions'); + return acc; + } + acc[mod.id] = mod.version.toString(); + return acc; + }, + {}, + ), + activeMods: [...modloader.loadedMods.values()], + inactiveMods: [...modloader.installedMods.values()].filter( + (mod) => !modloader.modDataStorage.isModEnabled(mod.id), + ), +}); + +// For some reason these were distinct events despite the fact that they fire +// right after eachother. After the `main` stage ran, `modsLoaded` was +// dispatched, while Simplify was already listening for it, causing it to +// trigger immediately. Strange decision to even include `simplifyInitialized`. +document.body.addEventListener('modsLoaded', () => { + document.body.dispatchEvent(new Event('simplifyInitialized', { bubbles: true })); +}); From b20c1ff98132d190418bc14f2a874535a461ecd3 Mon Sep 17 00:00:00 2001 From: Alyxia Sother Date: Mon, 28 Jul 2025 04:05:57 +0200 Subject: [PATCH 2/4] Fix legacy asset paths in manifest --- packages/core/src/modloader.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/core/src/modloader.ts b/packages/core/src/modloader.ts index c2047df..2101622 100644 --- a/packages/core/src/modloader.ts +++ b/packages/core/src/modloader.ts @@ -304,6 +304,20 @@ async function loadModMetadata(baseDirectory: string): Promise { } else { manifestData = manifestData as Manifest; manifestValidator.validate(manifestData); + + // NOTE: During the migration period of legacy mods to the new format, + // their `package.json`s were converted to `ccmod.json`. The problem is + // that apparently nobody involved in this process (even the ones who + // implemented this detail) didn't remember that in the new format, paths + // are assumed to be within `assets/`. So, what happened? The `assets` + // array from `package.json` was copied 1:1 to `ccmod.json`, meaning that + // there are now `ccmod.json`s with paths in `assets` that start with + // `assets/`. This is resolved exclusively for legacy manifests + // (obviously) by the `convertFromLegacy` call in the `if` block above, + // but not for `ccmod.json`s that were incorrectly migrated. Instead of + // going through the hassle of getting those mods updated *again*, I'll + // just fix it once and for all. + manifestData.assets = manifestData.assets?.map(e => e.replace(/^assets\//, '')); } } catch (err) { if (utils.errorHasMessage(err)) { From a219a051cc8a3bfbfdad3e1b8a541443a1139638 Mon Sep 17 00:00:00 2001 From: Alyxia Sother Date: Mon, 28 Jul 2025 04:08:06 +0200 Subject: [PATCH 3/4] Run the formatter --- packages/core/src/modloader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/modloader.ts b/packages/core/src/modloader.ts index 2101622..7424948 100644 --- a/packages/core/src/modloader.ts +++ b/packages/core/src/modloader.ts @@ -317,7 +317,7 @@ async function loadModMetadata(baseDirectory: string): Promise { // but not for `ccmod.json`s that were incorrectly migrated. Instead of // going through the hassle of getting those mods updated *again*, I'll // just fix it once and for all. - manifestData.assets = manifestData.assets?.map(e => e.replace(/^assets\//, '')); + manifestData.assets = manifestData.assets?.map((e) => e.replace(/^assets\//, '')); } } catch (err) { if (utils.errorHasMessage(err)) { From 4bd9037cf348c5f630fed22e3d16540686e11177 Mon Sep 17 00:00:00 2001 From: Alyxia Sother Date: Wed, 30 Jul 2025 00:47:25 +0200 Subject: [PATCH 4/4] Apply suggestions --- packages/runtime/src/fixes/ccloader2-polyfill.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/fixes/ccloader2-polyfill.ts b/packages/runtime/src/fixes/ccloader2-polyfill.ts index 6dc659b..e2d4a43 100644 --- a/packages/runtime/src/fixes/ccloader2-polyfill.ts +++ b/packages/runtime/src/fixes/ccloader2-polyfill.ts @@ -1,6 +1,7 @@ /* eslint-disable consistent-return */ // This may be one of the worst pieces of this codebase. Please don't judge too heavily! +import semver from '@ccloader3/common/vendor-libs/semver'; import type { LocalizedString } from 'ultimate-crosscode-typedefs/file-types/mod-manifest'; interface LegacyMod { @@ -65,8 +66,8 @@ const simplify = new Proxy(_simplify, { return; } - console.debug(new Error(`Simplify property '${p}' requested. This is no longer supported.`)); - if (prop) return prop; + console.debug(new Error(`Simplify property '${p}' requested. This is deprecated.`)); + return prop; }, }); @@ -74,6 +75,7 @@ Object.assign(window, { cc, simplify, Plugin, + semver, versions: Array.from(modloader.installedMods.values()).reduce>( (acc, mod) => {