From 1287bc9bf18c614e937b93ef075920977a7daf0c Mon Sep 17 00:00:00 2001 From: tobspr Date: Sat, 22 Jan 2022 09:03:42 +0100 Subject: [PATCH 1/8] Allow specifying minimumGameVersion --- mod_examples/add_building_basic.js | 1 + mod_examples/add_building_flipper.js | 1 + mod_examples/base.js | 1 + mod_examples/buildings_have_cost.js | 1 + mod_examples/class_extensions.js | 1 + mod_examples/custom_css.js | 1 + mod_examples/custom_drawing.js | 1 + mod_examples/custom_keybinding.js | 1 + mod_examples/custom_sub_shapes.js | 1 + mod_examples/custom_theme.js | 1 + mod_examples/mod_settings.js | 1 + mod_examples/modify_existing_building.js | 1 + mod_examples/modify_theme.js | 1 + mod_examples/modify_ui.js | 1 + mod_examples/new_item_type.js | 1 + mod_examples/notification_blocks.js | 2 ++ mod_examples/pasting.js | 1 + mod_examples/replace_builtin_sprites.js | 1 + mod_examples/translations.js | 1 + mod_examples/usage_statistics.js | 2 ++ package.json | 1 + src/js/mods/modloader.js | 25 ++++++++++++++++++++++++ yarn.lock | 19 ++++++++++++++++++ 23 files changed, 67 insertions(+) diff --git a/mod_examples/add_building_basic.js b/mod_examples/add_building_basic.js index 97e0a358..4f834bc2 100644 --- a/mod_examples/add_building_basic.js +++ b/mod_examples/add_building_basic.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "add-building-basic", description: "Shows how to add a new basic building", + minimumGameVersion: "^1.5.0", }; class MetaDemoModBuilding extends shapez.ModMetaBuilding { diff --git a/mod_examples/add_building_flipper.js b/mod_examples/add_building_flipper.js index c04354bf..670f012a 100644 --- a/mod_examples/add_building_flipper.js +++ b/mod_examples/add_building_flipper.js @@ -7,6 +7,7 @@ const METADATA = { id: "add-building-extended", description: "Shows how to add a new building with logic, in this case it flips/mirrors shapez from top to down", + minimumGameVersion: "^1.5.0", }; // Declare a new type of item processor diff --git a/mod_examples/base.js b/mod_examples/base.js index 6dc8df8f..9810e823 100644 --- a/mod_examples/base.js +++ b/mod_examples/base.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "base", description: "The most basic mod", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/buildings_have_cost.js b/mod_examples/buildings_have_cost.js index 79061d35..04d1e14e 100644 --- a/mod_examples/buildings_have_cost.js +++ b/mod_examples/buildings_have_cost.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "patch-methods", description: "Shows how to patch existing methods to change the game by making the belts cost shapes", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/class_extensions.js b/mod_examples/class_extensions.js index c5b5b95e..904a5a03 100644 --- a/mod_examples/class_extensions.js +++ b/mod_examples/class_extensions.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "class-extensions", description: "Shows how to extend builtin classes", + minimumGameVersion: "^1.5.0", }; const BeltExtension = ({ $super, $old }) => ({ diff --git a/mod_examples/custom_css.js b/mod_examples/custom_css.js index 74d19057..2df83afd 100644 --- a/mod_examples/custom_css.js +++ b/mod_examples/custom_css.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "custom-css", description: "Shows how to add custom css", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/custom_drawing.js b/mod_examples/custom_drawing.js index 6ba49454..f491b94b 100644 --- a/mod_examples/custom_drawing.js +++ b/mod_examples/custom_drawing.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "base", description: "Displays an indicator on every item processing building when its working", + minimumGameVersion: "^1.5.0", }; class ItemProcessorStatusGameSystem extends shapez.GameSystem { diff --git a/mod_examples/custom_keybinding.js b/mod_examples/custom_keybinding.js index 650065f0..46ef71a6 100644 --- a/mod_examples/custom_keybinding.js +++ b/mod_examples/custom_keybinding.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "base", description: "Shows how to add a new keybinding", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/custom_sub_shapes.js b/mod_examples/custom_sub_shapes.js index afb901c0..906e3c9b 100644 --- a/mod_examples/custom_sub_shapes.js +++ b/mod_examples/custom_sub_shapes.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "custom-sub-shapes", description: "Shows how to add custom sub shapes", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/custom_theme.js b/mod_examples/custom_theme.js index a596799c..400e3b7c 100644 --- a/mod_examples/custom_theme.js +++ b/mod_examples/custom_theme.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "custom-theme", description: "Shows how to add a custom game theme", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/mod_settings.js b/mod_examples/mod_settings.js index bbcfe3fd..8f8e20de 100644 --- a/mod_examples/mod_settings.js +++ b/mod_examples/mod_settings.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "mod-settings", description: "Shows how to add settings to your mod", + minimumGameVersion: "^1.5.0", settings: { timesLaunched: 0, diff --git a/mod_examples/modify_existing_building.js b/mod_examples/modify_existing_building.js index 1264b2c3..c88fad7e 100644 --- a/mod_examples/modify_existing_building.js +++ b/mod_examples/modify_existing_building.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "modify-existing-building", description: "Shows how to modify an existing building", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/modify_theme.js b/mod_examples/modify_theme.js index dfdfb6e9..8a7f4318 100644 --- a/mod_examples/modify_theme.js +++ b/mod_examples/modify_theme.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "modify-theme", description: "Shows how to modify builtin themes", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/modify_ui.js b/mod_examples/modify_ui.js index 749e191e..ef8d2455 100644 --- a/mod_examples/modify_ui.js +++ b/mod_examples/modify_ui.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "modify-ui", description: "Shows how to modify a builtin game state, in this case the main menu", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/new_item_type.js b/mod_examples/new_item_type.js index ee06538d..3c8dad5c 100644 --- a/mod_examples/new_item_type.js +++ b/mod_examples/new_item_type.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "new-item-type", description: "Shows how to add a new item type (fluid)", + minimumGameVersion: "^1.5.0", }; // Define which fluid types there are diff --git a/mod_examples/notification_blocks.js b/mod_examples/notification_blocks.js index a8116849..4d8cf476 100644 --- a/mod_examples/notification_blocks.js +++ b/mod_examples/notification_blocks.js @@ -7,6 +7,8 @@ const METADATA = { id: "notification-blocks", description: "Adds a new building to the wires layer, 'Notification Blocks' which show a custom notification when they get a truthy signal.", + + minimumGameVersion: "^1.5.0", }; //////////////////////////////////////////////////////////////////////// diff --git a/mod_examples/pasting.js b/mod_examples/pasting.js index edd4952c..de253910 100644 --- a/mod_examples/pasting.js +++ b/mod_examples/pasting.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "pasting", description: "Shows how to properly receive paste events ingame", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/replace_builtin_sprites.js b/mod_examples/replace_builtin_sprites.js index 9865121e..1d93a36c 100644 --- a/mod_examples/replace_builtin_sprites.js +++ b/mod_examples/replace_builtin_sprites.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "replace-builtin-sprites", description: "Shows how to replace builtin sprites", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/translations.js b/mod_examples/translations.js index 8a3e07da..080be45c 100644 --- a/mod_examples/translations.js +++ b/mod_examples/translations.js @@ -6,6 +6,7 @@ const METADATA = { version: "1", id: "translations", description: "Shows how to add and modify translations", + minimumGameVersion: "^1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/usage_statistics.js b/mod_examples/usage_statistics.js index 36bb81f5..1412e4dd 100644 --- a/mod_examples/usage_statistics.js +++ b/mod_examples/usage_statistics.js @@ -7,6 +7,8 @@ const METADATA = { id: "usage-statistics", description: "Shows how to add a new component to the game, how to save additional data and how to add custom logic and drawings", + + minimumGameVersion: "^1.5.0", }; /** diff --git a/package.json b/package.json index 4ee134b7..ef752aac 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "promise-polyfill": "^8.1.0", "query-string": "^6.8.1", "rusha": "^0.8.13", + "semver": "^7.3.5", "serialize-error": "^3.0.0", "strictdom": "^1.0.1", "string-replace-webpack-plugin": "^0.1.3", diff --git a/src/js/mods/modloader.js b/src/js/mods/modloader.js index 96743038..48911abd 100644 --- a/src/js/mods/modloader.js +++ b/src/js/mods/modloader.js @@ -10,6 +10,9 @@ import { Mod } from "./mod"; import { ModInterface } from "./mod_interface"; import { MOD_SIGNALS } from "./mod_signals"; +import semverValidRange from "semver/ranges/valid"; +import semverSatisifies from "semver/functions/satisfies"; + const LOG = createLogger("mods"); /** @@ -20,6 +23,7 @@ const LOG = createLogger("mods"); * website: string; * description: string; * id: string; + * minimumGameVersion?: string; * settings: [] * }} ModMetadata */ @@ -158,6 +162,27 @@ export class ModLoader { const { modClass, meta } = this.modLoadQueue[i]; const modDataFile = "modsettings_" + meta.id + "__" + meta.version + ".json"; + if (meta.minimumGameVersion) { + console.warn(meta.minimumGameVersion, G_BUILD_VERSION); + const minimumGameVersion = meta.minimumGameVersion; + if (!semverValidRange(minimumGameVersion)) { + alert("Mod " + meta.id + " has invalid minimumGameVersion: " + minimumGameVersion); + continue; + } + if (!semverSatisifies(G_BUILD_VERSION, minimumGameVersion)) { + alert( + "Mod '" + + meta.id + + "' is incompatible with this version of the game: \n\n" + + "Mod requires version " + + minimumGameVersion + + " but this game has version " + + G_BUILD_VERSION + ); + continue; + } + } + let settings = meta.settings; if (meta.settings) { diff --git a/yarn.lock b/yarn.lock index cdcdd19e..27552f93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5245,6 +5245,13 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lz-string@^1.4.4: version "1.4.4" resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz" @@ -7496,6 +7503,13 @@ semver@^7.2.1, semver@^7.3.2: resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz" @@ -8800,6 +8814,11 @@ yallist@^3.0.2: resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml-js@^0.1.3: version "0.1.5" resolved "https://registry.npmjs.org/yaml-js/-/yaml-js-0.1.5.tgz" From ade7176dba0f37d3478d380fc11cf452b43738e3 Mon Sep 17 00:00:00 2001 From: tobspr Date: Sat, 22 Jan 2022 09:34:38 +0100 Subject: [PATCH 2/8] Add sandbox example --- mod_examples/README.md | 1 + mod_examples/sandbox.js | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 mod_examples/sandbox.js diff --git a/mod_examples/README.md b/mod_examples/README.md index 25b1d75e..e38d5834 100644 --- a/mod_examples/README.md +++ b/mod_examples/README.md @@ -41,6 +41,7 @@ To get into shapez.io modding, I highly recommend checking out all of the exampl | [modify_existing_building.js](modify_existing_building.js) | Makes the rotator building always unlocked and adds a new statistic to the building panel | Modifying a builtin building, replacing builtin methods | | [modify_ui.js](modify_ui.js) | Shows how to add custom IU elements to builtin game states (the Main Menu in this case) | Extending builtin UI states, Adding CSS | | [pasting.js](pasting.js) | Shows a dialog when pasting text in the game | Listening to paste events | +| [sandbox.js](sandbox.js) | Makes blueprints free and always unlocked | Overriding builtin methods | ### Advanced Examples diff --git a/mod_examples/sandbox.js b/mod_examples/sandbox.js new file mode 100644 index 00000000..d57e1e0e --- /dev/null +++ b/mod_examples/sandbox.js @@ -0,0 +1,21 @@ +// @ts-nocheck +const METADATA = { + website: "https://tobspr.io", + author: "tobspr", + name: "Sandbox", + version: "1", + id: "sandbox", + description: "Blueprints are always unlocked and cost no money, also all buildings are unlocked", + minimumGameVersion: "^1.5.0", +}; + +class Mod extends shapez.Mod { + init() { + this.modInterface.replaceMethod(shapez.Blueprint, "getCost", function () { + return 0; + }); + this.modInterface.replaceMethod(shapez.HubGoals, "isRewardUnlocked", function () { + return true; + }); + } +} From a3dfe6f5fb2cba520c72a495ddea16abd7fb34be Mon Sep 17 00:00:00 2001 From: saile515 <63782477+saile515@users.noreply.github.com> Date: Sat, 22 Jan 2022 09:50:02 +0100 Subject: [PATCH 3/8] Replaced concatenated strings with template literals (#1347) --- mod_examples/mod_settings.js | 2 +- mod_examples/new_item_type.js | 4 ++-- mod_examples/pasting.js | 2 +- mod_examples/replace_builtin_sprites.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mod_examples/mod_settings.js b/mod_examples/mod_settings.js index 8f8e20de..873468c4 100644 --- a/mod_examples/mod_settings.js +++ b/mod_examples/mod_settings.js @@ -24,7 +24,7 @@ class Mod extends shapez.Mod { if (state instanceof shapez.MainMenuState) { this.dialogs.showInfo( "Welcome back", - "You have launched this mod " + this.settings.timesLaunched + " times" + `You have launched this mod ${this.settings.timesLaunched} times` ); } }); diff --git a/mod_examples/new_item_type.js b/mod_examples/new_item_type.js index 3c8dad5c..a9fa30ca 100644 --- a/mod_examples/new_item_type.js +++ b/mod_examples/new_item_type.js @@ -76,7 +76,7 @@ class FluidItem extends shapez.BaseItem { */ drawFullSizeOnCanvas(context, size) { if (!this.cachedSprite) { - this.cachedSprite = shapez.Loader.getSprite("sprites/fluids/" + this.fluidType + ".png"); + this.cachedSprite = shapez.Loader.getSprite(`sprites/fluids/${this.fluidType}.png`); } this.cachedSprite.drawCentered(context, size / 2, size / 2, size); } @@ -90,7 +90,7 @@ class FluidItem extends shapez.BaseItem { drawItemCenteredClipped(x, y, parameters, diameter = globalConfig.defaultItemDiameter) { const realDiameter = diameter * 0.6; if (!this.cachedSprite) { - this.cachedSprite = shapez.Loader.getSprite("sprites/fluids/" + this.fluidType + ".png"); + this.cachedSprite = shapez.Loader.getSprite(`sprites/fluids/${this.fluidType}.png`); } this.cachedSprite.drawCachedCentered(parameters, x, y, realDiameter); } diff --git a/mod_examples/pasting.js b/mod_examples/pasting.js index de253910..b514f137 100644 --- a/mod_examples/pasting.js +++ b/mod_examples/pasting.js @@ -16,7 +16,7 @@ class Mod extends shapez.Mod { event.preventDefault(); const data = event.clipboardData.getData("text"); - this.dialogs.showInfo("Pasted", "You pasted: '" + data + "'"); + this.dialogs.showInfo("Pasted", `You pasted: '${data}'`); }); }); } diff --git a/mod_examples/replace_builtin_sprites.js b/mod_examples/replace_builtin_sprites.js index 1d93a36c..d0407692 100644 --- a/mod_examples/replace_builtin_sprites.js +++ b/mod_examples/replace_builtin_sprites.js @@ -13,7 +13,7 @@ class Mod extends shapez.Mod { init() { // Replace a builtin sprite ["red", "green", "blue", "yellow", "purple", "cyan", "white"].forEach(color => { - this.modInterface.registerSprite("sprites/colors/" + color + ".png", RESOURCES[color + ".png"]); + this.modInterface.registerSprite(`sprites/colors/${color}.png`, RESOURCES[color + ".png"]); }); } } From 408d1a7dcacc44700c5cb3749e2868fe298cfdfb Mon Sep 17 00:00:00 2001 From: tobspr Date: Sat, 22 Jan 2022 10:03:42 +0100 Subject: [PATCH 4/8] Mod improvements --- src/css/states/main_menu.scss | 43 +++++++++++++++++++++++------------ src/css/states/mods.scss | 9 ++++++++ src/js/core/config.js | 2 ++ src/js/states/main_menu.js | 10 ++++++-- src/js/states/mods.js | 17 +++++++++++++- translations/base-en.yaml | 1 + 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/css/states/main_menu.scss b/src/css/states/main_menu.scss index 2458350e..9027d8a8 100644 --- a/src/css/states/main_menu.scss +++ b/src/css/states/main_menu.scss @@ -199,10 +199,6 @@ transform: translateX(50%) rotate(-7deg) scale(1.1); } } - - @include DarkThemeOverride { - color: $colorBlueBright; - } } } @@ -326,6 +322,7 @@ /* @load-async */ background-image: uiResource("icons/edit_key.png") !important; } + @include DarkThemeInvert; } } @@ -354,13 +351,14 @@ box-sizing: border-box; @include PlainText; @include S(margin-bottom, 5px); - display: grid; - grid-template-columns: 1fr auto auto; - @include S(grid-gap, 5px); + display: flex; + flex-direction: column; .author, .version { @include SuperSmallText; + align-self: end; + opacity: 0.4; } .name { overflow: hidden; @@ -457,19 +455,19 @@ .newGameButton { @include IncreasedClickArea(0px); - @include S(margin-left, 15px); + @include S(margin-left, 10px); } .modsButton { @include IncreasedClickArea(0px); - @include S(margin-left, 15px); + @include S(margin-left, 10px); - @include S(width, 20px); + // @include S(width, 20px); - & { - /* @load-async */ - background-image: uiResource("res/ui/icons/mods_white.png") !important; - } + // & { + // /* @load-async */ + // background-image: uiResource("res/ui/icons/mods_white.png") !important; + // } background-position: center center; background-size: D(15px); background-color: $modsColor !important; @@ -837,6 +835,23 @@ } } + .modsOverview { + background: $darkModeControlsBackground; + + .modsList { + border-color: darken($darkModeControlsBackground, 5); + + .mod { + background: darken($darkModeControlsBackground, 5); + color: white; + } + } + + .dlcHint { + color: $accentColorBright; + } + } + .footer { > a, .sidelinks > a { diff --git a/src/css/states/mods.scss b/src/css/states/mods.scss index 54d8422b..acec41fb 100644 --- a/src/css/states/mods.scss +++ b/src/css/states/mods.scss @@ -62,6 +62,11 @@ @include S(margin-top, 100px); color: lighten($accentColorDark, 15); + button { + @include S(margin-top, 10px); + @include S(padding, 10px, 20px); + } + &::before { @include S(margin-bottom, 15px); content: ""; @@ -94,6 +99,10 @@ display: grid; grid-template-columns: 1fr D(100px) D(80px) D(50px); + @include DarkThemeOverride { + background: darken($darkModeControlsBackground, 5); + } + .checkbox { align-self: center; justify-self: center; diff --git a/src/js/core/config.js b/src/js/core/config.js index 773295ed..b451e848 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.js @@ -28,6 +28,8 @@ export const THIRDPARTY_URLS = { 25: "https://www.youtube.com/watch?v=7OCV1g40Iew&", 26: "https://www.youtube.com/watch?v=gfm6dS1dCoY", }, + + modBrowser: "https://shapez.mod.io/?preview=f55f6304ca4873d9a25f3b575571b948", }; // export const A_B_TESTING_LINK_TYPE = Math.random() > 0.95 ? "steam_1_pr" : "steam_2_npr"; diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js index b23a15f3..4d62f2ce 100644 --- a/src/js/states/main_menu.js +++ b/src/js/states/main_menu.js @@ -161,7 +161,10 @@ export class MainMenuState extends GameState { ${MODS.mods .map(mod => { return ` -
${mod.metadata.name} @ v${mod.metadata.version}
+
+
${mod.metadata.name}
+
by ${mod.metadata.author}
+
`; }) .join("")} @@ -413,7 +416,10 @@ export class MainMenuState extends GameState { } // Mods - this.trackClicks(makeButton(outerDiv, ["modsButton", "styledButton"], " "), this.onModsClicked); + this.trackClicks( + makeButton(outerDiv, ["modsButton", "styledButton"], T.mods.title), + this.onModsClicked + ); buttonContainer.appendChild(outerDiv); } diff --git a/src/js/states/mods.js b/src/js/states/mods.js index c3cbce52..42add8bd 100644 --- a/src/js/states/mods.js +++ b/src/js/states/mods.js @@ -18,6 +18,11 @@ export class ModsState extends TextualGameState {

${this.getStateHeaderTitle()}

+ ${ + (G_IS_STANDALONE || G_IS_DEV) && MODS.mods.length > 0 + ? `` + : "" + } ${ G_IS_STANDALONE || G_IS_DEV ? `` @@ -53,8 +58,9 @@ export class ModsState extends TextualGameState { return `
- ${T.mods.modsInfo} + +
`; @@ -100,6 +106,10 @@ export class ModsState extends TextualGameState { if (openModsFolder) { this.trackClicks(openModsFolder, this.openModsFolder); } + const browseMods = this.htmlElement.querySelector(".browseMods"); + if (browseMods) { + this.trackClicks(browseMods, this.openBrowseMods); + } const checkboxes = this.htmlElement.querySelectorAll(".checkbox"); Array.from(checkboxes).forEach(checkbox => { @@ -119,6 +129,11 @@ export class ModsState extends TextualGameState { ipcRenderer.invoke("open-mods-folder"); } + openBrowseMods() { + this.app.analytics.trackUiClick("mods_sbrowse_link"); + this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.modBrowser); + } + onSteamLinkClicked() { this.app.analytics.trackUiClick("mods_steam_link"); this.app.platformWrapper.openExternalLink( diff --git a/translations/base-en.yaml b/translations/base-en.yaml index 2f76c00f..7070c318 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -1098,6 +1098,7 @@ mods: version: Version openFolder: Open Mods Folder folderOnlyStandalone: Opening the mod folder is only possible when running the standalone. + browseMods: Browse Mods modsInfo: >- To install and manage mods, copy them to the mods folder within the game directory. You can also use the 'Open Mods Folder' button on the top right. From 0540a010a618f3149275df28f6c3985d1a30bcfb Mon Sep 17 00:00:00 2001 From: tobspr Date: Sat, 22 Jan 2022 18:23:05 +0100 Subject: [PATCH 5/8] Make wired pins component optional on the storage --- src/js/game/systems/storage.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/js/game/systems/storage.js b/src/js/game/systems/storage.js index cd204448..20204a89 100644 --- a/src/js/game/systems/storage.js +++ b/src/js/game/systems/storage.js @@ -50,8 +50,13 @@ export class StorageSystem extends GameSystemWithFilter { let targetAlpha = storageComp.storedCount > 0 ? 1 : 0; storageComp.overlayOpacity = lerp(storageComp.overlayOpacity, targetAlpha, 0.05); - pinsComp.slots[0].value = storageComp.storedItem; - pinsComp.slots[1].value = storageComp.getIsFull() ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; + // a wired pins component is not guaranteed, but if its there, set the value + if (pinsComp) { + pinsComp.slots[0].value = storageComp.storedItem; + pinsComp.slots[1].value = storageComp.getIsFull() + ? BOOL_TRUE_SINGLETON + : BOOL_FALSE_SINGLETON; + } } } From 509c01f64280aef587633590102cbe55bcfe2e7e Mon Sep 17 00:00:00 2001 From: tobspr Date: Sat, 22 Jan 2022 22:04:49 +0100 Subject: [PATCH 6/8] Fix mod examples --- mod_examples/add_building_basic.js | 2 +- mod_examples/add_building_flipper.js | 2 +- mod_examples/base.js | 2 +- mod_examples/buildings_have_cost.js | 2 +- mod_examples/class_extensions.js | 2 +- mod_examples/custom_css.js | 2 +- mod_examples/custom_drawing.js | 2 +- mod_examples/custom_keybinding.js | 2 +- mod_examples/custom_sub_shapes.js | 2 +- mod_examples/custom_theme.js | 2 +- mod_examples/mod_settings.js | 2 +- mod_examples/modify_existing_building.js | 2 +- mod_examples/modify_theme.js | 2 +- mod_examples/modify_ui.js | 2 +- mod_examples/new_item_type.js | 2 +- mod_examples/notification_blocks.js | 2 +- mod_examples/pasting.js | 2 +- mod_examples/replace_builtin_sprites.js | 2 +- mod_examples/sandbox.js | 2 +- mod_examples/translations.js | 2 +- mod_examples/usage_statistics.js | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/mod_examples/add_building_basic.js b/mod_examples/add_building_basic.js index 4f834bc2..6b92e769 100644 --- a/mod_examples/add_building_basic.js +++ b/mod_examples/add_building_basic.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "add-building-basic", description: "Shows how to add a new basic building", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class MetaDemoModBuilding extends shapez.ModMetaBuilding { diff --git a/mod_examples/add_building_flipper.js b/mod_examples/add_building_flipper.js index 670f012a..03442499 100644 --- a/mod_examples/add_building_flipper.js +++ b/mod_examples/add_building_flipper.js @@ -7,7 +7,7 @@ const METADATA = { id: "add-building-extended", description: "Shows how to add a new building with logic, in this case it flips/mirrors shapez from top to down", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; // Declare a new type of item processor diff --git a/mod_examples/base.js b/mod_examples/base.js index 9810e823..09e12f61 100644 --- a/mod_examples/base.js +++ b/mod_examples/base.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "base", description: "The most basic mod", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/buildings_have_cost.js b/mod_examples/buildings_have_cost.js index 04d1e14e..3dae84ae 100644 --- a/mod_examples/buildings_have_cost.js +++ b/mod_examples/buildings_have_cost.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "patch-methods", description: "Shows how to patch existing methods to change the game by making the belts cost shapes", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/class_extensions.js b/mod_examples/class_extensions.js index 904a5a03..8647fd45 100644 --- a/mod_examples/class_extensions.js +++ b/mod_examples/class_extensions.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "class-extensions", description: "Shows how to extend builtin classes", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; const BeltExtension = ({ $super, $old }) => ({ diff --git a/mod_examples/custom_css.js b/mod_examples/custom_css.js index 2df83afd..dce316c5 100644 --- a/mod_examples/custom_css.js +++ b/mod_examples/custom_css.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "custom-css", description: "Shows how to add custom css", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/custom_drawing.js b/mod_examples/custom_drawing.js index f491b94b..e1c25b30 100644 --- a/mod_examples/custom_drawing.js +++ b/mod_examples/custom_drawing.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "base", description: "Displays an indicator on every item processing building when its working", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class ItemProcessorStatusGameSystem extends shapez.GameSystem { diff --git a/mod_examples/custom_keybinding.js b/mod_examples/custom_keybinding.js index 46ef71a6..0a6b11fc 100644 --- a/mod_examples/custom_keybinding.js +++ b/mod_examples/custom_keybinding.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "base", description: "Shows how to add a new keybinding", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/custom_sub_shapes.js b/mod_examples/custom_sub_shapes.js index 906e3c9b..3aea03cf 100644 --- a/mod_examples/custom_sub_shapes.js +++ b/mod_examples/custom_sub_shapes.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "custom-sub-shapes", description: "Shows how to add custom sub shapes", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/custom_theme.js b/mod_examples/custom_theme.js index 400e3b7c..cc4c9de8 100644 --- a/mod_examples/custom_theme.js +++ b/mod_examples/custom_theme.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "custom-theme", description: "Shows how to add a custom game theme", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/mod_settings.js b/mod_examples/mod_settings.js index 873468c4..b87c138b 100644 --- a/mod_examples/mod_settings.js +++ b/mod_examples/mod_settings.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "mod-settings", description: "Shows how to add settings to your mod", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", settings: { timesLaunched: 0, diff --git a/mod_examples/modify_existing_building.js b/mod_examples/modify_existing_building.js index c88fad7e..b09f5a20 100644 --- a/mod_examples/modify_existing_building.js +++ b/mod_examples/modify_existing_building.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "modify-existing-building", description: "Shows how to modify an existing building", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/modify_theme.js b/mod_examples/modify_theme.js index 8a7f4318..4bc9be34 100644 --- a/mod_examples/modify_theme.js +++ b/mod_examples/modify_theme.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "modify-theme", description: "Shows how to modify builtin themes", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/modify_ui.js b/mod_examples/modify_ui.js index ef8d2455..0b2d1341 100644 --- a/mod_examples/modify_ui.js +++ b/mod_examples/modify_ui.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "modify-ui", description: "Shows how to modify a builtin game state, in this case the main menu", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/new_item_type.js b/mod_examples/new_item_type.js index a9fa30ca..3cd52cef 100644 --- a/mod_examples/new_item_type.js +++ b/mod_examples/new_item_type.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "new-item-type", description: "Shows how to add a new item type (fluid)", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; // Define which fluid types there are diff --git a/mod_examples/notification_blocks.js b/mod_examples/notification_blocks.js index 4d8cf476..23f95943 100644 --- a/mod_examples/notification_blocks.js +++ b/mod_examples/notification_blocks.js @@ -8,7 +8,7 @@ const METADATA = { description: "Adds a new building to the wires layer, 'Notification Blocks' which show a custom notification when they get a truthy signal.", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; //////////////////////////////////////////////////////////////////////// diff --git a/mod_examples/pasting.js b/mod_examples/pasting.js index b514f137..698edeff 100644 --- a/mod_examples/pasting.js +++ b/mod_examples/pasting.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "pasting", description: "Shows how to properly receive paste events ingame", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/replace_builtin_sprites.js b/mod_examples/replace_builtin_sprites.js index d0407692..885846e7 100644 --- a/mod_examples/replace_builtin_sprites.js +++ b/mod_examples/replace_builtin_sprites.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "replace-builtin-sprites", description: "Shows how to replace builtin sprites", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/sandbox.js b/mod_examples/sandbox.js index d57e1e0e..f405ab59 100644 --- a/mod_examples/sandbox.js +++ b/mod_examples/sandbox.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "sandbox", description: "Blueprints are always unlocked and cost no money, also all buildings are unlocked", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/translations.js b/mod_examples/translations.js index 080be45c..2f3a4015 100644 --- a/mod_examples/translations.js +++ b/mod_examples/translations.js @@ -6,7 +6,7 @@ const METADATA = { version: "1", id: "translations", description: "Shows how to add and modify translations", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; class Mod extends shapez.Mod { diff --git a/mod_examples/usage_statistics.js b/mod_examples/usage_statistics.js index 1412e4dd..64da102b 100644 --- a/mod_examples/usage_statistics.js +++ b/mod_examples/usage_statistics.js @@ -8,7 +8,7 @@ const METADATA = { description: "Shows how to add a new component to the game, how to save additional data and how to add custom logic and drawings", - minimumGameVersion: "^1.5.0", + minimumGameVersion: ">=1.5.0", }; /** From 8dcb5faf5f7562ed646c1bcec8f74e44f9427c9a Mon Sep 17 00:00:00 2001 From: Bagel03 <70449196+Bagel03@users.noreply.github.com> Date: Sun, 23 Jan 2022 11:14:03 -0500 Subject: [PATCH 7/8] Bind `this` for method overriding JSDoc (#1352) --- src/js/mods/mod_interface.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/js/mods/mod_interface.js b/src/js/mods/mod_interface.js index e3b9e59b..195c005b 100644 --- a/src/js/mods/mod_interface.js +++ b/src/js/mods/mod_interface.js @@ -31,6 +31,12 @@ import { BaseHUDPart } from "../game/hud/base_hud_part"; * @typedef {{new(...args: any[]): any, prototype: any}} constructable */ +/** + * @template {(...args: any) => any} F The function + * @template {object} T The value of this + * @typedef {(this: T, ...args: Parameters) => ReturnType} bindThis + */ + /** * @template {(...args: any[]) => any} F * @template P @@ -400,7 +406,7 @@ export class ModInterface { * @template {extendsPrams} O the method that will override the old one * @param {C} classHandle * @param {M} methodName - * @param {beforePrams} override + * @param {bindThis, InstanceType>} override */ replaceMethod(classHandle, methodName, override) { const oldMethod = classHandle.prototype[methodName]; @@ -418,7 +424,7 @@ export class ModInterface { * @template {extendsPrams} O the method that will run before the old one * @param {C} classHandle * @param {M} methodName - * @param {O} executeBefore + * @param {bindThis>} executeBefore */ runBeforeMethod(classHandle, methodName, executeBefore) { const oldHandle = classHandle.prototype[methodName]; @@ -437,7 +443,7 @@ export class ModInterface { * @template {extendsPrams} O the method that will run before the old one * @param {C} classHandle * @param {M} methodName - * @param {O} executeAfter + * @param {bindThis>} executeAfter */ runAfterMethod(classHandle, methodName, executeAfter) { const oldHandle = classHandle.prototype[methodName]; From 431453f1a2db1977bd5b50ffc6c9cdb366111d4e Mon Sep 17 00:00:00 2001 From: Emerald Block <69981203+EmeraldBlock@users.noreply.github.com> Date: Sun, 23 Jan 2022 10:14:24 -0600 Subject: [PATCH 8/8] fix entity debugger reaching HTML elements (#1353) --- src/js/game/hud/parts/entity_debugger.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/js/game/hud/parts/entity_debugger.js b/src/js/game/hud/parts/entity_debugger.js index 640ad4d6..debd456d 100644 --- a/src/js/game/hud/parts/entity_debugger.js +++ b/src/js/game/hud/parts/entity_debugger.js @@ -94,11 +94,12 @@ export class HUDEntityDebugger extends BaseHUDPart {
`; for (const property in val) { - const isRoot = val[property] == this.root; - const isRecursive = recursion.includes(val[property]); - - let hiddenValue = isRoot ? "" : null; - if (isRecursive) { + let hiddenValue = null; + if (val[property] == this.root) { + hiddenValue = ""; + } else if (val[property] instanceof Node) { + hiddenValue = `<${val[property].constructor.name}>`; + } else if (recursion.includes(val[property])) { // Avoid recursion by not "expanding" object more than once hiddenValue = ""; }