Merge steam-demo branch

This commit is contained in:
tobspr 2022-06-06 14:06:09 +02:00
parent 09551fa0e5
commit 222ea8c261
56 changed files with 792 additions and 1081 deletions

View File

@ -1,9 +0,0 @@
[[actions]]
name = "play"
path = "shapezio.exe"
platform = "windows"
[[actions]]
name = "play"
path = "play.sh"
platform = "linux"

66
gulp/build_variants.js Normal file
View File

@ -0,0 +1,66 @@
/**
* @type {Record<string, {
* standalone: boolean,
* environment?: 'dev' | 'staging' | 'prod',
* electronBaseDir?: string,
* steamAppId?: number,
* executableName?: string,
* buildArgs: {
* chineseVersion?: boolean,
* wegameVersion?: boolean,
* steamDemo?: boolean
* }}>}
*/
const BUILD_VARIANTS = {
"web-localhost": {
standalone: false,
environment: "dev",
buildArgs: {},
},
"web-shapezio-beta": {
standalone: false,
environment: "staging",
buildArgs: {},
},
"web-shapezio": {
standalone: false,
environment: "prod",
buildArgs: {},
},
"standalone-steam": {
standalone: true,
executableName: "shapez",
steamAppId: 1318690,
buildArgs: {},
},
"standalone-steam-china": {n
standalone: true,
steamAppId: 1318690,
buildArgs: {
chineseVersion: true,
},
},
"standalone-steam-demo": {
standalone: true,
steamAppId: 1930750,
buildArgs: {
steamDemo: true,
},
},
"standalone-steam-china-demo": {
standalone: true,
steamAppId: 1930750,
buildArgs: {
steamDemo: true,
chineseVersion: true,
},
},
"standalone-wegame": {
standalone: true,
electronBaseDir: "electron_wegame",
buildArgs: {
wegameVersion: true,
},
},
};
module.exports = { BUILD_VARIANTS };

139
gulp/cordova.js vendored
View File

@ -1,139 +0,0 @@
const path = require("path");
const fs = require("fs");
const buildUtils = require("./buildutils");
function gulptasksCordova($, gulp, buildFolder) {
const cdvRes = path.join("..", "..", "res");
// Cleans up the app assets
// Removes all temporary folders used while optimizing the assets
gulp.task("cleanupAppAssetsBuiltFolder", () => {
return gulp
.src(path.join(cdvRes, "built"), { read: false, allowEmpty: true })
.pipe($.clean({ force: true }));
});
// Optimizes all built assets
gulp.task("optimizeBuiltAppAssets", () => {
return gulp
.src(path.join(cdvRes, "built", "**", "*.png"))
.pipe($.flatten())
.pipe($.imagemin([$.imagemin.optipng({ optimizationLevel: 1 })]))
.pipe(gulp.dest(path.join(cdvRes, "built")));
});
// Scales the icon resources
gulp.task("scaleIconIos", async () => {
const sizes = [
180,
60,
120,
76,
152,
40,
80,
57,
114,
72,
144,
167,
29,
58,
87,
50,
100,
167,
20,
1024,
24,
48,
55,
172,
196,
];
for (let i = 0; i < sizes.length; ++i) {
const size = sizes[i];
console.log("Scaling icon to", size, "x", size);
const img = await $.jimp.read(path.join(cdvRes, "ios", "icon-prefab.png"));
await img.resize(size, size).write(path.join(cdvRes, "built", "ios", "icon@" + size + ".png"));
}
});
gulp.task("copyOtherIosResources", () => {
return gulp
.src(path.join(cdvRes, "ios", "splash-prefab.png"))
.pipe($.rename("Default@2x~universal~anyany.png"))
.pipe(gulp.dest(path.join(cdvRes, "built", "ios")));
});
gulp.task("prepareIosRes", gulp.series("scaleIconIos", "copyOtherIosResources"));
gulp.task("copyAndroidResources", () => {
return gulp
.src(path.join(cdvRes, "android", "**", "*.*"))
.pipe(gulp.dest(path.join(cdvRes, "built", "android")));
});
gulp.task("prepareAndroidRes", gulp.series("copyAndroidResources"));
gulp.task(
"prepareCordovaAssets",
gulp.series(
"cleanupAppAssetsBuiltFolder",
gulp.parallel("prepareIosRes", "prepareAndroidRes"),
"optimizeBuiltAppAssets"
)
);
// Patches the config.xml by replacing the app id to app_beta
gulp.task("patchConfigXML", cb => {
const configUrl = path.join("..", "..", "config.xml");
let configContent = fs.readFileSync(configUrl).toString();
const version = buildUtils.getVersion();
configContent = configContent.replace("%VERSION%", version);
configContent = configContent.replace(' id="io.shapez.app" ', ' id="io.shapez.app_beta" ');
configContent = configContent.replace("<name>Shapez.io</name>", "<name>Shapez.io BETA</name>");
fs.writeFileSync(configUrl, configContent);
cb();
});
gulp.task("patchConfigXMLChangeStagingToProd", cb => {
const configUrl = path.join("..", "..", "config.xml");
let configContent = fs.readFileSync(configUrl).toString();
configContent = configContent.replace(' id="io.shapez.app_beta" ', ' id="io.shapez.app" ');
configContent = configContent.replace("<name>Shapez.io BETA</name>", "<name>Shapez.io</name>");
fs.writeFileSync(configUrl, configContent);
cb();
});
// Triggers a new build on phonegap
gulp.task("triggerPhonegapBuild", () => {
return gulp
.src("src/html/", { dot: false })
.pipe(
$.phonegapBuild({
isRepository: true,
appId: "3339820",
platforms: ["android", "ios"],
user: {
token: process.env.SHAPEZ_CLI_PHONEGAP_KEY,
},
})
)
.pipe(
$.phonegapBuild({
isRepository: true,
appId: "3537816",
platforms: ["android", "ios"],
user: {
token: process.env.SHAPEZ_CLI_PHONEGAP_KEY,
},
})
);
});
}
module.exports = {
gulptasksCordova,
};

View File

@ -18,7 +18,6 @@ const $ = require("gulp-load-plugins")({
const envVars = [
"SHAPEZ_CLI_SERVER_HOST",
// "SHAPEZ_CLI_PHONEGAP_KEY",
"SHAPEZ_CLI_ALPHA_FTP_USER",
"SHAPEZ_CLI_ALPHA_FTP_PW",
"SHAPEZ_CLI_STAGING_FTP_USER",
@ -33,8 +32,7 @@ const envVars = [
for (let i = 0; i < envVars.length; ++i) {
if (!process.env[envVars[i]]) {
console.warn("Please set", envVars[i]);
// process.exit(1);
console.warn("Unset environment variable, might cause issues:", envVars[i]);
}
}
@ -57,7 +55,7 @@ const js = require("./js");
js.gulptasksJS($, gulp, buildFolder, browserSync);
const html = require("./html");
html.gulptasksHTML($, gulp, buildFolder, browserSync);
html.gulptasksHTML($, gulp, buildFolder);
const ftp = require("./ftp");
ftp.gulptasksFTP($, gulp, buildFolder);
@ -66,13 +64,11 @@ const docs = require("./docs");
docs.gulptasksDocs($, gulp, buildFolder);
const standalone = require("./standalone");
standalone.gulptasksStandalone($, gulp, buildFolder);
const releaseUploader = require("./release-uploader");
releaseUploader.gulptasksReleaseUploader($, gulp, buildFolder);
standalone.gulptasksStandalone($, gulp);
const translations = require("./translations");
translations.gulptasksTranslations($, gulp, buildFolder);
const { BUILD_VARIANTS } = require("./build_variants");
translations.gulptasksTranslations($, gulp);
///////////////////// BUILD TASKS /////////////////////
@ -142,9 +138,9 @@ gulp.task("main.webserver", () => {
/**
*
* @param {object} param0
* @param {"web"|"standalone"|"china"|"wegame"} param0.version
* @param {keyof typeof BUILD_VARIANTS} param0.version
*/
function serve({ version = "web" }) {
function serveHTML({ version = "web-dev" }) {
browserSync.init({
server: [buildFolder, path.join(baseDir, "mod_examples")],
port: 3005,
@ -168,10 +164,7 @@ function serve({ version = "web" }) {
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild
gulp.watch("../src/**/*.html", gulp.series(version === "web" ? "html.dev" : "html.standalone-dev"));
// Watch sound files
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev"));
gulp.watch("../src/**/*.html", gulp.series("html." + version + ".dev"));
// Watch translations
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
@ -204,27 +197,7 @@ function serve({ version = "web" }) {
return gulp.src(path).pipe(browserSync.reload({ stream: true }));
});
switch (version) {
case "web": {
gulp.series("js.dev.watch")(() => true);
break;
}
case "standalone": {
gulp.series("js.standalone-dev.watch")(() => true);
break;
}
case "china": {
gulp.series("china.js.dev.watch")(() => true);
break;
}
case "wegame": {
gulp.series("wegame.js.dev.watch")(() => true);
break;
}
default: {
throw new Error("Unknown version " + version);
}
}
gulp.series("js." + version + ".dev.watch")(() => true);
}
///////////////////// RUNNABLE TASKS /////////////////////
@ -238,9 +211,9 @@ gulp.task("step.deleteEmpty", cb => {
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
// Builds everything (dev)
// // Builds everything (dev)
gulp.task(
"build.dev",
"build.prepare.dev",
gulp.series(
"utils.cleanup",
"utils.copyAdditionalBuildFiles",
@ -252,146 +225,95 @@ gulp.task(
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"css.dev",
"html.dev"
"css.dev"
)
);
// Builds everything (standalone -dev)
gulp.task(
"build.standalone.dev",
gulp.series(
"utils.cleanup",
"localConfig.findOrCreate",
"imgres.buildAtlas",
"imgres.atlasToJson",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"css.dev",
"html.standalone-dev"
)
);
// // Builds everything (staging)
// gulp.task("step.staging.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.staging"));
// gulp.task(
// "step.staging.mainbuild",
// gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code")
// );
// gulp.task("step.staging.all", gulp.series("step.staging.mainbuild", "css.prod", "html.staging"));
// gulp.task("build.staging", gulp.series("utils.cleanup", "step.staging.all", "step.postbuild"));
// Builds everything (staging)
gulp.task("step.staging.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.staging"));
gulp.task(
"step.staging.mainbuild",
gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code")
);
gulp.task("step.staging.all", gulp.series("step.staging.mainbuild", "css.prod", "html.staging"));
gulp.task("build.staging", gulp.series("utils.cleanup", "step.staging.all", "step.postbuild"));
// // Builds everything (prod)
// gulp.task("step.prod.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.prod"));
// gulp.task(
// "step.prod.mainbuild",
// gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code")
// );
// gulp.task("step.prod.all", gulp.series("step.prod.mainbuild", "css.prod", "html.prod"));
// gulp.task("build.prod", gulp.series("utils.cleanup", "step.prod.all", "step.postbuild"));
// Builds everything (prod)
gulp.task("step.prod.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.prod"));
gulp.task(
"step.prod.mainbuild",
gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code")
);
gulp.task("step.prod.all", gulp.series("step.prod.mainbuild", "css.prod", "html.prod"));
gulp.task("build.prod", gulp.series("utils.cleanup", "step.prod.all", "step.postbuild"));
// Builds everything for every variant
for (const variant in BUILD_VARIANTS) {
const data = BUILD_VARIANTS[variant];
const buildName = "build." + variant;
// Builds everything (standalone-beta)
gulp.task(
"step.standalone-beta.code",
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", "js.standalone-beta")
);
gulp.task("step.standalone-beta.mainbuild", gulp.parallel("step.baseResources", "step.standalone-beta.code"));
gulp.task(
"step.standalone-beta.all",
gulp.series("step.standalone-beta.mainbuild", "css.prod-standalone", "html.standalone-beta")
);
gulp.task(
"build.standalone-beta",
gulp.series("utils.cleanup", "step.standalone-beta.all", "step.postbuild")
);
// Builds everything (standalone-prod)
for (const prefix of ["", "china.", "wegame."]) {
gulp.task(
prefix + "step.standalone-prod.code",
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", prefix + "js.standalone-prod")
buildName + ".code",
gulp.series(
data.standalone ? "sounds.fullbuildHQ" : "sounds.fullbuild",
"translations.fullBuild",
"js." + variant + ".prod"
)
);
gulp.task(
prefix + "step.standalone-prod.mainbuild",
gulp.parallel("step.baseResources", prefix + "step.standalone-prod.code")
);
gulp.task(buildName + ".resourcesAndCode", gulp.parallel("step.baseResources", buildName + ".code"));
gulp.task(
prefix + "step.standalone-prod.all",
gulp.series(prefix + "step.standalone-prod.mainbuild", "css.prod-standalone", "html.standalone-prod")
buildName + ".all",
gulp.series(buildName + ".resourcesAndCode", "css.prod-standalone", "html." + variant + ".prod")
);
gulp.task(buildName, gulp.series("utils.cleanup", buildName + ".all", "step.postbuild"));
// serve
gulp.task(
prefix + "build.standalone-prod",
gulp.series("utils.cleanup", prefix + "step.standalone-prod.all", "step.postbuild")
"serve." + variant,
gulp.series("build.prepare.dev", "html." + variant + ".dev", () => serveHTML({ version: variant }))
);
}
// OS X build and release upload
gulp.task(
"build.darwin64-prod",
gulp.series(
"build.standalone-prod",
"standalone.prepare",
"standalone.package.prod.darwin64.signManually"
)
);
// gulp.task(
// "build.darwin64-prod",
// gulp.series(
// "build.standalone-prod",
// "standalone.prepare",
// "standalone.package.prod.darwin64.signManually"
// )
// );
// Deploying!
gulp.task(
"main.deploy.alpha",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.alpha")
"deploy.staging",
gulp.series("utils.requireCleanWorkingTree", "build.web-shapezio-beta", "ftp.upload.staging")
);
gulp.task(
"main.deploy.staging",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.staging")
);
gulp.task("main.deploy.prod", gulp.series("utils.requireCleanWorkingTree", "build.prod", "ftp.upload.prod"));
gulp.task("main.deploy.all", gulp.series("main.deploy.staging", "main.deploy.prod"));
// steam
gulp.task("regular.main.standalone", gulp.series("build.standalone-prod", "standalone.package.prod"));
// china
gulp.task(
"china.main.standalone",
gulp.series("china.build.standalone-prod", "china.standalone.package.prod")
"deploy.prod",
gulp.series("utils.requireCleanWorkingTree", "build.web-shapezio", "ftp.upload.prod")
);
// wegame
gulp.task(
"wegame.main.standalone",
gulp.series("wegame.build.standalone-prod", "wegame.standalone.package.prod")
);
// // china
// gulp.task(
// "china.main.standalone",
// gulp.series("china.build.standalone-prod", "china.standalone.package.prod")
// );
// all (except wegame)
gulp.task("standalone.steam", gulp.series("regular.main.standalone", "china.main.standalone"));
gulp.task(
"standalone.all",
gulp.series("regular.main.standalone", "china.main.standalone", "wegame.main.standalone")
);
// // wegame
// gulp.task(
// "wegame.main.standalone",
// gulp.series("wegame.build.standalone-prod", "wegame.standalone.package.prod")
// );
// Live-development
gulp.task(
"main.serveDev",
gulp.series("build.dev", () => serve({ version: "web" }))
);
gulp.task(
"main.serveStandalone",
gulp.series("build.standalone.dev", () => serve({ version: "standalone" }))
);
gulp.task(
"china.main.serveDev",
gulp.series("build.dev", () => serve({ version: "china" }))
);
gulp.task(
"wegame.main.serveDev",
gulp.series("build.dev", () => serve({ version: "wegame" }))
);
// // all (except wegame)
// gulp.task("standalone.steam", gulp.series("regular.main.standalone", "china.main.standalone"));
// gulp.task(
// "standalone.all",
// gulp.series("regular.main.standalone", "china.main.standalone", "wegame.main.standalone")
// );
gulp.task("default", gulp.series("main.serveDev"));
gulp.task("default", gulp.series("serve.web-localhost"));

View File

@ -2,6 +2,7 @@ const buildUtils = require("./buildutils");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const { BUILD_VARIANTS } = require("./build_variants");
function computeIntegrityHash(fullPath, algorithm = "sha256") {
const file = fs.readFileSync(fullPath);
@ -9,12 +10,20 @@ function computeIntegrityHash(fullPath, algorithm = "sha256") {
return algorithm + "-" + hash;
}
/**
* PROVIDES (per <variant>)
*
* html.<variant>.dev
* html.<variant>.prod
*/
function gulptasksHTML($, gulp, buildFolder) {
const commitHash = buildUtils.getRevision();
async function buildHtml(
apiUrl,
{ analytics = false, standalone = false, app = false, integrity = true, enableCachebust = true }
) {
async function buildHtml({
googleAnalytics = false,
standalone = false,
integrity = true,
enableCachebust = true,
}) {
function cachebust(url) {
if (enableCachebust) {
return buildUtils.cachebust(url, commitHash);
@ -22,7 +31,7 @@ function gulptasksHTML($, gulp, buildFolder) {
return url;
}
const hasLocalFiles = standalone || app;
const hasLocalFiles = standalone;
return gulp
.src("../src/html/" + (standalone ? "index.standalone.html" : "index.html"))
@ -31,13 +40,6 @@ function gulptasksHTML($, gulp, buildFolder) {
/** @this {Document} **/ function () {
const document = this;
// Preconnect to api
const prefetchLink = document.createElement("link");
prefetchLink.rel = "preconnect";
prefetchLink.href = apiUrl;
prefetchLink.setAttribute("crossorigin", "anonymous");
document.head.appendChild(prefetchLink);
// Append css
const css = document.createElement("link");
css.rel = "stylesheet";
@ -53,31 +55,8 @@ function gulptasksHTML($, gulp, buildFolder) {
}
document.head.appendChild(css);
// Append async css
// const asyncCss = document.createElement("link");
// asyncCss.rel = "stylesheet";
// asyncCss.type = "text/css";
// asyncCss.media = "none";
// asyncCss.setAttribute("onload", "this.media='all'");
// asyncCss.href = cachebust("async-resources.css");
// if (integrity) {
// asyncCss.setAttribute(
// "integrity",
// computeIntegrityHash(path.join(buildFolder, "async-resources.css"))
// );
// }
// document.head.appendChild(asyncCss);
if (app) {
// Append cordova link
const cdv = document.createElement("script");
cdv.src = "cordova.js";
cdv.type = "text/javascript";
document.head.appendChild(cdv);
}
// Google analytics
if (analytics) {
if (googleAnalytics) {
const tagManagerScript = document.createElement("script");
tagManagerScript.src =
"https://www.googletagmanager.com/gtag/js?id=UA-165342524-1";
@ -92,14 +71,6 @@ function gulptasksHTML($, gulp, buildFolder) {
gtag('config', 'UA-165342524-1', { anonymize_ip: true });
`;
document.head.appendChild(initScript);
const abTestingScript = document.createElement("script");
abTestingScript.setAttribute(
"src",
"https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"
);
abTestingScript.setAttribute("async", "");
document.head.appendChild(abTestingScript);
}
// Do not need to preload in app or standalone
@ -250,50 +221,25 @@ function gulptasksHTML($, gulp, buildFolder) {
.pipe(gulp.dest(buildFolder));
}
gulp.task("html.dev", () => {
return buildHtml("http://localhost:5005", {
analytics: false,
integrity: false,
enableCachebust: false,
for (const variant in BUILD_VARIANTS) {
const data = BUILD_VARIANTS[variant];
gulp.task("html." + variant + ".dev", () => {
return buildHtml({
googleAnalytics: false,
standalone: data.standalone,
integrity: false,
enableCachebust: false,
});
});
});
gulp.task("html.staging", () => {
return buildHtml("https://api-staging.shapez.io", {
analytics: true,
gulp.task("html." + variant + ".prod", () => {
return buildHtml({
googleAnalytics: !data.standalone,
standalone: data.standalone,
integrity: true,
enableCachebust: !data.standalone,
});
});
});
gulp.task("html.prod", () => {
return buildHtml("https://analytics.shapez.io", {
analytics: true,
});
});
gulp.task("html.standalone-dev", () => {
return buildHtml("https://localhost:5005", {
analytics: false,
standalone: true,
integrity: false,
enableCachebust: false,
});
});
gulp.task("html.standalone-beta", () => {
return buildHtml("https://api-staging.shapez.io", {
analytics: false,
standalone: true,
enableCachebust: false,
});
});
gulp.task("html.standalone-prod", () => {
return buildHtml("https://analytics.shapez.io", {
analytics: false,
standalone: true,
enableCachebust: false,
});
});
}
}
module.exports = {

View File

@ -1,260 +1,122 @@
const path = require("path");
const { BUILD_VARIANTS } = require("./build_variants");
function requireUncached(module) {
delete require.cache[require.resolve(module)];
return require(module);
}
/**
* PROVIDES (per <variant>)
*
* js.<variant>.dev.watch
* js.<variant>.dev
* js.<variant>.prod
*
*/
function gulptasksJS($, gulp, buildFolder, browserSync) {
//// DEV
gulp.task("js.dev.watch", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
watch: true,
})
for (const variant in BUILD_VARIANTS) {
const data = BUILD_VARIANTS[variant];
gulp.task("js." + variant + ".dev.watch", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
...data.buildArgs,
standalone: data.standalone,
watch: true,
})
)
)
)
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("js.dev", () => {
return gulp
.src("../src/js/main.js")
.pipe($.webpackStream(requireUncached("./webpack.config.js")({})))
.pipe(gulp.dest(buildFolder));
});
if (!data.standalone) {
// WEB
//// DEV CHINA
gulp.task("js." + variant + ".dev", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
...data.buildArgs,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("china.js.dev.watch", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
watch: true,
chineseVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("js." + variant + ".prod.transpiled", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
es6: false,
...data.buildArgs,
})
)
)
.pipe($.rename("bundle-transpiled.js"))
.pipe(gulp.dest(buildFolder));
});
gulp.task("china.js.dev", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
chineseVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
//// DEV WEGAME
gulp.task("wegame.js.dev.watch", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
watch: true,
wegameVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("wegame.js.dev", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
wegameVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
//// STAGING
gulp.task("js.staging.transpiled", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: true,
environment: "staging",
es6: false,
})
)
)
.pipe($.rename("bundle-transpiled.js"))
.pipe(gulp.dest(buildFolder));
});
gulp.task("js.staging.latest", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: true,
environment: "staging",
es6: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("js.staging", gulp.parallel("js.staging.transpiled", "js.staging.latest"));
//// PROD
gulp.task("js.prod.transpiled", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: false,
environment: "prod",
es6: false,
})
)
)
.pipe($.rename("bundle-transpiled.js"))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("js.prod.latest", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: false,
environment: "prod",
es6: true,
})
)
)
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("js.prod", gulp.parallel("js.prod.transpiled", "js.prod.latest"));
//// STANDALONE
gulp.task("js.standalone-dev.watch", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
watch: true,
standalone: true,
})
)
)
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("js.standalone-dev", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
standalone: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("js.standalone-beta", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: true,
environment: "staging",
es6: true,
standalone: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("js.standalone-prod", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: false,
environment: "prod",
es6: true,
standalone: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("china.js.standalone-prod", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: false,
environment: "prod",
es6: true,
standalone: true,
chineseVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("wegame.js.standalone-prod", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: false,
environment: "prod",
es6: false,
standalone: true,
wegameVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("js." + variant + ".prod.es6", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
es6: true,
...data.buildArgs,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task(
"js." + variant + ".prod",
gulp.parallel("js." + variant + ".prod.transpiled", "js." + variant + ".prod.es6")
);
} else {
// STANDALONE
gulp.task("js." + variant + ".dev", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
...data.buildArgs,
standalone: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("js." + variant + ".prod", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
...data.buildArgs,
environment: "prod",
es6: true,
standalone: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
}
}
}
module.exports = {

View File

@ -1,66 +0,0 @@
const path = require("path");
const fs = require("fs");
const execSync = require("child_process").execSync;
const { Octokit } = require("@octokit/rest");
const buildutils = require("./buildutils");
function gulptasksReleaseUploader($, gulp, buildFolder) {
const standaloneDir = path.join(__dirname, "..", "tmp_standalone_files");
const darwinApp = path.join(standaloneDir, "shapez.io-standalone-darwin-x64", "shapez.io-standalone.app");
const dmgName = "shapez.io-standalone.dmg";
const dmgPath = path.join(standaloneDir, "shapez.io-standalone-darwin-x64", dmgName);
gulp.task("standalone.uploadRelease.darwin64.cleanup", () => {
return gulp.src(dmgPath, { read: false, allowEmpty: true }).pipe($.clean({ force: true }));
});
gulp.task("standalone.uploadRelease.darwin64.compress", cb => {
console.log("Packaging disk image", dmgPath);
execSync(`hdiutil create -format UDBZ -srcfolder ${darwinApp} ${dmgPath}`);
cb();
});
gulp.task("standalone.uploadRelease.darwin64.upload", async cb => {
const currentTag = buildutils.getTag();
const octokit = new Octokit({
auth: process.env.SHAPEZ_CLI_GITHUB_TOKEN
});
const createdRelease = await octokit.request("POST /repos/{owner}/{repo}/releases", {
owner: process.env.SHAPEZ_CLI_GITHUB_USER,
repo: "shapez.io",
tag_name: currentTag,
name: currentTag,
draft: true
});
const { data: { id, upload_url } } = createdRelease;
console.log(`Created release ${id} for tag ${currentTag}`);
const dmgContents = fs.readFileSync(dmgPath);
const dmgSize = fs.statSync(dmgPath).size;
console.log("Uploading", dmgContents.length / 1024 / 1024, "MB to", upload_url);
await octokit.request({
method: "POST",
url: upload_url,
headers: {
"content-type": "application/x-apple-diskimage"
},
name: dmgName,
data: dmgContents
});
cb();
});
gulp.task("standalone.uploadRelease.darwin64",
gulp.series(
"standalone.uploadRelease.darwin64.cleanup",
"standalone.uploadRelease.darwin64.compress",
"standalone.uploadRelease.darwin64.upload"
));
}
module.exports = { gulptasksReleaseUploader };

View File

@ -8,6 +8,7 @@ const fse = require("fs-extra");
const buildutils = require("./buildutils");
const execSync = require("child_process").execSync;
const electronNotarize = require("electron-notarize");
const { BUILD_VARIANTS } = require("./build_variants");
let signAsync;
try {
@ -17,56 +18,32 @@ try {
}
function gulptasksStandalone($, gulp) {
const targets = [
{
tempDestDir: path.join(__dirname, "..", "tmp_standalone_files"),
suffix: "",
taskPrefix: "",
electronBaseDir: path.join(__dirname, "..", "electron"),
steam: true,
},
{
tempDestDir: path.join(__dirname, "..", "tmp_standalone_files_china"),
suffix: "china",
taskPrefix: "china.",
electronBaseDir: path.join(__dirname, "..", "electron"),
steam: true,
},
{
tempDestDir: path.join(__dirname, "..", "tmp_standalone_files_wegame"),
suffix: "wegame",
taskPrefix: "wegame.",
electronBaseDir: path.join(__dirname, "..", "electron_wegame"),
steam: false,
},
];
for (const { tempDestDir, suffix, taskPrefix, electronBaseDir, steam } of targets) {
for (const variant in BUILD_VARIANTS) {
const variantData = BUILD_VARIANTS[variant];
if (!variantData.standalone) {
continue;
}
const tempDestDir = path.join(__dirname, "..", "build_output", variant);
const taskPrefix = "standalone." + variant;
const electronBaseDir = path.join(__dirname, "..", variantData.electronBaseDir || "electron");
const tempDestBuildDir = path.join(tempDestDir, "built");
gulp.task(taskPrefix + "standalone.prepare.cleanup", () => {
gulp.task(taskPrefix + ".prepare.cleanup", () => {
return gulp.src(tempDestDir, { read: false, allowEmpty: true }).pipe($.clean({ force: true }));
});
gulp.task(taskPrefix + "standalone.prepare.copyPrefab", () => {
gulp.task(taskPrefix + ".prepare.copyPrefab", () => {
const requiredFiles = [
path.join(electronBaseDir, "node_modules", "**", "*.*"),
path.join(electronBaseDir, "node_modules", "**", ".*"),
path.join(electronBaseDir, "wegame_sdk", "**", "*.*"),
path.join(electronBaseDir, "wegame_sdk", "**", ".*"),
path.join(electronBaseDir, "favicon*"),
// fails on platforms which support symlinks
// https://github.com/gulpjs/gulp/issues/1427
// path.join(electronBaseDir, "node_modules", "**", "*"),
];
if (steam) {
requiredFiles.push(path.join(electronBaseDir, "steam_appid.txt"));
}
return gulp.src(requiredFiles, { base: electronBaseDir }).pipe(gulp.dest(tempDestBuildDir));
});
gulp.task(taskPrefix + "standalone.prepare.writePackageJson", cb => {
gulp.task(taskPrefix + ".prepare.writePackageJson", cb => {
const packageJsonString = JSON.stringify(
{
scripts: {
@ -85,52 +62,15 @@ function gulptasksStandalone($, gulp) {
cb();
});
gulp.task(taskPrefix + "standalone.prepareVDF", cb => {
if (!steam) {
cb();
return;
}
const hash = buildutils.getRevision();
const steampipeDir = path.join(__dirname, "steampipe", "scripts");
const templateContents = fs
.readFileSync(path.join(steampipeDir, "app.vdf.template"), { encoding: "utf-8" })
.toString();
const convertedContents = templateContents.replace("$DESC$", "Commit " + hash);
fs.writeFileSync(path.join(steampipeDir, "app.vdf"), convertedContents);
cb();
});
gulp.task(taskPrefix + "standalone.prepareVDF.darwin", cb => {
if (!steam) {
cb();
return;
}
const hash = buildutils.getRevision();
const steampipeDir = path.join(__dirname, "steampipe-darwin", "scripts");
const templateContents = fs
.readFileSync(path.join(steampipeDir, "app.vdf.template"), { encoding: "utf-8" })
.toString();
const convertedContents = templateContents.replace("$DESC$", "Commit " + hash);
fs.writeFileSync(path.join(steampipeDir, "app.vdf"), convertedContents);
cb();
});
gulp.task(taskPrefix + "standalone.prepare.minifyCode", () => {
gulp.task(taskPrefix + ".prepare.minifyCode", () => {
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
});
gulp.task(taskPrefix + "standalone.prepare.copyGamefiles", () => {
gulp.task(taskPrefix + ".prepare.copyGamefiles", () => {
return gulp.src("../build/**/*.*", { base: "../build" }).pipe(gulp.dest(tempDestBuildDir));
});
gulp.task(taskPrefix + "standalone.killRunningInstances", cb => {
gulp.task(taskPrefix + ".killRunningInstances", cb => {
try {
execSync("taskkill /F /IM shapezio.exe");
} catch (ex) {
@ -140,14 +80,14 @@ function gulptasksStandalone($, gulp) {
});
gulp.task(
taskPrefix + "standalone.prepare",
taskPrefix + ".prepare",
gulp.series(
taskPrefix + "standalone.killRunningInstances",
taskPrefix + "standalone.prepare.cleanup",
taskPrefix + "standalone.prepare.copyPrefab",
taskPrefix + "standalone.prepare.writePackageJson",
taskPrefix + "standalone.prepare.minifyCode",
taskPrefix + "standalone.prepare.copyGamefiles"
taskPrefix + ".killRunningInstances",
taskPrefix + ".prepare.cleanup",
taskPrefix + ".prepare.copyPrefab",
taskPrefix + ".prepare.writePackageJson",
taskPrefix + ".prepare.minifyCode",
taskPrefix + ".prepare.copyGamefiles"
)
);
@ -158,11 +98,13 @@ function gulptasksStandalone($, gulp) {
* @param {function():void} cb
*/
function packageStandalone(platform, arch, cb, isRelease = true) {
const tomlFile = fs.readFileSync(path.join(__dirname, ".itch.toml"));
const privateArtifactsPath = "node_modules/shapez.io-private-artifacts";
let asar = steam;
if (steam && fs.existsSync(path.join(tempDestBuildDir, privateArtifactsPath))) {
// Only use asar on steam builds (not supported by wegame)
let asar = Boolean(variantData.steamAppId);
// Unpack private artifacts though
if (asar && fs.existsSync(path.join(tempDestBuildDir, privateArtifactsPath))) {
// @ts-expect-error
asar = { unpackDir: privateArtifactsPath };
}
@ -177,10 +119,10 @@ function gulptasksStandalone($, gulp) {
asar: asar,
executableName: "shapezio",
icon: path.join(electronBaseDir, "favicon"),
name: "shapez.io-standalone" + suffix,
name: "shapez-" + variant,
out: tempDestDir,
overwrite: true,
appBundleId: "tobspr.shapezio.standalone",
appBundleId: "tobspr.shapezio." + variant,
appCategoryType: "public.app-category.games",
...(isRelease &&
platform === "darwin" && {
@ -189,6 +131,7 @@ function gulptasksStandalone($, gulp) {
"hardenedRuntime": true,
"entitlements": "entitlements.plist",
"entitlements-inherit": "entitlements.plist",
// @ts-ignore
"signatureFlags": ["library"],
"version": "16.0.7",
},
@ -202,43 +145,42 @@ function gulptasksStandalone($, gulp) {
console.log("Packages created:", appPaths);
appPaths.forEach(appPath => {
if (!fs.existsSync(appPath)) {
console.error("Bad app path gotten:", appPath);
console.error("Bad app path:", appPath);
return;
}
if (steam) {
if (variantData.steamAppId) {
fs.writeFileSync(
path.join(appPath, "LICENSE"),
fs.readFileSync(path.join(__dirname, "..", "LICENSE"))
);
fse.copySync(
path.join(tempDestBuildDir, "steam_appid.txt"),
path.join(appPath, "steam_appid.txt")
fs.writeFileSync(
path.join(appPath, "steam_appid.txt"),
String(variantData.steamAppId)
);
fs.writeFileSync(path.join(appPath, ".itch.toml"), tomlFile);
if (platform === "linux") {
// Write launcher script
fs.writeFileSync(
path.join(appPath, "play.sh"),
'#!/usr/bin/env bash\n./shapezio --no-sandbox "$@"\n'
);
fs.chmodSync(path.join(appPath, "play.sh"), 0o775);
}
if (platform === "darwin") {
if (!isRelease) {
fse.copySync(
path.join(tempDestBuildDir, "steam_appid.txt"),
// Needs special location
fs.writeFileSync(
path.join(
path.join(
appPath,
"shapez.io-standalone.app",
"Contents",
"MacOS"
),
appPath,
"shapez.io-standalone.app",
"Contents",
"MacOS",
"steam_appid.txt"
)
),
String(variantData.steamAppId)
);
}
}
@ -255,7 +197,7 @@ function gulptasksStandalone($, gulp) {
}
// Manual signing with patched @electron/osx-sign (we need --no-strict)
gulp.task(taskPrefix + "standalone.package.prod.darwin64.signManually", cb =>
gulp.task(taskPrefix + ".package.darwin64", cb =>
packageStandalone(
"darwin",
"x64",
@ -327,29 +269,44 @@ function gulptasksStandalone($, gulp) {
)
);
gulp.task(taskPrefix + "standalone.package.prod.win64", cb => packageStandalone("win32", "x64", cb));
gulp.task(taskPrefix + "standalone.package.prod.linux64", cb =>
packageStandalone("linux", "x64", cb)
);
gulp.task(taskPrefix + "standalone.package.prod.darwin64", cb =>
packageStandalone("darwin", "x64", cb)
);
gulp.task(taskPrefix + "standalone.package.prod.darwin64.unsigned", cb =>
packageStandalone("darwin", "x64", cb, false)
);
gulp.task(taskPrefix + ".package.win64", cb => packageStandalone("win32", "x64", cb));
gulp.task(taskPrefix + ".package.linux64", cb => packageStandalone("linux", "x64", cb));
gulp.task(
taskPrefix + "standalone.package.prod",
taskPrefix + ".build-from-windows",
gulp.series(
taskPrefix + "standalone.prepare",
gulp.parallel(
taskPrefix + "standalone.package.prod.win64",
taskPrefix + "standalone.package.prod.linux64",
taskPrefix + "standalone.package.prod.darwin64"
)
taskPrefix + ".prepare",
gulp.parallel(taskPrefix + ".package.win64", taskPrefix + ".package.linux64")
)
);
gulp.task(
taskPrefix + ".build-from-darwin",
gulp.series(taskPrefix + ".prepare", gulp.parallel(taskPrefix + ".package.darwin64"))
);
}
// Steam helpers
gulp.task("standalone.prepareVDF", cb => {
const hash = buildutils.getRevision();
const version = buildutils.getVersion();
for (const platform of ["steampipe", "steampipe-darwin"]) {
const steampipeDir = path.join(__dirname, platform, "scripts");
for (const buildVariant of ["app", "app-demo"]) {
const templateContents = fs
.readFileSync(path.join(steampipeDir, buildVariant + ".vdf.template"), {
encoding: "utf-8",
})
.toString();
const convertedContents = templateContents.replace(
"$DESC$",
platform + " " + buildVariant + " version " + version + ", commit " + hash
);
fs.writeFileSync(path.join(steampipeDir, buildVariant + ".vdf"), convertedContents);
}
}
cb();
});
}
module.exports = { gulptasksStandalone };

View File

@ -0,0 +1,14 @@
"appbuild"
{
"appid" "1930750"
"desc" "$DESC$"
"buildoutput" "$STEAMPIPE_DIR$/steamtmp"
"contentroot" ""
"setlive" ""
"preview" "0"
"local" ""
"depots"
{
"1930756" "$STEAMPIPE_DIR$/scripts/demo-darwin.vdf"
}
}

View File

@ -2,13 +2,13 @@
{
"appid" "1318690"
"desc" "$DESC$"
"buildoutput" "/Users/tobiasspringer/work/shapez.io/gulp/steampipe-darwin/steamtmp"
"buildoutput" "$PROJECT_DIR$/gulp/steampipe-darwin/steamtmp"
"contentroot" ""
"setlive" ""
"preview" "0"
"local" ""
"depots"
{
"1318693" "/Users/tobiasspringer/work/shapez.io/gulp/steampipe-darwin/scripts/darwin.vdf"
"1318693" "$PROJECT_DIR$/gulp/steampipe-darwin/scripts/darwin.vdf"
}
}

View File

@ -1,7 +1,7 @@
"DepotBuildConfig"
{
"DepotID" "1318693"
"contentroot" "/Users/tobiasspringer/work/shapez.io/tmp_standalone_files/shapez.io-standalone-darwin-x64"
"contentroot" "$PROJECT_DIR$/tmp_standalone_files/shapez.io-standalone-darwin-x64"
"FileMapping"
{
"LocalPath" "*"

View File

@ -0,0 +1,12 @@
"DepotBuildConfig"
{
"DepotID" "1930756"
"contentroot" "$PROJECT_DIR$/tmp_standalone_files/shapez.io-demo-darwin-x64"
"FileMapping"
{
"LocalPath" "*"
"DepotPath" "."
"recursive" "1"
}
"FileExclusion" "*.pdb"
}

View File

@ -1,3 +1,3 @@
#!/bin/sh
yarn gulp standalone.prepareVDF.darwin
yarn gulp standalone.prepareVDF
steamcmd.sh +login $STEAM_UPLOAD_SHAPEZ_ID $STEAM_UPLOAD_SHAPEZ_USER +run_app_build $PWD/scripts/app.vdf +quit

View File

@ -0,0 +1,17 @@
"appbuild"
{
"appid" "1930750"
"desc" "$DESC$"
"buildoutput" "$STEAMPIPE_DIR$\steamtemp"
"contentroot" ""
"setlive" ""
"preview" "0"
"local" ""
"depots"
{
"1930753" "$STEAMPIPE_DIR$\scripts\demo-windows.vdf"
"1930754" "$STEAMPIPE_DIR$\scripts\demo-china-windows.vdf"
"1930752" "$STEAMPIPE_DIR$\scripts\demo-linux.vdf"
"1930755" "$STEAMPIPE_DIR$\scripts\demo-china-linux.vdf"
}
}

View File

@ -2,16 +2,16 @@
{
"appid" "1318690"
"desc" "$DESC$"
"buildoutput" "C:\work\shapez\shapez.io\gulp\steampipe\steamtemp"
"buildoutput" "$STEAMPIPE_DIR$\steamtemp"
"contentroot" ""
"setlive" ""
"preview" "0"
"local" ""
"depots"
{
"1318691" "C:\work\shapez\shapez.io\gulp\steampipe\scripts\windows.vdf"
"1318694" "C:\work\shapez\shapez.io\gulp\steampipe\scripts\china-windows.vdf"
"1318692" "C:\work\shapez\shapez.io\gulp\steampipe\scripts\linux.vdf"
"1318695" "C:\work\shapez\shapez.io\gulp\steampipe\scripts\china-linux.vdf"
"1318691" "$STEAMPIPE_DIR$\scripts\windows.vdf"
"1318694" "$STEAMPIPE_DIR$\scripts\china-windows.vdf"
"1318692" "$STEAMPIPE_DIR$\scripts\linux.vdf"
"1318695" "$STEAMPIPE_DIR$\scripts\china-linux.vdf"
}
}

View File

@ -1,7 +1,7 @@
"DepotBuildConfig"
{
"DepotID" "1318695"
"contentroot" "C:\work\shapez\shapez.io\tmp_standalone_files_china\shapez.io-standalonechina-linux-x64"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files_china\shapez.io-standalonechina-linux-x64"
"FileMapping"
{
"LocalPath" "*"

View File

@ -1,7 +1,7 @@
"DepotBuildConfig"
{
"DepotID" "1318694"
"contentroot" "C:\work\shapez\shapez.io\tmp_standalone_files_china\shapez.io-standalonechina-win32-x64"
"contentroot" "$PROJECT_DIR$\shapez.io-standalonechina-win32-x64"
"FileMapping"
{
"LocalPath" "*"

View File

@ -0,0 +1,12 @@
"DepotBuildConfig"
{
"DepotID" "1930755"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files_china\shapez.io-demochina-linux-x64"
"FileMapping"
{
"LocalPath" "*"
"DepotPath" "."
"recursive" "1"
}
"FileExclusion" "*.pdb"
}

View File

@ -0,0 +1,12 @@
"DepotBuildConfig"
{
"DepotID" "1930754"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files_china\shapez.io-demochina-win32-x64"
"FileMapping"
{
"LocalPath" "*"
"DepotPath" "."
"recursive" "1"
}
"FileExclusion" "*.pdb"
}

View File

@ -0,0 +1,12 @@
"DepotBuildConfig"
{
"DepotID" "1930752"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files\shapez.io-demo-linux-x64"
"FileMapping"
{
"LocalPath" "*"
"DepotPath" "."
"recursive" "1"
}
"FileExclusion" "*.pdb"
}

View File

@ -0,0 +1,12 @@
"DepotBuildConfig"
{
"DepotID" "1930753"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files\shapez.io-demo-win32-x64"
"FileMapping"
{
"LocalPath" "*"
"DepotPath" "."
"recursive" "1"
}
"FileExclusion" "*.pdb"
}

View File

@ -1,7 +1,7 @@
"DepotBuildConfig"
{
"DepotID" "1318692"
"contentroot" "C:\work\shapez\shapez.io\tmp_standalone_files\shapez.io-standalone-linux-x64"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files\shapez.io-standalone-linux-x64"
"FileMapping"
{
"LocalPath" "*"

View File

@ -1,7 +1,7 @@
"DepotBuildConfig"
{
"DepotID" "1318691"
"contentroot" "C:\work\shapez\shapez.io\tmp_standalone_files\shapez.io-standalone-win32-x64"
"contentroot" "$PROJECT_DIR$\tmp_standalone_files\shapez.io-standalone-win32-x64"
"FileMapping"
{
"LocalPath" "*"

View File

@ -0,0 +1,3 @@
@echo off
cmd /c yarn gulp standalone.prepareVDF
steamcmd +login %STEAM_UPLOAD_SHAPEZ_ID% %STEAM_UPLOAD_SHAPEZ_USER% +run_app_build %cd%/scripts/app-demo.vdf +quit

View File

@ -1,4 +1,3 @@
@echo off
cmd /c yarn gulp standalone.prepareVDF
steamcmd +login %STEAM_UPLOAD_SHAPEZ_ID% %STEAM_UPLOAD_SHAPEZ_USER% +run_app_build %cd%/scripts/app.vdf +quit
start https://partner.steamgames.com/apps/builds/1318690

View File

@ -3,10 +3,15 @@
const path = require("path");
const webpack = require("webpack");
const { getRevision, getVersion, getAllResourceImages } = require("./buildutils");
const lzString = require("lz-string");
const CircularDependencyPlugin = require("circular-dependency-plugin");
module.exports = ({ watch = false, standalone = false, chineseVersion = false, wegameVersion = false }) => {
module.exports = ({
watch = false,
standalone = false,
chineseVersion = false,
wegameVersion = false,
steamDemo = false,
}) => {
return {
mode: "development",
devtool: "cheap-source-map",
@ -31,16 +36,13 @@ module.exports = ({ watch = false, standalone = false, chineseVersion = false, w
"window.assert(false, 'abstract method called of: ' + (this.name || (this.constructor && this.constructor.name)));",
G_HAVE_ASSERT: "true",
G_APP_ENVIRONMENT: JSON.stringify("dev"),
G_TRACKING_ENDPOINT: JSON.stringify(
lzString.compressToEncodedURIComponent("http://localhost:10005/v1")
),
G_CHINA_VERSION: JSON.stringify(chineseVersion),
G_WEGAME_VERSION: JSON.stringify(wegameVersion),
G_IS_DEV: "true",
G_IS_RELEASE: "false",
G_IS_MOBILE_APP: "false",
G_IS_BROWSER: "true",
G_IS_STANDALONE: standalone ? "true" : "false",
G_IS_STANDALONE: JSON.stringify(standalone),
G_IS_STEAM_DEMO: JSON.stringify(steamDemo),
G_BUILD_TIME: "" + new Date().getTime(),
G_BUILD_COMMIT_HASH: JSON.stringify(getRevision()),
G_BUILD_VERSION: JSON.stringify(getVersion()),

View File

@ -3,24 +3,24 @@
const path = require("path");
const webpack = require("webpack");
const { getRevision, getVersion, getAllResourceImages } = require("./buildutils");
const lzString = require("lz-string");
const TerserPlugin = require("terser-webpack-plugin");
const StringReplacePlugin = require("string-replace-webpack-plugin");
const UnusedFilesPlugin = require("unused-files-webpack-plugin").UnusedFilesWebpackPlugin;
module.exports = ({
enableAssert = false,
environment,
es6 = false,
standalone = false,
isBrowser = true,
mobileApp = false,
chineseVersion = false,
wegameVersion = false,
steamDemo = false,
}) => {
const globalDefs = {
assert: enableAssert ? "window.assert" : "false && window.assert",
assert: "false && window.assert",
assertAlways: "window.assert",
abstract: "window.assert(false, 'abstract method called');",
G_IS_DEV: "false",
@ -29,13 +29,10 @@ module.exports = ({
G_WEGAME_VERSION: JSON.stringify(wegameVersion),
G_IS_RELEASE: environment === "prod" ? "true" : "false",
G_IS_STANDALONE: standalone ? "true" : "false",
G_IS_STEAM_DEMO: JSON.stringify(steamDemo),
G_IS_BROWSER: isBrowser ? "true" : "false",
G_IS_MOBILE_APP: mobileApp ? "true" : "false",
G_TRACKING_ENDPOINT: JSON.stringify(
lzString.compressToEncodedURIComponent("https://tracking.shapez.io/v1")
),
G_APP_ENVIRONMENT: JSON.stringify(environment),
G_HAVE_ASSERT: enableAssert ? "true" : "false",
G_HAVE_ASSERT: "false",
G_BUILD_TIME: "" + new Date().getTime(),
G_BUILD_COMMIT_HASH: JSON.stringify(getRevision()),
G_BUILD_VERSION: JSON.stringify(getVersion()),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 210 KiB

View File

@ -52,6 +52,11 @@
}
}
.playtimeDisclaimer {
@include S(margin-bottom, 10px);
@include PlainText;
}
.steamLinkButton {
@include IncreasedClickArea(5px);
@include S(margin, 0);

View File

@ -1,10 +1,16 @@
#ingame_HUD_CatMemes {
#ingame_HUD_SteamCapsule {
position: absolute;
@include S(width, 150px);
@include S(height, 150px);
background: transparent center center / contain no-repeat;
@include S(height, 119px);
background: transparent center center / cover no-repeat;
right: 0;
pointer-events: all;
overflow: hidden;
@include S(right, 10px);
border: D(2px) solid #000;
@include S(border-radius, $globalBorderRadius);
cursor: pointer;
@include S(bottom, 150px);
& {
@ -12,6 +18,10 @@
background-image: uiResource("res/ui/memes/cat1.png") !important;
}
&:hover {
opacity: 0.95;
}
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateX(100%);

View File

@ -57,7 +57,7 @@
@import "ingame_hud/shape_viewer";
@import "ingame_hud/sandbox_controller";
@import "ingame_hud/standalone_advantages";
@import "ingame_hud/cat_memes";
@import "ingame_hud/steam_capsule";
@import "ingame_hud/puzzle_back_to_menu";
@import "ingame_hud/puzzle_editor_review";
@import "ingame_hud/puzzle_dlc_logo";
@ -105,6 +105,7 @@ ingame_HUD_Waypoints_Hint,
ingame_HUD_WatermarkClicker,
ingame_HUD_Watermark,
ingame_HUD_ColorBlindBelowTileHelper,
ingame_HUD_SteamCapsule,
ingame_HUD_SandboxController,
// Overlays
@ -118,8 +119,7 @@ ingame_HUD_StandaloneAdvantages,
ingame_HUD_UnlockNotification,
ingame_HUD_PuzzleCompleteNotification,
ingame_HUD_SettingsMenu,
ingame_HUD_ModalDialogs,
ingame_HUD_CatMemes;
ingame_HUD_ModalDialogs;
$zindex: 100;
@ -132,7 +132,7 @@ $zindex: 100;
}
body.uiHidden {
> div {
> div:not(.ingameDialog):not(#ingame_HUD_SettingsMenu):not(#ingame_HUD_ModalDialogs):not(#ingame_HUD_UnlockNotification):not(#ingame_HUD_PuzzleCompleteNotification) {
display: none !important;
}
}

View File

@ -97,7 +97,7 @@
}
.standaloneBanner {
background: rgb(216, 79, 76);
background: rgba(12, 168, 93, 0.957);
@include S(border-radius, $globalBorderRadius);
box-sizing: border-box;
@include S(padding, 15px);
@ -129,8 +129,18 @@
@include S(padding-left, 20px);
li {
@include Text;
color: #fff;
}
}
strong {
margin: 0;
}
.playtimeDisclaimer {
color: #fff;
@include S(margin-top, 15px);
@include SuperSmallText;
}
.steamLink {
align-self: center;
@ -153,6 +163,12 @@
opacity: 0.9;
}
@include InlineAnimation(1s ease-in-out infinite) {
50% {
transform: scale(1.02, 1.03);
}
}
> .discount {
position: absolute;
@include S(top, -7px);
@ -186,9 +202,8 @@
img {
@include S(width, 300px);
}
position: relative;
@include S(left, -22px);
@include S(left, -8px);
.updateLabel {
position: absolute;
@ -677,25 +692,19 @@
}
.footer {
display: grid;
display: flex;
flex-grow: 1;
justify-content: center;
align-items: flex-end;
width: 100%;
grid-template-columns: auto auto auto 1fr;
@include S(padding, 10px);
box-sizing: border-box;
@include S(grid-gap, 4px);
&.noLinks {
grid-template-columns: auto 1fr;
}
&.wegameDisclaimer {
@include SuperSmallText;
display: grid;
justify-content: center;
grid-template-columns: 1fr auto 1fr;
text-align: center;
> .disclaimer {

View File

@ -47,6 +47,10 @@
align-self: end;
margin-top: auto;
&.noabout {
align-self: start;
}
@include StyleBelowWidth($layoutBreak) {
margin-top: 0;
display: grid;

View File

@ -41,7 +41,6 @@ import { ModsState } from "./states/mods";
/**
* @typedef {import("./platform/achievement_provider").AchievementProviderInterface} AchievementProviderInterface
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
* @typedef {import("./platform/sound").SoundInterface} SoundInterface
* @typedef {import("./platform/storage").StorageInterface} StorageInterface
*/
@ -118,7 +117,7 @@ export class Application {
/** @type {AnalyticsInterface} */
this.analytics = null;
/** @type {GameAnalyticsInterface} */
/** @type {ShapezGameAnalytics} */
this.gameAnalytics = null;
this.initPlatformDependentInstances();
@ -227,12 +226,10 @@ export class Application {
window.addEventListener("resize", () => this.checkResize(), true);
window.addEventListener("orientationchange", () => this.checkResize(), true);
if (!G_IS_MOBILE_APP && !IS_MOBILE) {
window.addEventListener("mousemove", this.handleMousemove.bind(this));
window.addEventListener("mouseout", this.handleMousemove.bind(this));
window.addEventListener("mouseover", this.handleMousemove.bind(this));
window.addEventListener("mouseleave", this.handleMousemove.bind(this));
}
window.addEventListener("mousemove", this.handleMousemove.bind(this));
window.addEventListener("mouseout", this.handleMousemove.bind(this));
window.addEventListener("mouseover", this.handleMousemove.bind(this));
window.addEventListener("mouseleave", this.handleMousemove.bind(this));
// Unload events
window.addEventListener("beforeunload", this.onBeforeUnload.bind(this), true);

View File

@ -17,6 +17,10 @@ export function getLogoSprite() {
return "logo_wegame.png";
}
if (G_IS_STEAM_DEMO) {
return "logo_demo.png";
}
if (G_CHINA_VERSION) {
return "logo_cn.png";
}

View File

@ -117,13 +117,7 @@ export const globalConfig = {
rendering: {},
debug: require("./config.local").default,
currentDiscount: {
amount: 50,
from: Date.parse("May 23 2022 17:00 +2:00"),
until: Date.parse("May 30 2022 23:59 +2:00"),
active: false, // computed later
},
currentDiscount: 0,
// Secret vars
info: {
@ -169,8 +163,3 @@ if (G_IS_DEV && globalConfig.debug.noArtificialDelays) {
globalConfig.warmupTimeSecondsFast = 0;
globalConfig.warmupTimeSecondsRegular = 0;
}
globalConfig.currentDiscount.active =
!G_IS_STANDALONE &&
new Date().getTime() < globalConfig.currentDiscount.until &&
new Date().getTime() > globalConfig.currentDiscount.from;

View File

@ -19,12 +19,10 @@ export function setGlobalApp(app) {
export const BUILD_OPTIONS = {
HAVE_ASSERT: G_HAVE_ASSERT,
APP_ENVIRONMENT: G_APP_ENVIRONMENT,
TRACKING_ENDPOINT: G_TRACKING_ENDPOINT,
CHINA_VERSION: G_CHINA_VERSION,
WEGAME_VERSION: G_WEGAME_VERSION,
IS_DEV: G_IS_DEV,
IS_RELEASE: G_IS_RELEASE,
IS_MOBILE_APP: G_IS_MOBILE_APP,
IS_BROWSER: G_IS_BROWSER,
IS_STANDALONE: G_IS_STANDALONE,
BUILD_TIME: G_BUILD_TIME,

View File

@ -2,7 +2,6 @@
import { Application } from "../application";
/* typehints:end */
import { ExplainedResult } from "./explained_result";
import { queryParamOptions } from "./query_parameters";
import { ReadWriteProxy } from "./read_write_proxy";
export class RestrictionManager extends ReadWriteProxy {
@ -56,13 +55,12 @@ export class RestrictionManager extends ReadWriteProxy {
* @returns {boolean}
*/
isLimitedVersion() {
if (G_IS_STANDALONE) {
// Standalone is never limited
return false;
if (G_IS_STEAM_DEMO) {
return true;
}
if (queryParamOptions.embedProvider === "gamedistribution") {
// also full version on gamedistribution
if (G_IS_STANDALONE) {
// Standalone is never limited
return false;
}

View File

@ -2,29 +2,6 @@ import { T } from "../translations";
const bigNumberSuffixTranslationKeys = ["thousands", "millions", "billions", "trillions"];
/**
* Returns if this platform is android
* @returns {boolean}
*/
export function isAndroid() {
if (!G_IS_MOBILE_APP) {
return false;
}
const platform = window.device.platform;
return platform === "Android" || platform === "amazon-fireos";
}
/**
* Returns if this platform is iOs
* @returns {boolean}
*/
export function isIos() {
if (!G_IS_MOBILE_APP) {
return false;
}
return window.device.platform === "iOS";
}
/**
* Returns a platform name
* @returns {"android" | "browser" | "ios" | "standalone" | "unknown"}
@ -34,10 +11,6 @@ export function getPlatformName() {
return "standalone";
} else if (G_IS_BROWSER) {
return "browser";
} else if (G_IS_MOBILE_APP && isAndroid()) {
return "android";
} else if (G_IS_MOBILE_APP && isIos()) {
return "ios";
}
return "unknown";
}
@ -456,7 +429,7 @@ export function isSupportedBrowser() {
// and if not iOS Chrome check
// so use the below updated condition
if (G_IS_MOBILE_APP || G_IS_STANDALONE) {
if (G_IS_STANDALONE) {
return true;
}

View File

@ -1,21 +0,0 @@
import { makeDiv } from "../../../core/utils";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const memeShowIntervalSeconds = 70 * 60;
const memeShowDuration = 5;
export class HUDCatMemes extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_CatMemes");
}
initialize() {
this.domAttach = new DynamicDomAttach(this.root, this.element);
}
update() {
const now = this.root.time.realtimeNow();
this.domAttach.update(now % memeShowIntervalSeconds > memeShowIntervalSeconds - memeShowDuration);
}
}

View File

@ -125,7 +125,11 @@ export class HUDModalDialogs extends BaseHUDPart {
dialog.buttonSignals.getStandalone.add(() => {
this.app.analytics.trackUiClick("demo_dialog_click");
window.open(THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_demo_dialog");
window.open(
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_demo_dialog" +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
});
return dialog.buttonSignals;

View File

@ -5,8 +5,6 @@ import { T } from "../../../translations";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const showIntervalSeconds = 9 * 60;
export class HUDStandaloneAdvantages extends BaseHUDPart {
createElements(parent) {
this.background = makeDiv(parent, "ingame_HUD_StandaloneAdvantages", ["ingameDialog"]);
@ -33,10 +31,11 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
</div>
<div class="lowerBar">
<div class="playtimeDisclaimer">${T.demoBanners.playtimeDisclaimer}</div>
<button class="steamLinkButton ${A_B_TESTING_LINK_TYPE}">
${
globalConfig.currentDiscount.active
? `<span class='discount'>${globalConfig.currentDiscount.amount}% off!</span>`
globalConfig.currentDiscount > 0
? `<span class='discount'>${globalConfig.currentDiscount}% off!</span>`
: ""
}
</button>
@ -46,13 +45,15 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
);
this.trackClicks(this.contentDiv.querySelector("button.steamLinkButton"), () => {
const discount = globalConfig.currentDiscount.active
? "_discount" + globalConfig.currentDiscount.amount
: "";
const discount =
globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
this.root.app.analytics.trackUiClick("standalone_advantage_visit_steam");
this.root.app.platformWrapper.openExternalLink(
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_std_advg" + discount
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_std_advg" +
discount +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
this.close();
});
@ -62,6 +63,22 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
});
}
get showIntervalSeconds() {
switch (this.root.app.gameAnalytics.abtVariant) {
case "0":
return 5 * 60;
case "1":
return 10 * 60;
case "2":
default:
return 15 * 60;
case "3":
return 20 * 60;
case "4":
return 1e14;
}
}
initialize() {
this.domAttach = new DynamicDomAttach(this.root, this.background, {
attachClass: "visible",
@ -86,7 +103,7 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
}
update() {
if (!this.visible && this.root.time.now() - this.lastShown > showIntervalSeconds) {
if (!this.visible && this.root.time.now() - this.lastShown > this.showIntervalSeconds) {
this.show();
}

View File

@ -0,0 +1,31 @@
import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
import { makeDiv } from "../../../core/utils";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const showCapsuleAfter = 30 * 60;
export class HUDSteamCapsule extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_SteamCapsule");
}
initialize() {
const discount = globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
this.domAttach = new DynamicDomAttach(this.root, this.element);
this.trackClicks(this.element, () => {
this.root.app.platformWrapper.openExternalLink(
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_steamcapsule" +
discount +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
});
}
update() {
this.domAttach.update(this.root.time.now() > showCapsuleAfter);
}
}

View File

@ -75,7 +75,7 @@ export class HUDUnlockNotification extends BaseHUDPart {
<div class="rewardName">
${T.ingame.levelCompleteNotification.unlockText.replace("<reward>", rewardName)}
</div>
<div class="rewardDesc">
${T.storyRewards[reward].desc}
</div>
@ -131,6 +131,13 @@ export class HUDUnlockNotification extends BaseHUDPart {
this.root.hud.signals.unlockNotificationFinished.dispatch();
if (
this.root.hubGoals.level === 7 &&
this.root.app.restrictionMgr.getIsStandaloneMarketingActive()
) {
this.root.hud.parts.standaloneAdvantages.show();
}
if (!this.root.app.settings.getAllSettings().offerHints) {
return;
}

View File

@ -2,66 +2,35 @@ import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const watermarkShowIntervalSeconds = G_IS_DEV ? 120 : 7 * 60;
const watermarkShowDuration = 5;
export class HUDWatermark extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(
parent,
"ingame_HUD_Watermark",
[],
`
<strong>${T.ingame.watermark.title}</strong>
<p>${T.ingame.watermark.desc}
</p>
`
);
this.linkElement = makeDiv(
parent,
"ingame_HUD_WatermarkClicker",
globalConfig.currentDiscount.active ? ["withDiscount"] : [],
globalConfig.currentDiscount > 0 ? ["withDiscount"] : [],
T.ingame.watermark.get_on_steam +
(globalConfig.currentDiscount.active
? `<span class='discount'>${globalConfig.currentDiscount.amount}% off!</span>`
(globalConfig.currentDiscount > 0
? `<span class='discount'>${globalConfig.currentDiscount}% off!</span>`
: "")
);
this.trackClicks(this.linkElement, () => {
this.root.app.analytics.trackUiClick("watermark_click_2_direct");
const discount = globalConfig.currentDiscount.active
? "_discount" + globalConfig.currentDiscount.amount
: "";
const discount =
globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
this.root.app.platformWrapper.openExternalLink(
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_watermark" + discount
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_watermark" +
discount +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
});
}
initialize() {
this.trackClicks(this.element, this.onWatermarkClick);
initialize() {}
this.domAttach = new DynamicDomAttach(this.root, this.element, {
attachClass: "visible",
timeToKeepSeconds: 0.5,
});
}
update() {
this.domAttach.update(
this.root.time.realtimeNow() % watermarkShowIntervalSeconds < watermarkShowDuration
);
}
onWatermarkClick() {
this.root.app.analytics.trackUiClick("watermark_click_2_new");
this.root.hud.parts.standaloneAdvantages.show();
}
update() {}
/**
*
@ -70,7 +39,7 @@ export class HUDWatermark extends BaseHUDPart {
drawOverlays(parameters) {
const w = this.root.gameWidth;
parameters.context.fillStyle = "rgba(230, 230, 230, 0.9)";
parameters.context.fillStyle = "rgba(20, 30, 40, 0.25)";
parameters.context.font = "bold " + this.root.app.getEffectiveUiScale() * 40 + "px GameFont";
parameters.context.textAlign = "center";
parameters.context.fillText(

View File

@ -31,11 +31,9 @@ import { IS_MOBILE } from "../../core/config";
import { HUDKeybindingOverlay } from "../hud/parts/keybinding_overlay";
import { HUDWatermark } from "../hud/parts/watermark";
import { HUDStandaloneAdvantages } from "../hud/parts/standalone_advantages";
import { HUDCatMemes } from "../hud/parts/cat_memes";
import { HUDSteamCapsule } from "../hud/parts/steam_capsule";
import { HUDPartTutorialHints } from "../hud/parts/tutorial_hints";
import { HUDInteractiveTutorial } from "../hud/parts/interactive_tutorial";
import { HUDSandboxController } from "../hud/parts/sandbox_controller";
import { queryParamOptions } from "../../core/query_parameters";
import { MetaBlockBuilding } from "../buildings/block";
import { MetaItemProducerBuilding } from "../buildings/item_producer";
import { MOD_SIGNALS } from "../../mods/mod_signals";
@ -584,7 +582,7 @@ export class RegularGameMode extends GameMode {
if (this.root.app.restrictionMgr.getIsStandaloneMarketingActive()) {
this.additionalHudParts.watermark = HUDWatermark;
this.additionalHudParts.standaloneAdvantages = HUDStandaloneAdvantages;
this.additionalHudParts.catMemes = HUDCatMemes;
this.additionalHudParts.catMemes = HUDSteamCapsule;
}
if (this.root.app.settings.getAllSettings().offerHints) {

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

@ -10,11 +10,10 @@ declare const G_APP_ENVIRONMENT: string;
declare const G_HAVE_ASSERT: boolean;
declare const G_BUILD_TIME: number;
declare const G_IS_STANDALONE: boolean;
declare const G_IS_STEAM_DEMO: boolean;
declare const G_IS_BROWSER: boolean;
declare const G_IS_MOBILE_APP: boolean;
declare const G_BUILD_COMMIT_HASH: string;
declare const G_TRACKING_ENDPOINT: string;
declare const G_BUILD_VERSION: string;
declare const G_ALL_UI_IMAGES: Array<string>;
declare const G_IS_RELEASE: boolean;

View File

@ -105,6 +105,10 @@ export class ModLoader {
}
exposeExports() {
if (G_IS_STEAM_DEMO) {
return;
}
if (G_IS_DEV || G_IS_STANDALONE) {
let exports = {};
const modules = require.context("../", true, /\.js$/);
@ -136,6 +140,11 @@ export class ModLoader {
}
async initMods() {
if (G_IS_STEAM_DEMO) {
this.initialized = true;
return;
}
if (!G_IS_STANDALONE && !G_IS_DEV) {
this.initialized = true;
return;

View File

@ -1,5 +1,6 @@
import { globalConfig } from "../../core/config";
import { createLogger } from "../../core/logging";
import { randomInt } from "../../core/utils";
import { BeltComponent } from "../../game/components/belt";
import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
import { RegularGameMode } from "../../game/modes/regular";
@ -13,16 +14,26 @@ const logger = createLogger("game_analytics");
const analyticsUrl = G_IS_DEV ? "http://localhost:8001" : "https://analytics.shapez.io";
// Be sure to increment the ID whenever it changes to make sure all
// users are tracked
const analyticsLocalFile = "shapez_token_123.bin";
// Be sure to increment the ID whenever it changes
const analyticsLocalFile = G_IS_STEAM_DEMO ? "shapez_token_steamdemo.bin" : "shapez_token_123.bin";
const currentABT = "abt_sa_si";
export class ShapezGameAnalytics extends GameAnalyticsInterface {
constructor(app) {
super(app);
this.abtVariant = "0";
}
get environment() {
if (G_IS_DEV) {
return "dev";
}
if (G_IS_STEAM_DEMO) {
return "steam-demo";
}
if (G_IS_STANDALONE) {
return "steam";
}
@ -38,6 +49,22 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
}
}
fetchABVariant() {
return this.app.storage.readFileAsync("shapez_" + currentABT + ".bin").then(
abt => {
this.abtVariant = abt;
logger.log("Got abtVariant:", abt);
},
err => {
if (err === FILE_NOT_FOUND) {
this.abtVariant = String(randomInt(0, 4));
logger.log("Determing abt variant to", this.abtVariant);
this.app.storage.writeFileAsync("shapez_" + currentABT + ".bin", this.abtVariant);
}
}
);
}
/**
* @returns {Promise<void>}
*/
@ -48,46 +75,68 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
return;
}
setInterval(() => this.sendTimePoints(), 60 * 1000);
// Retrieve sync key from player
return this.app.storage.readFileAsync(analyticsLocalFile).then(
syncKey => {
this.syncKey = syncKey;
logger.log("Player sync key read:", this.syncKey);
},
error => {
// File was not found, retrieve new key
if (error === FILE_NOT_FOUND) {
logger.log("Retrieving new player key");
return this.fetchABVariant().then(() => {
setInterval(() => this.sendTimePoints(), 60 * 1000);
// Perform call to get a new key from the API
this.sendToApi("/v1/register", {
environment: this.environment,
standalone:
G_IS_STANDALONE &&
this.app.achievementProvider instanceof SteamAchievementProvider,
commit: G_BUILD_COMMIT_HASH,
})
.then(res => {
// Try to read and parse the key from the api
if (res.key && typeof res.key === "string" && res.key.length === 40) {
this.syncKey = res.key;
logger.log("Key retrieved:", this.syncKey);
this.app.storage.writeFileAsync(analyticsLocalFile, res.key);
} else {
throw new Error("Bad response from analytics server: " + res);
}
})
.catch(err => {
logger.error("Failed to register on analytics api:", err);
});
} else {
logger.error("Failed to read ga key:", error);
}
return;
if (this.app.restrictionMgr.isLimitedVersion()) {
fetch(
analyticsUrl +
"/track/shapez_launch_" +
this.environment +
"_" +
currentABT +
"_" +
this.abtVariant,
{
method: "GET",
mode: "no-cors",
cache: "no-cache",
referrer: "no-referrer",
credentials: "omit",
}
).catch(err => {});
}
);
return this.app.storage.readFileAsync(analyticsLocalFile).then(
syncKey => {
this.syncKey = syncKey;
logger.log("Player sync key read:", this.syncKey);
},
error => {
// File was not found, retrieve new key
if (error === FILE_NOT_FOUND) {
logger.log("Retrieving new player key");
// Perform call to get a new key from the API
this.sendToApi("/v1/register", {
environment: this.environment,
standalone:
G_IS_STANDALONE &&
!G_IS_STEAM_DEMO &&
this.app.achievementProvider instanceof SteamAchievementProvider,
commit: G_BUILD_COMMIT_HASH,
})
.then(res => {
// Try to read and parse the key from the api
if (res.key && typeof res.key === "string" && res.key.length === 40) {
this.syncKey = res.key;
logger.log("Key retrieved:", this.syncKey);
this.app.storage.writeFileAsync(analyticsLocalFile, res.key);
} else {
throw new Error("Bad response from analytics server: " + res);
}
})
.catch(err => {
logger.error("Failed to register on analytics api:", err);
});
} else {
logger.error("Failed to read ga key:", error);
}
return;
}
);
});
}
/**

View File

@ -1,7 +0,0 @@
import { GameAnalyticsInterface } from "../game_analytics";
export class NoGameAnalytics extends GameAnalyticsInterface {
initialize() {
return Promise.resolve();
}
}

View File

@ -189,7 +189,7 @@ function initializeSettings() {
},
/**
* @param {Application} app
*/ app => app.restrictionMgr.getHasExtendedSettings()
*/ app => G_IS_STANDALONE
),
new BoolSetting(
@ -514,7 +514,7 @@ export class ApplicationSettings extends ReadWriteProxy {
const settings = data.settings;
// MODS
if (!THEMES[settings.theme]) {
if (!THEMES[settings.theme] || !this.app.restrictionMgr.getHasExtendedSettings()) {
console.warn("Resetting theme because its no longer available: " + settings.theme);
settings.theme = "light";
}
@ -700,7 +700,7 @@ export class ApplicationSettings extends ReadWriteProxy {
}
// MODS
if (!THEMES[data.settings.theme]) {
if (!THEMES[data.settings.theme] || !this.app.restrictionMgr.getHasExtendedSettings()) {
console.warn("Resetting theme because its no longer available: " + data.settings.theme);
data.settings.theme = "light";
}

View File

@ -38,9 +38,8 @@ export class MainMenuState extends GameState {
getInnerHTML() {
const showLanguageIcon = !G_CHINA_VERSION && !G_WEGAME_VERSION;
const showExitAppButton = G_IS_STANDALONE;
const showUpdateLabel = !G_WEGAME_VERSION;
const showBrowserWarning = !G_IS_STANDALONE && !isSupportedBrowser();
const showPuzzleDLC = !G_WEGAME_VERSION && G_IS_STANDALONE;
const showPuzzleDLC = !G_WEGAME_VERSION && G_IS_STANDALONE && !G_IS_STEAM_DEMO;
const showWegameFooter = G_WEGAME_VERSION;
const hasMods = MODS.anyModsActive();
@ -69,15 +68,17 @@ export class MainMenuState extends GameState {
const ownsPuzzleDLC =
G_IS_DEV ||
(G_IS_STANDALONE &&
!G_IS_STEAM_DEMO &&
/** @type { PlatformWrapperImplElectron}*/ (this.app.platformWrapper).dlcs.puzzle);
const bannerHtml = `
<h3>${T.demoBanners.title}</h3>
<p>${T.demoBanners.intro}</p>
<span class="playtimeDisclaimer">${T.demoBanners.playtimeDisclaimer}</span>
<a href="#" class="steamLink ${A_B_TESTING_LINK_TYPE}" target="_blank">
${
globalConfig.currentDiscount.active
? `<span class='discount'>${globalConfig.currentDiscount.amount}% off!</span>`
globalConfig.currentDiscount > 0
? `<span class='discount'>${globalConfig.currentDiscount}% off!</span>`
: ""
}
@ -201,7 +202,7 @@ export class MainMenuState extends GameState {
<div class="footer ${showExternalLinks ? "" : "noLinks"} ">
${
showExternalLinks
showExternalLinks && !G_IS_STEAM_DEMO
? `
<a class="githubLink boxLink" target="_blank">
${T.mainMenu.openSourceHint}
@ -453,11 +454,12 @@ export class MainMenuState extends GameState {
onSteamLinkClicked() {
this.app.analytics.trackUiClick("main_menu_steam_link_" + A_B_TESTING_LINK_TYPE);
const discount = globalConfig.currentDiscount.active
? "_discount" + globalConfig.currentDiscount.amount
: "";
const discount = globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
this.app.platformWrapper.openExternalLink(
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_mainmenu" + discount
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_mainmenu" +
discount +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
return false;
@ -743,7 +745,9 @@ export class MainMenuState extends GameState {
getStandalone.add(() => {
this.app.analytics.trackUiClick("visit_steampage_from_slot_limit");
this.app.platformWrapper.openExternalLink(
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_slotlimit"
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_slotlimit" +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
});
}

View File

@ -3,6 +3,8 @@ import { TextualGameState } from "../core/textual_game_state";
import { MODS } from "../mods/modloader";
import { T } from "../translations";
const MODS_SUPPORTED = !G_IS_STEAM_DEMO && (G_IS_STANDALONE || G_IS_DEV);
export class ModsState extends TextualGameState {
constructor() {
super("ModsState");
@ -19,12 +21,12 @@ export class ModsState extends TextualGameState {
<div class="actions">
${
(G_IS_STANDALONE || G_IS_DEV) && MODS.mods.length > 0
MODS_SUPPORTED && MODS.mods.length > 0
? `<button class="styledButton browseMods">${T.mods.browseMods}</button>`
: ""
}
${
G_IS_STANDALONE || G_IS_DEV
MODS_SUPPORTED
? `<button class="styledButton openModsFolder">${T.mods.openFolder}</button>`
: ""
}
@ -41,7 +43,7 @@ export class ModsState extends TextualGameState {
}
getMainContentHTML() {
if (!G_IS_STANDALONE && !G_IS_DEV) {
if (!MODS_SUPPORTED) {
return `
<div class="noModSupport">
@ -137,7 +139,9 @@ export class ModsState extends TextualGameState {
onSteamLinkClicked() {
this.app.analytics.trackUiClick("mods_steam_link");
this.app.platformWrapper.openExternalLink(
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_modsettings"
THIRDPARTY_URLS.stanaloneCampaignLink +
"/shapez_modsettings" +
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
);
return false;

View File

@ -61,6 +61,26 @@ export class PreloadState extends GameState {
this.startLoading();
}
async fetchDiscounts() {
await Promise.race([
new Promise((resolve, reject) => {
setTimeout(() => {
reject("Failed to resolve steam discounts within timeout");
}, 2000);
}),
fetch("https://analytics.shapez.io/v1/discounts")
.then(res => res.json())
.then(data => {
globalConfig.currentDiscount = Number(
data["1318690"].data.price_overview.discount_percent
);
logger.log("Fetched current discount:", globalConfig.currentDiscount);
}),
]).catch(err => {
logger.warn("Failed to fetch current discount:", err);
});
}
onLeave() {
// this.dialogs.cleanup();
}
@ -101,6 +121,9 @@ export class PreloadState extends GameState {
.then(() => this.app.analytics.initialize())
.then(() => this.app.gameAnalytics.initialize())
.then(() => this.setStatus("Connecting to api"))
.then(() => this.fetchDiscounts())
.then(() => this.setStatus("Initializing settings"))
.then(() => {
return this.app.settings.initialize();

View File

@ -36,13 +36,11 @@ export class SettingsState extends TextualGameState {
: `
<button class="styledButton categoryButton manageMods">${T.mods.title}
<span class="newBadge">${T.settings.newBadge}</span>
</button>
`
</button>`
}
<div class="other">
<div class="other ${G_CHINA_VERSION || G_WEGAME_VERSION ? "noabout" : ""}">
${
G_CHINA_VERSION || G_WEGAME_VERSION

View File

@ -22,7 +22,7 @@
---
steamPage:
# This is the short text appearing on the steam page
shortText: shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map.
shortText: shapez is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map.
# This is the text shown above the Discord link
discordLinkShort: Official Discord
@ -30,18 +30,18 @@ steamPage:
intro: >-
Do you like automation games? Then you are in the right place!
shapez.io is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
shapez is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! While you only have to process shapes at the beginning, you will later have to color them - by extracting and mixing colors!
Buying the game on Steam gives you access to the full version, but you can also play a demo at shapez.io first and decide later!
Buying the game on Steam gives you access to the full version, but you can also play a demo at shapez first and decide later!
what_others_say: What people say about shapez.io
what_others_say: What people say about shapez
nothernlion_comment: >-
This game is great - I'm having a wonderful time playing, and time has flown by.
notch_comment: >-
Oh crap. I really should sleep, but I think I just figured out how to make a computer in shapez.io
Oh crap. I really should sleep, but I think I just figured out how to make a computer in shapez
steam_review_comment: >-
This game has stolen my life and I don't want it back. Very chill factory game that won't let me stop making my lines more efficient.
@ -94,9 +94,18 @@ global:
demoBanners:
# This is the "advertisement" shown in the main menu and other various places
title: Demo Version
title: Demo
intro: >-
Get the full game to unlock all features and content!
Get the full game <strong>now</strong> to unlock:<ul>
<li>All 26 levels + infinite Freeplay</li>
<li>22 new buildings</li>
<li>Mod support</li>
<li>Achievements</li>
<li>Dark Mode</li>
<li>... and a lot more!</li>
</ul>
playtimeDisclaimer: >-
The full version contains more than <strong>24 hours of content</strong>.
mainMenu:
play: Play
@ -141,7 +150,7 @@ puzzleMenu:
validatingPuzzle: Validating Puzzle
submittingPuzzle: Submitting Puzzle
noPuzzles: There are currently no puzzles in this section.
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking shapez.io in your library, selecting Properties > DLCs.
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking shapez in your library, selecting Properties > DLCs.
categories:
levels: Levels
@ -654,7 +663,7 @@ ingame:
support:
title: Support me
desc: I develop the game in my spare time!
desc: I develop shapez in my spare time!
# puzzle mode
puzzleEditorSettings:
@ -1111,7 +1120,7 @@ mods:
modsInfo: >-
To install and manage mods, copy them to the mods folder (use the 'Open Mods Folder' button). Be sure to restart the game afterwards, otherwise the mods will not show up.
noModSupport: You need the full version on Steam to install mods.
noModSupport: Get the full version on Steam to install mods!
togglingComingSoon:
title: Coming Soon
@ -1427,7 +1436,7 @@ about:
body: >-
This game is open source and developed by <a href="https://github.com/tobspr" target="_blank">Tobias Springer</a> (this is me).<br><br>
If you want to contribute, check out <a href="<githublink>" target="_blank">shapez.io on GitHub</a>.<br><br>
If you want to contribute, check out <a href="<githublink>" target="_blank">shapez on GitHub</a>.<br><br>
This game wouldn't have been possible without the great Discord community around my games - You should really join the <a href="<discordlink>" target="_blank">Discord server</a>!<br><br>