diff --git a/README.md b/README.md index 2b8d208b..3d93ece5 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts ## Building - Make sure `ffmpeg` is on your path -- Install Node.js and Yarn +- Install Node.js (v16.0 or earlier) and Yarn - Install Java (required for textures) - Run `yarn` in the root folder - Cd into `gulp` folder diff --git a/gulp/webpack.config.js b/gulp/webpack.config.js index c696d2bd..3c07d7cc 100644 --- a/gulp/webpack.config.js +++ b/gulp/webpack.config.js @@ -97,7 +97,6 @@ module.exports = ({ watch = false, standalone = false, chineseVersion = false, w loader: path.resolve(__dirname, "mod.js"), }, ], - ], }, { test: /\.worker\.js$/, diff --git a/mod_examples/README.md b/mod_examples/README.md index c0b101e4..b8e501c8 100644 --- a/mod_examples/README.md +++ b/mod_examples/README.md @@ -50,7 +50,7 @@ To get into shapez.io modding, I highly recommend checking out all of the exampl | [usage_statistics.js](usage_statistics.js) | Displays a percentage on every building showing its utilization | Adding a new component, Adding a new GameSystem, Drawing within a GameSystem, Modifying builtin buildings, Adding custom game logic | | [new_item_type.js](new_item_type.js) | Adds a new type of items to the map (fluids) | Adding a new item type, modifying map generation | | [buildings_have_cost.js](buildings_have_cost.js) | Adds a new currency, and belts cost 1 of that currency | Extending and replacing builtin methods, Adding CSS and custom sprites | -| [mirrored_cutter.js](mirrored_cutter.js) | Adds a mirorred variant of the cutter | Adding a new variant to existing buildings | +| [mirrored_cutter.js](mirrored_cutter.js) | Adds a mirrored variant of the cutter | Adding a new variant to existing buildings | ### Creating new sprites diff --git a/mod_examples/class_extensions.js b/mod_examples/class_extensions.js index 8647fd45..ace5aae9 100644 --- a/mod_examples/class_extensions.js +++ b/mod_examples/class_extensions.js @@ -15,9 +15,9 @@ const BeltExtension = ({ $super, $old }) => ({ return !$old.getShowWiresLayerPreview(); }, - getIsReplaceable() { + getIsReplaceable(variant, rotationVariant) { // Instead of super, use $super - return $super.getIsReplaceable.call(this); + return $super.getIsReplaceable.call(this, variant, rotationVariant); }, getIsRemoveable() { diff --git a/mod_examples/new_item_type.js b/mod_examples/new_item_type.js index 3f47d4d2..104ef0a0 100644 --- a/mod_examples/new_item_type.js +++ b/mod_examples/new_item_type.js @@ -87,7 +87,7 @@ class FluidItem extends shapez.BaseItem { * @param {number} diameter * @param {DrawParameters} parameters */ - drawItemCenteredClipped(x, y, parameters, diameter = globalConfig.defaultItemDiameter) { + drawItemCenteredClipped(x, y, parameters, diameter = shapez.globalConfig.defaultItemDiameter) { const realDiameter = diameter * 0.6; if (!this.cachedSprite) { this.cachedSprite = shapez.Loader.getSprite(`sprites/fluids/${this.fluidType}.png`); @@ -120,19 +120,19 @@ class Mod extends shapez.Mod { this.modInterface.registerSprite("sprites/fluids/water.png", RESOURCES["water.png"]); // Make the item spawn on the map - this.modInterface.runAfterMethod( - shapez.MapChunk, - "generatePatches", - function ({ rng, chunkCenter, distanceToOriginInChunks }) { - // Generate a simple patch - // ALWAYS use rng and NEVER use Math.random() otherwise the map will look different - // every time you resume the game - if (rng.next() > 0.8) { - const fluidType = rng.choice(Array.from(Object.keys(enumFluidType))); - this.internalGeneratePatch(rng, 4, FLUID_ITEM_SINGLETONS[fluidType]); - } + this.modInterface.runAfterMethod(shapez.MapChunk, "generatePatches", function ({ + rng, + chunkCenter, + distanceToOriginInChunks, + }) { + // Generate a simple patch + // ALWAYS use rng and NEVER use Math.random() otherwise the map will look different + // every time you resume the game + if (rng.next() > 0.8) { + const fluidType = rng.choice(Array.from(Object.keys(enumFluidType))); + this.internalGeneratePatch(rng, 4, FLUID_ITEM_SINGLETONS[fluidType]); } - ); + }); this.modInterface.registerItem(FluidItem, itemData => FLUID_ITEM_SINGLETONS[itemData]); } diff --git a/src/js/changelog.js b/src/js/changelog.js index 05c7395c..6640dd9e 100644 --- a/src/js/changelog.js +++ b/src/js/changelog.js @@ -1,9 +1,10 @@ export const CHANGELOG = [ { - version: "1.5.0", - date: "unreleased", + version: "1.5.1", + date: "25.02.2022", entries: [ - "This version adds an official modloader! You can now load mods by placing it in the mods/ folder of the game.", + "This version adds an official modloader! You can now load mods by extracting them and placing the .js file in the mods/ folder of the game.", + "Mods can be found here", "When holding shift while placing a belt, the indicator now becomes red when crossing buildings", "Lots of performance improvements, leading to up to 50% more FPS", ], diff --git a/src/js/core/game_state.js b/src/js/core/game_state.js index b08bef77..fb08e28d 100644 --- a/src/js/core/game_state.js +++ b/src/js/core/game_state.js @@ -211,6 +211,7 @@ export class GameState { /** * Should return the html code of the state. * @returns {string} + * @abstract */ getInnerHTML() { abstract; diff --git a/src/js/core/query_parameters.js b/src/js/core/query_parameters.js index 7837acb5..b3dab1b3 100644 --- a/src/js/core/query_parameters.js +++ b/src/js/core/query_parameters.js @@ -3,20 +3,8 @@ const options = queryString.parse(location.search); export let queryParamOptions = { embedProvider: null, - fullVersion: false, - sandboxMode: false, }; if (options.embed) { queryParamOptions.embedProvider = options.embed; } - -// Allow testing full version outside of standalone -if (options.fullVersion && !G_IS_RELEASE) { - queryParamOptions.fullVersion = true; -} - -// Allow testing full version outside of standalone -if (options.sandboxMode && !G_IS_RELEASE) { - queryParamOptions.sandboxMode = true; -} diff --git a/src/js/core/rectangle.js b/src/js/core/rectangle.js index bd3421d9..e2c85082 100644 --- a/src/js/core/rectangle.js +++ b/src/js/core/rectangle.js @@ -268,7 +268,7 @@ export class Rectangle { } /** - * Returns if hte rectangle contains the given point + * Returns if the rectangle contains the given point * @param {number} x * @param {number} y * @returns {boolean} diff --git a/src/js/core/restriction_manager.js b/src/js/core/restriction_manager.js index c899b494..3ca30597 100644 --- a/src/js/core/restriction_manager.js +++ b/src/js/core/restriction_manager.js @@ -84,11 +84,6 @@ export class RestrictionManager extends ReadWriteProxy { return false; } - if (queryParamOptions.fullVersion) { - // Full version is activated via flag - return false; - } - if (queryParamOptions.embedProvider === "gamedistribution") { // also full version on gamedistribution return false; diff --git a/src/js/core/sprites.js b/src/js/core/sprites.js index 51032e4e..d568f994 100644 --- a/src/js/core/sprites.js +++ b/src/js/core/sprites.js @@ -11,6 +11,7 @@ export class BaseSprite { /** * Returns the raw handle * @returns {HTMLImageElement|HTMLCanvasElement} + * @abstract */ getRawTexture() { abstract; diff --git a/src/js/game/base_item.js b/src/js/game/base_item.js index f6ed1672..a6b38a08 100644 --- a/src/js/game/base_item.js +++ b/src/js/game/base_item.js @@ -29,6 +29,7 @@ export class BaseItem extends BasicSerializableObject { /** * Returns a string id of the item * @returns {string} + * @abstract */ getAsCopyableKey() { abstract; @@ -49,9 +50,9 @@ export class BaseItem extends BasicSerializableObject { /** * Override for custom comparison - * @abstract * @param {BaseItem} other * @returns {boolean} + * @abstract */ equalsImpl(other) { abstract; @@ -62,6 +63,7 @@ export class BaseItem extends BasicSerializableObject { * Draws the item to a canvas * @param {CanvasRenderingContext2D} context * @param {number} size + * @abstract */ drawFullSizeOnCanvas(context, size) { abstract; @@ -86,6 +88,7 @@ export class BaseItem extends BasicSerializableObject { * @param {number} y * @param {DrawParameters} parameters * @param {number=} diameter + * @abstract */ drawItemCenteredImpl(x, y, parameters, diameter = globalConfig.defaultItemDiameter) { abstract; diff --git a/src/js/game/belt_path.js b/src/js/game/belt_path.js index bb59b19b..6cda9f22 100644 --- a/src/js/game/belt_path.js +++ b/src/js/game/belt_path.js @@ -1526,7 +1526,17 @@ export class BeltPath extends BasicSerializableObject { const sprite = this.root.buffers.getForKey({ key: "beltpaths", - subKey: "stack-" + directionProp + "-" + dpi + "-" + stack.length + firstItem[1].serialize(), + subKey: + "stack-" + + directionProp + + "-" + + dpi + + "#" + + stack.length + + "#" + + firstItem[1].getItemType() + + "#" + + firstItem[1].serialize(), dpi, w: dimensions.x, h: dimensions.y, diff --git a/src/js/game/component.js b/src/js/game/component.js index cff14d62..9e1b63f4 100644 --- a/src/js/game/component.js +++ b/src/js/game/component.js @@ -4,6 +4,7 @@ export class Component extends BasicSerializableObject { /** * Returns the components unique id * @returns {string} + * @abstract */ static getId() { abstract; diff --git a/src/js/game/entity.js b/src/js/game/entity.js index 3010f067..9acaf26b 100644 --- a/src/js/game/entity.js +++ b/src/js/game/entity.js @@ -224,6 +224,7 @@ export class Entity extends BasicSerializableObject { /** * override, should draw the entity * @param {DrawParameters} parameters + * @abstract */ drawImpl(parameters) { abstract; diff --git a/src/js/game/game_mode.js b/src/js/game/game_mode.js index 5414306c..2c4527e3 100644 --- a/src/js/game/game_mode.js +++ b/src/js/game/game_mode.js @@ -144,6 +144,7 @@ export class GameMode extends BasicSerializableObject { /** * @param {number} w * @param {number} h + * @abstract */ adjustZone(w = 0, h = 0) { abstract; diff --git a/src/js/game/hud/base_hud_part.js b/src/js/game/hud/base_hud_part.js index 84b6d619..91b3fd3a 100644 --- a/src/js/game/hud/base_hud_part.js +++ b/src/js/game/hud/base_hud_part.js @@ -25,6 +25,7 @@ export class BaseHUDPart { /** * Should initialize the element, called *after* the elements have been created + * @abstract */ initialize() { abstract; diff --git a/src/js/game/hud/parts/building_placer_logic.js b/src/js/game/hud/parts/building_placer_logic.js index 7ed412f6..23ac6df3 100644 --- a/src/js/game/hud/parts/building_placer_logic.js +++ b/src/js/game/hud/parts/building_placer_logic.js @@ -192,7 +192,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { const metaBuilding = this.currentMetaBuilding.get(); return ( metaBuilding && - metaBuilding.getHasDirectionLockAvailable() && + metaBuilding.getHasDirectionLockAvailable(this.currentVariant.get()) && this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.lockBeltDirection).pressed ); } diff --git a/src/js/game/hud/parts/keybinding_overlay.js b/src/js/game/hud/parts/keybinding_overlay.js index 2384ab84..0a050484 100644 --- a/src/js/game/hud/parts/keybinding_overlay.js +++ b/src/js/game/hud/parts/keybinding_overlay.js @@ -49,7 +49,7 @@ export class HUDKeybindingOverlay extends BaseHUDPart { !this.mapOverviewActive && placer && placer.currentMetaBuilding.get() && - placer.currentMetaBuilding.get().getHasDirectionLockAvailable() + placer.currentMetaBuilding.get().getHasDirectionLockAvailable(placer.currentVariant.get()) ); } diff --git a/src/js/game/item_resolver.js b/src/js/game/item_resolver.js index ff91b0a3..3e7c87af 100644 --- a/src/js/game/item_resolver.js +++ b/src/js/game/item_resolver.js @@ -16,7 +16,7 @@ export function itemResolverSingleton(root, data) { const itemData = data.data; if (MODS_ADDITIONAL_ITEMS[itemType]) { - return MODS_ADDITIONAL_ITEMS[itemType](itemData); + return MODS_ADDITIONAL_ITEMS[itemType](itemData, root); } switch (itemType) { diff --git a/src/js/game/logic.js b/src/js/game/logic.js index 0e915fea..3fdc871e 100644 --- a/src/js/game/logic.js +++ b/src/js/game/logic.js @@ -72,8 +72,13 @@ export class GameLogic { // Check if there is any direct collision const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer); if (otherEntity) { - const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding(); - if (!allowReplaceBuildings || !metaClass.getIsReplaceable()) { + const staticComp = otherEntity.components.StaticMapEntity; + if ( + !allowReplaceBuildings || + !staticComp + .getMetaBuilding() + .getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()) + ) { // This one is a direct blocker return false; } @@ -140,8 +145,11 @@ export class GameLogic { for (let y = rect.y; y < rect.y + rect.h; ++y) { const contents = this.root.map.getLayerContentXY(x, y, entity.layer); if (contents) { + const staticComp = contents.components.StaticMapEntity; assertAlways( - contents.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(), + staticComp + .getMetaBuilding() + .getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()), "Tried to replace non-repleaceable entity" ); if (!this.tryDeleteBuilding(contents)) { diff --git a/src/js/game/meta_building.js b/src/js/game/meta_building.js index 0e92d3d9..c661b84f 100644 --- a/src/js/game/meta_building.js +++ b/src/js/game/meta_building.js @@ -52,8 +52,9 @@ export class MetaBuilding { /** * Returns whether the building has the direction lock switch available + * @param {string} variant */ - getHasDirectionLockAvailable() { + getHasDirectionLockAvailable(variant) { return false; } @@ -88,8 +89,10 @@ export class MetaBuilding { /** * Returns whether this building can get replaced + * @param {string} variant + * @param {number} rotationVariant */ - getIsReplaceable() { + getIsReplaceable(variant, rotationVariant) { return false; } @@ -278,6 +281,7 @@ export class MetaBuilding { * Should setup the entity components * @param {Entity} entity * @param {GameRoot} root + * @abstract */ setupEntityComponents(entity, root) { abstract; diff --git a/src/js/game/modes/puzzle_edit.js b/src/js/game/modes/puzzle_edit.js index e3d2e40d..28b59184 100644 --- a/src/js/game/modes/puzzle_edit.js +++ b/src/js/game/modes/puzzle_edit.js @@ -22,6 +22,7 @@ import { MetaTransistorBuilding } from "../buildings/transistor"; import { HUDPuzzleEditorControls } from "../hud/parts/puzzle_editor_controls"; import { HUDPuzzleEditorReview } from "../hud/parts/puzzle_editor_review"; import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings"; +import { HUDConstantSignalEdit } from "../hud/parts/constant_signal_edit"; export class PuzzleEditGameMode extends PuzzleGameMode { static getId() { @@ -58,6 +59,7 @@ export class PuzzleEditGameMode extends PuzzleGameMode { this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls; this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview; this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings; + this.additionalHudParts.constantSignalEdit = HUDConstantSignalEdit; } getIsEditor() { diff --git a/src/js/game/modes/regular.js b/src/js/game/modes/regular.js index cd14833e..68fbb3ad 100644 --- a/src/js/game/modes/regular.js +++ b/src/js/game/modes/regular.js @@ -594,18 +594,13 @@ export class RegularGameMode extends GameMode { this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial; } - // @ts-ignore - if (queryParamOptions.sandboxMode || window.sandboxMode || G_IS_DEV) { - this.additionalHudParts.sandboxController = HUDSandboxController; - } - /** @type {(typeof MetaBuilding)[]} */ - this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding]; - - // @ts-ignore - if (!(G_IS_DEV || window.sandboxMode || queryParamOptions.sandboxMode)) { - this.hiddenBuildings.push(MetaItemProducerBuilding); - } + this.hiddenBuildings = [ + MetaConstantProducerBuilding, + MetaGoalAcceptorBuilding, + MetaBlockBuilding, + MetaItemProducerBuilding, + ]; } /** diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js index 1790525c..c5294427 100644 --- a/src/js/game/systems/item_processor.js +++ b/src/js/game/systems/item_processor.js @@ -39,6 +39,11 @@ import { ShapeItem } from "../items/shape_item"; */ export const MOD_ITEM_PROCESSOR_HANDLERS = {}; +/** + * @type {Object boolean>} + */ +export const MODS_CAN_PROCESS = {}; + export class ItemProcessorSystem extends GameSystemWithFilter { constructor(root) { super(root, [ItemProcessorComponent]); @@ -168,6 +173,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter { const acceptorComp = entity.components.ItemAcceptor; const processorComp = entity.components.ItemProcessor; + if (MODS_CAN_PROCESS[processorComp.processingRequirement]) { + return MODS_CAN_PROCESS[processorComp.processingRequirement].bind(this)({ + entity, + }); + } + switch (processorComp.processingRequirement) { // DEFAULT // By default, we can start processing once all inputs are there diff --git a/src/js/game/systems/wired_pins.js b/src/js/game/systems/wired_pins.js index e8bc1882..e73e85f0 100644 --- a/src/js/game/systems/wired_pins.js +++ b/src/js/game/systems/wired_pins.js @@ -59,7 +59,11 @@ export class WiredPinsSystem extends GameSystemWithFilter { continue; } - if (staticComp.getMetaBuilding().getIsReplaceable()) { + if ( + staticComp + .getMetaBuilding() + .getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()) + ) { // Don't mind here, even if there would be a collision we // could replace it continue; @@ -113,7 +117,12 @@ export class WiredPinsSystem extends GameSystemWithFilter { // If there's an entity, and it can't get removed -> That's a collision if (collidingEntity) { - if (!collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable()) { + const staticComp = collidingEntity.components.StaticMapEntity; + if ( + !staticComp + .getMetaBuilding() + .getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()) + ) { return true; } } @@ -138,8 +147,11 @@ export class WiredPinsSystem extends GameSystemWithFilter { const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos); const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, "wires"); if (collidingEntity) { + const staticComp = collidingEntity.components.StaticMapEntity; assertAlways( - collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(), + staticComp + .getMetaBuilding() + .getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()), "Tried to replace non-repleaceable entity for pins" ); if (!this.root.logic.tryDeleteBuilding(collidingEntity)) { diff --git a/src/js/platform/achievement_provider.js b/src/js/platform/achievement_provider.js index 583dbfb2..3b60ad95 100644 --- a/src/js/platform/achievement_provider.js +++ b/src/js/platform/achievement_provider.js @@ -92,6 +92,7 @@ export class AchievementProviderInterface { /** * Initializes the achievement provider. * @returns {Promise} + * @abstract */ initialize() { abstract; @@ -102,6 +103,7 @@ export class AchievementProviderInterface { * Opportunity to do additional initialization work with the GameRoot. * @param {GameRoot} root * @returns {Promise} + * @abstract */ onLoad(root) { abstract; @@ -118,6 +120,7 @@ export class AchievementProviderInterface { * Call to activate an achievement with the provider * @param {string} key - Maps to an Achievement * @returns {Promise} + * @abstract */ activate(key) { abstract; @@ -127,6 +130,7 @@ export class AchievementProviderInterface { /** * Checks if achievements are supported in the current build * @returns {boolean} + * @abstract */ hasAchievements() { abstract; diff --git a/src/js/platform/ad_provider.js b/src/js/platform/ad_provider.js index a614a793..4aa8949c 100644 --- a/src/js/platform/ad_provider.js +++ b/src/js/platform/ad_provider.js @@ -19,6 +19,7 @@ export class AdProviderInterface { /** * Returns if this provider serves ads at all * @returns {boolean} + * @abstract */ getHasAds() { abstract; @@ -29,6 +30,7 @@ export class AdProviderInterface { * Returns if it would be possible to show a video ad *now*. This can be false if for * example the last video ad is * @returns {boolean} + * @abstract */ getCanShowVideoAd() { abstract; diff --git a/src/js/platform/analytics.js b/src/js/platform/analytics.js index 7bd7ae50..cf839aca 100644 --- a/src/js/platform/analytics.js +++ b/src/js/platform/analytics.js @@ -11,6 +11,7 @@ export class AnalyticsInterface { /** * Initializes the analytics * @returns {Promise} + * @abstract */ initialize() { abstract; diff --git a/src/js/platform/browser/game_analytics.js b/src/js/platform/browser/game_analytics.js index 9411b258..aa0ac796 100644 --- a/src/js/platform/browser/game_analytics.js +++ b/src/js/platform/browser/game_analytics.js @@ -1,6 +1,5 @@ import { globalConfig } from "../../core/config"; import { createLogger } from "../../core/logging"; -import { queryParamOptions } from "../../core/query_parameters"; import { BeltComponent } from "../../game/components/belt"; import { StaticMapEntityComponent } from "../../game/components/static_map_entity"; import { RegularGameMode } from "../../game/modes/regular"; @@ -24,9 +23,6 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface { } if (G_IS_STANDALONE) { - if (queryParamOptions.sandboxMode) { - return "steam-sandbox"; - } return "steam"; } @@ -35,14 +31,8 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface { } if (window.location.host.indexOf("alpha") >= 0) { - if (queryParamOptions.sandboxMode) { - return "alpha-sandbox"; - } return "alpha"; } else { - if (queryParamOptions.sandboxMode) { - return "beta-sandbox"; - } return "beta"; } } diff --git a/src/js/platform/game_analytics.js b/src/js/platform/game_analytics.js index 00286fc2..19fdf752 100644 --- a/src/js/platform/game_analytics.js +++ b/src/js/platform/game_analytics.js @@ -11,6 +11,7 @@ export class GameAnalyticsInterface { /** * Initializes the analytics * @returns {Promise} + * @abstract */ initialize() { abstract; @@ -43,6 +44,7 @@ export class GameAnalyticsInterface { /** * Activates a DLC * @param {string} dlc + * @abstract */ activateDlc(dlc) { abstract; diff --git a/src/js/platform/storage.js b/src/js/platform/storage.js index 165ee828..c5c3701c 100644 --- a/src/js/platform/storage.js +++ b/src/js/platform/storage.js @@ -13,6 +13,7 @@ export class StorageInterface { /** * Initializes the storage * @returns {Promise} + * @abstract */ initialize() { abstract; @@ -24,6 +25,7 @@ export class StorageInterface { * @param {string} filename * @param {string} contents * @returns {Promise} + * @abstract */ writeFileAsync(filename, contents) { abstract; @@ -34,6 +36,7 @@ export class StorageInterface { * Reads a string asynchronously. Returns Promise if file was not found. * @param {string} filename * @returns {Promise} + * @abstract */ readFileAsync(filename) { abstract; diff --git a/src/js/platform/wrapper.js b/src/js/platform/wrapper.js index f80c2fd6..e0a896fb 100644 --- a/src/js/platform/wrapper.js +++ b/src/js/platform/wrapper.js @@ -81,6 +81,7 @@ export class PlatformWrapperInterface { * Attempt to open an external url * @param {string} url * @param {boolean=} force Whether to always open the url even if not allowed + * @abstract */ openExternalLink(url, force = false) { abstract; @@ -88,6 +89,7 @@ export class PlatformWrapperInterface { /** * Attempt to restart the app + * @abstract */ performRestart() { abstract; @@ -103,6 +105,7 @@ export class PlatformWrapperInterface { /** * Should set the apps fullscreen state to the desired state * @param {boolean} flag + * @abstract */ setFullscreen(flag) { abstract; @@ -117,6 +120,7 @@ export class PlatformWrapperInterface { /** * Attempts to quit the app + * @abstract */ exitApp() { abstract; diff --git a/src/js/profile/setting_types.js b/src/js/profile/setting_types.js index 4df02892..943e8e53 100644 --- a/src/js/profile/setting_types.js +++ b/src/js/profile/setting_types.js @@ -64,6 +64,7 @@ export class BaseSetting { /** * Returns the HTML for this setting * @param {Application} app + * @abstract */ getHtml(app) { abstract; @@ -84,6 +85,7 @@ export class BaseSetting { /** * Attempts to modify the setting + * @abstract */ modify() { abstract; @@ -107,6 +109,7 @@ export class BaseSetting { * Validates the set value * @param {any} value * @returns {boolean} + * @abstract */ validate(value) { abstract; diff --git a/src/js/savegame/serialization_data_types.js b/src/js/savegame/serialization_data_types.js index df352e78..c27e2295 100644 --- a/src/js/savegame/serialization_data_types.js +++ b/src/js/savegame/serialization_data_types.js @@ -48,6 +48,7 @@ export class BaseDataType { /** * Serializes a given raw value * @param {any} value + * @abstract */ serialize(value) { abstract; @@ -68,6 +69,7 @@ export class BaseDataType { * @param {object} targetObject * @param {string|number} targetKey * @returns {string|void} String error code or null on success + * @abstract */ deserialize(value, targetObject, targetKey, root) { abstract; @@ -92,6 +94,7 @@ export class BaseDataType { /** * INTERNAL Should return the json schema representation + * @abstract */ getAsJsonSchemaUncached() { abstract; @@ -131,6 +134,7 @@ export class BaseDataType { /** * Should return a cacheable key + * @abstract */ getCacheKey() { abstract; diff --git a/translations/base-ja.yaml b/translations/base-ja.yaml index c98a1b85..ebce66dd 100644 --- a/translations/base-ja.yaml +++ b/translations/base-ja.yaml @@ -1013,10 +1013,8 @@ tips: - SHIFTを押したままにするとベルトプランナーが有効になり、長距離のベルトを簡単に配置できます。 - 切断機は配置された向きを考慮せず、常に垂直に切断します。 - ストレージは左側の出力を優先します。 - - 増築可能なデザインを作るために時間を使ってください。それだけの価値があります! - - Invest time to build repeatable designs - it's worth it! + - 増築可能なデザインを目指してみましょう。それだけの価値があります! - ALTを押しながらベルトを設置すると、向きを逆転できます。 - - You can hold ALT to invert the direction of placed belts. - ハブから遠くに離れるほど、形状資源はより複雑な形になります。 - 機械の速度には上限があるので、最大効率を得るためには入力を分割してください。 - 効率を最大化するために分配機/合流機を使用できます。 @@ -1032,8 +1030,7 @@ tips: - モジュールがあれば、空間はただの認識に過ぎなくなる――生ある人間に対する気遣いだ。 - 設計図としての工場を別に作っておくと、工場のモジュール化において重要な役割を果たします。 - 混色機をよく見ると、色の混ぜ方が解ります。 - - Have a closer look at the color mixer, and your questions will be answered. - - Use CTRL + Click to select an area. + - CTRLを押したままクリックすると、領域を選択できます。 - アップグレードリストの各形状の横にあるピンのアイコンは、その形状を画面左に固定表示します。 - 三原色全てを混ぜ合わせると白になります! - マップは無限の広さがあります。臆せずに拡張してください。 @@ -1046,8 +1043,7 @@ tips: - ベルトの中身をクリアするには、範囲選択して同じ場所に貼り付けをします。 - F4を押すことで、FPSとTickレートを表示できます。 - F4を2回押すと、マウスとカメラの座標を表示できます。 - - 左のピン留めされた図形をクリックすると、固定を解除できます。 - - You can click a pinned shape on the left side to unpin it. + - 左のピン留めされた図形をクリックすると、ピン留めを解除できます。 puzzleMenu: play: Play edit: Edit diff --git a/translations/base-ru.yaml b/translations/base-ru.yaml index f3bb7c95..b605180e 100644 --- a/translations/base-ru.yaml +++ b/translations/base-ru.yaml @@ -50,7 +50,7 @@ global: escape: ESC shift: SHIFT space: ПРОБЕЛ - loggingIn: Logging in + loggingIn: Вход demoBanners: title: Демоверсия intro: Приобретите полную версию, чтобы разблокировать все возможности! @@ -74,14 +74,14 @@ mainMenu: puzzleMode: Головоломка back: Назад puzzleDlcText: Нравится оптимизировать фабрики и делать их меньше? Купите - обновление "Головоломка" в Steam сейчас и получите еще больше + обновление «Головоломка» в Steam сейчас и получите еще больше удовольствия! puzzleDlcWishlist: Добавь в список желаемого! puzzleDlcViewNow: Посмотреть mods: - title: Active Mods - warningPuzzleDLC: Playing the Puzzle DLC is not possible with mods. Please - disable all mods to play the DLC. + title: Активные моды + warningPuzzleDLC: Обновление «Головоломка» невозможна с модами. Пожалуйста, + отключите все моды, чтобы играть в DLC. dialogs: buttons: ok: OK @@ -230,8 +230,8 @@ dialogs: desc: "Не удалось отправить вашу головоломку:" puzzleSubmitOk: title: Головоломка опубликована - desc: Поздравляю! Ваша головоломка была опубликована, и теперь в нее могут - играть остальные. Теперь вы можете найти ее в разделе "Мои + desc: Поздравляю! Ваша головоломка была опубликована, и теперь в неё могут + играть остальные. Теперь вы можете найти её в разделе "Мои головоломки". puzzleCreateOffline: title: Оффлайн режим @@ -265,12 +265,13 @@ dialogs: title: Удалить головоломку? desc: Вы уверены, что хотите удалить ''? Это действие нельзя отменить! modsDifference: - title: Mod Warning - desc: The currently installed mods differ from the mods the savegame was created - with. This might cause the savegame to break or not load at all. Are - you sure you want to continue? - missingMods: Missing Mods - newMods: Newly installed Mods + title: Предупреждение Мода + desc: Установленные в данный момент моды отличаются от модов, с которыми была + создана игра сохранения с ним. Это может привести к тому, что сохранение + не загрузится или вообще ничего не загрузится. Вы вы уверены, что хотите + продолжить? + missingMods: Отсутствуют Моды + newMods: Недавно установленные Моды ingame: keybindingsOverlay: moveMap: Передвижение @@ -1312,19 +1313,19 @@ backendErrors: все еще хотите удалить ее, обратитесь в support@shapez.io! no-permission: У вас нет прав на выполнение этого действия. mods: - title: Mods - author: Author - version: Version - modWebsite: Website - 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. - noModSupport: You need the standalone version on Steam to install mods. + title: Моды + author: Автор + version: Версия + modWebsite: Веб-сайт + openFolder: Открыть папку с Модами + folderOnlyStandalone: Открытие папки Модов возможно только при запуске автономного режима. + browseMods: Просмотреть Моды + modsInfo: Чтобы установить и управлять модами, скопируйте их в папку модов в + директории игры. Вы также можете воспользоваться кнопкой "Открыть папку модов" в + справа вверху. + noModSupport: Для установки модов вам нужна автономная версия в Steam. togglingComingSoon: - title: Coming Soon - description: Enabling or disabling mods is currently only possible by copying - the mod file from or to the mods/ folder. However, being able to - toggle them here is planned for a future update! + title: Совсем скоро + description: Включение или отключение модов в настоящее время возможно только + путем копирования файла мода из/в папку mods/. Однако, возможность + управлять ими здесь планируется в будущем обновлении! diff --git a/translations/base-sv.yaml b/translations/base-sv.yaml index 5ad75c0c..617ffa27 100644 --- a/translations/base-sv.yaml +++ b/translations/base-sv.yaml @@ -52,7 +52,7 @@ global: escape: ESC shift: SKIFT space: MELLANSLAG - loggingIn: Logging in + loggingIn: Loggar in demoBanners: title: Demo-version intro: Skaffa den fristående versionen för att låsa upp alla funktioner! diff --git a/version b/version index 3e1ad720..8e03717d 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.5.0 \ No newline at end of file +1.5.1 \ No newline at end of file