Support shorthand notation for colours

Implement the shorthand notations that Factorio recognises for colours
where individual components may be left out or the colour specified as
an array of values instead of an object.
This commit is contained in:
Hornwitser committed 2024-02-08 18:42:38 +01:00
1 parent 96082e32b7
commit 1021e29c98
8 files changed
+80 -12

No files matched your search

+1 -1
View File
@@ -320,7 +320,7 @@ module.exports = {
"semi-style": "off",
"sort-imports": "off",
"sort-keys": "off",
"sort-vars": "error",
"sort-vars": "off",
"space-before-blocks": "error",
"space-before-function-paren": "off",
"space-in-parens": ["error", "never"],
+1
View File
@@ -11,6 +11,7 @@
- Fixed Web UI not showing instance saves when the permission to list and subscribe the saves is granted but the user is not a cluster admin.
- Similarly fixed Web UI not showing the mod pack create, delete, list and host revoke token actions if the user is not a cluster admin.
- Fixed Research Sync applying progress of a previous techology level to the level on the controller when it's the active research during instance startup.
- Fixed data export with a mod using shorthand notation for the default value of a color-setting causing the ModPack data to be set to invalid data.
## Version 2.0.0-alpha.16
+3 -10
View File
@@ -18,11 +18,10 @@ interface SimpleIconSpecification {
icon_size: number;
icon_mipmaps?: number;
}
type Color = { r: number, g: number, b: number, a: number };
interface IconLayer {
icon: string;
icon_size: number;
tint?: Color,
tint?: lib.FactorioColor,
shift?: [number, number],
scale?: number,
icon_mipmaps?: number,
@@ -202,15 +201,9 @@ async function loadLayeredIcon(
iconLayer = iconLayer.clone();
let tint: Color;
let tint: lib.Color;
if (layer.tint) {
let divisor = (layer.tint.r > 1 || layer.tint.g > 1 || layer.tint.b > 1) ? 255 : 1;
tint = {
r: (layer.tint.r || 0) / divisor,
g: (layer.tint.g || 0) / divisor,
b: (layer.tint.b || 0) / divisor,
a: layer.tint.a || 1,
};
tint = lib.normalizeColor(layer.tint);
} else {
tint = { r: 1, b: 1, g: 1, a: 1 };
}
+1
View File
@@ -6,6 +6,7 @@ export * from "./src/factorio/exchange_string";
export * from "./src/helpers";
export * from "./src/ini";
export * from "./src/link";
export * from "./src/lua_tools";
export * from "./src/logging";
export * from "./src/permissions";
export * from "./src/plugin";
+6 -1
View File
@@ -2,6 +2,7 @@ import zlib from "zlib";
import { Type, Static } from "@sinclair/typebox";
import * as libSchema from "../schema";
import * as libLuaTools from "../lua_tools";
import ExportManifest from "./ExportManifest";
import { integerFactorioVersion } from "./version";
@@ -363,7 +364,11 @@ export default class ModPack {
continue;
}
this.settings[settingType].set(prototype.name, { value: prototype.default_value });
let value = prototype.default_value;
if (prototype.type === "color-setting") {
value = libLuaTools.normalizeColor(value);
}
this.settings[settingType].set(prototype.name, { value });
}
}
}
+48
View File
@@ -3,6 +3,54 @@
* @module lib/lua_tools
*/
/**
* A colour as it may originate from Factorio Lua code, see
* https://lua-api.factorio.com/latest/types/Color.html
*/
export type FactorioColor = { r?: number, g?: number, b?: number, a?: number } | [number, number, number, number?];
export type Color = { r: number, g: number, b: number, a: number };
/**
* Normalise a color as it may appear in Factorio Lua code to be an object
* with r, g, b, a properties in the range 0 to 1.
*
* @param color -
* A colour that may be specified with left out components or as an
* array and have the range 1 to 0 or 255 to 0.
* @returns
* Normalised colour where all 4 components are present as properties in
* the range 0 to 1.
*/
export function normalizeColor(color: FactorioColor) {
let r, g, b, a;
if (color instanceof Array) {
([r, g, b, a] = color);
} else {
({ r, g, b, a } = color);
}
r ??= NaN;
g ??= NaN;
b ??= NaN;
a ??= NaN;
// Note NaN > 1 is false and NaN / 255 is NaN
if (r > 1 || g > 1 || b > 1 || a > 1) {
r /= 255;
g /= 255;
b /= 255;
a /= 255;
}
return {
r: Number.isNaN(r) ? 0 : r,
g: Number.isNaN(g) ? 0 : g,
b: Number.isNaN(b) ? 0 : b,
a: Number.isNaN(a) ? 1 : a,
};
}
/**
* Escapes a string for inclusion into a lua string
*
+1
View File
@@ -12,6 +12,7 @@
"./src/hash.ts",
"./src/ini.ts",
"./src/link/*.ts",
"./src/lua_tools.ts",
"./src/logging.ts",
"./src/permissions.ts",
"./src/prometheus.ts",
+19
View File
@@ -5,6 +5,25 @@ const lib = require("@clusterio/lib");
describe("lib/lua_tools", function() {
describe("normalizeColor()", function() {
it("should normalise colours according to the documentation", function() {
const nc = lib.normalizeColor;
assert.deepEqual(nc({ r: 1, g: 0.2, b: 0.4, a: 0.8 }), { r: 1, g: 0.2, b: 0.4, a: 0.8 });
assert.deepEqual(nc({ r: 1, g: 0.2, b: 0.4 }), { r: 1, g: 0.2, b: 0.4, a: 1 });
assert.deepEqual(nc({ r: 1, b: 0.4 }), { r: 1, g: 0, b: 0.4, a: 1 });
assert.deepEqual(nc({ a: 0.4 }), { r: 0, g: 0, b: 0, a: 0.4 });
assert.deepEqual(nc({}), { r: 0, g: 0, b: 0, a: 1 });
assert.deepEqual(nc([1, 0.2, 0.4, 0.8]), { r: 1, g: 0.2, b: 0.4, a: 0.8 });
assert.deepEqual(nc([1, 0.2, 0.4]), { r: 1, g: 0.2, b: 0.4, a: 1 });
assert.deepEqual(nc({ r: 255, g: 51, b: 102, a: 204 }), { r: 1, g: 0.2, b: 0.4, a: 0.8 });
assert.deepEqual(nc({ r: 255, g: 51, b: 102 }), { r: 1, g: 0.2, b: 0.4, a: 1 });
assert.deepEqual(nc({ r: 255, b: 102 }), { r: 1, g: 0, b: 0.4, a: 1 });
assert.deepEqual(nc({ a: 102 }), { r: 0, g: 0, b: 0, a: 0.4 });
assert.deepEqual(nc({}), { r: 0, g: 0, b: 0, a: 1 });
assert.deepEqual(nc([255, 51, 102, 204]), { r: 1, g: 0.2, b: 0.4, a: 0.8 });
assert.deepEqual(nc([255, 51, 102]), { r: 1, g: 0.2, b: 0.4, a: 1 });
});
});
describe("escapeString()", function() {
it("should escape backslashes", function() {
assert.equal(lib.escapeString("\\a"), "\\\\a");