1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Update to latest version

This commit is contained in:
Sense101 2022-03-05 21:42:29 +00:00
parent 55f968ea4a
commit bf17ccf202
39 changed files with 154 additions and 110 deletions

View File

@ -23,7 +23,7 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts
## Building ## Building
- Make sure `ffmpeg` is on your path - 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) - Install Java (required for textures)
- Run `yarn` in the root folder - Run `yarn` in the root folder
- Cd into `gulp` folder - Cd into `gulp` folder

View File

@ -97,7 +97,6 @@ module.exports = ({ watch = false, standalone = false, chineseVersion = false, w
loader: path.resolve(__dirname, "mod.js"), loader: path.resolve(__dirname, "mod.js"),
}, },
], ],
],
}, },
{ {
test: /\.worker\.js$/, test: /\.worker\.js$/,

View File

@ -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 | | [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 | | [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 | | [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 ### Creating new sprites

View File

@ -15,9 +15,9 @@ const BeltExtension = ({ $super, $old }) => ({
return !$old.getShowWiresLayerPreview(); return !$old.getShowWiresLayerPreview();
}, },
getIsReplaceable() { getIsReplaceable(variant, rotationVariant) {
// Instead of super, use $super // Instead of super, use $super
return $super.getIsReplaceable.call(this); return $super.getIsReplaceable.call(this, variant, rotationVariant);
}, },
getIsRemoveable() { getIsRemoveable() {

View File

@ -87,7 +87,7 @@ class FluidItem extends shapez.BaseItem {
* @param {number} diameter * @param {number} diameter
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */
drawItemCenteredClipped(x, y, parameters, diameter = globalConfig.defaultItemDiameter) { drawItemCenteredClipped(x, y, parameters, diameter = shapez.globalConfig.defaultItemDiameter) {
const realDiameter = diameter * 0.6; const realDiameter = diameter * 0.6;
if (!this.cachedSprite) { if (!this.cachedSprite) {
this.cachedSprite = shapez.Loader.getSprite(`sprites/fluids/${this.fluidType}.png`); 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"]); this.modInterface.registerSprite("sprites/fluids/water.png", RESOURCES["water.png"]);
// Make the item spawn on the map // Make the item spawn on the map
this.modInterface.runAfterMethod( this.modInterface.runAfterMethod(shapez.MapChunk, "generatePatches", function ({
shapez.MapChunk, rng,
"generatePatches", chunkCenter,
function ({ rng, chunkCenter, distanceToOriginInChunks }) { distanceToOriginInChunks,
// Generate a simple patch }) {
// ALWAYS use rng and NEVER use Math.random() otherwise the map will look different // Generate a simple patch
// every time you resume the game // ALWAYS use rng and NEVER use Math.random() otherwise the map will look different
if (rng.next() > 0.8) { // every time you resume the game
const fluidType = rng.choice(Array.from(Object.keys(enumFluidType))); if (rng.next() > 0.8) {
this.internalGeneratePatch(rng, 4, FLUID_ITEM_SINGLETONS[fluidType]); 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]); this.modInterface.registerItem(FluidItem, itemData => FLUID_ITEM_SINGLETONS[itemData]);
} }

View File

@ -1,9 +1,10 @@
export const CHANGELOG = [ export const CHANGELOG = [
{ {
version: "1.5.0", version: "1.5.1",
date: "unreleased", date: "25.02.2022",
entries: [ 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 <a href='https://shapez.mod.io'>here</a>",
"When holding shift while placing a belt, the indicator now becomes red when crossing buildings", "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", "Lots of performance improvements, leading to up to 50% more FPS",
], ],

View File

@ -211,6 +211,7 @@ export class GameState {
/** /**
* Should return the html code of the state. * Should return the html code of the state.
* @returns {string} * @returns {string}
* @abstract
*/ */
getInnerHTML() { getInnerHTML() {
abstract; abstract;

View File

@ -3,20 +3,8 @@ const options = queryString.parse(location.search);
export let queryParamOptions = { export let queryParamOptions = {
embedProvider: null, embedProvider: null,
fullVersion: false,
sandboxMode: false,
}; };
if (options.embed) { if (options.embed) {
queryParamOptions.embedProvider = 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;
}

View File

@ -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} x
* @param {number} y * @param {number} y
* @returns {boolean} * @returns {boolean}

View File

@ -84,11 +84,6 @@ export class RestrictionManager extends ReadWriteProxy {
return false; return false;
} }
if (queryParamOptions.fullVersion) {
// Full version is activated via flag
return false;
}
if (queryParamOptions.embedProvider === "gamedistribution") { if (queryParamOptions.embedProvider === "gamedistribution") {
// also full version on gamedistribution // also full version on gamedistribution
return false; return false;

View File

@ -11,6 +11,7 @@ export class BaseSprite {
/** /**
* Returns the raw handle * Returns the raw handle
* @returns {HTMLImageElement|HTMLCanvasElement} * @returns {HTMLImageElement|HTMLCanvasElement}
* @abstract
*/ */
getRawTexture() { getRawTexture() {
abstract; abstract;

View File

@ -29,6 +29,7 @@ export class BaseItem extends BasicSerializableObject {
/** /**
* Returns a string id of the item * Returns a string id of the item
* @returns {string} * @returns {string}
* @abstract
*/ */
getAsCopyableKey() { getAsCopyableKey() {
abstract; abstract;
@ -49,9 +50,9 @@ export class BaseItem extends BasicSerializableObject {
/** /**
* Override for custom comparison * Override for custom comparison
* @abstract
* @param {BaseItem} other * @param {BaseItem} other
* @returns {boolean} * @returns {boolean}
* @abstract
*/ */
equalsImpl(other) { equalsImpl(other) {
abstract; abstract;
@ -62,6 +63,7 @@ export class BaseItem extends BasicSerializableObject {
* Draws the item to a canvas * Draws the item to a canvas
* @param {CanvasRenderingContext2D} context * @param {CanvasRenderingContext2D} context
* @param {number} size * @param {number} size
* @abstract
*/ */
drawFullSizeOnCanvas(context, size) { drawFullSizeOnCanvas(context, size) {
abstract; abstract;
@ -86,6 +88,7 @@ export class BaseItem extends BasicSerializableObject {
* @param {number} y * @param {number} y
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @param {number=} diameter * @param {number=} diameter
* @abstract
*/ */
drawItemCenteredImpl(x, y, parameters, diameter = globalConfig.defaultItemDiameter) { drawItemCenteredImpl(x, y, parameters, diameter = globalConfig.defaultItemDiameter) {
abstract; abstract;

View File

@ -1526,7 +1526,17 @@ export class BeltPath extends BasicSerializableObject {
const sprite = this.root.buffers.getForKey({ const sprite = this.root.buffers.getForKey({
key: "beltpaths", key: "beltpaths",
subKey: "stack-" + directionProp + "-" + dpi + "-" + stack.length + firstItem[1].serialize(), subKey:
"stack-" +
directionProp +
"-" +
dpi +
"#" +
stack.length +
"#" +
firstItem[1].getItemType() +
"#" +
firstItem[1].serialize(),
dpi, dpi,
w: dimensions.x, w: dimensions.x,
h: dimensions.y, h: dimensions.y,

View File

@ -4,6 +4,7 @@ export class Component extends BasicSerializableObject {
/** /**
* Returns the components unique id * Returns the components unique id
* @returns {string} * @returns {string}
* @abstract
*/ */
static getId() { static getId() {
abstract; abstract;

View File

@ -224,6 +224,7 @@ export class Entity extends BasicSerializableObject {
/** /**
* override, should draw the entity * override, should draw the entity
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
* @abstract
*/ */
drawImpl(parameters) { drawImpl(parameters) {
abstract; abstract;

View File

@ -144,6 +144,7 @@ export class GameMode extends BasicSerializableObject {
/** /**
* @param {number} w * @param {number} w
* @param {number} h * @param {number} h
* @abstract
*/ */
adjustZone(w = 0, h = 0) { adjustZone(w = 0, h = 0) {
abstract; abstract;

View File

@ -25,6 +25,7 @@ export class BaseHUDPart {
/** /**
* Should initialize the element, called *after* the elements have been created * Should initialize the element, called *after* the elements have been created
* @abstract
*/ */
initialize() { initialize() {
abstract; abstract;

View File

@ -192,7 +192,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
const metaBuilding = this.currentMetaBuilding.get(); const metaBuilding = this.currentMetaBuilding.get();
return ( return (
metaBuilding && metaBuilding &&
metaBuilding.getHasDirectionLockAvailable() && metaBuilding.getHasDirectionLockAvailable(this.currentVariant.get()) &&
this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.lockBeltDirection).pressed this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.lockBeltDirection).pressed
); );
} }

View File

@ -49,7 +49,7 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
!this.mapOverviewActive && !this.mapOverviewActive &&
placer && placer &&
placer.currentMetaBuilding.get() && placer.currentMetaBuilding.get() &&
placer.currentMetaBuilding.get().getHasDirectionLockAvailable() placer.currentMetaBuilding.get().getHasDirectionLockAvailable(placer.currentVariant.get())
); );
} }

View File

@ -16,7 +16,7 @@ export function itemResolverSingleton(root, data) {
const itemData = data.data; const itemData = data.data;
if (MODS_ADDITIONAL_ITEMS[itemType]) { if (MODS_ADDITIONAL_ITEMS[itemType]) {
return MODS_ADDITIONAL_ITEMS[itemType](itemData); return MODS_ADDITIONAL_ITEMS[itemType](itemData, root);
} }
switch (itemType) { switch (itemType) {

View File

@ -72,8 +72,13 @@ export class GameLogic {
// Check if there is any direct collision // Check if there is any direct collision
const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer); const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer);
if (otherEntity) { if (otherEntity) {
const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding(); const staticComp = otherEntity.components.StaticMapEntity;
if (!allowReplaceBuildings || !metaClass.getIsReplaceable()) { if (
!allowReplaceBuildings ||
!staticComp
.getMetaBuilding()
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant())
) {
// This one is a direct blocker // This one is a direct blocker
return false; return false;
} }
@ -140,8 +145,11 @@ export class GameLogic {
for (let y = rect.y; y < rect.y + rect.h; ++y) { for (let y = rect.y; y < rect.y + rect.h; ++y) {
const contents = this.root.map.getLayerContentXY(x, y, entity.layer); const contents = this.root.map.getLayerContentXY(x, y, entity.layer);
if (contents) { if (contents) {
const staticComp = contents.components.StaticMapEntity;
assertAlways( assertAlways(
contents.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(), staticComp
.getMetaBuilding()
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()),
"Tried to replace non-repleaceable entity" "Tried to replace non-repleaceable entity"
); );
if (!this.tryDeleteBuilding(contents)) { if (!this.tryDeleteBuilding(contents)) {

View File

@ -52,8 +52,9 @@ export class MetaBuilding {
/** /**
* Returns whether the building has the direction lock switch available * Returns whether the building has the direction lock switch available
* @param {string} variant
*/ */
getHasDirectionLockAvailable() { getHasDirectionLockAvailable(variant) {
return false; return false;
} }
@ -88,8 +89,10 @@ export class MetaBuilding {
/** /**
* Returns whether this building can get replaced * Returns whether this building can get replaced
* @param {string} variant
* @param {number} rotationVariant
*/ */
getIsReplaceable() { getIsReplaceable(variant, rotationVariant) {
return false; return false;
} }
@ -278,6 +281,7 @@ export class MetaBuilding {
* Should setup the entity components * Should setup the entity components
* @param {Entity} entity * @param {Entity} entity
* @param {GameRoot} root * @param {GameRoot} root
* @abstract
*/ */
setupEntityComponents(entity, root) { setupEntityComponents(entity, root) {
abstract; abstract;

View File

@ -22,6 +22,7 @@ import { MetaTransistorBuilding } from "../buildings/transistor";
import { HUDPuzzleEditorControls } from "../hud/parts/puzzle_editor_controls"; import { HUDPuzzleEditorControls } from "../hud/parts/puzzle_editor_controls";
import { HUDPuzzleEditorReview } from "../hud/parts/puzzle_editor_review"; import { HUDPuzzleEditorReview } from "../hud/parts/puzzle_editor_review";
import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings"; import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings";
import { HUDConstantSignalEdit } from "../hud/parts/constant_signal_edit";
export class PuzzleEditGameMode extends PuzzleGameMode { export class PuzzleEditGameMode extends PuzzleGameMode {
static getId() { static getId() {
@ -58,6 +59,7 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls; this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls;
this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview; this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview;
this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings; this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings;
this.additionalHudParts.constantSignalEdit = HUDConstantSignalEdit;
} }
getIsEditor() { getIsEditor() {

View File

@ -594,18 +594,13 @@ export class RegularGameMode extends GameMode {
this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial; this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial;
} }
// @ts-ignore
if (queryParamOptions.sandboxMode || window.sandboxMode || G_IS_DEV) {
this.additionalHudParts.sandboxController = HUDSandboxController;
}
/** @type {(typeof MetaBuilding)[]} */ /** @type {(typeof MetaBuilding)[]} */
this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding]; this.hiddenBuildings = [
MetaConstantProducerBuilding,
// @ts-ignore MetaGoalAcceptorBuilding,
if (!(G_IS_DEV || window.sandboxMode || queryParamOptions.sandboxMode)) { MetaBlockBuilding,
this.hiddenBuildings.push(MetaItemProducerBuilding); MetaItemProducerBuilding,
} ];
} }
/** /**

View File

@ -39,6 +39,11 @@ import { ShapeItem } from "../items/shape_item";
*/ */
export const MOD_ITEM_PROCESSOR_HANDLERS = {}; export const MOD_ITEM_PROCESSOR_HANDLERS = {};
/**
* @type {Object<string, ({entity: Entity}) => boolean>}
*/
export const MODS_CAN_PROCESS = {};
export class ItemProcessorSystem extends GameSystemWithFilter { export class ItemProcessorSystem extends GameSystemWithFilter {
constructor(root) { constructor(root) {
super(root, [ItemProcessorComponent]); super(root, [ItemProcessorComponent]);
@ -168,6 +173,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
const acceptorComp = entity.components.ItemAcceptor; const acceptorComp = entity.components.ItemAcceptor;
const processorComp = entity.components.ItemProcessor; const processorComp = entity.components.ItemProcessor;
if (MODS_CAN_PROCESS[processorComp.processingRequirement]) {
return MODS_CAN_PROCESS[processorComp.processingRequirement].bind(this)({
entity,
});
}
switch (processorComp.processingRequirement) { switch (processorComp.processingRequirement) {
// DEFAULT // DEFAULT
// By default, we can start processing once all inputs are there // By default, we can start processing once all inputs are there

View File

@ -59,7 +59,11 @@ export class WiredPinsSystem extends GameSystemWithFilter {
continue; 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 // Don't mind here, even if there would be a collision we
// could replace it // could replace it
continue; 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 there's an entity, and it can't get removed -> That's a collision
if (collidingEntity) { if (collidingEntity) {
if (!collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable()) { const staticComp = collidingEntity.components.StaticMapEntity;
if (
!staticComp
.getMetaBuilding()
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant())
) {
return true; return true;
} }
} }
@ -138,8 +147,11 @@ export class WiredPinsSystem extends GameSystemWithFilter {
const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos); const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos);
const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, "wires"); const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, "wires");
if (collidingEntity) { if (collidingEntity) {
const staticComp = collidingEntity.components.StaticMapEntity;
assertAlways( assertAlways(
collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(), staticComp
.getMetaBuilding()
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()),
"Tried to replace non-repleaceable entity for pins" "Tried to replace non-repleaceable entity for pins"
); );
if (!this.root.logic.tryDeleteBuilding(collidingEntity)) { if (!this.root.logic.tryDeleteBuilding(collidingEntity)) {

View File

@ -92,6 +92,7 @@ export class AchievementProviderInterface {
/** /**
* Initializes the achievement provider. * Initializes the achievement provider.
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
initialize() { initialize() {
abstract; abstract;
@ -102,6 +103,7 @@ export class AchievementProviderInterface {
* Opportunity to do additional initialization work with the GameRoot. * Opportunity to do additional initialization work with the GameRoot.
* @param {GameRoot} root * @param {GameRoot} root
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
onLoad(root) { onLoad(root) {
abstract; abstract;
@ -118,6 +120,7 @@ export class AchievementProviderInterface {
* Call to activate an achievement with the provider * Call to activate an achievement with the provider
* @param {string} key - Maps to an Achievement * @param {string} key - Maps to an Achievement
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
activate(key) { activate(key) {
abstract; abstract;
@ -127,6 +130,7 @@ export class AchievementProviderInterface {
/** /**
* Checks if achievements are supported in the current build * Checks if achievements are supported in the current build
* @returns {boolean} * @returns {boolean}
* @abstract
*/ */
hasAchievements() { hasAchievements() {
abstract; abstract;

View File

@ -19,6 +19,7 @@ export class AdProviderInterface {
/** /**
* Returns if this provider serves ads at all * Returns if this provider serves ads at all
* @returns {boolean} * @returns {boolean}
* @abstract
*/ */
getHasAds() { getHasAds() {
abstract; 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 * Returns if it would be possible to show a video ad *now*. This can be false if for
* example the last video ad is * example the last video ad is
* @returns {boolean} * @returns {boolean}
* @abstract
*/ */
getCanShowVideoAd() { getCanShowVideoAd() {
abstract; abstract;

View File

@ -11,6 +11,7 @@ export class AnalyticsInterface {
/** /**
* Initializes the analytics * Initializes the analytics
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
initialize() { initialize() {
abstract; abstract;

View File

@ -1,6 +1,5 @@
import { globalConfig } from "../../core/config"; import { globalConfig } from "../../core/config";
import { createLogger } from "../../core/logging"; import { createLogger } from "../../core/logging";
import { queryParamOptions } from "../../core/query_parameters";
import { BeltComponent } from "../../game/components/belt"; import { BeltComponent } from "../../game/components/belt";
import { StaticMapEntityComponent } from "../../game/components/static_map_entity"; import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
import { RegularGameMode } from "../../game/modes/regular"; import { RegularGameMode } from "../../game/modes/regular";
@ -24,9 +23,6 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
} }
if (G_IS_STANDALONE) { if (G_IS_STANDALONE) {
if (queryParamOptions.sandboxMode) {
return "steam-sandbox";
}
return "steam"; return "steam";
} }
@ -35,14 +31,8 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
} }
if (window.location.host.indexOf("alpha") >= 0) { if (window.location.host.indexOf("alpha") >= 0) {
if (queryParamOptions.sandboxMode) {
return "alpha-sandbox";
}
return "alpha"; return "alpha";
} else { } else {
if (queryParamOptions.sandboxMode) {
return "beta-sandbox";
}
return "beta"; return "beta";
} }
} }

View File

@ -11,6 +11,7 @@ export class GameAnalyticsInterface {
/** /**
* Initializes the analytics * Initializes the analytics
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
initialize() { initialize() {
abstract; abstract;
@ -43,6 +44,7 @@ export class GameAnalyticsInterface {
/** /**
* Activates a DLC * Activates a DLC
* @param {string} dlc * @param {string} dlc
* @abstract
*/ */
activateDlc(dlc) { activateDlc(dlc) {
abstract; abstract;

View File

@ -13,6 +13,7 @@ export class StorageInterface {
/** /**
* Initializes the storage * Initializes the storage
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
initialize() { initialize() {
abstract; abstract;
@ -24,6 +25,7 @@ export class StorageInterface {
* @param {string} filename * @param {string} filename
* @param {string} contents * @param {string} contents
* @returns {Promise<void>} * @returns {Promise<void>}
* @abstract
*/ */
writeFileAsync(filename, contents) { writeFileAsync(filename, contents) {
abstract; abstract;
@ -34,6 +36,7 @@ export class StorageInterface {
* Reads a string asynchronously. Returns Promise<FILE_NOT_FOUND> if file was not found. * Reads a string asynchronously. Returns Promise<FILE_NOT_FOUND> if file was not found.
* @param {string} filename * @param {string} filename
* @returns {Promise<string>} * @returns {Promise<string>}
* @abstract
*/ */
readFileAsync(filename) { readFileAsync(filename) {
abstract; abstract;

View File

@ -81,6 +81,7 @@ export class PlatformWrapperInterface {
* Attempt to open an external url * Attempt to open an external url
* @param {string} url * @param {string} url
* @param {boolean=} force Whether to always open the url even if not allowed * @param {boolean=} force Whether to always open the url even if not allowed
* @abstract
*/ */
openExternalLink(url, force = false) { openExternalLink(url, force = false) {
abstract; abstract;
@ -88,6 +89,7 @@ export class PlatformWrapperInterface {
/** /**
* Attempt to restart the app * Attempt to restart the app
* @abstract
*/ */
performRestart() { performRestart() {
abstract; abstract;
@ -103,6 +105,7 @@ export class PlatformWrapperInterface {
/** /**
* Should set the apps fullscreen state to the desired state * Should set the apps fullscreen state to the desired state
* @param {boolean} flag * @param {boolean} flag
* @abstract
*/ */
setFullscreen(flag) { setFullscreen(flag) {
abstract; abstract;
@ -117,6 +120,7 @@ export class PlatformWrapperInterface {
/** /**
* Attempts to quit the app * Attempts to quit the app
* @abstract
*/ */
exitApp() { exitApp() {
abstract; abstract;

View File

@ -64,6 +64,7 @@ export class BaseSetting {
/** /**
* Returns the HTML for this setting * Returns the HTML for this setting
* @param {Application} app * @param {Application} app
* @abstract
*/ */
getHtml(app) { getHtml(app) {
abstract; abstract;
@ -84,6 +85,7 @@ export class BaseSetting {
/** /**
* Attempts to modify the setting * Attempts to modify the setting
* @abstract
*/ */
modify() { modify() {
abstract; abstract;
@ -107,6 +109,7 @@ export class BaseSetting {
* Validates the set value * Validates the set value
* @param {any} value * @param {any} value
* @returns {boolean} * @returns {boolean}
* @abstract
*/ */
validate(value) { validate(value) {
abstract; abstract;

View File

@ -48,6 +48,7 @@ export class BaseDataType {
/** /**
* Serializes a given raw value * Serializes a given raw value
* @param {any} value * @param {any} value
* @abstract
*/ */
serialize(value) { serialize(value) {
abstract; abstract;
@ -68,6 +69,7 @@ export class BaseDataType {
* @param {object} targetObject * @param {object} targetObject
* @param {string|number} targetKey * @param {string|number} targetKey
* @returns {string|void} String error code or null on success * @returns {string|void} String error code or null on success
* @abstract
*/ */
deserialize(value, targetObject, targetKey, root) { deserialize(value, targetObject, targetKey, root) {
abstract; abstract;
@ -92,6 +94,7 @@ export class BaseDataType {
/** /**
* INTERNAL Should return the json schema representation * INTERNAL Should return the json schema representation
* @abstract
*/ */
getAsJsonSchemaUncached() { getAsJsonSchemaUncached() {
abstract; abstract;
@ -131,6 +134,7 @@ export class BaseDataType {
/** /**
* Should return a cacheable key * Should return a cacheable key
* @abstract
*/ */
getCacheKey() { getCacheKey() {
abstract; abstract;

View File

@ -1013,10 +1013,8 @@ tips:
- <b>SHIFT</b>を押したままにするとベルトプランナーが有効になり、長距離のベルトを簡単に配置できます。 - <b>SHIFT</b>を押したままにするとベルトプランナーが有効になり、長距離のベルトを簡単に配置できます。
- 切断機は配置された向きを考慮せず、常に垂直に切断します。 - 切断機は配置された向きを考慮せず、常に垂直に切断します。
- ストレージは左側の出力を優先します。 - ストレージは左側の出力を優先します。
- 増築可能なデザインを作るために時間を使ってください。それだけの価値があります! - 増築可能なデザインを目指してみましょう。それだけの価値があります!
- Invest time to build repeatable designs - it's worth it!
- <b>ALT</b>を押しながらベルトを設置すると、向きを逆転できます。 - <b>ALT</b>を押しながらベルトを設置すると、向きを逆転できます。
- You can hold <b>ALT</b> 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. - <b>CTRL</b>を押したままクリックすると、領域を選択できます。
- Use <b>CTRL</b> + Click to select an area.
- アップグレードリストの各形状の横にあるピンのアイコンは、その形状を画面左に固定表示します。 - アップグレードリストの各形状の横にあるピンのアイコンは、その形状を画面左に固定表示します。
- 三原色全てを混ぜ合わせると白になります! - 三原色全てを混ぜ合わせると白になります!
- マップは無限の広さがあります。臆せずに拡張してください。 - マップは無限の広さがあります。臆せずに拡張してください。
@ -1046,8 +1043,7 @@ tips:
- ベルトの中身をクリアするには、範囲選択して同じ場所に貼り付けをします。 - ベルトの中身をクリアするには、範囲選択して同じ場所に貼り付けをします。
- F4を押すことで、FPSとTickレートを表示できます。 - F4を押すことで、FPSとTickレートを表示できます。
- F4を2回押すと、マウスとカメラの座標を表示できます。 - F4を2回押すと、マウスとカメラの座標を表示できます。
- 左のピン留めされた図形をクリックすると、固定を解除できます。 - 左のピン留めされた図形をクリックすると、ピン留めを解除できます。
- You can click a pinned shape on the left side to unpin it.
puzzleMenu: puzzleMenu:
play: Play play: Play
edit: Edit edit: Edit

View File

@ -50,7 +50,7 @@ global:
escape: ESC escape: ESC
shift: SHIFT shift: SHIFT
space: ПРОБЕЛ space: ПРОБЕЛ
loggingIn: Logging in loggingIn: Вход
demoBanners: demoBanners:
title: Демоверсия title: Демоверсия
intro: Приобретите полную версию, чтобы разблокировать все возможности! intro: Приобретите полную версию, чтобы разблокировать все возможности!
@ -74,14 +74,14 @@ mainMenu:
puzzleMode: Головоломка puzzleMode: Головоломка
back: Назад back: Назад
puzzleDlcText: Нравится оптимизировать фабрики и делать их меньше? Купите puzzleDlcText: Нравится оптимизировать фабрики и делать их меньше? Купите
обновление "Головоломка" в Steam сейчас и получите еще больше обновление «Головоломка» в Steam сейчас и получите еще больше
удовольствия! удовольствия!
puzzleDlcWishlist: Добавь в список желаемого! puzzleDlcWishlist: Добавь в список желаемого!
puzzleDlcViewNow: Посмотреть puzzleDlcViewNow: Посмотреть
mods: mods:
title: Active Mods title: Активные моды
warningPuzzleDLC: Playing the Puzzle DLC is not possible with mods. Please warningPuzzleDLC: Обновление «Головоломка» невозможна с модами. Пожалуйста,
disable all mods to play the DLC. отключите все моды, чтобы играть в DLC.
dialogs: dialogs:
buttons: buttons:
ok: OK ok: OK
@ -230,8 +230,8 @@ dialogs:
desc: "Не удалось отправить вашу головоломку:" desc: "Не удалось отправить вашу головоломку:"
puzzleSubmitOk: puzzleSubmitOk:
title: Головоломка опубликована title: Головоломка опубликована
desc: Поздравляю! Ваша головоломка была опубликована, и теперь в нее могут desc: Поздравляю! Ваша головоломка была опубликована, и теперь в неё могут
играть остальные. Теперь вы можете найти ее в разделе "Мои играть остальные. Теперь вы можете найти её в разделе "Мои
головоломки". головоломки".
puzzleCreateOffline: puzzleCreateOffline:
title: Оффлайн режим title: Оффлайн режим
@ -265,12 +265,13 @@ dialogs:
title: Удалить головоломку? title: Удалить головоломку?
desc: Вы уверены, что хотите удалить '<title>'? Это действие нельзя отменить! desc: Вы уверены, что хотите удалить '<title>'? Это действие нельзя отменить!
modsDifference: modsDifference:
title: Mod Warning title: Предупреждение Мода
desc: The currently installed mods differ from the mods the savegame was created desc: Установленные в данный момент моды отличаются от модов, с которыми была
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 missingMods: Отсутствуют Моды
newMods: Недавно установленные Моды
ingame: ingame:
keybindingsOverlay: keybindingsOverlay:
moveMap: Передвижение moveMap: Передвижение
@ -1312,19 +1313,19 @@ backendErrors:
все еще хотите удалить ее, обратитесь в support@shapez.io! все еще хотите удалить ее, обратитесь в support@shapez.io!
no-permission: У вас нет прав на выполнение этого действия. no-permission: У вас нет прав на выполнение этого действия.
mods: mods:
title: Mods title: Моды
author: Author author: Автор
version: Version version: Версия
modWebsite: Website modWebsite: Веб-сайт
openFolder: Open Mods Folder openFolder: Открыть папку с Модами
folderOnlyStandalone: Opening the mod folder is only possible when running the standalone. folderOnlyStandalone: Открытие папки Модов возможно только при запуске автономного режима.
browseMods: Browse Mods browseMods: Просмотреть Моды
modsInfo: To install and manage mods, copy them to the mods folder within the modsInfo: Чтобы установить и управлять модами, скопируйте их в папку модов в
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. noModSupport: Для установки модов вам нужна автономная версия в Steam.
togglingComingSoon: togglingComingSoon:
title: Coming Soon title: Совсем скоро
description: Enabling or disabling mods is currently only possible by copying description: Включение или отключение модов в настоящее время возможно только
the mod file from or to the mods/ folder. However, being able to путем копирования файла мода из/в папку mods/. Однако, возможность
toggle them here is planned for a future update! управлять ими здесь планируется в будущем обновлении!

View File

@ -52,7 +52,7 @@ global:
escape: ESC escape: ESC
shift: SKIFT shift: SKIFT
space: MELLANSLAG space: MELLANSLAG
loggingIn: Logging in loggingIn: Loggar in
demoBanners: demoBanners:
title: Demo-version title: Demo-version
intro: Skaffa den fristående versionen för att låsa upp alla funktioner! intro: Skaffa den fristående versionen för att låsa upp alla funktioner!

View File

@ -1 +1 @@
1.5.0 1.5.1