1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-12 09:41:51 +00:00

Merge branch 'master' of https://github.com/tobspr/shapez.io into arrays-now-sets

This commit is contained in:
dgs4349 2020-09-27 10:22:42 -04:00
commit 7bbc72cc7f
347 changed files with 32783 additions and 30691 deletions

View File

@ -64,7 +64,7 @@ This project is based on ES5. Some ES2015 features are used but most of them are
5. Add a constructor. **The constructor must be called with optional parameters only!** `new MyFancyComponent({})` should always work. 5. Add a constructor. **The constructor must be called with optional parameters only!** `new MyFancyComponent({})` should always work.
6. Add any props you need in the constructor. 6. Add any props you need in the constructor.
7. Add the component in `src/js/game/component_registry.js` 7. Add the component in `src/js/game/component_registry.js`
8. Add the componetn in `src/js/game/entity_components.js` 8. Add the component in `src/js/game/entity_components.js`
9. Done! You can use your component now 9. Done! You can use your component now
#### Adding a new building #### Adding a new building
@ -81,7 +81,7 @@ This project is based on ES5. Some ES2015 features are used but most of them are
8. In `translations/base-en.yaml` add it to two sections: `buildings.[my_building].XXX` (See other buildings) and also `keybindings.mappings.[my_building]`. Be sure to do it the same way as other buildings do! 8. In `translations/base-en.yaml` add it to two sections: `buildings.[my_building].XXX` (See other buildings) and also `keybindings.mappings.[my_building]`. Be sure to do it the same way as other buildings do!
9. Create a icon (128x128, [prefab](https://github.com/tobspr/shapez.io-artwork/blob/master/ui/toolbar-icons.psd)) for your building and save it in `res/ui/buildings_icons` with the id of your building 9. Create a icon (128x128, [prefab](https://github.com/tobspr/shapez.io-artwork/blob/master/ui/toolbar-icons.psd)) for your building and save it in `res/ui/buildings_icons` with the id of your building
10. Create a tutorial image (600x600) for your building and save it in `res/ui/building_tutorials` 10. Create a tutorial image (600x600) for your building and save it in `res/ui/building_tutorials`
11. In `src/css/icons.scss` add your building to `$buildings` as well as `$buildingAndVariants` 11. In `src/css/resources.scss` add your building to `$buildings` as well as `$buildingAndVariants`
12. Done! Optional: Add a new reward for unlocking your building at some point. 12. Done! Optional: Add a new reward for unlocking your building at some point.
#### Adding a new game system #### Adding a new game system
@ -92,10 +92,32 @@ This project is based on ES5. Some ES2015 features are used but most of them are
4. Add the system in `src/js/game/game_system_manager.js` (To `this.systems` and also call `add` in the `internalInitSystems()` method) 4. Add the system in `src/js/game/game_system_manager.js` (To `this.systems` and also call `add` in the `internalInitSystems()` method)
5. If your system should draw stuff, this is a bit more complicated. Have a look at existing systems on how they do it. 5. If your system should draw stuff, this is a bit more complicated. Have a look at existing systems on how they do it.
#### Checklist for a new building / testing it
This is a quick checklist, if a new building is added this points should be fulfilled:
2. The translation for all variants is done and finalized
3. The artwork (regular sprite) is finalized
4. The blueprint sprite has been generated and is up to date
5. The building has been added to the appropriate toolbar
6. The building has a keybinding which makes sense
7. The building has a reward assigned and is unlocked at a meaningful point
8. The reward for the building has a proper translation
9. The reward for the building has a proper image
10. The building has a proper tutorial image assigned
11. The buliding has a proper toolbar icon
12. The reward requires a proper shape
13. The building has a proper silhouette color
14. The building has a proper matrix for being rendered on the minimap
15. The building has proper statistics in the dialog
16. The building properly contributes to the shapes produced analytics
17. The building is properly persisted in the savegame
18. The building is explained properly, ideally via an interactive tutorial
### Assets ### Assets
For most assets I use Adobe Photoshop, you can find them in `assets/`. For most assets I use Adobe Photoshop, you can find them in `assets/`.
You will need a <a href="https://www.codeandweb.com/texturepacker" target="_blank">Texture Packer</a> license in order to regenerate the atlas. If you don't have one but want to contribute assets, let me know and I might compile it for you. I'm currently switching to an open source solution but I can't give an estimate when thats done. You will need a <a href="https://www.codeandweb.com/texturepacker" target="_blank">Texture Packer</a> license in order to regenerate the atlas. If you don't have one but want to contribute assets, let me know and I might compile it for you. I'm currently switching to an open source solution but I can't give an estimate when that's done.
<img src="https://i.imgur.com/W25Fkl0.png" alt="shapez.io Screenshot"> <img src="https://i.imgur.com/W25Fkl0.png" alt="shapez.io Screenshot">

View File

@ -1,96 +0,0 @@
// Converts the atlas description to a JSON file
String.prototype.replaceAll = function (search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
const fs = require("fs");
const path = require("path");
const folder = path.join(__dirname, "res_built", "atlas");
const files = fs.readdirSync(folder);
const metadata = [];
files.forEach(filename => {
if (filename.endsWith(".atlas")) {
// Read content
const content = fs.readFileSync(path.join(folder, filename), "ascii");
const lines = content.replaceAll("\r", "").replaceAll("\t", "").split("\n");
const readLine = () => lines.splice(0, 1)[0];
const readValue = () => readLine().replaceAll(" ", "").split(":")[1];
const readVector = () =>
readValue()
.split(",")
.map(d => parseInt(d, 10));
let maxAtlas = 100;
atlasLoop: while (maxAtlas-- > 0 && lines.length >= 7) {
const result = {
entries: [],
};
// Extract header
const header_fileStart = readLine();
const header_fileName = readLine();
const header_size = readVector();
const header_format = readLine();
const header_filter = readLine();
const header_repeat = readLine();
const baseAtlasName = header_fileName.replace(".png", "");
// Store size
result.size = header_size;
lineLoop: while (lines.length >= 7) {
const entryResult = {};
const nextLine = lines[0];
if (nextLine.length === 0) {
break;
}
const entry_fileName = readLine() + ".png";
const entry_rotate = readValue();
const entry_xy = readVector();
const entry_size = readVector();
const entry_orig = readVector();
const entry_offset = readVector();
const entry_index = readValue();
entryResult.filename = entry_fileName;
entryResult.xy = entry_xy;
entryResult.size = entry_size;
// entryResult.offset = entry_offset;
entryResult.origSize = entry_orig;
let offset = [0, 0];
// GDX Atlas packer uses 1 - y coordinates. This sucks, and we have to convert it
offset[0] = entry_offset[0];
offset[1] = entry_orig[1] - entry_offset[1] - entry_size[1];
entryResult.offset = offset;
result.entries.push(entryResult);
}
console.log("[Atlas]", "'" + baseAtlasName + "'", "has", result.entries.length, "entries");
// fs.writeFileSync(path.join(folder, baseAtlasName + ".gen.json"), JSON.stringify(result));
metadata.push({
filename: baseAtlasName + ".png",
entries: result,
});
}
}
});
fs.writeFileSync(path.join(folder, "meta.gen.json"), JSON.stringify(metadata, null, 4));

View File

@ -1,99 +1,137 @@
const path = require("path"); const path = require("path");
const buildUtils = require("./buildutils"); const buildUtils = require("./buildutils");
function gulptasksCSS($, gulp, buildFolder, browserSync) { function gulptasksCSS($, gulp, buildFolder, browserSync) {
// The assets plugin copies the files // The assets plugin copies the files
const commitHash = buildUtils.getRevision(); const commitHash = buildUtils.getRevision();
const postcssAssetsPlugin = cachebust => const postcssAssetsPlugin = cachebust =>
$.postcssAssets({ $.postcssAssets({
loadPaths: [path.join(buildFolder, "res", "ui")], loadPaths: [path.join(buildFolder, "res", "ui")],
basePath: buildFolder, basePath: buildFolder,
baseUrl: ".", baseUrl: ".",
cachebuster: cachebust cachebuster: cachebust
? (filePath, urlPathname) => ({ ? (filePath, urlPathname) => ({
pathname: buildUtils.cachebust(urlPathname, commitHash), pathname: buildUtils.cachebust(urlPathname, commitHash),
}) })
: "", : "",
}); });
// Postcss configuration // Postcss configuration
const postcssPlugins = (prod, { cachebust = false }) => { const postcssPlugins = (prod, { cachebust = false }) => {
const plugins = [postcssAssetsPlugin(cachebust)]; const plugins = [postcssAssetsPlugin(cachebust)];
if (prod) { if (prod) {
plugins.unshift( plugins.unshift(
$.postcssUnprefix(), $.postcssUnprefix(),
$.postcssPresetEnv({ $.postcssPresetEnv({
browsers: ["> 0.1%"], browsers: ["> 0.1%"],
}) })
); );
plugins.push( plugins.push(
$.cssMqpacker({ $.cssMqpacker({
sort: true, sort: true,
}), }),
$.cssnano({ $.cssnano({
preset: [ preset: [
"advanced", "advanced",
{ {
cssDeclarationSorter: false, cssDeclarationSorter: false,
discardUnused: true, discardUnused: true,
mergeIdents: false, mergeIdents: false,
reduceIdents: true, reduceIdents: true,
zindex: true, zindex: true,
}, },
], ],
}), }),
$.postcssRoundSubpixels() $.postcssRoundSubpixels()
); );
} }
return plugins; return plugins;
}; };
// Performs linting on css // Performs linting on css
gulp.task("css.lint", () => { gulp.task("css.lint", () => {
return gulp return gulp
.src(["../src/css/**/*.scss"]) .src(["../src/css/**/*.scss"])
.pipe($.sassLint({ configFile: ".sasslint.yml" })) .pipe($.sassLint({ configFile: ".sasslint.yml" }))
.pipe($.sassLint.format()) .pipe($.sassLint.format())
.pipe($.sassLint.failOnError()); .pipe($.sassLint.failOnError());
}); });
// Builds the css in dev mode function resourcesTask({ cachebust, isProd }) {
gulp.task("css.dev", () => { return gulp
return gulp .src("../src/css/main.scss", { cwd: __dirname })
.src(["../src/css/main.scss"]) .pipe($.plumber())
.pipe($.plumber()) .pipe($.sass.sync().on("error", $.sass.logError))
.pipe($.sass.sync().on("error", $.sass.logError)) .pipe(
.pipe($.postcss(postcssPlugins(false, {}))) $.postcss([
.pipe(gulp.dest(buildFolder)) $.postcssCriticalSplit({
.pipe(browserSync.stream()); blockTag: "@load-async",
}); }),
])
// Builds the css in production mode (=minified) )
gulp.task("css.prod", () => { .pipe($.rename("async-resources.css"))
return ( .pipe($.postcss(postcssPlugins(isProd, { cachebust })))
gulp .pipe(gulp.dest(buildFolder))
.src("../src/css/main.scss", { cwd: __dirname }) .pipe(browserSync.stream());
.pipe($.plumber()) }
.pipe($.sass.sync({ outputStyle: "compressed" }).on("error", $.sass.logError))
.pipe($.postcss(postcssPlugins(true, { cachebust: true }))) // Builds the css resources
.pipe(gulp.dest(buildFolder)) gulp.task("css.resources.dev", () => {
); return resourcesTask({ cachebust: false, isProd: false });
}); });
// Builds the css in production mode (=minified), without cachebusting // Builds the css resources in prod (=minified)
gulp.task("css.prod-standalone", () => { gulp.task("css.resources.prod", () => {
return ( return resourcesTask({ cachebust: true, isProd: true });
gulp });
.src("../src/css/main.scss", { cwd: __dirname })
.pipe($.plumber()) // Builds the css resources in prod (=minified), without cachebusting
.pipe($.sass.sync({ outputStyle: "compressed" }).on("error", $.sass.logError)) gulp.task("css.resources.prod-standalone", () => {
.pipe($.postcss(postcssPlugins(true, { cachebust: false }))) return resourcesTask({ cachebust: false, isProd: true });
.pipe(gulp.dest(buildFolder)) });
);
}); function mainTask({ cachebust, isProd }) {
} return gulp
.src("../src/css/main.scss", { cwd: __dirname })
module.exports = { .pipe($.plumber())
gulptasksCSS, .pipe($.sass.sync().on("error", $.sass.logError))
}; .pipe(
$.postcss([
$.postcssCriticalSplit({
blockTag: "@load-async",
output: "rest",
}),
])
)
.pipe($.postcss(postcssPlugins(isProd, { cachebust })))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
}
// Builds the css main
gulp.task("css.main.dev", () => {
return mainTask({ cachebust: false, isProd: false });
});
// Builds the css main in prod (=minified)
gulp.task("css.main.prod", () => {
return mainTask({ cachebust: true, isProd: true });
});
// Builds the css main in prod (=minified), without cachebusting
gulp.task("css.main.prod-standalone", () => {
return mainTask({ cachebust: false, isProd: true });
});
gulp.task("css.dev", gulp.parallel("css.main.dev", "css.resources.dev"));
gulp.task("css.prod", gulp.parallel("css.main.prod", "css.resources.prod"));
gulp.task(
"css.prod-standalone",
gulp.parallel("css.main.prod-standalone", "css.resources.prod-standalone")
);
}
module.exports = {
gulptasksCSS,
};

View File

@ -1,325 +1,325 @@
/* eslint-disable */ /* eslint-disable */
require("colors"); require("colors");
const gulp = require("gulp"); const gulp = require("gulp");
const browserSync = require("browser-sync").create({}); const browserSync = require("browser-sync").create({});
const path = require("path"); const path = require("path");
const deleteEmpty = require("delete-empty"); const deleteEmpty = require("delete-empty");
const execSync = require("child_process").execSync; const execSync = require("child_process").execSync;
const lfsOutput = execSync("git lfs install", { encoding: "utf-8" }); const lfsOutput = execSync("git lfs install", { encoding: "utf-8" });
if (!lfsOutput.toLowerCase().includes("git lfs initialized")) { if (!lfsOutput.toLowerCase().includes("git lfs initialized")) {
console.error(` console.error(`
Git LFS is not installed, unable to build. Git LFS is not installed, unable to build.
To install Git LFS on Linux: To install Git LFS on Linux:
- Arch: - Arch:
sudo pacman -S git-lfs sudo pacman -S git-lfs
- Debian/Ubuntu: - Debian/Ubuntu:
sudo apt install git-lfs sudo apt install git-lfs
For other systems, see: For other systems, see:
https://github.com/git-lfs/git-lfs/wiki/Installation https://github.com/git-lfs/git-lfs/wiki/Installation
`); `);
process.exit(1); process.exit(1);
} }
// Load other plugins dynamically // Load other plugins dynamically
const $ = require("gulp-load-plugins")({ const $ = require("gulp-load-plugins")({
scope: ["devDependencies"], scope: ["devDependencies"],
pattern: "*", pattern: "*",
}); });
// Check environment variables // Check environment variables
const envVars = [ const envVars = [
"SHAPEZ_CLI_SERVER_HOST", "SHAPEZ_CLI_SERVER_HOST",
// "SHAPEZ_CLI_PHONEGAP_KEY", // "SHAPEZ_CLI_PHONEGAP_KEY",
"SHAPEZ_CLI_ALPHA_FTP_USER", "SHAPEZ_CLI_ALPHA_FTP_USER",
"SHAPEZ_CLI_ALPHA_FTP_PW", "SHAPEZ_CLI_ALPHA_FTP_PW",
"SHAPEZ_CLI_STAGING_FTP_USER", "SHAPEZ_CLI_STAGING_FTP_USER",
"SHAPEZ_CLI_STAGING_FTP_PW", "SHAPEZ_CLI_STAGING_FTP_PW",
"SHAPEZ_CLI_LIVE_FTP_USER", "SHAPEZ_CLI_LIVE_FTP_USER",
"SHAPEZ_CLI_LIVE_FTP_PW", "SHAPEZ_CLI_LIVE_FTP_PW",
]; ];
for (let i = 0; i < envVars.length; ++i) { for (let i = 0; i < envVars.length; ++i) {
if (!process.env[envVars[i]]) { if (!process.env[envVars[i]]) {
console.warn("Please set", envVars[i]); console.warn("Please set", envVars[i]);
// process.exit(1); // process.exit(1);
} }
} }
const baseDir = path.join(__dirname, ".."); const baseDir = path.join(__dirname, "..");
const buildFolder = path.join(baseDir, "build"); const buildFolder = path.join(baseDir, "build");
const imgres = require("./image-resources"); const imgres = require("./image-resources");
imgres.gulptasksImageResources($, gulp, buildFolder); imgres.gulptasksImageResources($, gulp, buildFolder);
const css = require("./css"); const css = require("./css");
css.gulptasksCSS($, gulp, buildFolder, browserSync); css.gulptasksCSS($, gulp, buildFolder, browserSync);
const sounds = require("./sounds"); const sounds = require("./sounds");
sounds.gulptasksSounds($, gulp, buildFolder); sounds.gulptasksSounds($, gulp, buildFolder);
const js = require("./js"); const js = require("./js");
js.gulptasksJS($, gulp, buildFolder, browserSync); js.gulptasksJS($, gulp, buildFolder, browserSync);
const html = require("./html"); const html = require("./html");
html.gulptasksHTML($, gulp, buildFolder, browserSync); html.gulptasksHTML($, gulp, buildFolder, browserSync);
const ftp = require("./ftp"); const ftp = require("./ftp");
ftp.gulptasksFTP($, gulp, buildFolder); ftp.gulptasksFTP($, gulp, buildFolder);
const docs = require("./docs"); const docs = require("./docs");
docs.gulptasksDocs($, gulp, buildFolder); docs.gulptasksDocs($, gulp, buildFolder);
const standalone = require("./standalone"); const standalone = require("./standalone");
standalone.gulptasksStandalone($, gulp, buildFolder); standalone.gulptasksStandalone($, gulp, buildFolder);
const translations = require("./translations"); const translations = require("./translations");
translations.gulptasksTranslations($, gulp, buildFolder); translations.gulptasksTranslations($, gulp, buildFolder);
// FIXME // FIXME
// const cordova = require("./cordova"); // const cordova = require("./cordova");
// cordova.gulptasksCordova($, gulp, buildFolder); // cordova.gulptasksCordova($, gulp, buildFolder);
///////////////////// BUILD TASKS ///////////////////// ///////////////////// BUILD TASKS /////////////////////
// Cleans up everything // Cleans up everything
gulp.task("utils.cleanBuildFolder", () => { gulp.task("utils.cleanBuildFolder", () => {
return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe($.clean({ force: true })); return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe($.clean({ force: true }));
}); });
gulp.task("utils.cleanBuildTempFolder", () => { gulp.task("utils.cleanBuildTempFolder", () => {
return gulp return gulp
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: true }) .src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
.pipe($.clean({ force: true })); .pipe($.clean({ force: true }));
}); });
gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder")); gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
// Requires no uncomitted files // Requires no uncomitted files
gulp.task("utils.requireCleanWorkingTree", cb => { gulp.task("utils.requireCleanWorkingTree", cb => {
let output = $.trim(execSync("git status -su").toString("ascii")).replace(/\r/gi, "").split("\n"); let output = $.trim(execSync("git status -su").toString("ascii")).replace(/\r/gi, "").split("\n");
// Filter files which are OK to be untracked // Filter files which are OK to be untracked
output = output output = output
.map(x => x.replace(/[\r\n]+/gi, "")) .map(x => x.replace(/[\r\n]+/gi, ""))
.filter(x => x.indexOf(".local.js") < 0) .filter(x => x.indexOf(".local.js") < 0)
.filter(x => x.length > 0); .filter(x => x.length > 0);
if (output.length > 0) { if (output.length > 0) {
console.error("\n\nYou have unstaged changes, please commit everything first!"); console.error("\n\nYou have unstaged changes, please commit everything first!");
console.error("Unstaged files:"); console.error("Unstaged files:");
console.error(output.map(x => "'" + x + "'").join("\n")); console.error(output.map(x => "'" + x + "'").join("\n"));
process.exit(1); process.exit(1);
} }
cb(); cb();
}); });
gulp.task("utils.copyAdditionalBuildFiles", cb => { gulp.task("utils.copyAdditionalBuildFiles", cb => {
const additionalFolder = path.join("additional_build_files"); const additionalFolder = path.join("additional_build_files");
const additionalSrcGlobs = [ const additionalSrcGlobs = [
path.join(additionalFolder, "**/*.*"), path.join(additionalFolder, "**/*.*"),
path.join(additionalFolder, "**/.*"), path.join(additionalFolder, "**/.*"),
path.join(additionalFolder, "**/*"), path.join(additionalFolder, "**/*"),
]; ];
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder)); return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
}); });
// Starts a webserver on the built directory (useful for testing prod build) // Starts a webserver on the built directory (useful for testing prod build)
gulp.task("main.webserver", () => { gulp.task("main.webserver", () => {
return gulp.src(buildFolder).pipe( return gulp.src(buildFolder).pipe(
$.webserver({ $.webserver({
livereload: { livereload: {
enable: true, enable: true,
}, },
directoryListing: false, directoryListing: false,
open: true, open: true,
port: 3005, port: 3005,
}) })
); );
}); });
function serve({ standalone }) { function serve({ standalone }) {
browserSync.init({ browserSync.init({
server: buildFolder, server: buildFolder,
port: 3005, port: 3005,
ghostMode: { ghostMode: {
clicks: false, clicks: false,
scroll: false, scroll: false,
location: false, location: false,
forms: false, forms: false,
}, },
logLevel: "info", logLevel: "info",
logPrefix: "BS", logPrefix: "BS",
online: false, online: false,
xip: false, xip: false,
notify: false, notify: false,
reloadDebounce: 100, reloadDebounce: 100,
reloadOnRestart: true, reloadOnRestart: true,
watchEvents: ["add", "change"], watchEvents: ["add", "change"],
}); });
// Watch .scss files, those trigger a css rebuild // Watch .scss files, those trigger a css rebuild
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev")); gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild // Watch .html files, those trigger a html rebuild
gulp.watch("../src/**/*.html", gulp.series(standalone ? "html.standalone-dev" : "html.dev")); gulp.watch("../src/**/*.html", gulp.series(standalone ? "html.standalone-dev" : "html.dev"));
// Watch sound files // Watch sound files
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev")); // gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev"));
// Watch translations // Watch translations
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson")); gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
gulp.watch( gulp.watch(
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"], ["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
gulp.series("sounds.sfx", "sounds.copy") gulp.series("sounds.sfx", "sounds.copy")
); );
gulp.watch( gulp.watch(
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"], ["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
gulp.series("sounds.music", "sounds.copy") gulp.series("sounds.music", "sounds.copy")
); );
// Watch resource files and copy them on change // Watch resource files and copy them on change
gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources")); gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources"));
gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources")); gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
// Watch .atlas files and recompile the atlas on change // Watch .atlas files and recompile the atlas on change
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas")); gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
// Watch the build folder and reload when anything changed // Watch the build folder and reload when anything changed
const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"]; const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"];
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (path) { gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (path) {
return gulp.src(path).pipe(browserSync.reload({ stream: true })); return gulp.src(path).pipe(browserSync.reload({ stream: true }));
}); });
gulp.watch("../src/js/built-temp/*.json").on("change", function (path) { gulp.watch("../src/js/built-temp/*.json").on("change", function (path) {
return gulp.src(path).pipe(browserSync.reload({ stream: true })); return gulp.src(path).pipe(browserSync.reload({ stream: true }));
}); });
// Start the webpack watching server (Will never return) // Start the webpack watching server (Will never return)
if (standalone) { if (standalone) {
gulp.series("js.standalone-dev.watch")(() => true); gulp.series("js.standalone-dev.watch")(() => true);
} else { } else {
gulp.series("js.dev.watch")(() => true); gulp.series("js.dev.watch")(() => true);
} }
} }
///////////////////// RUNNABLE TASKS ///////////////////// ///////////////////// RUNNABLE TASKS /////////////////////
// Pre and postbuild // Pre and postbuild
gulp.task("step.baseResources", gulp.series("imgres.allOptimized")); gulp.task("step.baseResources", gulp.series("imgres.allOptimized"));
gulp.task("step.deleteEmpty", cb => { gulp.task("step.deleteEmpty", cb => {
deleteEmpty.sync(buildFolder); deleteEmpty.sync(buildFolder);
cb(); cb();
}); });
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty")); gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
// Builds everything (dev) // Builds everything (dev)
gulp.task( gulp.task(
"build.dev", "build.dev",
gulp.series( gulp.series(
"utils.cleanup", "utils.cleanup",
"utils.copyAdditionalBuildFiles", "utils.copyAdditionalBuildFiles",
"imgres.atlas", "imgres.atlas",
"sounds.dev", "sounds.dev",
"imgres.copyImageResources", "imgres.copyImageResources",
"imgres.copyNonImageResources", "imgres.copyNonImageResources",
"translations.fullBuild", "translations.fullBuild",
"css.dev", "css.dev",
"html.dev" "html.dev"
) )
); );
// Builds everything (standalone -dev) // Builds everything (standalone -dev)
gulp.task( gulp.task(
"build.standalone.dev", "build.standalone.dev",
gulp.series( gulp.series(
"utils.cleanup", "utils.cleanup",
"imgres.atlas", "imgres.atlas",
"sounds.dev", "sounds.dev",
"imgres.copyImageResources", "imgres.copyImageResources",
"imgres.copyNonImageResources", "imgres.copyNonImageResources",
"translations.fullBuild", "translations.fullBuild",
"js.standalone-dev", "js.standalone-dev",
"css.dev", "css.dev",
"html.standalone-dev" "html.standalone-dev"
) )
); );
// Builds everything (staging) // Builds everything (staging)
gulp.task("step.staging.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.staging")); gulp.task("step.staging.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.staging"));
gulp.task( gulp.task(
"step.staging.mainbuild", "step.staging.mainbuild",
gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code") 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("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")); gulp.task("build.staging", gulp.series("utils.cleanup", "step.staging.all", "step.postbuild"));
// Builds everything (prod) // Builds everything (prod)
gulp.task("step.prod.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.prod")); gulp.task("step.prod.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.prod"));
gulp.task( gulp.task(
"step.prod.mainbuild", "step.prod.mainbuild",
gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code") 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("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")); gulp.task("build.prod", gulp.series("utils.cleanup", "step.prod.all", "step.postbuild"));
// Builds everything (standalone-beta) // Builds everything (standalone-beta)
gulp.task( gulp.task(
"step.standalone-beta.code", "step.standalone-beta.code",
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", "js.standalone-beta") 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.mainbuild", gulp.parallel("step.baseResources", "step.standalone-beta.code"));
gulp.task( gulp.task(
"step.standalone-beta.all", "step.standalone-beta.all",
gulp.series("step.standalone-beta.mainbuild", "css.prod-standalone", "html.standalone-beta") gulp.series("step.standalone-beta.mainbuild", "css.prod-standalone", "html.standalone-beta")
); );
gulp.task( gulp.task(
"build.standalone-beta", "build.standalone-beta",
gulp.series("utils.cleanup", "step.standalone-beta.all", "step.postbuild") gulp.series("utils.cleanup", "step.standalone-beta.all", "step.postbuild")
); );
// Builds everything (standalone-prod) // Builds everything (standalone-prod)
gulp.task( gulp.task(
"step.standalone-prod.code", "step.standalone-prod.code",
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", "js.standalone-prod") gulp.series("sounds.fullbuildHQ", "translations.fullBuild", "js.standalone-prod")
); );
gulp.task("step.standalone-prod.mainbuild", gulp.parallel("step.baseResources", "step.standalone-prod.code")); gulp.task("step.standalone-prod.mainbuild", gulp.parallel("step.baseResources", "step.standalone-prod.code"));
gulp.task( gulp.task(
"step.standalone-prod.all", "step.standalone-prod.all",
gulp.series("step.standalone-prod.mainbuild", "css.prod-standalone", "html.standalone-prod") gulp.series("step.standalone-prod.mainbuild", "css.prod-standalone", "html.standalone-prod")
); );
gulp.task( gulp.task(
"build.standalone-prod", "build.standalone-prod",
gulp.series("utils.cleanup", "step.standalone-prod.all", "step.postbuild") gulp.series("utils.cleanup", "step.standalone-prod.all", "step.postbuild")
); );
// Deploying! // Deploying!
gulp.task( gulp.task(
"main.deploy.alpha", "main.deploy.alpha",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.alpha") gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.alpha")
); );
gulp.task( gulp.task(
"main.deploy.staging", "main.deploy.staging",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.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.prod", gulp.series("utils.requireCleanWorkingTree", "build.prod", "ftp.upload.prod"));
gulp.task("main.deploy.all", gulp.series("main.deploy.staging", "main.deploy.prod")); gulp.task("main.deploy.all", gulp.series("main.deploy.staging", "main.deploy.prod"));
gulp.task("main.standalone", gulp.series("build.standalone-prod", "standalone.package.prod")); gulp.task("main.standalone", gulp.series("build.standalone-prod", "standalone.package.prod"));
// Live-development // Live-development
gulp.task( gulp.task(
"main.serveDev", "main.serveDev",
gulp.series("build.dev", () => serve({ standalone: false })) gulp.series("build.dev", () => serve({ standalone: false }))
); );
gulp.task( gulp.task(
"main.serveStandalone", "main.serveStandalone",
gulp.series("build.standalone.dev", () => serve({ standalone: true })) gulp.series("build.standalone.dev", () => serve({ standalone: true }))
); );
gulp.task("default", gulp.series("main.serveDev")); gulp.task("default", gulp.series("main.serveDev"));

View File

@ -1,283 +1,301 @@
const buildUtils = require("./buildutils"); const buildUtils = require("./buildutils");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const crypto = require("crypto"); const crypto = require("crypto");
function computeIntegrityHash(fullPath, algorithm = "sha256") { function computeIntegrityHash(fullPath, algorithm = "sha256") {
const file = fs.readFileSync(fullPath); const file = fs.readFileSync(fullPath);
const hash = crypto.createHash(algorithm).update(file).digest("base64"); const hash = crypto.createHash(algorithm).update(file).digest("base64");
return algorithm + "-" + hash; return algorithm + "-" + hash;
} }
function gulptasksHTML($, gulp, buildFolder) { function gulptasksHTML($, gulp, buildFolder) {
const commitHash = buildUtils.getRevision(); const commitHash = buildUtils.getRevision();
async function buildHtml( async function buildHtml(
apiUrl, apiUrl,
{ analytics = false, standalone = false, app = false, integrity = true, enableCachebust = true } { analytics = false, standalone = false, app = false, integrity = true, enableCachebust = true }
) { ) {
function cachebust(url) { function cachebust(url) {
if (enableCachebust) { if (enableCachebust) {
return buildUtils.cachebust(url, commitHash); return buildUtils.cachebust(url, commitHash);
} }
return url; return url;
} }
const hasLocalFiles = standalone || app; const hasLocalFiles = standalone || app;
return gulp return gulp
.src("../src/html/" + (standalone ? "index.standalone.html" : "index.html")) .src("../src/html/" + (standalone ? "index.standalone.html" : "index.html"))
.pipe( .pipe(
$.dom(/** @this {Document} **/ function () { $.dom(
const document = this; /** @this {Document} **/ function () {
const document = this;
// Preconnect to api
const prefetchLink = document.createElement("link"); // Preconnect to api
prefetchLink.rel = "preconnect"; const prefetchLink = document.createElement("link");
prefetchLink.href = apiUrl; prefetchLink.rel = "preconnect";
prefetchLink.setAttribute("crossorigin", "anonymous"); prefetchLink.href = apiUrl;
document.head.appendChild(prefetchLink); prefetchLink.setAttribute("crossorigin", "anonymous");
document.head.appendChild(prefetchLink);
// Append css
const css = document.createElement("link"); // Append css
css.rel = "stylesheet"; const css = document.createElement("link");
css.type = "text/css"; css.rel = "stylesheet";
css.media = "none"; css.type = "text/css";
css.setAttribute("onload", "this.media='all'"); css.media = "none";
css.href = cachebust("main.css"); css.setAttribute("onload", "this.media='all'");
if (integrity) { css.href = cachebust("main.css");
css.setAttribute( if (integrity) {
"integrity", css.setAttribute(
computeIntegrityHash(path.join(buildFolder, "main.css")) "integrity",
); computeIntegrityHash(path.join(buildFolder, "main.css"))
} );
document.head.appendChild(css); }
document.head.appendChild(css);
if (app) {
// Append cordova link // Append async css
const cdv = document.createElement("script"); const asyncCss = document.createElement("link");
cdv.src = "cordova.js"; asyncCss.rel = "stylesheet";
cdv.type = "text/javascript"; asyncCss.type = "text/css";
document.head.appendChild(cdv); asyncCss.media = "none";
} asyncCss.setAttribute("onload", "this.media='all'");
asyncCss.href = cachebust("async-resources.css");
// Google analytics if (integrity) {
if (analytics) { asyncCss.setAttribute(
const tagManagerScript = document.createElement("script"); "integrity",
tagManagerScript.src = "https://www.googletagmanager.com/gtag/js?id=UA-165342524-1"; computeIntegrityHash(path.join(buildFolder, "async-resources.css"))
tagManagerScript.setAttribute("async", ""); );
document.head.appendChild(tagManagerScript); }
document.head.appendChild(asyncCss);
const initScript = document.createElement("script");
initScript.textContent = ` if (app) {
window.dataLayer = window.dataLayer || []; // Append cordova link
function gtag(){dataLayer.push(arguments);} const cdv = document.createElement("script");
gtag('js', new Date()); cdv.src = "cordova.js";
gtag('config', 'UA-165342524-1', { anonymize_ip: true }); cdv.type = "text/javascript";
`; document.head.appendChild(cdv);
document.head.appendChild(initScript); }
const abTestingScript = document.createElement("script"); // Google analytics
abTestingScript.setAttribute( if (analytics) {
"src", const tagManagerScript = document.createElement("script");
"https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7" tagManagerScript.src =
); "https://www.googletagmanager.com/gtag/js?id=UA-165342524-1";
abTestingScript.setAttribute("async", ""); tagManagerScript.setAttribute("async", "");
document.head.appendChild(abTestingScript); document.head.appendChild(tagManagerScript);
}
const initScript = document.createElement("script");
// Do not need to preload in app or standalone initScript.textContent = `
if (!hasLocalFiles) { window.dataLayer = window.dataLayer || [];
// Preload essentials function gtag(){dataLayer.push(arguments);}
const preloads = ["fonts/GameFont.woff2"]; gtag('js', new Date());
gtag('config', 'UA-165342524-1', { anonymize_ip: true });
preloads.forEach(src => { `;
const preloadLink = document.createElement("link"); document.head.appendChild(initScript);
preloadLink.rel = "preload";
preloadLink.href = cachebust("res/" + src); const abTestingScript = document.createElement("script");
if (src.endsWith(".woff2")) { abTestingScript.setAttribute(
preloadLink.setAttribute("crossorigin", "anonymous"); "src",
preloadLink.setAttribute("as", "font"); "https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"
} else { );
preloadLink.setAttribute("as", "image"); abTestingScript.setAttribute("async", "");
} document.head.appendChild(abTestingScript);
document.head.appendChild(preloadLink); }
});
} // Do not need to preload in app or standalone
if (!hasLocalFiles) {
const loadingSvg = `background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46YXV0bztiYWNrZ3JvdW5kOjAgMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgZGlzcGxheT0iYmxvY2siPjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzM5Mzc0NyIgc3Ryb2tlLXdpZHRoPSIzIiByPSI0MiIgc3Ryb2tlLWRhc2hhcnJheT0iMTk3LjkyMDMzNzE3NjE1Njk4IDY3Ljk3MzQ0NTcyNTM4NTY2IiB0cmFuc2Zvcm09InJvdGF0ZSg0OC4yNjUgNTAgNTApIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGR1cj0iNS41NTU1NTU1NTU1NTU1NTVzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIi8+PC9jaXJjbGU+PC9zdmc+")`; // Preload essentials
const preloads = ["fonts/GameFont.woff2"];
const loadingCss = `
@font-face { preloads.forEach(src => {
font-family: 'GameFont'; const preloadLink = document.createElement("link");
font-style: normal; preloadLink.rel = "preload";
font-weight: normal; preloadLink.href = cachebust("res/" + src);
font-display: swap; if (src.endsWith(".woff2")) {
src: url('${cachebust("res/fonts/GameFont.woff2")}') format('woff2'); preloadLink.setAttribute("crossorigin", "anonymous");
} preloadLink.setAttribute("as", "font");
} else {
#ll_fp { preloadLink.setAttribute("as", "image");
font-family: GameFont; }
font-size: 14px; document.head.appendChild(preloadLink);
position: fixed; });
z-index: -1; }
top: 0;
left: 0; const loadingSvg = `background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46YXV0bztiYWNrZ3JvdW5kOjAgMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgZGlzcGxheT0iYmxvY2siPjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzM5Mzc0NyIgc3Ryb2tlLXdpZHRoPSIzIiByPSI0MiIgc3Ryb2tlLWRhc2hhcnJheT0iMTk3LjkyMDMzNzE3NjE1Njk4IDY3Ljk3MzQ0NTcyNTM4NTY2IiB0cmFuc2Zvcm09InJvdGF0ZSg0OC4yNjUgNTAgNTApIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGR1cj0iNS41NTU1NTU1NTU1NTU1NTVzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIi8+PC9jaXJjbGU+PC9zdmc+")`;
opacity: 0.05;
} const loadingCss = `
@font-face {
#ll_p { font-family: 'GameFont';
display: flex; font-style: normal;
position: fixed; font-weight: normal;
z-index: 99999; font-display: swap;
top: 0; src: url('${cachebust("res/fonts/GameFont.woff2")}') format('woff2');
left: 0; }
right: 0;
bottom: 0; #ll_fp {
justify-content: font-family: GameFont;
center; font-size: 14px;
align-items: center; position: fixed;
} z-index: -1;
top: 0;
#ll_p > div { left: 0;
position: absolute; opacity: 0.05;
text-align: center; }
bottom: 40px;
left: 20px; #ll_p {
right: 20px; display: flex;
color: #393747; position: fixed;
font-family: 'GameFont', sans-serif; z-index: 99999;
font-size: 20px; top: 0;
} left: 0;
right: 0;
#ll_p > span { bottom: 0;
width: 60px; justify-content:
height: 60px; center;
display: inline-flex; align-items: center;
background: center center / contain no-repeat; }
${loadingSvg};
} #ll_p > div {
`; position: absolute;
text-align: center;
const style = document.createElement("style"); bottom: 40px;
style.setAttribute("type", "text/css"); left: 20px;
style.textContent = loadingCss; right: 20px;
document.head.appendChild(style); color: #393747;
font-family: 'GameFont', sans-serif;
// Append loader, but not in standalone (directly include bundle there) font-size: 20px;
if (standalone) { }
const bundleScript = document.createElement("script");
bundleScript.type = "text/javascript"; #ll_p > span {
bundleScript.src = "bundle.js"; width: 60px;
if (integrity) { height: 60px;
bundleScript.setAttribute( display: inline-flex;
"integrity", background: center center / contain no-repeat;
computeIntegrityHash(path.join(buildFolder, "bundle.js")) ${loadingSvg};
); }
} `;
document.head.appendChild(bundleScript);
} else { const style = document.createElement("style");
const loadJs = document.createElement("script"); style.setAttribute("type", "text/css");
loadJs.type = "text/javascript"; style.textContent = loadingCss;
let scriptContent = ""; document.head.appendChild(style);
scriptContent += `var bundleSrc = '${cachebust("bundle.js")}';\n`;
scriptContent += `var bundleSrcTranspiled = '${cachebust( // Append loader, but not in standalone (directly include bundle there)
"bundle-transpiled.js" if (standalone) {
)}';\n`; const bundleScript = document.createElement("script");
bundleScript.type = "text/javascript";
if (integrity) { bundleScript.src = "bundle.js";
scriptContent += if (integrity) {
"var bundleIntegrity = '" + bundleScript.setAttribute(
computeIntegrityHash(path.join(buildFolder, "bundle.js")) + "integrity",
"';\n"; computeIntegrityHash(path.join(buildFolder, "bundle.js"))
scriptContent += );
"var bundleIntegrityTranspiled = '" + }
computeIntegrityHash(path.join(buildFolder, "bundle-transpiled.js")) + document.head.appendChild(bundleScript);
"';\n"; } else {
} else { const loadJs = document.createElement("script");
scriptContent += "var bundleIntegrity = null;\n"; loadJs.type = "text/javascript";
scriptContent += "var bundleIntegrityTranspiled = null;\n"; let scriptContent = "";
} scriptContent += `var bundleSrc = '${cachebust("bundle.js")}';\n`;
scriptContent += `var bundleSrcTranspiled = '${cachebust(
scriptContent += fs.readFileSync("./bundle-loader.js").toString(); "bundle-transpiled.js"
loadJs.textContent = scriptContent; )}';\n`;
document.head.appendChild(loadJs);
} if (integrity) {
scriptContent +=
const bodyContent = ` "var bundleIntegrity = '" +
<div id="ll_fp">_</div> computeIntegrityHash(path.join(buildFolder, "bundle.js")) +
<div id="ll_p"> "';\n";
<span></span> scriptContent +=
<div>${hasLocalFiles ? "Loading" : "Downloading"} Game Files</div > "var bundleIntegrityTranspiled = '" +
</div > computeIntegrityHash(path.join(buildFolder, "bundle-transpiled.js")) +
`; "';\n";
} else {
document.body.innerHTML = bodyContent; scriptContent += "var bundleIntegrity = null;\n";
}) scriptContent += "var bundleIntegrityTranspiled = null;\n";
) }
.pipe(
$.htmlmin({ scriptContent += fs.readFileSync("./bundle-loader.js").toString();
caseSensitive: true, loadJs.textContent = scriptContent;
collapseBooleanAttributes: true, document.head.appendChild(loadJs);
collapseInlineTagWhitespace: true, }
collapseWhitespace: true,
preserveLineBreaks: true, const bodyContent = `
minifyJS: true, <div id="ll_fp">_</div>
minifyCSS: true, <div id="ll_p">
quoteCharacter: '"', <span></span>
useShortDoctype: true, <div>${hasLocalFiles ? "Loading" : "Downloading"} Game Files</div >
}) </div >
) `;
.pipe($.htmlBeautify())
.pipe($.rename("index.html")) document.body.innerHTML = bodyContent;
.pipe(gulp.dest(buildFolder)); }
} )
)
gulp.task("html.dev", () => { .pipe(
return buildHtml("http://localhost:5005", { $.htmlmin({
analytics: false, caseSensitive: true,
integrity: false, collapseBooleanAttributes: true,
enableCachebust: false, collapseInlineTagWhitespace: true,
}); collapseWhitespace: true,
}); preserveLineBreaks: true,
minifyJS: true,
gulp.task("html.staging", () => { minifyCSS: true,
return buildHtml("https://api-staging.shapez.io", { quoteCharacter: '"',
analytics: true, useShortDoctype: true,
}); })
}); )
.pipe($.htmlBeautify())
gulp.task("html.prod", () => { .pipe($.rename("index.html"))
return buildHtml("https://analytics.shapez.io", { .pipe(gulp.dest(buildFolder));
analytics: true, }
});
}); gulp.task("html.dev", () => {
return buildHtml("http://localhost:5005", {
gulp.task("html.standalone-dev", () => { analytics: false,
return buildHtml("https://localhost:5005", { integrity: false,
analytics: false, enableCachebust: false,
standalone: true, });
integrity: false, });
enableCachebust: false,
}); gulp.task("html.staging", () => {
}); return buildHtml("https://api-staging.shapez.io", {
analytics: true,
gulp.task("html.standalone-beta", () => { });
return buildHtml("https://api-staging.shapez.io", { });
analytics: false,
standalone: true, gulp.task("html.prod", () => {
enableCachebust: false, return buildHtml("https://analytics.shapez.io", {
}); analytics: true,
}); });
});
gulp.task("html.standalone-prod", () => {
return buildHtml("https://analytics.shapez.io", { gulp.task("html.standalone-dev", () => {
analytics: false, return buildHtml("https://localhost:5005", {
standalone: true, analytics: false,
enableCachebust: false, standalone: true,
}); integrity: false,
}); enableCachebust: false,
} });
});
module.exports = {
gulptasksHTML, 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 = {
gulptasksHTML,
};

View File

@ -1,148 +1,141 @@
// @ts-ignore // @ts-ignore
const path = require("path"); const path = require("path");
// Globs for non-ui resources // Globs for non-ui resources
const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"]; const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
// Globs for ui resources // Globs for ui resources
const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg", "../res/**/*.gif"]; const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg", "../res/**/*.gif"];
function gulptasksImageResources($, gulp, buildFolder) { function gulptasksImageResources($, gulp, buildFolder) {
// Lossless options // Lossless options
const minifyImagesOptsLossless = () => [ const minifyImagesOptsLossless = () => [
$.imageminJpegtran({ $.imageminJpegtran({
progressive: true, progressive: true,
}), }),
$.imagemin.svgo({}), $.imagemin.svgo({}),
$.imagemin.optipng({ $.imagemin.optipng({
optimizationLevel: 3, optimizationLevel: 3,
}), }),
$.imageminGifsicle({ $.imageminGifsicle({
optimizationLevel: 3, optimizationLevel: 3,
colors: 128, colors: 128,
}), }),
]; ];
// Lossy options // Lossy options
const minifyImagesOpts = () => [ const minifyImagesOpts = () => [
$.imagemin.mozjpeg({ $.imagemin.mozjpeg({
quality: 80, quality: 80,
maxMemory: 1024 * 1024 * 8, maxMemory: 1024 * 1024 * 8,
}), }),
$.imagemin.svgo({}), $.imagemin.svgo({}),
$.imageminPngquant({ $.imageminPngquant({
speed: 1, speed: 1,
strip: true, strip: true,
quality: [0.65, 0.9], quality: [0.65, 0.9],
dithering: false, dithering: false,
verbose: false, verbose: false,
}), }),
$.imagemin.optipng({ $.imagemin.optipng({
optimizationLevel: 3, optimizationLevel: 3,
}), }),
$.imageminGifsicle({ $.imageminGifsicle({
optimizationLevel: 3, optimizationLevel: 3,
colors: 128, colors: 128,
}), }),
]; ];
// Where the resources folder are // Where the resources folder are
const resourcesDestFolder = path.join(buildFolder, "res"); const resourcesDestFolder = path.join(buildFolder, "res");
/** /**
* Determines if an atlas must use lossless compression * Determines if an atlas must use lossless compression
* @param {string} fname * @param {string} fname
*/ */
function fileMustBeLossless(fname) { function fileMustBeLossless(fname) {
return fname.indexOf("lossless") >= 0; return fname.indexOf("lossless") >= 0;
} }
/////////////// ATLAS ///////////////////// /////////////// ATLAS /////////////////////
// Copies the atlas to the final destination // Copies the atlas to the final destination
gulp.task("imgres.atlas", () => { gulp.task("imgres.atlas", () => {
return gulp return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
.src(["../res_built/atlas/*.png"]) });
.pipe($.cached("imgres.atlas"))
.pipe(gulp.dest(resourcesDestFolder)); // Copies the atlas to the final destination after optimizing it (lossy compression)
}); gulp.task("imgres.atlasOptimized", () => {
return gulp
// Copies the atlas to the final destination after optimizing it (lossy compression) .src(["../res_built/atlas/*.png"])
gulp.task("imgres.atlasOptimized", () => { .pipe(
return gulp $.if(
.src(["../res_built/atlas/*.png"]) fname => fileMustBeLossless(fname.history[0]),
.pipe($.cached("imgres.atlasOptimized")) $.imagemin(minifyImagesOptsLossless()),
.pipe( $.imagemin(minifyImagesOpts())
$.if( )
fname => fileMustBeLossless(fname.history[0]), )
$.imagemin(minifyImagesOptsLossless()), .pipe(gulp.dest(resourcesDestFolder));
$.imagemin(minifyImagesOpts()) });
)
) //////////////////// RESOURCES //////////////////////
.pipe(gulp.dest(resourcesDestFolder));
}); // Copies all resources which are no ui resources
gulp.task("imgres.copyNonImageResources", () => {
//////////////////// RESOURCES ////////////////////// return gulp.src(nonImageResourcesGlobs).pipe(gulp.dest(resourcesDestFolder));
});
// Copies all resources which are no ui resources
gulp.task("imgres.copyNonImageResources", () => { // Copies all ui resources
return gulp gulp.task("imgres.copyImageResources", () => {
.src(nonImageResourcesGlobs) return gulp
.pipe($.cached("imgres.copyNonImageResources")) .src(imageResourcesGlobs)
.pipe(gulp.dest(resourcesDestFolder));
}); .pipe($.cached("imgres.copyImageResources"))
.pipe(gulp.dest(path.join(resourcesDestFolder)));
// Copies all ui resources });
gulp.task("imgres.copyImageResources", () => {
return gulp // Copies all ui resources and optimizes them
.src(imageResourcesGlobs) gulp.task("imgres.copyImageResourcesOptimized", () => {
.pipe($.cached("copyImageResources")) return gulp
.pipe(gulp.dest(path.join(resourcesDestFolder))); .src(imageResourcesGlobs)
}); .pipe(
$.if(
// Copies all ui resources and optimizes them fname => fileMustBeLossless(fname.history[0]),
gulp.task("imgres.copyImageResourcesOptimized", () => { $.imagemin(minifyImagesOptsLossless()),
return gulp $.imagemin(minifyImagesOpts())
.src(imageResourcesGlobs) )
.pipe($.cached("imgres.copyImageResourcesOptimized")) )
.pipe( .pipe(gulp.dest(path.join(resourcesDestFolder)));
$.if( });
fname => fileMustBeLossless(fname.history[0]),
$.imagemin(minifyImagesOptsLossless()), // Copies all resources and optimizes them
$.imagemin(minifyImagesOpts()) gulp.task(
) "imgres.allOptimized",
) gulp.parallel(
.pipe(gulp.dest(path.join(resourcesDestFolder))); "imgres.atlasOptimized",
}); "imgres.copyNonImageResources",
"imgres.copyImageResourcesOptimized"
// Copies all resources and optimizes them )
gulp.task( );
"imgres.allOptimized",
gulp.parallel( // Cleans up unused images which are instead inline into the css
"imgres.atlasOptimized", gulp.task("imgres.cleanupUnusedCssInlineImages", () => {
"imgres.copyNonImageResources", return gulp
"imgres.copyImageResourcesOptimized" .src(
) [
); path.join(buildFolder, "res", "ui", "**", "*.png"),
path.join(buildFolder, "res", "ui", "**", "*.jpg"),
// Cleans up unused images which are instead inline into the css path.join(buildFolder, "res", "ui", "**", "*.svg"),
gulp.task("imgres.cleanupUnusedCssInlineImages", () => { path.join(buildFolder, "res", "ui", "**", "*.gif"),
return gulp ],
.src( { read: false }
[ )
path.join(buildFolder, "res", "ui", "**", "*.png"), .pipe($.if(fname => fname.history[0].indexOf("noinline") < 0, $.clean({ force: true })));
path.join(buildFolder, "res", "ui", "**", "*.jpg"), });
path.join(buildFolder, "res", "ui", "**", "*.svg"), }
path.join(buildFolder, "res", "ui", "**", "*.gif"),
], module.exports = {
{ read: false } nonImageResourcesGlobs,
) imageResourcesGlobs,
.pipe($.if(fname => fname.history[0].indexOf("noinline") < 0, $.clean({ force: true }))); gulptasksImageResources,
}); };
}
module.exports = {
nonImageResourcesGlobs,
imageResourcesGlobs,
gulptasksImageResources,
};

View File

@ -1,110 +1,111 @@
{ {
"name": "builder", "name": "builder",
"version": "1.0.0", "version": "1.0.0",
"description": "builder", "description": "builder",
"private": true, "private": true,
"scripts": { "scripts": {
"gulp": "gulp" "gulp": "gulp"
}, },
"author": "tobspr", "author": "tobspr",
"license": "private", "license": "private",
"dependencies": { "dependencies": {
"@babel/core": "^7.9.0", "@babel/core": "^7.9.0",
"@babel/plugin-transform-block-scoping": "^7.4.4", "@babel/plugin-transform-block-scoping": "^7.4.4",
"@babel/plugin-transform-classes": "^7.5.5", "@babel/plugin-transform-classes": "^7.5.5",
"@babel/preset-env": "^7.5.4", "@babel/preset-env": "^7.5.4",
"@types/cordova": "^0.0.34", "@types/cordova": "^0.0.34",
"@types/filesystem": "^0.0.29", "@types/filesystem": "^0.0.29",
"@types/node": "^12.7.5", "@types/node": "^12.7.5",
"ajv": "^6.10.2", "ajv": "^6.10.2",
"audiosprite": "^0.7.2", "audiosprite": "^0.7.2",
"babel-loader": "^8.1.0", "babel-loader": "^8.1.0",
"browser-sync": "^2.26.10", "browser-sync": "^2.26.10",
"circular-dependency-plugin": "^5.0.2", "circular-dependency-plugin": "^5.0.2",
"circular-json": "^0.5.9", "circular-json": "^0.5.9",
"clipboard-copy": "^3.1.0", "clipboard-copy": "^3.1.0",
"colors": "^1.3.3", "colors": "^1.3.3",
"core-js": "3", "core-js": "3",
"crypto": "^1.0.1", "crypto": "^1.0.1",
"cssnano-preset-advanced": "^4.0.7", "cssnano-preset-advanced": "^4.0.7",
"delete-empty": "^3.0.0", "delete-empty": "^3.0.0",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"eslint": "^5.9.0", "eslint": "^5.9.0",
"fastdom": "^1.0.9", "fastdom": "^1.0.9",
"flatted": "^2.0.1", "flatted": "^2.0.1",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",
"gulp-audiosprite": "^1.1.0", "gulp-audiosprite": "^1.1.0",
"howler": "^2.1.2", "howler": "^2.1.2",
"html-loader": "^0.5.5", "html-loader": "^0.5.5",
"ignore-loader": "^0.1.2", "ignore-loader": "^0.1.2",
"lz-string": "^1.4.4", "lz-string": "^1.4.4",
"markdown-loader": "^5.1.0", "markdown-loader": "^5.1.0",
"node-sri": "^1.1.1", "node-sri": "^1.1.1",
"phonegap-plugin-mobile-accessibility": "^1.0.5", "phonegap-plugin-mobile-accessibility": "^1.0.5",
"promise-polyfill": "^8.1.0", "promise-polyfill": "^8.1.0",
"query-string": "^6.8.1", "query-string": "^6.8.1",
"rusha": "^0.8.13", "rusha": "^0.8.13",
"serialize-error": "^3.0.0", "serialize-error": "^3.0.0",
"strictdom": "^1.0.1", "strictdom": "^1.0.1",
"string-replace-webpack-plugin": "^0.1.3", "string-replace-webpack-plugin": "^0.1.3",
"terser-webpack-plugin": "^1.1.0", "terser-webpack-plugin": "^1.1.0",
"through2": "^3.0.1", "through2": "^3.0.1",
"uglify-template-string-loader": "^1.1.0", "uglify-template-string-loader": "^1.1.0",
"unused-files-webpack-plugin": "^3.4.0", "unused-files-webpack-plugin": "^3.4.0",
"webpack": "^4.43.0", "webpack": "^4.43.0",
"webpack-cli": "^3.1.0", "webpack-cli": "^3.1.0",
"webpack-deep-scope-plugin": "^1.6.0", "webpack-deep-scope-plugin": "^1.6.0",
"webpack-plugin-replace": "^1.1.1", "webpack-plugin-replace": "^1.1.1",
"webpack-strip-block": "^0.2.0", "webpack-strip-block": "^0.2.0",
"whatwg-fetch": "^3.0.0", "whatwg-fetch": "^3.0.0",
"worker-loader": "^2.0.0" "worker-loader": "^2.0.0"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^9.4.3", "autoprefixer": "^9.4.3",
"babel-plugin-closure-elimination": "^1.3.0", "babel-plugin-closure-elimination": "^1.3.0",
"babel-plugin-console-source": "^2.0.2", "babel-plugin-console-source": "^2.0.2",
"babel-plugin-danger-remove-unused-import": "^1.1.2", "babel-plugin-danger-remove-unused-import": "^1.1.2",
"css-mqpacker": "^7.0.0", "css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"electron-packager": "^14.0.6", "postcss-critical-split": "^2.5.3",
"faster.js": "^1.1.0", "electron-packager": "^14.0.6",
"glob": "^7.1.3", "faster.js": "^1.1.0",
"gulp": "^4.0.2", "glob": "^7.1.3",
"gulp-cache": "^1.1.3", "gulp": "^4.0.2",
"gulp-cached": "^1.1.1", "gulp-cache": "^1.1.3",
"gulp-clean": "^0.4.0", "gulp-cached": "^1.1.1",
"gulp-dom": "^1.0.0", "gulp-clean": "^0.4.0",
"gulp-flatten": "^0.4.0", "gulp-dom": "^1.0.0",
"gulp-fluent-ffmpeg": "^2.0.0", "gulp-flatten": "^0.4.0",
"gulp-html-beautify": "^1.0.1", "gulp-fluent-ffmpeg": "^2.0.0",
"gulp-htmlmin": "^5.0.1", "gulp-html-beautify": "^1.0.1",
"gulp-if": "^3.0.0", "gulp-htmlmin": "^5.0.1",
"gulp-imagemin": "^7.1.0", "gulp-if": "^3.0.0",
"gulp-load-plugins": "^2.0.3", "gulp-imagemin": "^7.1.0",
"gulp-phonegap-build": "^0.1.5", "gulp-load-plugins": "^2.0.3",
"gulp-plumber": "^1.2.1", "gulp-phonegap-build": "^0.1.5",
"gulp-pngquant": "^1.0.13", "gulp-plumber": "^1.2.1",
"gulp-postcss": "^8.0.0", "gulp-pngquant": "^1.0.13",
"gulp-rename": "^2.0.0", "gulp-postcss": "^8.0.0",
"gulp-sass": "^4.1.0", "gulp-rename": "^2.0.0",
"gulp-sass-lint": "^1.4.0", "gulp-sass": "^4.1.0",
"gulp-sftp": "git+https://git@github.com/webksde/gulp-sftp", "gulp-sass-lint": "^1.4.0",
"gulp-terser": "^1.2.0", "gulp-sftp": "git+https://git@github.com/webksde/gulp-sftp",
"gulp-webserver": "^0.9.1", "gulp-terser": "^1.2.0",
"gulp-yaml": "^2.0.4", "gulp-webserver": "^0.9.1",
"imagemin-gifsicle": "^7.0.0", "gulp-yaml": "^2.0.4",
"imagemin-jpegtran": "^7.0.0", "imagemin-gifsicle": "^7.0.0",
"imagemin-pngquant": "^9.0.0", "imagemin-jpegtran": "^7.0.0",
"jimp": "^0.6.1", "imagemin-pngquant": "^9.0.0",
"js-yaml": "^3.13.1", "jimp": "^0.6.1",
"postcss-assets": "^5.0.0", "js-yaml": "^3.13.1",
"postcss-preset-env": "^6.5.0", "postcss-assets": "^5.0.0",
"postcss-round-subpixels": "^1.2.0", "postcss-preset-env": "^6.5.0",
"postcss-unprefix": "^2.1.3", "postcss-round-subpixels": "^1.2.0",
"sass-unused": "^0.3.0", "postcss-unprefix": "^2.1.3",
"strip-json-comments": "^3.0.1", "sass-unused": "^0.3.0",
"trim": "^0.0.1", "strip-json-comments": "^3.0.1",
"webpack-stream": "^5.2.1", "trim": "^0.0.1",
"yaml-loader": "^0.6.0" "webpack-stream": "^5.2.1",
} "yaml-loader": "^0.6.0"
} }
}

View File

@ -16,6 +16,12 @@ function gulptasksSounds($, gulp, buildFolder) {
cacheDirName: "shapezio-precompiled-sounds", cacheDirName: "shapezio-precompiled-sounds",
}); });
function getFileCacheValue(file) {
const { _isVinyl, base, cwd, contents, history, stat, path } = file;
const encodedContents = Buffer.from(contents).toString("base64");
return { _isVinyl, base, cwd, contents: encodedContents, history, stat, path };
}
// Encodes the game music // Encodes the game music
gulp.task("sounds.music", () => { gulp.task("sounds.music", () => {
return gulp return gulp
@ -34,6 +40,7 @@ function gulptasksSounds($, gulp, buildFolder) {
{ {
name: "music", name: "music",
fileCache, fileCache,
value: getFileCacheValue,
} }
) )
) )
@ -58,6 +65,7 @@ function gulptasksSounds($, gulp, buildFolder) {
{ {
name: "music-high-quality", name: "music-high-quality",
fileCache, fileCache,
value: getFileCacheValue,
} }
) )
) )
@ -110,7 +118,6 @@ function gulptasksSounds($, gulp, buildFolder) {
return gulp return gulp
.src(path.join(builtSoundsDir, "**", "*.mp3")) .src(path.join(builtSoundsDir, "**", "*.mp3"))
.pipe($.plumber()) .pipe($.plumber())
.pipe($.cached("sounds.copy"))
.pipe(gulp.dest(path.join(buildFolder, "res", "sounds"))); .pipe(gulp.dest(path.join(buildFolder, "res", "sounds")));
}); });

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 B

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 927 B

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 279 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 KiB

After

Width:  |  Height:  |  Size: 700 KiB

View File

@ -104,7 +104,7 @@
</struct> </struct>
</struct> </struct>
<key>shapePadding</key> <key>shapePadding</key>
<uint>0</uint> <uint>2</uint>
<key>jpgQuality</key> <key>jpgQuality</key>
<uint>80</uint> <uint>80</uint>
<key>pngOptimizationLevel</key> <key>pngOptimizationLevel</key>
@ -118,7 +118,7 @@
<key>textureFormat</key> <key>textureFormat</key>
<enum type="SettingsBase::TextureFormat">png</enum> <enum type="SettingsBase::TextureFormat">png</enum>
<key>borderPadding</key> <key>borderPadding</key>
<uint>1</uint> <uint>3</uint>
<key>maxTextureSize</key> <key>maxTextureSize</key>
<QSize> <QSize>
<key>width</key> <key>width</key>
@ -257,81 +257,84 @@
<key type="filename">sprites/belt/built/right_7.png</key> <key type="filename">sprites/belt/built/right_7.png</key>
<key type="filename">sprites/belt/built/right_8.png</key> <key type="filename">sprites/belt/built/right_8.png</key>
<key type="filename">sprites/belt/built/right_9.png</key> <key type="filename">sprites/belt/built/right_9.png</key>
<key type="filename">sprites/blueprints/analyzer.png</key>
<key type="filename">sprites/blueprints/balancer-merger-inverse.png</key>
<key type="filename">sprites/blueprints/balancer-merger.png</key>
<key type="filename">sprites/blueprints/balancer-splitter-inverse.png</key>
<key type="filename">sprites/blueprints/balancer-splitter.png</key>
<key type="filename">sprites/blueprints/belt_left.png</key>
<key type="filename">sprites/blueprints/belt_right.png</key>
<key type="filename">sprites/blueprints/belt_top.png</key>
<key type="filename">sprites/blueprints/comparator.png</key>
<key type="filename">sprites/blueprints/constant_signal.png</key> <key type="filename">sprites/blueprints/constant_signal.png</key>
<key type="filename">sprites/blueprints/display.png</key> <key type="filename">sprites/blueprints/display.png</key>
<key type="filename">sprites/blueprints/lever.png</key> <key type="filename">sprites/blueprints/lever.png</key>
<key type="filename">sprites/blueprints/logic_gate-not.png</key> <key type="filename">sprites/blueprints/logic_gate-not.png</key>
<key type="filename">sprites/blueprints/logic_gate-or.png</key> <key type="filename">sprites/blueprints/logic_gate-or.png</key>
<key type="filename">sprites/blueprints/logic_gate-transistor.png</key>
<key type="filename">sprites/blueprints/logic_gate-xor.png</key> <key type="filename">sprites/blueprints/logic_gate-xor.png</key>
<key type="filename">sprites/blueprints/logic_gate.png</key> <key type="filename">sprites/blueprints/logic_gate.png</key>
<key type="filename">sprites/blueprints/miner-chainable.png</key> <key type="filename">sprites/blueprints/miner-chainable.png</key>
<key type="filename">sprites/blueprints/miner.png</key> <key type="filename">sprites/blueprints/miner.png</key>
<key type="filename">sprites/blueprints/reader.png</key> <key type="filename">sprites/blueprints/reader.png</key>
<key type="filename">sprites/blueprints/rotater-ccw.png</key> <key type="filename">sprites/blueprints/rotater-ccw.png</key>
<key type="filename">sprites/blueprints/rotater-fl.png</key> <key type="filename">sprites/blueprints/rotater-rotate180.png</key>
<key type="filename">sprites/blueprints/rotater.png</key> <key type="filename">sprites/blueprints/rotater.png</key>
<key type="filename">sprites/blueprints/splitter-compact-inverse.png</key> <key type="filename">sprites/blueprints/transistor-mirrored.png</key>
<key type="filename">sprites/blueprints/splitter-compact-merge-inverse.png</key> <key type="filename">sprites/blueprints/transistor.png</key>
<key type="filename">sprites/blueprints/splitter-compact-merge.png</key>
<key type="filename">sprites/blueprints/splitter-compact.png</key>
<key type="filename">sprites/blueprints/trash.png</key> <key type="filename">sprites/blueprints/trash.png</key>
<key type="filename">sprites/blueprints/underground_belt_entry-tier2.png</key> <key type="filename">sprites/blueprints/underground_belt_entry-tier2.png</key>
<key type="filename">sprites/blueprints/underground_belt_entry.png</key> <key type="filename">sprites/blueprints/underground_belt_entry.png</key>
<key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key> <key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key>
<key type="filename">sprites/blueprints/underground_belt_exit.png</key> <key type="filename">sprites/blueprints/underground_belt_exit.png</key>
<key type="filename">sprites/blueprints/virtual_processor-analyzer.png</key> <key type="filename">sprites/blueprints/virtual_processor-painter.png</key>
<key type="filename">sprites/blueprints/virtual_processor-rotater.png</key> <key type="filename">sprites/blueprints/virtual_processor-rotater.png</key>
<key type="filename">sprites/blueprints/virtual_processor-shapecompare.png</key> <key type="filename">sprites/blueprints/virtual_processor-stacker.png</key>
<key type="filename">sprites/blueprints/virtual_processor-unstacker.png</key> <key type="filename">sprites/blueprints/virtual_processor-unstacker.png</key>
<key type="filename">sprites/blueprints/virtual_processor.png</key> <key type="filename">sprites/blueprints/virtual_processor.png</key>
<key type="filename">sprites/blueprints/wire_tunnel-coating.png</key>
<key type="filename">sprites/blueprints/wire_tunnel.png</key> <key type="filename">sprites/blueprints/wire_tunnel.png</key>
<key type="filename">sprites/buildings/analyzer.png</key>
<key type="filename">sprites/buildings/balancer-merger-inverse.png</key>
<key type="filename">sprites/buildings/balancer-merger.png</key>
<key type="filename">sprites/buildings/balancer-splitter-inverse.png</key>
<key type="filename">sprites/buildings/balancer-splitter.png</key>
<key type="filename">sprites/buildings/comparator.png</key>
<key type="filename">sprites/buildings/constant_signal.png</key> <key type="filename">sprites/buildings/constant_signal.png</key>
<key type="filename">sprites/buildings/display.png</key> <key type="filename">sprites/buildings/display.png</key>
<key type="filename">sprites/buildings/lever.png</key> <key type="filename">sprites/buildings/lever.png</key>
<key type="filename">sprites/buildings/logic_gate-not.png</key> <key type="filename">sprites/buildings/logic_gate-not.png</key>
<key type="filename">sprites/buildings/logic_gate-or.png</key> <key type="filename">sprites/buildings/logic_gate-or.png</key>
<key type="filename">sprites/buildings/logic_gate-transistor.png</key>
<key type="filename">sprites/buildings/logic_gate-xor.png</key> <key type="filename">sprites/buildings/logic_gate-xor.png</key>
<key type="filename">sprites/buildings/logic_gate.png</key> <key type="filename">sprites/buildings/logic_gate.png</key>
<key type="filename">sprites/buildings/miner-chainable.png</key> <key type="filename">sprites/buildings/miner-chainable.png</key>
<key type="filename">sprites/buildings/reader.png</key> <key type="filename">sprites/buildings/reader.png</key>
<key type="filename">sprites/buildings/rotater-ccw.png</key> <key type="filename">sprites/buildings/rotater-ccw.png</key>
<key type="filename">sprites/buildings/rotater-fl.png</key> <key type="filename">sprites/buildings/rotater-rotate180.png</key>
<key type="filename">sprites/buildings/splitter-compact-inverse.png</key> <key type="filename">sprites/buildings/transistor-mirrored.png</key>
<key type="filename">sprites/buildings/splitter-compact-merge-inverse.png</key> <key type="filename">sprites/buildings/transistor.png</key>
<key type="filename">sprites/buildings/splitter-compact-merge.png</key>
<key type="filename">sprites/buildings/splitter-compact.png</key>
<key type="filename">sprites/buildings/underground_belt_entry-tier2.png</key> <key type="filename">sprites/buildings/underground_belt_entry-tier2.png</key>
<key type="filename">sprites/buildings/underground_belt_entry.png</key> <key type="filename">sprites/buildings/underground_belt_entry.png</key>
<key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key> <key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key>
<key type="filename">sprites/buildings/underground_belt_exit.png</key> <key type="filename">sprites/buildings/underground_belt_exit.png</key>
<key type="filename">sprites/buildings/virtual_processor-analyzer.png</key> <key type="filename">sprites/buildings/virtual_processor-painter.png</key>
<key type="filename">sprites/buildings/virtual_processor-rotater.png</key> <key type="filename">sprites/buildings/virtual_processor-rotater.png</key>
<key type="filename">sprites/buildings/virtual_processor-shapecompare.png</key> <key type="filename">sprites/buildings/virtual_processor-stacker.png</key>
<key type="filename">sprites/buildings/virtual_processor-unstacker.png</key> <key type="filename">sprites/buildings/virtual_processor-unstacker.png</key>
<key type="filename">sprites/buildings/virtual_processor.png</key> <key type="filename">sprites/buildings/virtual_processor.png</key>
<key type="filename">sprites/buildings/wire_tunnel-coating.png</key>
<key type="filename">sprites/buildings/wire_tunnel.png</key> <key type="filename">sprites/buildings/wire_tunnel.png</key>
<key type="filename">sprites/misc/reader_overlay.png</key> <key type="filename">sprites/misc/reader_overlay.png</key>
<key type="filename">sprites/wires/lever_on.png</key> <key type="filename">sprites/wires/lever_on.png</key>
<key type="filename">sprites/wires/sets/color_cross.png</key>
<key type="filename">sprites/wires/sets/color_forward.png</key>
<key type="filename">sprites/wires/sets/color_split.png</key>
<key type="filename">sprites/wires/sets/color_turn.png</key>
<key type="filename">sprites/wires/sets/conflict_cross.png</key> <key type="filename">sprites/wires/sets/conflict_cross.png</key>
<key type="filename">sprites/wires/sets/conflict_forward.png</key> <key type="filename">sprites/wires/sets/conflict_forward.png</key>
<key type="filename">sprites/wires/sets/conflict_split.png</key> <key type="filename">sprites/wires/sets/conflict_split.png</key>
<key type="filename">sprites/wires/sets/conflict_turn.png</key> <key type="filename">sprites/wires/sets/conflict_turn.png</key>
<key type="filename">sprites/wires/sets/regular_cross.png</key> <key type="filename">sprites/wires/sets/first_cross.png</key>
<key type="filename">sprites/wires/sets/regular_forward.png</key> <key type="filename">sprites/wires/sets/first_forward.png</key>
<key type="filename">sprites/wires/sets/regular_split.png</key> <key type="filename">sprites/wires/sets/first_split.png</key>
<key type="filename">sprites/wires/sets/regular_turn.png</key> <key type="filename">sprites/wires/sets/first_turn.png</key>
<key type="filename">sprites/wires/sets/shape_cross.png</key> <key type="filename">sprites/wires/sets/second_cross.png</key>
<key type="filename">sprites/wires/sets/shape_forward.png</key> <key type="filename">sprites/wires/sets/second_forward.png</key>
<key type="filename">sprites/wires/sets/shape_split.png</key> <key type="filename">sprites/wires/sets/second_split.png</key>
<key type="filename">sprites/wires/sets/shape_turn.png</key> <key type="filename">sprites/wires/sets/second_turn.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>
<point_f>0.5,0.5</point_f> <point_f>0.5,0.5</point_f>
@ -346,20 +349,16 @@
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>
<key type="filename">sprites/blueprints/belt_left.png</key> <key type="filename">sprites/blueprints/balancer.png</key>
<key type="filename">sprites/blueprints/belt_right.png</key> <key type="filename">sprites/blueprints/cutter.png</key>
<key type="filename">sprites/blueprints/belt_top.png</key> <key type="filename">sprites/blueprints/filter.png</key>
<key type="filename">sprites/blueprints/wire-cross.png</key> <key type="filename">sprites/blueprints/mixer.png</key>
<key type="filename">sprites/blueprints/wire-split.png</key> <key type="filename">sprites/blueprints/painter-mirrored.png</key>
<key type="filename">sprites/blueprints/wire-turn.png</key> <key type="filename">sprites/blueprints/painter.png</key>
<key type="filename">sprites/blueprints/wire.png</key> <key type="filename">sprites/blueprints/stacker.png</key>
<key type="filename">sprites/buildings/belt_left.png</key> <key type="filename">sprites/buildings/balancer.png</key>
<key type="filename">sprites/buildings/belt_right.png</key> <key type="filename">sprites/buildings/filter.png</key>
<key type="filename">sprites/buildings/belt_top.png</key> <key type="filename">sprites/buildings/painter-mirrored.png</key>
<key type="filename">sprites/buildings/wire-cross.png</key>
<key type="filename">sprites/buildings/wire-split.png</key>
<key type="filename">sprites/buildings/wire-turn.png</key>
<key type="filename">sprites/buildings/wire.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>
<point_f>0.5,0.5</point_f> <point_f>0.5,0.5</point_f>
@ -368,9 +367,9 @@
<key>scale9Enabled</key> <key>scale9Enabled</key>
<false/> <false/>
<key>scale9Borders</key> <key>scale9Borders</key>
<rect>32,32,63,63</rect> <rect>96,48,192,96</rect>
<key>scale9Paddings</key> <key>scale9Paddings</key>
<rect>32,32,63,63</rect> <rect>96,48,192,96</rect>
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>
@ -392,15 +391,10 @@
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>
<key type="filename">sprites/blueprints/cutter.png</key> <key type="filename">sprites/blueprints/painter-double.png</key>
<key type="filename">sprites/blueprints/filter.png</key> <key type="filename">sprites/blueprints/storage.png</key>
<key type="filename">sprites/blueprints/mixer.png</key> <key type="filename">sprites/buildings/painter-double.png</key>
<key type="filename">sprites/blueprints/painter-mirrored.png</key> <key type="filename">sprites/buildings/storage.png</key>
<key type="filename">sprites/blueprints/painter.png</key>
<key type="filename">sprites/blueprints/splitter.png</key>
<key type="filename">sprites/blueprints/stacker.png</key>
<key type="filename">sprites/buildings/filter.png</key>
<key type="filename">sprites/buildings/painter-mirrored.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>
<point_f>0.5,0.5</point_f> <point_f>0.5,0.5</point_f>
@ -409,15 +403,15 @@
<key>scale9Enabled</key> <key>scale9Enabled</key>
<false/> <false/>
<key>scale9Borders</key> <key>scale9Borders</key>
<rect>96,48,192,96</rect> <rect>96,96,192,192</rect>
<key>scale9Paddings</key> <key>scale9Paddings</key>
<rect>96,48,192,96</rect> <rect>96,96,192,192</rect>
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>
<key type="filename">sprites/blueprints/painter-double.png</key> <key type="filename">sprites/buildings/belt_left.png</key>
<key type="filename">sprites/blueprints/trash-storage.png</key> <key type="filename">sprites/buildings/belt_right.png</key>
<key type="filename">sprites/buildings/painter-double.png</key> <key type="filename">sprites/buildings/belt_top.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>
<point_f>0.5,0.5</point_f> <point_f>0.5,0.5</point_f>
@ -426,16 +420,15 @@
<key>scale9Enabled</key> <key>scale9Enabled</key>
<false/> <false/>
<key>scale9Borders</key> <key>scale9Borders</key>
<rect>96,96,192,192</rect> <rect>32,32,63,63</rect>
<key>scale9Paddings</key> <key>scale9Paddings</key>
<rect>96,96,192,192</rect> <rect>32,32,63,63</rect>
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>
<key type="filename">sprites/buildings/cutter.png</key> <key type="filename">sprites/buildings/cutter.png</key>
<key type="filename">sprites/buildings/mixer.png</key> <key type="filename">sprites/buildings/mixer.png</key>
<key type="filename">sprites/buildings/painter.png</key> <key type="filename">sprites/buildings/painter.png</key>
<key type="filename">sprites/buildings/splitter.png</key>
<key type="filename">sprites/buildings/stacker.png</key> <key type="filename">sprites/buildings/stacker.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>
@ -488,7 +481,14 @@
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>
<key type="filename">sprites/buildings/trash-storage.png</key> <key type="filename">sprites/colors/blue.png</key>
<key type="filename">sprites/colors/cyan.png</key>
<key type="filename">sprites/colors/green.png</key>
<key type="filename">sprites/colors/purple.png</key>
<key type="filename">sprites/colors/red.png</key>
<key type="filename">sprites/colors/uncolored.png</key>
<key type="filename">sprites/colors/white.png</key>
<key type="filename">sprites/colors/yellow.png</key>
<struct type="IndividualSpriteSettings"> <struct type="IndividualSpriteSettings">
<key>pivotPoint</key> <key>pivotPoint</key>
<point_f>0.5,0.5</point_f> <point_f>0.5,0.5</point_f>
@ -497,9 +497,9 @@
<key>scale9Enabled</key> <key>scale9Enabled</key>
<false/> <false/>
<key>scale9Borders</key> <key>scale9Borders</key>
<rect>144,144,288,288</rect> <rect>18,18,36,36</rect>
<key>scale9Paddings</key> <key>scale9Paddings</key>
<rect>144,144,288,288</rect> <rect>18,18,36,36</rect>
<key>scale9FromFile</key> <key>scale9FromFile</key>
<false/> <false/>
</struct> </struct>

View File

@ -1,226 +1,212 @@
/** /**
* *
* Run `yarn global add canvas` first * Run `yarn global add canvas` first
*/ */
const { createCanvas } = require("canvas"); const { createCanvas } = require("canvas");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const outputFolder = path.join(__dirname, "..", "wires", "sets"); const outputFolder = path.join(__dirname, "..", "wires", "sets");
const dimensions = 192; const dimensions = 192;
const lineSize = 12; const lineSize = 14;
const lowerLineSize = 20; const lowerLineSize = 32;
function hexToRGB(h) { const variants = {
let r = 0, first: "#61ef6f",
g = 0, second: "#5fb2f1",
b = 0; conflict: "#f74c4c",
};
// 3 digits
if (h.length == 4) { function hexToRGB(h) {
r = "0x" + h[1] + h[1]; let r = 0,
g = "0x" + h[2] + h[2]; g = 0,
b = "0x" + h[3] + h[3]; b = 0;
// 6 digits // 3 digits
} else if (h.length == 7) { if (h.length == 4) {
r = "0x" + h[1] + h[2]; r = "0x" + h[1] + h[1];
g = "0x" + h[3] + h[4]; g = "0x" + h[2] + h[2];
b = "0x" + h[5] + h[6]; b = "0x" + h[3] + h[3];
}
// 6 digits
return [+r, +g, +b]; } else if (h.length == 7) {
} r = "0x" + h[1] + h[2];
g = "0x" + h[3] + h[4];
function RGBToHSL(r, g, b) { b = "0x" + h[5] + h[6];
// Make r, g, and b fractions of 1 }
r /= 255;
g /= 255; return [+r, +g, +b];
b /= 255; }
// Find greatest and smallest channel values function RGBToHSL(r, g, b) {
let cmin = Math.min(r, g, b), // Make r, g, and b fractions of 1
cmax = Math.max(r, g, b), r /= 255;
delta = cmax - cmin, g /= 255;
h = 0, b /= 255;
s = 0,
l = 0; // Find greatest and smallest channel values
// Calculate hue let cmin = Math.min(r, g, b),
// No difference cmax = Math.max(r, g, b),
if (delta == 0) h = 0; delta = cmax - cmin,
// Red is max h = 0,
else if (cmax == r) h = ((g - b) / delta) % 6; s = 0,
// Green is max l = 0;
else if (cmax == g) h = (b - r) / delta + 2; // Calculate hue
// Blue is max // No difference
else h = (r - g) / delta + 4; if (delta == 0) h = 0;
// Red is max
h = Math.round(h * 60); else if (cmax == r) h = ((g - b) / delta) % 6;
// Green is max
// Make negative hues positive behind 360° else if (cmax == g) h = (b - r) / delta + 2;
if (h < 0) h += 360; // Blue is max
else h = (r - g) / delta + 4;
// Calculate lightness
l = (cmax + cmin) / 2; h = Math.round(h * 60);
// Calculate saturation // Make negative hues positive behind 360°
s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); if (h < 0) h += 360;
// Multiply l and s by 100 // Calculate lightness
s = +(s * 100).toFixed(1); l = (cmax + cmin) / 2;
l = +(l * 100).toFixed(1);
// Calculate saturation
return [h, s, l]; s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
}
// Multiply l and s by 100
function HSLToRGB(h, s, l) { s = +(s * 100).toFixed(1);
// Must be fractions of 1 l = +(l * 100).toFixed(1);
s /= 100;
l /= 100; return [h, s, l];
}
let c = (1 - Math.abs(2 * l - 1)) * s,
x = c * (1 - Math.abs(((h / 60) % 2) - 1)), function HSLToRGB(h, s, l) {
m = l - c / 2, // Must be fractions of 1
r = 0, s /= 100;
g = 0, l /= 100;
b = 0;
let c = (1 - Math.abs(2 * l - 1)) * s,
if (0 <= h && h < 60) { x = c * (1 - Math.abs(((h / 60) % 2) - 1)),
r = c; m = l - c / 2,
g = x; r = 0,
b = 0; g = 0,
} else if (60 <= h && h < 120) { b = 0;
r = x;
g = c; if (0 <= h && h < 60) {
b = 0; r = c;
} else if (120 <= h && h < 180) { g = x;
r = 0; b = 0;
g = c; } else if (60 <= h && h < 120) {
b = x; r = x;
} else if (180 <= h && h < 240) { g = c;
r = 0; b = 0;
g = x; } else if (120 <= h && h < 180) {
b = c; r = 0;
} else if (240 <= h && h < 300) { g = c;
r = x; b = x;
g = 0; } else if (180 <= h && h < 240) {
b = c; r = 0;
} else if (300 <= h && h < 360) { g = x;
r = c; b = c;
g = 0; } else if (240 <= h && h < 300) {
b = x; r = x;
} g = 0;
r = Math.round((r + m) * 255); b = c;
g = Math.round((g + m) * 255); } else if (300 <= h && h < 360) {
b = Math.round((b + m) * 255); r = c;
g = 0;
return [r, g, b]; b = x;
} }
r = Math.round((r + m) * 255);
async function run() { g = Math.round((g + m) * 255);
console.log("Running"); b = Math.round((b + m) * 255);
const variants = { return [r, g, b];
regular: "#25fff2", }
color: "#eba458",
shape: "#8858eb", async function run() {
conflict: "#ff3e3e", console.log("Running");
};
const promises = [];
const promises = [];
for (const variantId in variants) {
for (const variantId in variants) { const variantColor = variants[variantId];
const variantColor = variants[variantId]; const variantHSL = RGBToHSL(...hexToRGB(variantColor));
const variantHSL = RGBToHSL(...hexToRGB(variantColor)); const darkenedColor = HSLToRGB(variantHSL[0], variantHSL[1] - 15, variantHSL[2] - 20);
const darkenedColor = HSLToRGB(variantHSL[0], variantHSL[1] - 15, variantHSL[2] - 20); const hexDarkenedColor = "rgb(" + darkenedColor.join(",") + ")";
const hexDarkenedColor = "rgb(" + darkenedColor.join(",") + ")";
console.log(variantColor, "->", hexToRGB(variantColor), variantHSL, "->", darkenedColor);
console.log(variantColor, "->", hexToRGB(variantColor), variantHSL, "->", darkenedColor);
const parts = {
const parts = { forward: [[0.5, 0, 0.5, 1]],
forward: [[0.5, 0, 0.5, 1]], turn: [
turn: [ [0.5, 0.5, 0.5, 1],
[0.5, 0.5, 0.5, 1], [0.5, 0.5, 1, 0.5],
[0.5, 0.5, 1, 0.5], ],
], split: [
split: [ [0.5, 0.5, 0.5, 1],
[0.5, 0.5, 0.5, 1], [0, 0.5, 1, 0.5],
[0, 0.5, 1, 0.5], ],
], cross: [
cross: [ [0, 0.5, 1, 0.5],
[0, 0.5, 1, 0.5], [0.5, 0, 0.5, 1],
[0.5, 0, 0.5, 1], ],
], };
};
for (const partId in parts) {
for (const partId in parts) { const partLines = parts[partId];
const partLines = parts[partId];
const canvas = createCanvas(dimensions, dimensions);
const canvas = createCanvas(dimensions, dimensions); const context = canvas.getContext("2d");
const context = canvas.getContext("2d"); context.quality = "best";
context.quality = "best"; context.clearRect(0, 0, dimensions, dimensions);
context.clearRect(0, 0, dimensions, dimensions);
const lineCanvas = createCanvas(dimensions, dimensions);
context.strokeStyle = hexDarkenedColor; const lineContext = lineCanvas.getContext("2d");
context.lineWidth = lowerLineSize; lineContext.quality = "best";
context.lineCap = "square"; lineContext.clearRect(0, 0, dimensions, dimensions);
context.imageSmoothingEnabled = false; lineContext.strokeStyle = hexDarkenedColor;
lineContext.lineWidth = lowerLineSize;
// Draw lower lines lineContext.lineCap = "square";
partLines.forEach(([x1, y1, x2, y2]) => { lineContext.imageSmoothingEnabled = false;
context.beginPath();
context.moveTo(x1 * dimensions, y1 * dimensions); // Draw lower lines
context.lineTo(x2 * dimensions, y2 * dimensions); partLines.forEach(([x1, y1, x2, y2]) => {
context.stroke(); lineContext.beginPath();
}); lineContext.moveTo(x1 * dimensions, y1 * dimensions);
lineContext.lineTo(x2 * dimensions, y2 * dimensions);
context.strokeStyle = variantColor; lineContext.stroke();
context.lineWidth = lineSize; });
// Draw upper lines context.globalAlpha = 0.4;
partLines.forEach(([x1, y1, x2, y2]) => { context.drawImage(lineCanvas, 0, 0, dimensions, dimensions);
context.beginPath();
context.moveTo(x1 * dimensions, y1 * dimensions); context.globalAlpha = 1;
context.lineTo(x2 * dimensions, y2 * dimensions); context.imageSmoothingEnabled = false;
context.stroke(); context.lineCap = "square";
}); context.strokeStyle = variantColor;
context.lineWidth = lineSize;
const out = fs.createWriteStream(path.join(outputFolder, variantId + "_" + partId + ".png"));
const stream = canvas.createPNGStream(); // Draw upper lines
stream.pipe(out); partLines.forEach(([x1, y1, x2, y2]) => {
promises.push(new Promise(resolve => stream.on("end", resolve))); context.beginPath();
} context.moveTo(x1 * dimensions, y1 * dimensions);
} context.lineTo(x2 * dimensions, y2 * dimensions);
context.stroke();
console.log("Waiting for completion"); });
await Promise.all(promises);
const out = fs.createWriteStream(path.join(outputFolder, variantId + "_" + partId + ".png"));
// Also wait a bit more const stream = canvas.createPNGStream();
await new Promise(resolve => setTimeout(resolve, 1000)); stream.pipe(out);
promises.push(new Promise(resolve => stream.on("end", resolve)));
console.log("Copying files to all locations"); }
}
// // Copy other files
fs.copyFileSync( console.log("Waiting for completion");
path.join(outputFolder, "regular_forward.png"), await Promise.all(promises);
path.join(__dirname, "..", "buildings", "wire.png")
); console.log("Done!");
fs.copyFileSync( }
path.join(outputFolder, "regular_turn.png"),
path.join(__dirname, "..", "buildings", "wire-turn.png") run();
);
fs.copyFileSync(
path.join(outputFolder, "regular_split.png"),
path.join(__dirname, "..", "buildings", "wire-split.png")
);
fs.copyFileSync(
path.join(outputFolder, "regular_cross.png"),
path.join(__dirname, "..", "buildings", "wire-cross.png")
);
console.log("Done!");
}
run();

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Some files were not shown because too many files have changed in this diff Show More