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 { try {
console.log("Step 2: Calling need restart app"); console.log("Step 2: Calling need restart app");
const need_restart = railsdk.RailNeedRestartAppForCheckingEnvironment( const need_restart = railsdk.RailNeedRestartAppForCheckingEnvironment(
2001639, 2002030,
[`--rail_render_pid=${process.pid}`] //,"--rail_debug_mode", [`--rail_render_pid=${process.pid}`] //,"--rail_debug_mode",
); );
console.log("Step 3: Needs restart =", need_restart); console.log("Step 3: Needs restart =", need_restart);
@ -58,6 +58,22 @@ function listen() {
return data; 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 }; module.exports = { init, listen };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@ import { BaseHUDPart } from "../base_hud_part";
export class HUDPuzzleDLCLogo extends BaseHUDPart { export class HUDPuzzleDLCLogo extends BaseHUDPart {
createElements(parent) { createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_PuzzleDLCLogo"); 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); parent.appendChild(this.element);
} }

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import { WEB_STEAM_SSO_AUTHENTICATED } from "../../core/steam_sso";
import { enumHubGoalRewards } from "../tutorial_goals"; import { enumHubGoalRewards } from "../tutorial_goals";
export const finalGameShape = "RuCw--Cw:----Ru--"; 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 // Tiers need % of the previous tier as requirement too
const tierGrowth = 2.5; const tierGrowth = 2.5;
const chinaShapes = G_WEGAME_VERSION || G_CHINA_VERSION; const chinaShapes = G_ISBN_VERSION || G_CHINA_VERSION;
const upgradesCache = {}; const upgradesCache = {};
@ -362,7 +362,7 @@ export class RegularGameMode extends GameMode {
} }
if (this.root.app.settings.getAllSettings().offerHints) { if (this.root.app.settings.getAllSettings().offerHints) {
if (!G_WEGAME_VERSION) { if (!G_ISBN_VERSION) {
this.additionalHudParts.tutorialHints = HUDPartTutorialHints; this.additionalHudParts.tutorialHints = HUDPartTutorialHints;
} }
this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial; 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_CHINA_VERSION: boolean;
declare const G_WEGAME_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 G_GOG_VERSION: boolean;
declare const shapez: any; declare const shapez: any;

View File

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

View File

@ -114,7 +114,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
initialize() { initialize() {
this.syncKey = null; this.syncKey = null;
if (G_WEGAME_VERSION) { if (G_ISBN_VERSION) {
return; return;
} }
@ -221,7 +221,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
sendToApi(endpoint, data) { sendToApi(endpoint, data) {
if (G_WEGAME_VERSION) { if (G_ISBN_VERSION) {
return Promise.resolve(); return Promise.resolve();
} }
@ -263,7 +263,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
* @param {string} value * @param {string} value
*/ */
sendGameEvent(category, value) { sendGameEvent(category, value) {
if (G_WEGAME_VERSION) { if (G_ISBN_VERSION) {
return; 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 { StorageImplElectron } from "./storage";
import { SteamAchievementProvider } from "./steam_achievement_provider"; import { SteamAchievementProvider } from "./steam_achievement_provider";
import { PlatformWrapperInterface } from "../wrapper"; import { PlatformWrapperInterface } from "../wrapper";
import { WegameAchievementProvider } from "./wegame_achievement_provider";
const logger = createLogger("electron-wrapper"); const logger = createLogger("electron-wrapper");
@ -24,7 +25,10 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
this.app.ticker.frameEmitted.add(this.steamOverlayFixRedrawCanvas, this); this.app.ticker.frameEmitted.add(this.steamOverlayFixRedrawCanvas, this);
this.app.storage = new StorageImplElectron(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() return this.initializeAchievementProvider()
.then(() => this.initializeDlcStatus()) .then(() => this.initializeDlcStatus())
@ -70,7 +74,7 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
} }
initializeDlcStatus() { initializeDlcStatus() {
if (G_WEGAME_VERSION) { if (G_ISBN_VERSION) {
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -140,7 +140,7 @@ function initializeSettings() {
options: Object.keys(LANGUAGES), options: Object.keys(LANGUAGES),
valueGetter: key => key, valueGetter: key => key,
textGetter: key => LANGUAGES[key].name, 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, restartRequired: true,
changeCb: (app, id) => null, changeCb: (app, id) => null,
magicValue: "auto-detect", magicValue: "auto-detect",

View File

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

View File

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

View File

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

View File

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