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.
*/