diff --git a/.gitignore b/.gitignore index 22d3fa8..0c775ee 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ assets/* assets/mods/* !assets/mods/simplify/ !assets/mods/ccloader-version-display/ +!assets/mods/ccmodmanager.ccmod \ No newline at end of file diff --git a/assets/mods/ccmodmanager.ccmod b/assets/mods/ccmodmanager.ccmod new file mode 100644 index 0000000..a7a1259 Binary files /dev/null and b/assets/mods/ccmodmanager.ccmod differ diff --git a/assets/mods/simplify/ccmod.json b/assets/mods/simplify/ccmod.json index ca5726a..826f55a 100644 --- a/assets/mods/simplify/ccmod.json +++ b/assets/mods/simplify/ccmod.json @@ -1,6 +1,6 @@ { "id": "Simplify", - "version": "2.14.1", + "version": "2.14.2", "title": "Simplify", "description": "Library mod for CCLoader2.", "repository": "https://github.com/CCDirectLink/CCLoader", diff --git a/assets/mods/simplify/package.json b/assets/mods/simplify/package.json index 58902ee..04d223f 100644 --- a/assets/mods/simplify/package.json +++ b/assets/mods/simplify/package.json @@ -6,7 +6,7 @@ "prestart": "prestart.js", "plugin": "plugin.js", "hidden": true, - "version": "2.14.1", + "version": "2.14.2", "ccmodDependencies": { "ccloader": "^2.22.0", "crosscode": "^1.0.0" diff --git a/assets/mods/simplify/pattern-fix.js b/assets/mods/simplify/pattern-fix.js new file mode 100644 index 0000000..0025b9b --- /dev/null +++ b/assets/mods/simplify/pattern-fix.js @@ -0,0 +1,67 @@ +let _canvas; +/** @returns {CanvasRenderingContext2D} */ +function _getTmpContext(width, height) { + if (!_canvas) { + _canvas = document.createElement('canvas'); + } + _canvas.width = width; + _canvas.height = height; + + const context = _canvas.getContext('2d', { willReadFrequently: true }); + context.clearRect(0, 0, width, height); + return context; +} + +export function fixPatterns() { + ig.ImagePattern.inject({ + // Only the draw calls and the assignment to this.image1 and this.image2 are changed. (usePatternDraw was removed because it is unused) + initBuffer() { + const scale = ig.system.scale; + this.sourceX = this.sourceX ? this.sourceX * scale : 0; + this.sourceY = this.sourceY ? this.sourceY * scale : 0; + this.width = (this.width ? this.width : this.sourceImage.width) * scale; + this.height = (this.height ? this.height : this.sourceImage.height) * scale; + const opt = ig.ImagePattern.OPT; + const widthFactor = Math.ceil((this.optMode == opt.NONE || this.optMode == opt.REPEAT_Y ? 1 : 256) / this.width); + const heightFactor = Math.ceil((this.optMode == opt.NONE || this.optMode == opt.REPEAT_X ? 1 : 256) / this.height); + const scaledWidth = widthFactor * this.width; + const scaledHeight = heightFactor * this.height; + const context = _getTmpContext(scaledWidth, this.optMode == opt.REPEAT_X_OR_Y ? this.height : scaledHeight); + for (let y = 0; y < (this.optMode == opt.REPEAT_X_OR_Y ? 1 : heightFactor); ++y) { + for (let x = 0; x < widthFactor; x++) { + context.drawImage(this.sourceImage.data, this.sourceX, this.sourceY, this.width, this.height, x * this.width, y * this.height, this.width, this.height); + ig.Image.drawCount++; + } + } + this.image1 = document.createElement('img'); + this.image1.src = context.canvas.toDataURL(); + + if (this.optMode == opt.REPEAT_X_OR_Y) { + const context2 = _getTmpContext(this.width, scaledHeight); + for (let y = 0; y < heightFactor; ++y) { + context.drawImage(this.sourceImage.data, this.sourceX, this.sourceY, this.width, this.height, 0, y * this.height, this.width, this.height); + ig.Image.drawCount++; + } + this.image2 = document.createElement('img'); + this.image2.src = context2.canvas.toDataURL(); + } + this.totalWidth = scaledWidth; + this.totalHeight = scaledHeight; + }, + clearCached() { + if (this.image1) { + this.image1 = null; + } + if (this.image2) { + this.image2 = null; + } + }, + }); + ig.ImagePattern.OPT = { + NONE: 0, + REPEAT_X: 1, + REPEAT_Y: 2, + REPEAT_X_OR_Y: 3, + REPEAT_X_AND_Y: 4 + }; +} \ No newline at end of file diff --git a/assets/mods/simplify/plugin.js b/assets/mods/simplify/plugin.js index 88f8ef6..16a3957 100644 --- a/assets/mods/simplify/plugin.js +++ b/assets/mods/simplify/plugin.js @@ -1,7 +1,8 @@ /// import * as compat from './compat.js'; -import './classInject.js' +import './classInject.js'; +import { fixPatterns } from './pattern-fix.js'; /** * @extends {ccloader.Plugin} @@ -18,7 +19,7 @@ export default class Simplify extends Plugin { this._applyArgs(); this._hookStart(); } - + postload() { this._applyArgs(); return import('./postloadModule.js'); @@ -28,12 +29,16 @@ export default class Simplify extends Plugin { await compat.apply(this.baseDir); } + prestart() { + fixPatterns(); + } + _hookStart() { let original = window.startCrossCode; Object.defineProperty(window, 'startCrossCode', { get() { if (original) { - return async(...args) => { + return async (...args) => { if (window.CrossAndroid && window.CrossAndroid.executePostGameLoad) { window.CrossAndroid.executePostGameLoad(); } @@ -44,11 +49,11 @@ export default class Simplify extends Plugin { console.error(`Could not run prestart of mod '${mod.name}': `, e); } } - + const event = document.createEvent('Event'); event.initEvent('prestart', true, false); document.dispatchEvent(event); - + return original(...args); }; } @@ -67,7 +72,7 @@ export default class Simplify extends Plugin { window[name] = value; } } - + /** * * @returns {[string, string][]} @@ -77,7 +82,7 @@ export default class Simplify extends Plugin { if (nwGui) { return nwGui.App.argv.map(e => e.split('=')); } else { - return Array.from(new URL(window.location.href).searchParams.entries()) + return Array.from(new URL(window.location.href).searchParams.entries()); } } } \ No newline at end of file diff --git a/ccloader/ccmod.json b/ccloader/ccmod.json index 339ad13..f309964 100644 --- a/ccloader/ccmod.json +++ b/ccloader/ccmod.json @@ -1,6 +1,6 @@ { "id": "ccloader", - "version": "2.24.2", + "version": "2.25.0", "title": "CCLoader", "description": "Modloader for CrossCode. This or a similar modloader is needed for most mods.", "repository": "https://github.com/CCDirectLink/CCLoader", diff --git a/ccloader/js/ccloader.js b/ccloader/js/ccloader.js index 0bc294d..0a7e571 100644 --- a/ccloader/js/ccloader.js +++ b/ccloader/js/ccloader.js @@ -5,7 +5,7 @@ import { Plugin } from './plugin.js'; import { Greenworks } from './greenworks.js'; import { Package } from './package.js'; -const CCLOADER_VERSION = '2.24.2'; +const CCLOADER_VERSION = '2.25.0'; const KNOWN_EXTENSIONS = ["post-game", "manlea", "ninja-skin", "fish-gear", "flying-hedgehag", "scorpion-robo", "snowman-tank"] export class ModLoader { @@ -34,6 +34,7 @@ export class ModLoader { await this.loader.initialize(); await this._loadModPackages(); + this._removeDuplicateMods(); this._orderCheckMods(); this._registerMods(); @@ -167,6 +168,29 @@ export class ModLoader { this.mods = await Promise.all(packages.map(pkg => pkg.load())); } + _removeDuplicateMods() { + /** @type {Map} The key is the name/id of the mod */ + const mods = new Map(); + for (const mod of this.mods) { + if (mods.has(mod.name)) { + const existing = mods.get(mod.name); + if (semver.lt(mod.version, existing.version)) { + console.warn(`Duplicate mod found: ${existing.displayName} preferred version ${existing.version} over ${mod.version}`); + mod.disabled = true; + continue; + } else if (semver.eq(mod.version, existing.version)) { + console.warn(`Duplicate mod found: ${mod.displayName} version ${mod.version}. Picking the first one.`); + existing.disabled = true; + } else { + console.warn(`Duplicate mod found: ${mod.displayName} preferred version ${mod.version} over ${existing.version}`); + existing.disabled = true; + } + } + + mods.set(mod.name, mod); + } + } + /** * Orders mods and checks their dependencies. Simplify is always loaded first. */