Compare commits

...

3 Commits

Author SHA1 Message Date
tobspr 728c8118e1 Update appid 2023-10-13 10:54:25 +02:00
tobspr 3f4ed3143f Update translations 2023-10-13 10:53:05 +02:00
tobspr 138d2e15fb Adjustments for steam china 2023-10-13 10:31:03 +02:00
36 changed files with 1391 additions and 93 deletions

1
electron_steam_isbn/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
mods/*.js

View File

@ -0,0 +1,13 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.exclude": {
"**/node_modules": true,
"**/typedefs_gen": true
}
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,389 @@
/* eslint-disable quotes,no-undef */
const { app, BrowserWindow, Menu, MenuItem, ipcMain, shell, dialog, session } = require("electron");
const path = require("path");
const url = require("url");
const fs = require("fs");
const steam = require("./steam");
const asyncLock = require("async-lock");
const windowStateKeeper = require("electron-window-state");
// Disable hardware key handling, i.e. being able to pause/resume the game music
// with hardware keys
app.commandLine.appendSwitch("disable-features", "HardwareMediaKeyHandling");
const isDev = app.commandLine.hasSwitch("dev");
const isLocal = app.commandLine.hasSwitch("local");
const safeMode = app.commandLine.hasSwitch("safe-mode");
const externalMod = app.commandLine.getSwitchValue("load-mod");
const roamingFolder =
process.env.APPDATA ||
(process.platform == "darwin"
? process.env.HOME + "/Library/Preferences"
: process.env.HOME + "/.local/share");
let storePath = path.join(roamingFolder, "shapez-china", "saves");
let modsPath = path.join(roamingFolder, "shapez-china", "mods");
if (!fs.existsSync(storePath)) {
// No try-catch by design
fs.mkdirSync(storePath, { recursive: true });
}
if (!fs.existsSync(modsPath)) {
fs.mkdirSync(modsPath, { recursive: true });
}
/** @type {BrowserWindow} */
let win = null;
let menu = null;
function createWindow() {
let faviconExtension = ".png";
if (process.platform === "win32") {
faviconExtension = ".ico";
}
const mainWindowState = windowStateKeeper({
defaultWidth: 1000,
defaultHeight: 800,
});
win = new BrowserWindow({
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
show: false,
backgroundColor: "#222428",
useContentSize: false,
minWidth: 800,
minHeight: 600,
title: "图形工厂",
transparent: false,
icon: path.join(__dirname, "favicon" + faviconExtension),
// fullscreen: true,
autoHideMenuBar: !isDev,
webPreferences: {
nodeIntegration: false,
nodeIntegrationInWorker: false,
nodeIntegrationInSubFrames: false,
contextIsolation: true,
enableRemoteModule: false,
disableBlinkFeatures: "Auxclick",
webSecurity: true,
sandbox: true,
preload: path.join(__dirname, "preload.js"),
experimentalFeatures: false,
},
allowRunningInsecureContent: false,
});
mainWindowState.manage(win);
if (isLocal) {
win.loadURL("http://localhost:3005");
} else {
win.loadURL(
url.format({
pathname: path.join(__dirname, "index.html"),
protocol: "file:",
slashes: true,
})
);
}
win.webContents.session.clearCache();
win.webContents.session.clearStorageData();
////// SECURITY
// Disable permission requests
win.webContents.session.setPermissionRequestHandler((webContents, permission, callback) => {
callback(false);
});
session.fromPartition("default").setPermissionRequestHandler((webContents, permission, callback) => {
callback(false);
});
app.on("web-contents-created", (event, contents) => {
// Disable vewbiew
contents.on("will-attach-webview", (event, webPreferences, params) => {
event.preventDefault();
});
// Disable navigation
contents.on("will-navigate", (event, navigationUrl) => {
event.preventDefault();
});
});
win.webContents.on("will-redirect", (contentsEvent, navigationUrl) => {
// Log and prevent the app from redirecting to a new page
console.error(
`The application tried to redirect to the following address: '${navigationUrl}'. This attempt was blocked.`
);
contentsEvent.preventDefault();
});
// Filter loading any module via remote;
// you shouldn't be using remote at all, though
// https://electronjs.org/docs/tutorial/security#16-filter-the-remote-module
app.on("remote-require", (event, webContents, moduleName) => {
event.preventDefault();
});
// built-ins are modules such as "app"
app.on("remote-get-builtin", (event, webContents, moduleName) => {
event.preventDefault();
});
app.on("remote-get-global", (event, webContents, globalName) => {
event.preventDefault();
});
app.on("remote-get-current-window", (event, webContents) => {
event.preventDefault();
});
app.on("remote-get-current-web-contents", (event, webContents) => {
event.preventDefault();
});
//// END SECURITY
win.webContents.on("new-window", (event, pth) => {
event.preventDefault();
if (pth.startsWith("https://") || pth.startsWith("steam://")) {
shell.openExternal(pth);
}
});
win.on("closed", () => {
console.log("Window closed");
win = null;
});
if (isDev) {
menu = new Menu();
win.webContents.toggleDevTools();
const mainItem = new MenuItem({
label: "Toggle Dev Tools",
click: () => win.webContents.toggleDevTools(),
accelerator: "F12",
});
menu.append(mainItem);
const reloadItem = new MenuItem({
label: "Reload",
click: () => win.reload(),
accelerator: "F5",
});
menu.append(reloadItem);
const fullscreenItem = new MenuItem({
label: "Fullscreen",
click: () => win.setFullScreen(!win.isFullScreen()),
accelerator: "F11",
});
menu.append(fullscreenItem);
const mainMenu = new Menu();
mainMenu.append(
new MenuItem({
label: "shapez.io",
submenu: menu,
})
);
Menu.setApplicationMenu(mainMenu);
} else {
Menu.setApplicationMenu(null);
}
win.once("ready-to-show", () => {
win.show();
win.focus();
});
}
if (!app.requestSingleInstanceLock()) {
app.exit(0);
} else {
app.on("second-instance", () => {
// Someone tried to run a second instance, we should focus
if (win) {
if (win.isMinimized()) {
win.restore();
}
win.focus();
}
});
}
app.on("ready", createWindow);
app.on("window-all-closed", () => {
console.log("All windows closed");
app.quit();
});
ipcMain.on("set-fullscreen", (event, flag) => {
win.setFullScreen(flag);
});
ipcMain.on("exit-app", () => {
win.close();
app.quit();
});
let renameCounter = 1;
const fileLock = new asyncLock({
timeout: 30000,
maxPending: 1000,
});
function niceFileName(filename) {
return filename.replace(storePath, "@");
}
async function writeFileSafe(filename, contents) {
++renameCounter;
const prefix = "[ " + renameCounter + ":" + niceFileName(filename) + " ] ";
const transactionId = String(new Date().getTime()) + "." + renameCounter;
if (fileLock.isBusy()) {
console.warn(prefix, "Concurrent write process on", filename);
}
fileLock.acquire(filename, async () => {
console.log(prefix, "Starting write on", niceFileName(filename), "in transaction", transactionId);
if (!fs.existsSync(filename)) {
// this one is easy
console.log(prefix, "Writing file instantly because it does not exist:", niceFileName(filename));
await fs.promises.writeFile(filename, contents, "utf8");
return;
}
// first, write a temporary file (.tmp-XXX)
const tempName = filename + ".tmp-" + transactionId;
console.log(prefix, "Writing temporary file", niceFileName(tempName));
await fs.promises.writeFile(tempName, contents, "utf8");
// now, rename the original file to (.backup-XXX)
const oldTemporaryName = filename + ".backup-" + transactionId;
console.log(
prefix,
"Renaming old file",
niceFileName(filename),
"to",
niceFileName(oldTemporaryName)
);
await fs.promises.rename(filename, oldTemporaryName);
// now, rename the temporary file (.tmp-XXX) to the target
console.log(
prefix,
"Renaming the temporary file",
niceFileName(tempName),
"to the original",
niceFileName(filename)
);
await fs.promises.rename(tempName, filename);
// we are done now, try to create a backup, but don't fail if the backup fails
try {
// check if there is an old backup file
const backupFileName = filename + ".backup";
if (fs.existsSync(backupFileName)) {
console.log(prefix, "Deleting old backup file", niceFileName(backupFileName));
// delete the old backup
await fs.promises.unlink(backupFileName);
}
// rename the old file to the new backup file
console.log(prefix, "Moving", niceFileName(oldTemporaryName), "to the backup file location");
await fs.promises.rename(oldTemporaryName, backupFileName);
} catch (ex) {
console.error(prefix, "Failed to switch backup files:", ex);
}
});
}
ipcMain.handle("fs-job", async (event, job) => {
const filenameSafe = job.filename.replace(/[^a-z\.\-_0-9]/gi, "_");
const fname = path.join(storePath, filenameSafe);
switch (job.type) {
case "read": {
if (!fs.existsSync(fname)) {
// Special FILE_NOT_FOUND error code
return { error: "file_not_found" };
}
return await fs.promises.readFile(fname, "utf8");
}
case "write": {
await writeFileSafe(fname, job.contents);
return job.contents;
}
case "delete": {
await fs.promises.unlink(fname);
return;
}
default:
throw new Error("Unknown fs job: " + job.type);
}
});
ipcMain.handle("open-mods-folder", async () => {
shell.openPath(modsPath);
});
console.log("Loading mods ...");
function loadMods() {
if (safeMode) {
console.log("Safe Mode enabled for mods, skipping mod search");
}
console.log("Loading mods from", modsPath);
let modFiles = safeMode
? []
: fs
.readdirSync(modsPath)
.filter(filename => filename.endsWith(".js"))
.map(filename => path.join(modsPath, filename));
if (externalMod) {
console.log("Adding external mod source:", externalMod);
const externalModPaths = externalMod.split(",");
modFiles = modFiles.concat(externalModPaths);
}
return modFiles.map(filename => fs.readFileSync(filename, "utf8"));
}
let mods = [];
try {
mods = loadMods();
console.log("Loaded", mods.length, "mods");
} catch (ex) {
console.error("Failed to load mods");
dialog.showErrorBox("Failed to load mods:", ex);
}
ipcMain.handle("get-mods", async () => {
return mods;
});
steam.init(isDev);
// Only allow achievements and puzzle DLC if no mods are loaded
if (mods.length === 0) {
steam.listen();
}

View File

@ -0,0 +1,6 @@
Here you can place mods. Every mod should be a single file ending with ".js".
--- WARNING ---
Mods can potentially access to your filesystem.
Please only install mods from trusted sources and developers.
--- WARNING ---

View File

@ -0,0 +1,21 @@
{
"name": "electron",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"scripts": {
"startDev": "electron --disable-direct-composition --in-process-gpu . --dev --local",
"startDevGpu": "electron --enable-gpu-rasterization --enable-accelerated-2d-canvas --num-raster-threads=8 --enable-zero-copy . --dev --local",
"start": "electron --disable-direct-composition --in-process-gpu ."
},
"devDependencies": {},
"optionalDependencies": {
"shapez.io-private-artifacts": "github:tobspr/shapez.io-private-artifacts#abi-v99"
},
"dependencies": {
"async-lock": "^1.2.8",
"electron": "16.2.8",
"electron-window-state": "^5.0.3"
}
}

View File

@ -0,0 +1,7 @@
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("ipcRenderer", {
invoke: ipcRenderer.invoke.bind(ipcRenderer),
on: ipcRenderer.on.bind(ipcRenderer),
send: ipcRenderer.send.bind(ipcRenderer),
});

View File

@ -0,0 +1,112 @@
const fs = require("fs");
const path = require("path");
const { ipcMain } = require("electron");
let greenworks = null;
let appId = null;
let initialized = false;
try {
greenworks = require("shapez.io-private-artifacts/steam/greenworks");
appId = parseInt(fs.readFileSync(path.join(__dirname, "steam_appid.txt"), "utf8"));
} catch (err) {
// greenworks is not installed
console.warn("Failed to load steam api:", err);
}
console.log("App ID:", appId);
function init(isDev) {
if (!greenworks) {
return;
}
if (!isDev) {
if (greenworks.restartAppIfNecessary(appId)) {
console.log("Restarting ...");
process.exit(0);
}
}
if (!greenworks.init()) {
console.log("Failed to initialize greenworks");
process.exit(1);
}
initialized = true;
}
function listen() {
ipcMain.handle("steam:is-initialized", isInitialized);
if (!initialized) {
console.warn("Steam not initialized, won't be able to listen");
return;
}
if (!greenworks) {
console.warn("Greenworks not loaded, won't be able to listen");
return;
}
console.log("Adding listeners");
ipcMain.handle("steam:get-achievement-names", getAchievementNames);
ipcMain.handle("steam:activate-achievement", activateAchievement);
function bufferToHex(buffer) {
return Array.from(new Uint8Array(buffer))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
ipcMain.handle("steam:get-ticket", (event, arg) => {
console.log("Requested steam ticket ...");
return new Promise((resolve, reject) => {
greenworks.getAuthSessionTicket(
success => {
const ticketHex = bufferToHex(success.ticket);
resolve(ticketHex);
},
error => {
console.error("Failed to get steam ticket:", error);
reject(error);
}
);
});
});
ipcMain.handle("steam:check-app-ownership", (event, appId) => {
return Promise.resolve(greenworks.isDLCInstalled(appId));
});
}
function isInitialized(event) {
return Promise.resolve(initialized);
}
function getAchievementNames(event) {
return new Promise((resolve, reject) => {
try {
const achievements = greenworks.getAchievementNames();
resolve(achievements);
} catch (err) {
reject(err);
}
});
}
function activateAchievement(event, id) {
return new Promise((resolve, reject) => {
greenworks.activateAchievement(
id,
() => resolve(),
err => reject(err)
);
});
}
module.exports = {
init,
listen,
};

View File

@ -0,0 +1 @@
1318690

View File

@ -0,0 +1,584 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@electron/get@^1.13.0":
version "1.13.1"
resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.13.1.tgz#42a0aa62fd1189638bd966e23effaebb16108368"
integrity sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==
dependencies:
debug "^4.1.1"
env-paths "^2.2.0"
fs-extra "^8.1.0"
got "^9.6.0"
progress "^2.0.3"
semver "^6.2.0"
sumchecker "^3.0.1"
optionalDependencies:
global-agent "^3.0.0"
global-tunnel-ng "^2.7.1"
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
dependencies:
defer-to-connect "^1.0.1"
"@types/node@^14.6.2":
version "14.18.20"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.20.tgz#268f028b36eaf51181c3300252f605488c4f0650"
integrity sha512-Q8KKwm9YqEmUBRsqJ2GWJDtXltBDxTdC4m5vTdXBolu2PeQh8LX+f6BTwU+OuXPu37fLxoN6gidqBmnky36FXA==
async-lock@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.2.8.tgz#7b02bdfa2de603c0713acecd11184cf97bbc7c4c"
integrity sha512-G+26B2jc0Gw0EG/WN2M6IczuGepBsfR1+DtqLnyFSH4p2C668qkOCtEkGNVEaaNAVlYwEMazy1+/jnLxltBkIQ==
boolean@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.2.tgz#df1baa18b6a2b0e70840475e1d93ec8fe75b2570"
integrity sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
cacheable-request@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^3.0.0"
lowercase-keys "^2.0.0"
normalize-url "^4.1.0"
responselike "^1.0.2"
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
concat-stream@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
config-chain@^1.1.11:
version "1.1.12"
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==
dependencies:
ini "^1.3.4"
proto-list "~1.2.1"
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
debug@^4.1.0, debug@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
decompress-response@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
dependencies:
mimic-response "^1.0.0"
defer-to-connect@^1.0.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
dependencies:
object-keys "^1.0.12"
detect-node@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
electron-window-state@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/electron-window-state/-/electron-window-state-5.0.3.tgz#4f36d09e3f953d87aff103bf010f460056050aa8"
integrity sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg==
dependencies:
jsonfile "^4.0.0"
mkdirp "^0.5.1"
electron@16.2.8:
version "16.2.8"
resolved "https://registry.yarnpkg.com/electron/-/electron-16.2.8.tgz#b7f2bd1184701e54a1bc902839d5a3ec95bb8982"
integrity sha512-KSOytY6SPLsh3iCziztqa/WgJyfDOKzCvNqku9gGIqSdT8CqtV66dTU1SOrKZQjRFLxHaF8LbyxUL1vwe4taqw==
dependencies:
"@electron/get" "^1.13.0"
"@types/node" "^14.6.2"
extract-zip "^1.0.3"
encodeurl@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
env-paths@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
es6-error@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
extract-zip@^1.0.3:
version "1.7.0"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927"
integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==
dependencies:
concat-stream "^1.6.2"
debug "^2.6.9"
mkdirp "^0.5.4"
yauzl "^2.10.0"
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
dependencies:
pend "~1.2.0"
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
get-stream@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
global-agent@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6"
integrity sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==
dependencies:
boolean "^3.0.1"
es6-error "^4.1.1"
matcher "^3.0.0"
roarr "^2.15.3"
semver "^7.3.2"
serialize-error "^7.0.1"
global-tunnel-ng@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f"
integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==
dependencies:
encodeurl "^1.0.2"
lodash "^4.17.10"
npm-conf "^1.1.3"
tunnel "^0.0.6"
globalthis@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b"
integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==
dependencies:
define-properties "^1.1.3"
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
dependencies:
"@sindresorhus/is" "^0.14.0"
"@szmarczak/http-timer" "^1.1.2"
cacheable-request "^6.0.0"
decompress-response "^3.3.0"
duplexer3 "^0.1.4"
get-stream "^4.1.0"
lowercase-keys "^1.0.1"
mimic-response "^1.0.1"
p-cancelable "^1.0.0"
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
http-cache-semantics@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
inherits@^2.0.3, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
ini@^1.3.4:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
json-stringify-safe@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
keyv@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
json-buffer "3.0.0"
lodash@^4.17.10:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
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"
matcher@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca"
integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==
dependencies:
escape-string-regexp "^4.0.0"
mimic-response@^1.0.0, mimic-response@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mkdirp@^0.5.1, mkdirp@^0.5.4:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.5"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
normalize-url@^4.1.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
npm-conf@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9"
integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==
dependencies:
config-chain "^1.1.11"
pify "^3.0.0"
object-keys@^1.0.12:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-cancelable@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
progress@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
readable-stream@^2.2.2:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
responselike@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
dependencies:
lowercase-keys "^1.0.0"
roarr@^2.15.3:
version "2.15.4"
resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd"
integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==
dependencies:
boolean "^3.0.1"
detect-node "^2.0.4"
globalthis "^1.0.1"
json-stringify-safe "^5.0.1"
semver-compare "^1.0.0"
sprintf-js "^1.1.2"
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w=
semver@^6.2.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
dependencies:
lru-cache "^6.0.0"
serialize-error@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18"
integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==
dependencies:
type-fest "^0.13.1"
"shapez.io-private-artifacts@github:tobspr/shapez.io-private-artifacts#abi-v99":
version "0.1.0"
resolved "git+ssh://git@github.com/tobspr/shapez.io-private-artifacts.git#3293b20be26060fd36e9f00ded9ab5d0bdf57338"
sprintf-js@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
sumchecker@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42"
integrity sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==
dependencies:
debug "^4.1.0"
to-readable-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
tunnel@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
type-fest@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
url-parse-lax@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
dependencies:
prepend-http "^2.0.0"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
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==
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"

View File

@ -7,7 +7,7 @@ function init(isDev) {
try {
console.log("Step 2: Calling need restart app");
const need_restart = railsdk.RailNeedRestartAppForCheckingEnvironment(
2001639,
2002030,
[`--rail_render_pid=${process.pid}`] //,"--rail_debug_mode",
);
console.log("Step 3: Needs restart =", need_restart);
@ -58,6 +58,22 @@ function listen() {
return data;
});
ipcMain.handle("wegame:activate-achievement", async (event, data) => {
console.log("Unlock wegame achievement", data);
var manager = railsdk.RailAchievementHelper.CreatePlayerAchievement("0");
var result = manager.MakeAchievement(data);
if (result != railsdk.RailResult.kSuccess) {
console.error("Unlock wegame achievement", data, "failed with code", result);
return false;
}
manager.AsyncStoreAchievement().then(
() => console.log("Achievements stored successfully."),
err => console.error("Failed to unlock achievement async:", err)
);
return true;
});
}
module.exports = { init, listen };

View File

@ -9,6 +9,7 @@
* chineseVersion?: boolean,
* wegameVersion?: boolean,
* steamDemo?: boolean,
* steamIsbnVersion?: boolean,
* gogVersion?: boolean
* }}>}
*/
@ -63,6 +64,13 @@ const BUILD_VARIANTS = {
wegameVersion: true,
},
},
"standalone-steam-isbn": {
standalone: true,
electronBaseDir: "electron_steam_isbn",
buildArgs: {
steamIsbnVersion: true,
},
},
"standalone-gog": {
standalone: true,
electronBaseDir: "electron_gog",

View File

@ -10,6 +10,7 @@ module.exports = ({
standalone = false,
chineseVersion = false,
wegameVersion = false,
steamIsbnVersion = false,
steamDemo = false,
gogVersion = false,
}) => {
@ -39,6 +40,8 @@ module.exports = ({
G_APP_ENVIRONMENT: JSON.stringify("dev"),
G_CHINA_VERSION: JSON.stringify(chineseVersion),
G_WEGAME_VERSION: JSON.stringify(wegameVersion),
G_ISBN_VERSION: JSON.stringify(wegameVersion || steamIsbnVersion),
G_STEAM_ISBN_VERSION: JSON.stringify(steamIsbnVersion),
G_GOG_VERSION: JSON.stringify(gogVersion),
G_IS_DEV: "true",
G_IS_RELEASE: "false",

View File

@ -17,6 +17,7 @@ module.exports = ({
chineseVersion = false,
wegameVersion = false,
steamIsbnVersion = false,
steamDemo = false,
gogVersion = false,
}) => {
@ -28,6 +29,8 @@ module.exports = ({
G_CHINA_VERSION: JSON.stringify(chineseVersion),
G_WEGAME_VERSION: JSON.stringify(wegameVersion),
G_ISBN_VERSION: JSON.stringify(wegameVersion || steamIsbnVersion),
G_STEAM_ISBN_VERSION: JSON.stringify(steamIsbnVersion),
G_GOG_VERSION: JSON.stringify(gogVersion),
G_IS_RELEASE: environment === "prod" ? "true" : "false",
G_IS_STANDALONE: standalone ? "true" : "false",

View File

@ -153,7 +153,7 @@ export class Application {
Loader.linkAppAfterBoot(this);
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
this.stateMgr.moveToState("WegameSplashState");
}

View File

@ -21,6 +21,8 @@ export const BUILD_OPTIONS = {
APP_ENVIRONMENT: G_APP_ENVIRONMENT,
CHINA_VERSION: G_CHINA_VERSION,
WEGAME_VERSION: G_WEGAME_VERSION,
ISBN_VERSION: G_ISBN_VERSION,
STEAM_ISBN_VERSION: G_STEAM_ISBN_VERSION,
IS_DEV: G_IS_DEV,
IS_RELEASE: G_IS_RELEASE,
IS_BROWSER: G_IS_BROWSER,

View File

@ -247,7 +247,7 @@ export function formatBigNumber(num, separator = T.global.decimalSeparator) {
if (num < 1000) {
return sign + "" + num;
} else {
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
if (num < 1000000) {
if (num < 10000) {
return sign + String(num).replace(".0", "").replace(".", separator);
@ -704,7 +704,7 @@ const romanLiteralsCache = ["0"];
* @returns {string}
*/
export function getRomanNumber(number) {
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
return String(number);
}
@ -763,7 +763,7 @@ export function getRomanNumber(number) {
* Returns the appropriate logo sprite path
*/
export function getLogoSprite() {
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
return "logo_wegame.png";
}

View File

@ -188,9 +188,7 @@ export class HUDInteractiveTutorial extends BaseHUDPart {
onHintChanged(hintId) {
this.elementDescription.innerHTML = T.ingame.interactiveTutorial.hints[hintId];
document.documentElement.setAttribute("data-tutorial-step", hintId);
const folder = G_WEGAME_VERSION
? "interactive_tutorial.cn.noinline"
: "interactive_tutorial.noinline";
const folder = G_ISBN_VERSION ? "interactive_tutorial.cn.noinline" : "interactive_tutorial.noinline";
this.elementGif.style.backgroundImage =
"url('" + cachebust("res/ui/" + folder + "/" + hintId + ".gif") + "')";

View File

@ -233,7 +233,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
// Show small info icon
let infoDetector;
if (!G_WEGAME_VERSION) {
if (!G_ISBN_VERSION) {
const infoButton = document.createElement("button");
infoButton.classList.add("infoButton");
element.appendChild(infoButton);

View File

@ -4,7 +4,7 @@ import { BaseHUDPart } from "../base_hud_part";
export class HUDPuzzleDLCLogo extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_PuzzleDLCLogo");
this.element.classList.toggle("china", G_CHINA_VERSION || G_WEGAME_VERSION);
this.element.classList.toggle("china", G_CHINA_VERSION || G_ISBN_VERSION);
parent.appendChild(this.element);
}

View File

@ -123,7 +123,7 @@ export class HUDShop extends BaseHUDPart {
container.appendChild(pinButton);
let infoDetector;
if (!G_WEGAME_VERSION) {
if (!G_ISBN_VERSION) {
const viewInfoButton = document.createElement("button");
viewInfoButton.classList.add("showInfo");
container.appendChild(viewInfoButton);

View File

@ -45,7 +45,7 @@ export class HUDWaypoints extends BaseHUDPart {
*/
createElements(parent) {
// Create the helper box on the lower right when zooming out
if (this.root.app.settings.getAllSettings().offerHints && !G_WEGAME_VERSION) {
if (this.root.app.settings.getAllSettings().offerHints && !G_ISBN_VERSION) {
this.hintElement = makeDiv(
parent,
"ingame_HUD_Waypoints_Hint",
@ -121,7 +121,7 @@ export class HUDWaypoints extends BaseHUDPart {
}
// Catch mouse and key events
if (!G_WEGAME_VERSION) {
if (!G_ISBN_VERSION) {
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.keyMapper
.getBinding(KEYMAPPINGS.navigation.createMarker)

View File

@ -5,7 +5,7 @@ import { WEB_STEAM_SSO_AUTHENTICATED } from "../../core/steam_sso";
import { enumHubGoalRewards } from "../tutorial_goals";
export const finalGameShape = "RuCw--Cw:----Ru--";
const chinaShapes = G_WEGAME_VERSION || G_CHINA_VERSION;
const chinaShapes = G_ISBN_VERSION || G_CHINA_VERSION;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

View File

@ -65,7 +65,7 @@ const preparementShape = "CpRpCp--:SwSwSwSw";
// Tiers need % of the previous tier as requirement too
const tierGrowth = 2.5;
const chinaShapes = G_WEGAME_VERSION || G_CHINA_VERSION;
const chinaShapes = G_ISBN_VERSION || G_CHINA_VERSION;
const upgradesCache = {};
@ -362,7 +362,7 @@ export class RegularGameMode extends GameMode {
}
if (this.root.app.settings.getAllSettings().offerHints) {
if (!G_WEGAME_VERSION) {
if (!G_ISBN_VERSION) {
this.additionalHudParts.tutorialHints = HUDPartTutorialHints;
}
this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial;

2
src/js/globals.d.ts vendored
View File

@ -20,6 +20,8 @@ declare const G_IS_RELEASE: boolean;
declare const G_CHINA_VERSION: boolean;
declare const G_WEGAME_VERSION: boolean;
declare const G_ISBN_VERSION: boolean;
declare const G_STEAM_ISBN_VERSION: boolean;
declare const G_GOG_VERSION: boolean;
declare const shapez: any;

View File

@ -12,7 +12,7 @@ export const LANGUAGES = {
"zh-CN": {
// simplified chinese
name: "简体中文",
data: G_WEGAME_VERSION
data: G_ISBN_VERSION
? require("./built-temp/base-zh-CN-ISBN.json")
: require("./built-temp/base-zh-CN.json"),
code: "zh",

View File

@ -114,7 +114,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
initialize() {
this.syncKey = null;
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
return;
}
@ -221,7 +221,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
* @returns {Promise<any>}
*/
sendToApi(endpoint, data) {
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
return Promise.resolve();
}
@ -263,7 +263,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
* @param {string} value
*/
sendGameEvent(category, value) {
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
return;
}

View File

@ -0,0 +1,141 @@
/* typehints:start */
import { Application } from "../../application";
import { GameRoot } from "../../game/root";
/* typehints:end */
import { createLogger } from "../../core/logging";
import { ACHIEVEMENTS, AchievementCollection, AchievementProviderInterface } from "../achievement_provider";
const logger = createLogger("achievements/wegame");
const ACHIEVEMENT_IDS = {
[ACHIEVEMENTS.belt500Tiles]: "belt_500_tiles",
[ACHIEVEMENTS.blueprint100k]: "blueprint_100k",
[ACHIEVEMENTS.blueprint1m]: "blueprint_1m",
[ACHIEVEMENTS.completeLvl26]: "complete_lvl_26",
[ACHIEVEMENTS.cutShape]: "cut_shape",
[ACHIEVEMENTS.darkMode]: "dark_mode",
[ACHIEVEMENTS.destroy1000]: "destroy_1000",
[ACHIEVEMENTS.irrelevantShape]: "irrelevant_shape",
[ACHIEVEMENTS.level100]: "level_100",
[ACHIEVEMENTS.level50]: "level_50",
[ACHIEVEMENTS.logoBefore18]: "logo_before_18",
[ACHIEVEMENTS.mam]: "mam",
[ACHIEVEMENTS.mapMarkers15]: "map_markers_15",
[ACHIEVEMENTS.openWires]: "open_wires",
[ACHIEVEMENTS.oldLevel17]: "old_level_17",
[ACHIEVEMENTS.noBeltUpgradesUntilBp]: "no_belt_upgrades_until_bp",
[ACHIEVEMENTS.noInverseRotater]: "no_inverse_rotator", // [sic]
[ACHIEVEMENTS.paintShape]: "paint_shape",
[ACHIEVEMENTS.place5000Wires]: "place_5000_wires",
[ACHIEVEMENTS.placeBlueprint]: "place_blueprint",
[ACHIEVEMENTS.placeBp1000]: "place_bp_1000",
[ACHIEVEMENTS.play1h]: "play_1h",
[ACHIEVEMENTS.play10h]: "play_10h",
[ACHIEVEMENTS.play20h]: "play_20h",
[ACHIEVEMENTS.produceLogo]: "produce_logo",
[ACHIEVEMENTS.produceMsLogo]: "produce_ms_logo",
[ACHIEVEMENTS.produceRocket]: "produce_rocket",
[ACHIEVEMENTS.rotateShape]: "rotate_shape",
[ACHIEVEMENTS.speedrunBp30]: "speedrun_bp_30",
[ACHIEVEMENTS.speedrunBp60]: "speedrun_bp_60",
[ACHIEVEMENTS.speedrunBp120]: "speedrun_bp_120",
[ACHIEVEMENTS.stack4Layers]: "stack_4_layers",
[ACHIEVEMENTS.stackShape]: "stack_shape",
[ACHIEVEMENTS.store100Unique]: "store_100_unique",
[ACHIEVEMENTS.storeShape]: "store_shape",
[ACHIEVEMENTS.throughputBp25]: "throughput_bp_25",
[ACHIEVEMENTS.throughputBp50]: "throughput_bp_50",
[ACHIEVEMENTS.throughputLogo25]: "throughput_logo_25",
[ACHIEVEMENTS.throughputLogo50]: "throughput_logo_50",
[ACHIEVEMENTS.throughputRocket10]: "throughput_rocket_10",
[ACHIEVEMENTS.throughputRocket20]: "throughput_rocket_20",
[ACHIEVEMENTS.trash1000]: "trash_1000",
[ACHIEVEMENTS.unlockWires]: "unlock_wires",
[ACHIEVEMENTS.upgradesTier5]: "upgrades_tier_5",
[ACHIEVEMENTS.upgradesTier8]: "upgrades_tier_8",
};
export class WegameAchievementProvider extends AchievementProviderInterface {
/** @param {Application} app */
constructor(app) {
super(app);
this.initialized = false;
this.collection = new AchievementCollection(this.activate.bind(this));
if (G_IS_DEV) {
for (let key in ACHIEVEMENT_IDS) {
assert(this.collection.map.has(key), "Key not found in collection: " + key);
}
}
logger.log("Collection created with", this.collection.map.size, "achievements");
}
/** @returns {boolean} */
hasAchievements() {
return true;
}
/**
* @param {GameRoot} root
* @returns {Promise<void>}
*/
onLoad(root) {
this.root = root;
try {
this.collection = new AchievementCollection(this.activate.bind(this));
this.collection.initialize(root);
logger.log("Initialized", this.collection.map.size, "relevant achievements");
return Promise.resolve();
} catch (err) {
logger.error("Failed to initialize the collection");
return Promise.reject(err);
}
}
/** @returns {Promise<void>} */
initialize() {
if (!G_IS_STANDALONE) {
logger.warn("Wegame unavailable. Achievements won't sync.");
return Promise.resolve();
}
if (!G_WEGAME_VERSION) {
return Promise.resolve();
}
this.initialized = true;
return Promise.resolve();
}
/**
* @param {string} key
* @returns {Promise<void>}
*/
activate(key) {
let promise;
if (!G_WEGAME_VERSION) {
return Promise.resolve();
}
if (!this.initialized) {
promise = Promise.resolve();
} else {
promise = ipcRenderer.invoke("wegame:activate-achievement", ACHIEVEMENT_IDS[key]);
}
return promise
.then(() => {
logger.log("Achievement activated:", key);
})
.catch(err => {
logger.error("Failed to activate achievement:", key, err);
throw err;
});
}
}

View File

@ -4,6 +4,7 @@ import { createLogger } from "../../core/logging";
import { StorageImplElectron } from "./storage";
import { SteamAchievementProvider } from "./steam_achievement_provider";
import { PlatformWrapperInterface } from "../wrapper";
import { WegameAchievementProvider } from "./wegame_achievement_provider";
const logger = createLogger("electron-wrapper");
@ -24,7 +25,10 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
this.app.ticker.frameEmitted.add(this.steamOverlayFixRedrawCanvas, this);
this.app.storage = new StorageImplElectron(this);
this.app.achievementProvider = new SteamAchievementProvider(this.app);
this.app.achievementProvider = G_WEGAME_VERSION
? new WegameAchievementProvider(this.app)
: new SteamAchievementProvider(this.app);
return this.initializeAchievementProvider()
.then(() => this.initializeDlcStatus())
@ -70,7 +74,7 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
}
initializeDlcStatus() {
if (G_WEGAME_VERSION) {
if (G_ISBN_VERSION) {
return Promise.resolve();
}

View File

@ -140,7 +140,7 @@ function initializeSettings() {
options: Object.keys(LANGUAGES),
valueGetter: key => key,
textGetter: key => LANGUAGES[key].name,
category: G_CHINA_VERSION || G_WEGAME_VERSION ? null : enumCategories.general,
category: G_CHINA_VERSION || G_ISBN_VERSION ? null : enumCategories.general,
restartRequired: true,
changeCb: (app, id) => null,
magicValue: "auto-detect",

View File

@ -39,21 +39,21 @@ export class MainMenuState extends GameState {
}
getInnerHTML() {
const showLanguageIcon = !G_CHINA_VERSION && !G_WEGAME_VERSION;
const showLanguageIcon = !G_CHINA_VERSION && !G_ISBN_VERSION;
const showExitAppButton = G_IS_STANDALONE;
const showPuzzleDLC =
!G_WEGAME_VERSION &&
!G_ISBN_VERSION &&
(G_IS_STANDALONE || WEB_STEAM_SSO_AUTHENTICATED) &&
!G_IS_STEAM_DEMO &&
!G_GOG_VERSION;
const showWegameFooter = G_WEGAME_VERSION;
const showWegameFooter = G_ISBN_VERSION;
const hasMods = MODS.anyModsActive();
const hasSteamBridge = !G_GOG_VERSION && !G_IS_STEAM_DEMO && !G_WEGAME_VERSION;
const hasSteamBridge = !G_GOG_VERSION && !G_IS_STEAM_DEMO && !G_ISBN_VERSION;
let showExternalLinks = true;
if (G_IS_STANDALONE) {
if (G_WEGAME_VERSION || G_CHINA_VERSION) {
if (G_ISBN_VERSION || G_CHINA_VERSION) {
showExternalLinks = false;
}
} else {
@ -711,7 +711,7 @@ export class MainMenuState extends GameState {
downloadButton.setAttribute("aria-label", "Download");
elem.appendChild(downloadButton);
if (!G_WEGAME_VERSION) {
if (!G_ISBN_VERSION) {
const renameButton = document.createElement("button");
renameButton.classList.add("styledButton", "renameGame");
renameButton.setAttribute("aria-label", "Rename Savegame");

View File

@ -155,7 +155,7 @@ export class PreloadState extends GameState {
.then(() => this.setStatus("Initializing language", 25))
.then(() => {
if (G_CHINA_VERSION || G_WEGAME_VERSION) {
if (G_CHINA_VERSION || G_ISBN_VERSION) {
return this.app.settings.updateLanguage("zh-CN");
}
@ -219,7 +219,7 @@ export class PreloadState extends GameState {
return;
}
if (G_CHINA_VERSION || G_WEGAME_VERSION) {
if (G_CHINA_VERSION || G_ISBN_VERSION) {
return;
}
@ -286,7 +286,7 @@ export class PreloadState extends GameState {
}
update() {
if (G_CHINA_VERSION || G_WEGAME_VERSION) {
if (G_CHINA_VERSION || G_ISBN_VERSION) {
return;
}
const now = performance.now();
@ -320,7 +320,7 @@ export class PreloadState extends GameState {
setStatus(text, progress) {
logger.log("✅ " + text);
if (G_CHINA_VERSION || G_WEGAME_VERSION) {
if (G_CHINA_VERSION || G_ISBN_VERSION) {
return Promise.resolve();
}
this.currentStatus = text;

View File

@ -35,10 +35,10 @@ export class SettingsState extends TextualGameState {
</button>
<div class="other ${G_CHINA_VERSION || G_WEGAME_VERSION ? "noabout" : ""}">
<div class="other ${G_CHINA_VERSION || G_ISBN_VERSION ? "noabout" : ""}">
${
G_CHINA_VERSION || G_WEGAME_VERSION
G_CHINA_VERSION || G_ISBN_VERSION
? ""
: `
<button class="styledButton about">${T.about.title}</button>
@ -47,7 +47,7 @@ export class SettingsState extends TextualGameState {
`
}
<div class="versionbar">
${G_WEGAME_VERSION ? "" : `<div class="buildVersion">${T.global.loading} ...</div>`}
${G_ISBN_VERSION ? "" : `<div class="buildVersion">${T.global.loading} ...</div>`}
</div>
</div>
</div>
@ -117,7 +117,7 @@ export class SettingsState extends TextualGameState {
onEnter(payload) {
this.renderBuildText();
if (!G_CHINA_VERSION && !G_WEGAME_VERSION) {
if (!G_CHINA_VERSION && !G_ISBN_VERSION) {
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
preventDefault: false,
});

View File

@ -49,18 +49,18 @@ global:
shift: SHIFT键
space: 空格键
loggingIn: 登录
loadingResources: Downloading additional resources (<percentage> %)
loadingResources: 正在下载资源(<percentage> %
discount: -<percentage>%
discountSummerSale: SPECIAL PROMOTION! Offer ends 7 July
discountSummerSale: 特别促销优惠将于7月7日结束
demoBanners:
title: 试玩版
intro: 购买完整版以解锁所有游戏内容!
playtimeDisclaimer: The full version contains more than <strong>20 hours of content</strong>.
playerCount: <playerCount> players like you are currently playing shapez on Steam
untilEndOfDemo: Until end of demo
playtimeDisclaimerDownload: You can continue your savegame in the full version!
Click <strong>here</strong> to download your savegame.
titleV2: "Play the full version now for:"
playtimeDisclaimer: 完整版本包括超过<strong>20小时游戏内容</strong>。
playerCount: 目前有超过<playerCount>玩家正在一起玩图形工厂
untilEndOfDemo: 直到DEMO结束
playtimeDisclaimerDownload: 你可以在完成版中继续游戏进度!
点击<strong>这里</strong>下载你的进度。
titleV2: "游玩完整版本:"
mainMenu:
play: 开始游戏
changelog: 更新日志
@ -82,14 +82,13 @@ mainMenu:
puzzleDlcWishlist: 添加心愿单!
puzzleDlcViewNow: 查看资料片!
mods:
title: Active Mods
warningPuzzleDLC: Playing the Puzzle DLC is not possible with mods. Please
disable all mods to play the DLC.
playingFullVersion: You are now playing the full version!
logout: Logout
noActiveSavegames: No active savegames found - Click play to start a new game!
playFullVersionV2: Bough shapez on Steam? Play the full version in your Browser!
playFullVersionStandalone: You can now also play the full version in your Browser!
title: 激活模组
warningPuzzleDLC: DLC谜题挑战者与模组不兼容。请屏蔽所有模组再游玩DLC。
playingFullVersion: 你现在正在游玩完整版本游戏!
logout: 登出
noActiveSavegames: 未找到游戏存档 - 点击开始游戏开始一局新游戏!
playFullVersionV2: 在浏览器中也能游玩完整版本!
playFullVersionStandalone: 在浏览器中也能游玩完整版本!
dialogs:
buttons:
ok: 确认
@ -242,25 +241,18 @@ dialogs:
title: 删除谜题吗?
desc: 您是否确认删除 '<title>'?删除谜题后将无法恢复!
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: 最新安装的模组
resourceLoadFailed:
title: Resources failed to load
demoLinkText: shapez demo on Steam
descWeb: "One ore more resources could not be loaded. Make sure you have a
stable internet connection and try again. If this still doesn't
work, make sure to also disable any browser extensions (including
adblockers).<br><br> As an alternative, you can also play the
<demoOnSteamLinkText>. <br><br> Error Message:"
descSteamDemo: "One ore more resources could not be loaded. Try restarting the
game - If that does not help, try reinstalling and verifying the
game files via Steam. <br><br> Error Message:"
title: 资源加载错误
demoLinkText: DEMO
descWeb: "一个或更多资源无法加载。请确保您的网络处于正常连接状态。如果仍旧出现问题,请确保已关闭所有浏览器插件(包括屏蔽广告插件)。<br><br>
作为一种选择,您也可以玩<demoOnSteamLinkText>。 <br><br>错误信息:"
descSteamDemo: "一个或更多资源无法加载。可以试着重启游戏 - 如果依旧不行,请试下重新安装或验证完整性。 <br><br>错误信息:"
steamSsoError:
title: Full Version Logout
title: 登出完成版本
desc: You have been logged out from the Full Browser Version since either your
network connection is unstable or you are playing on another
device.<br><br> Please make sure you don't have shapez open in any
@ -421,11 +413,11 @@ ingame:
title: 成就
desc: 挑战全成就解锁!
mods:
title: Modding support!
desc: Over 80 mods available!
titleV2: "Get the full version now on Steam to unlock:"
titleExpiredV2: Demo completed!
titleEnjoyingDemo: Enjoy the demo?
title: 支持模组!
desc: 超过80个可用模组
titleV2: "获取完整版解锁:"
titleExpiredV2: DEMO已通关
titleEnjoyingDemo: DEMO是否让您满意
puzzleEditorSettings:
zoneTitle: 区域
zoneWidth: 宽度
@ -909,7 +901,7 @@ keybindings:
massSelect: 批量选择
buildings: 设施快捷键
placementModifiers: 放置设施修饰键
mods: Provided by Mods
mods: 由模组提供
mappings:
confirm: 确认
back: 返回
@ -1130,21 +1122,16 @@ backendErrors:
too-many-likes-already: 您的谜题已经得到了许多玩家的赞赏。如果您仍然希望删除它,请联系客服!
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: 你需要完整版才能安装模组。
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!
browserNoSupport: Due to browser restrictions it is currently only possible to
install mods in the Steam version - Sorry!
title: 即将开放
description: 当前只能通过复制、移除模组文件才能启用/安装模组。不久的将来,可以通过界面来启用/安装模组,敬请期待!
browserNoSupport: 由于浏览器限制,目前网页版无法使用模组 - 非常抱歉!