mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-13 18:21:51 +00:00
Squashed commit of the following:
commit 176343785eea110e529f26027bf864ae04068384
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Fri Dec 8 23:03:51 2023 -0600
update readme
commit 8c1c3a0c47f5125126cb00d32a48f4f9344a3fb3
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Fri Dec 8 23:00:05 2023 -0600
fix bugs
commit ea881e68c693a447e0698a3a6e7cfb1f25ccb6cc
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Fri Dec 8 22:46:46 2023 -0600
expose all tasks with old api
commit fa6d7a3920ff573eadb61425cc077f0e00406164
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Fri Dec 8 21:51:20 2023 -0600
switch to exported gulp tasks
commit 348b19a0171e65400bcd434cf7b7432f3488a411
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Mon Nov 20 22:55:38 2023 -0600
parallelize dev build
commit 56de73e2d18d20e5ea7202afc021573a746e5012
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Mon Nov 20 20:44:10 2023 -0600
use promises in gulpfile
commit 6ab54372482f26acb4769428eefbdc48240a12a1
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Mon Nov 20 20:33:36 2023 -0600
make java -version print again
commit b0e4cf57bdc404bb3b0e45b7b233d5f7648c800e
Author: EmeraldBlock <yygengjunior@gmail.com>
Date: Mon Nov 20 20:14:13 2023 -0600
use promises for gulp tasks
This commit is contained in:
parent
b5a7f7736a
commit
39b7e6cb59
@ -57,8 +57,7 @@ and does not intend to provide compatibility for older clients.
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- [ffmpeg](https://www.ffmpeg.org/download.html)
|
- [ffmpeg](https://www.ffmpeg.org/download.html)
|
||||||
- [Node.js 16](https://nodejs.org/en/about/previous-releases)
|
- [Node.js](https://nodejs.org)
|
||||||
(not 17+, see <https://github.com/tobspr-games/shapez.io/issues/1473>)
|
|
||||||
- [Yarn 1](https://classic.yarnpkg.com/en/docs/install) (not 2, we haven't migrated yet)
|
- [Yarn 1](https://classic.yarnpkg.com/en/docs/install) (not 2, we haven't migrated yet)
|
||||||
- [Java](https://www.oracle.com/java/technologies/downloads/) (or [OpenJDK](https://openjdk.org/)) to run the texture packer
|
- [Java](https://www.oracle.com/java/technologies/downloads/) (or [OpenJDK](https://openjdk.org/)) to run the texture packer
|
||||||
- [cURL](https://curl.se/download.html)[^1] to download the texture packer
|
- [cURL](https://curl.se/download.html)[^1] to download the texture packer
|
||||||
|
|||||||
44
gulp/config.js
Normal file
44
gulp/config.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import path from "path/posix";
|
||||||
|
import BrowserSync from "browser-sync";
|
||||||
|
|
||||||
|
export const baseDir = path.resolve("..");
|
||||||
|
export const buildFolder = path.join(baseDir, "build");
|
||||||
|
export const buildOutputFolder = path.join(baseDir, "build_output");
|
||||||
|
|
||||||
|
// Globs for atlas resources
|
||||||
|
export const rawImageResourcesGlobs = ["../res_raw/atlas.json", "../res_raw/**/*.png"];
|
||||||
|
|
||||||
|
// Globs for non-ui resources
|
||||||
|
export const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
|
||||||
|
|
||||||
|
// Globs for ui resources
|
||||||
|
export const imageResourcesGlobs = [
|
||||||
|
"../res/**/*.png",
|
||||||
|
"../res/**/*.svg",
|
||||||
|
"../res/**/*.jpg",
|
||||||
|
"../res/**/*.gif",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const browserSync = BrowserSync.create({});
|
||||||
|
|
||||||
|
// Check environment variables
|
||||||
|
|
||||||
|
const envVars = [
|
||||||
|
"SHAPEZ_CLI_SERVER_HOST",
|
||||||
|
"SHAPEZ_CLI_ALPHA_FTP_USER",
|
||||||
|
"SHAPEZ_CLI_ALPHA_FTP_PW",
|
||||||
|
"SHAPEZ_CLI_STAGING_FTP_USER",
|
||||||
|
"SHAPEZ_CLI_STAGING_FTP_PW",
|
||||||
|
"SHAPEZ_CLI_LIVE_FTP_USER",
|
||||||
|
"SHAPEZ_CLI_LIVE_FTP_PW",
|
||||||
|
"SHAPEZ_CLI_APPLE_ID",
|
||||||
|
"SHAPEZ_CLI_APPLE_CERT_NAME",
|
||||||
|
"SHAPEZ_CLI_GITHUB_USER",
|
||||||
|
"SHAPEZ_CLI_GITHUB_TOKEN",
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < envVars.length; ++i) {
|
||||||
|
if (!process.env[envVars[i]]) {
|
||||||
|
console.warn("Unset environment variable, might cause issues:", envVars[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
188
gulp/css.js
188
gulp/css.js
@ -1,5 +1,7 @@
|
|||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
|
import gulp from "gulp";
|
||||||
import { getRevision } from "./buildutils.js";
|
import { getRevision } from "./buildutils.js";
|
||||||
|
import { buildFolder, browserSync } from "./config.js";
|
||||||
|
|
||||||
import gulpPostcss from "gulp-postcss";
|
import gulpPostcss from "gulp-postcss";
|
||||||
import postcssAssets from "postcss-assets";
|
import postcssAssets from "postcss-assets";
|
||||||
@ -13,112 +15,106 @@ import gulpDartSass from "gulp-dart-sass";
|
|||||||
import gulpPlumber from "gulp-plumber";
|
import gulpPlumber from "gulp-plumber";
|
||||||
import gulpRename from "gulp-rename";
|
import gulpRename from "gulp-rename";
|
||||||
|
|
||||||
export default function gulptasksCSS(gulp, buildFolder, browserSync) {
|
// The assets plugin copies the files
|
||||||
// The assets plugin copies the files
|
const commitHash = getRevision();
|
||||||
const commitHash = getRevision();
|
const postcssAssetsPlugin = postcssAssets({
|
||||||
const postcssAssetsPlugin = postcssAssets({
|
loadPaths: [path.join(buildFolder, "res", "ui")],
|
||||||
loadPaths: [path.join(buildFolder, "res", "ui")],
|
basePath: buildFolder,
|
||||||
basePath: buildFolder,
|
baseUrl: ".",
|
||||||
baseUrl: ".",
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Postcss configuration
|
// Postcss configuration
|
||||||
const postcssPlugins = prod => {
|
const postcssPlugins = prod => {
|
||||||
const plugins = [postcssAssetsPlugin];
|
const plugins = [postcssAssetsPlugin];
|
||||||
if (prod) {
|
if (prod) {
|
||||||
plugins.unshift(
|
plugins.unshift(
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Performs linting on css
|
|
||||||
gulp.task("css.lint", () => {
|
|
||||||
return gulp
|
|
||||||
.src(["../src/css/**/*.scss"])
|
|
||||||
.pipe(gulpSassLint({ configFile: ".sasslint.yml" }))
|
|
||||||
.pipe(gulpSassLint.format())
|
|
||||||
.pipe(gulpSassLint.failOnError());
|
|
||||||
});
|
|
||||||
|
|
||||||
function resourcesTask({ isProd }) {
|
|
||||||
return gulp
|
|
||||||
.src("../src/css/main.scss")
|
|
||||||
.pipe(gulpPlumber())
|
|
||||||
.pipe(gulpDartSass.sync().on("error", gulpDartSass.logError))
|
|
||||||
.pipe(
|
|
||||||
gulpPostcss([
|
|
||||||
postcssCriticalSplit({
|
|
||||||
blockTag: "@load-async",
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.pipe(gulpRename("async-resources.css"))
|
|
||||||
.pipe(gulpPostcss(postcssPlugins(isProd)))
|
|
||||||
.pipe(gulp.dest(buildFolder))
|
|
||||||
.pipe(browserSync.stream());
|
|
||||||
}
|
}
|
||||||
|
return plugins;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Performs linting on css
|
||||||
|
export function lint() {
|
||||||
|
return gulp
|
||||||
|
.src(["../src/css/**/*.scss"])
|
||||||
|
.pipe(gulpSassLint({ configFile: ".sasslint.yml" }))
|
||||||
|
.pipe(gulpSassLint.format())
|
||||||
|
.pipe(gulpSassLint.failOnError());
|
||||||
|
}
|
||||||
|
|
||||||
|
function resourcesTask({ isProd }) {
|
||||||
|
return gulp
|
||||||
|
.src("../src/css/main.scss")
|
||||||
|
.pipe(gulpPlumber())
|
||||||
|
.pipe(gulpDartSass.sync().on("error", gulpDartSass.logError))
|
||||||
|
.pipe(
|
||||||
|
gulpPostcss([
|
||||||
|
postcssCriticalSplit({
|
||||||
|
blockTag: "@load-async",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
.pipe(gulpRename("async-resources.css"))
|
||||||
|
.pipe(gulpPostcss(postcssPlugins(isProd)))
|
||||||
|
.pipe(gulp.dest(buildFolder))
|
||||||
|
.pipe(browserSync.stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
export const resources = {
|
||||||
// Builds the css resources
|
// Builds the css resources
|
||||||
gulp.task("css.resources.dev", () => {
|
dev: () => resourcesTask({ isProd: false }),
|
||||||
return resourcesTask({ isProd: false });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Builds the css resources in prod (=minified)
|
// Builds the css resources in prod (=minified)
|
||||||
gulp.task("css.resources.prod", () => {
|
prod: () => resourcesTask({ isProd: true }),
|
||||||
return resourcesTask({ isProd: true });
|
};
|
||||||
});
|
|
||||||
|
|
||||||
function mainTask({ isProd }) {
|
function mainTask({ isProd }) {
|
||||||
return gulp
|
return gulp
|
||||||
.src("../src/css/main.scss")
|
.src("../src/css/main.scss")
|
||||||
.pipe(gulpPlumber())
|
.pipe(gulpPlumber())
|
||||||
.pipe(gulpDartSass.sync().on("error", gulpDartSass.logError))
|
.pipe(gulpDartSass.sync().on("error", gulpDartSass.logError))
|
||||||
.pipe(
|
.pipe(
|
||||||
gulpPostcss([
|
gulpPostcss([
|
||||||
postcssCriticalSplit({
|
postcssCriticalSplit({
|
||||||
blockTag: "@load-async",
|
blockTag: "@load-async",
|
||||||
output: "rest",
|
output: "rest",
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
.pipe(gulpPostcss(postcssPlugins(isProd)))
|
.pipe(gulpPostcss(postcssPlugins(isProd)))
|
||||||
.pipe(gulp.dest(buildFolder))
|
.pipe(gulp.dest(buildFolder))
|
||||||
.pipe(browserSync.stream());
|
.pipe(browserSync.stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const main = {
|
||||||
// Builds the css main
|
// Builds the css main
|
||||||
gulp.task("css.main.dev", () => {
|
dev: () => mainTask({ isProd: false }),
|
||||||
return mainTask({ isProd: false });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Builds the css main in prod (=minified)
|
// Builds the css main in prod (=minified)
|
||||||
gulp.task("css.main.prod", () => {
|
prod: () => mainTask({ isProd: true }),
|
||||||
return mainTask({ isProd: true });
|
};
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("css.dev", gulp.parallel("css.main.dev", "css.resources.dev"));
|
export const dev = gulp.parallel(main.dev, resources.dev);
|
||||||
gulp.task("css.prod", gulp.parallel("css.main.prod", "css.resources.prod"));
|
export const prod = gulp.parallel(main.prod, resources.prod);
|
||||||
}
|
|
||||||
|
|||||||
62
gulp/docs.js
62
gulp/docs.js
@ -1,38 +1,36 @@
|
|||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import fs from "fs";
|
import fs from "fs/promises";
|
||||||
|
import gulp from "gulp";
|
||||||
|
|
||||||
import gulpRename from "gulp-rename";
|
import gulpRename from "gulp-rename";
|
||||||
import stripJsonComments from "strip-json-comments";
|
import stripJsonComments from "strip-json-comments";
|
||||||
|
|
||||||
export default function gulptasksDocs(gulp, buildFolder) {
|
export function convertJsToTs() {
|
||||||
gulp.task("docs.convertJsToTs", () => {
|
return gulp
|
||||||
return gulp
|
.src(path.join("..", "src", "js", "**", "*.js"))
|
||||||
.src(path.join("..", "src", "js", "**", "*.js"))
|
.pipe(
|
||||||
.pipe(
|
gulpRename(path => {
|
||||||
gulpRename(path => {
|
path.extname = ".ts";
|
||||||
path.extname = ".ts";
|
})
|
||||||
})
|
)
|
||||||
)
|
.pipe(gulp.dest(path.join("..", "tsc_temp")));
|
||||||
.pipe(gulp.dest(path.join("..", "tsc_temp")));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("docs.copyTsconfigForHints", cb => {
|
|
||||||
const src = fs.readFileSync(path.join("..", "src", "js", "tsconfig.json")).toString();
|
|
||||||
const baseConfig = JSON.parse(stripJsonComments(src));
|
|
||||||
|
|
||||||
baseConfig.allowJs = false;
|
|
||||||
baseConfig.checkJs = false;
|
|
||||||
baseConfig.declaration = true;
|
|
||||||
baseConfig.noEmit = false;
|
|
||||||
baseConfig.strict = false;
|
|
||||||
baseConfig.strictFunctionTypes = false;
|
|
||||||
baseConfig.strictBindCallApply = false;
|
|
||||||
baseConfig.alwaysStrict = false;
|
|
||||||
baseConfig.composite = true;
|
|
||||||
baseConfig.outFile = "bundled-ts.js";
|
|
||||||
fs.writeFileSync(path.join("..", "tsc_temp", "tsconfig.json"), JSON.stringify(baseConfig));
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("main.prepareDocs", gulp.series("docs.convertJsToTs", "docs.copyTsconfigForHints"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function copyTsconfigForHints() {
|
||||||
|
const src = (await fs.readFile(path.join("..", "src", "js", "tsconfig.json"))).toString();
|
||||||
|
const baseConfig = JSON.parse(stripJsonComments(src));
|
||||||
|
|
||||||
|
baseConfig.allowJs = false;
|
||||||
|
baseConfig.checkJs = false;
|
||||||
|
baseConfig.declaration = true;
|
||||||
|
baseConfig.noEmit = false;
|
||||||
|
baseConfig.strict = false;
|
||||||
|
baseConfig.strictFunctionTypes = false;
|
||||||
|
baseConfig.strictBindCallApply = false;
|
||||||
|
baseConfig.alwaysStrict = false;
|
||||||
|
baseConfig.composite = true;
|
||||||
|
baseConfig.outFile = "bundled-ts.js";
|
||||||
|
await fs.writeFile(path.join("..", "tsc_temp", "tsconfig.json"), JSON.stringify(baseConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const prepareDocs = gulp.series(convertJsToTs, copyTsconfigForHints);
|
||||||
|
|||||||
137
gulp/ftp.js
137
gulp/ftp.js
@ -1,68 +1,69 @@
|
|||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import fs from "fs";
|
import fs from "fs/promises";
|
||||||
|
import gulp from "gulp";
|
||||||
|
import { buildFolder } from "./config.js";
|
||||||
|
|
||||||
import { getRevision, getVersion } from "./buildutils.js";
|
import { getRevision, getVersion } from "./buildutils.js";
|
||||||
|
|
||||||
import gulpRename from "gulp-rename";
|
import gulpRename from "gulp-rename";
|
||||||
import gulpSftp from "gulp-sftp";
|
import gulpSftp from "gulp-sftp";
|
||||||
|
|
||||||
export default function gulptasksFTP(gulp, buildFolder) {
|
const commitHash = getRevision();
|
||||||
const commitHash = getRevision();
|
|
||||||
|
|
||||||
const additionalFolder = path.join("additional_build_files");
|
const additionalFolder = path.join("additional_build_files");
|
||||||
|
|
||||||
const additionalFiles = [
|
const additionalGlobs = [
|
||||||
path.join(additionalFolder, "*"),
|
path.join(additionalFolder, "*"),
|
||||||
path.join(additionalFolder, "*.*"),
|
path.join(additionalFolder, "*.*"),
|
||||||
path.join(additionalFolder, ".*"),
|
path.join(additionalFolder, ".*"),
|
||||||
];
|
];
|
||||||
|
|
||||||
const credentials = {
|
const credentials = {
|
||||||
alpha: {
|
alpha: {
|
||||||
host: process.env.SHAPEZ_CLI_SERVER_HOST,
|
host: process.env.SHAPEZ_CLI_SERVER_HOST,
|
||||||
user: process.env.SHAPEZ_CLI_ALPHA_FTP_USER,
|
user: process.env.SHAPEZ_CLI_ALPHA_FTP_USER,
|
||||||
pass: process.env.SHAPEZ_CLI_ALPHA_FTP_PW,
|
pass: process.env.SHAPEZ_CLI_ALPHA_FTP_PW,
|
||||||
},
|
},
|
||||||
staging: {
|
staging: {
|
||||||
host: process.env.SHAPEZ_CLI_SERVER_HOST,
|
host: process.env.SHAPEZ_CLI_SERVER_HOST,
|
||||||
user: process.env.SHAPEZ_CLI_STAGING_FTP_USER,
|
user: process.env.SHAPEZ_CLI_STAGING_FTP_USER,
|
||||||
pass: process.env.SHAPEZ_CLI_STAGING_FTP_PW,
|
pass: process.env.SHAPEZ_CLI_STAGING_FTP_PW,
|
||||||
},
|
},
|
||||||
prod: {
|
prod: {
|
||||||
host: process.env.SHAPEZ_CLI_SERVER_HOST,
|
host: process.env.SHAPEZ_CLI_SERVER_HOST,
|
||||||
user: process.env.SHAPEZ_CLI_LIVE_FTP_USER,
|
user: process.env.SHAPEZ_CLI_LIVE_FTP_USER,
|
||||||
pass: process.env.SHAPEZ_CLI_LIVE_FTP_PW,
|
pass: process.env.SHAPEZ_CLI_LIVE_FTP_PW,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the "commit.txt" file
|
// Write the "commit.txt" file
|
||||||
gulp.task("ftp.writeVersion", cb => {
|
export async function writeVersion() {
|
||||||
fs.writeFileSync(
|
await fs.writeFile(
|
||||||
path.join(buildFolder, "version.json"),
|
path.join(buildFolder, "version.json"),
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
{
|
{
|
||||||
commit: getRevision(),
|
commit: getRevision(),
|
||||||
appVersion: getVersion(),
|
appVersion: getVersion(),
|
||||||
buildTime: new Date().getTime(),
|
buildTime: new Date().getTime(),
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
4
|
4
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
cb();
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const gameSrcGlobs = [
|
const gameSrcGlobs = [
|
||||||
path.join(buildFolder, "**/*.*"),
|
path.join(buildFolder, "**/*.*"),
|
||||||
path.join(buildFolder, "**/.*"),
|
path.join(buildFolder, "**/.*"),
|
||||||
path.join(buildFolder, "**/*"),
|
path.join(buildFolder, "**/*"),
|
||||||
path.join(buildFolder, "!**/index.html"),
|
path.join(buildFolder, "!**/index.html"),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const deployEnv of ["alpha", "prod", "staging"]) {
|
export const upload = Object.fromEntries(
|
||||||
|
["alpha", "prod", "staging"].map(deployEnv => {
|
||||||
const deployCredentials = credentials[deployEnv];
|
const deployCredentials = credentials[deployEnv];
|
||||||
|
|
||||||
gulp.task(`ftp.upload.${deployEnv}.game`, () => {
|
function game() {
|
||||||
return gulp
|
return gulp
|
||||||
.src(gameSrcGlobs, { base: buildFolder })
|
.src(gameSrcGlobs, { base: buildFolder })
|
||||||
.pipe(
|
.pipe(
|
||||||
@ -71,30 +72,28 @@ export default function gulptasksFTP(gulp, buildFolder) {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulpSftp(deployCredentials));
|
.pipe(gulpSftp(deployCredentials));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task(`ftp.upload.${deployEnv}.indexHtml`, () => {
|
function indexHtml() {
|
||||||
return gulp
|
return gulp
|
||||||
.src([path.join(buildFolder, "index.html"), path.join(buildFolder, "version.json")], {
|
.src([path.join(buildFolder, "index.html"), path.join(buildFolder, "version.json")], {
|
||||||
base: buildFolder,
|
base: buildFolder,
|
||||||
})
|
})
|
||||||
.pipe(gulpSftp(deployCredentials));
|
.pipe(gulpSftp(deployCredentials));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task(`ftp.upload.${deployEnv}.additionalFiles`, () => {
|
function additionalFiles() {
|
||||||
return gulp
|
return gulp.src(additionalGlobs, { base: additionalFolder }).pipe(gulpSftp(deployCredentials));
|
||||||
.src(additionalFiles, { base: additionalFolder }) //
|
}
|
||||||
.pipe(gulpSftp(deployCredentials));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(
|
return [
|
||||||
`ftp.upload.${deployEnv}`,
|
deployEnv,
|
||||||
gulp.series(
|
{
|
||||||
"ftp.writeVersion",
|
game,
|
||||||
`ftp.upload.${deployEnv}.game`,
|
indexHtml,
|
||||||
`ftp.upload.${deployEnv}.indexHtml`,
|
additionalFiles,
|
||||||
`ftp.upload.${deployEnv}.additionalFiles`
|
all: gulp.series(writeVersion, game, indexHtml, additionalFiles),
|
||||||
)
|
},
|
||||||
);
|
];
|
||||||
}
|
})
|
||||||
}
|
);
|
||||||
|
|||||||
310
gulp/gulpfile.js
310
gulp/gulpfile.js
@ -1,303 +1,23 @@
|
|||||||
import gulp from "gulp";
|
import gulp from "gulp";
|
||||||
import BrowserSync from "browser-sync";
|
import * as tasks from "./tasks.js";
|
||||||
const browserSync = BrowserSync.create({});
|
|
||||||
import path from "path/posix";
|
|
||||||
import pathNative from "path";
|
|
||||||
import deleteEmpty from "delete-empty";
|
|
||||||
import { execSync } from "child_process";
|
|
||||||
|
|
||||||
// Load other plugins
|
|
||||||
import gulpClean from "gulp-clean";
|
|
||||||
import gulpWebserver from "gulp-webserver";
|
|
||||||
|
|
||||||
// Check environment variables
|
|
||||||
|
|
||||||
const envVars = [
|
|
||||||
"SHAPEZ_CLI_SERVER_HOST",
|
|
||||||
"SHAPEZ_CLI_ALPHA_FTP_USER",
|
|
||||||
"SHAPEZ_CLI_ALPHA_FTP_PW",
|
|
||||||
"SHAPEZ_CLI_STAGING_FTP_USER",
|
|
||||||
"SHAPEZ_CLI_STAGING_FTP_PW",
|
|
||||||
"SHAPEZ_CLI_LIVE_FTP_USER",
|
|
||||||
"SHAPEZ_CLI_LIVE_FTP_PW",
|
|
||||||
"SHAPEZ_CLI_APPLE_ID",
|
|
||||||
"SHAPEZ_CLI_APPLE_CERT_NAME",
|
|
||||||
"SHAPEZ_CLI_GITHUB_USER",
|
|
||||||
"SHAPEZ_CLI_GITHUB_TOKEN",
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i = 0; i < envVars.length; ++i) {
|
|
||||||
if (!process.env[envVars[i]]) {
|
|
||||||
console.warn("Unset environment variable, might cause issues:", envVars[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseDir = path.resolve("..");
|
|
||||||
const buildFolder = path.join(baseDir, "build");
|
|
||||||
const buildOuptutFolder = path.join(baseDir, "build_output");
|
|
||||||
|
|
||||||
import gulptasksImageResources, * as imgres from "./image-resources.js";
|
|
||||||
gulptasksImageResources(gulp, buildFolder);
|
|
||||||
|
|
||||||
import gulptasksCSS from "./css.js";
|
|
||||||
gulptasksCSS(gulp, buildFolder, browserSync);
|
|
||||||
|
|
||||||
import gulptasksSounds from "./sounds.js";
|
|
||||||
gulptasksSounds(gulp, buildFolder);
|
|
||||||
|
|
||||||
import gulptasksLocalConfig from "./local-config.js";
|
|
||||||
gulptasksLocalConfig(gulp);
|
|
||||||
|
|
||||||
import gulptasksJS from "./js.js";
|
|
||||||
gulptasksJS(gulp, buildFolder, browserSync);
|
|
||||||
|
|
||||||
import gulptasksHTML from "./html.js";
|
|
||||||
gulptasksHTML(gulp, buildFolder);
|
|
||||||
|
|
||||||
import gulptasksFTP from "./ftp.js";
|
|
||||||
gulptasksFTP(gulp, buildFolder);
|
|
||||||
|
|
||||||
import gulptasksDocs from "./docs.js";
|
|
||||||
gulptasksDocs(gulp, buildFolder);
|
|
||||||
|
|
||||||
import gulptasksStandalone from "./standalone.js";
|
|
||||||
gulptasksStandalone(gulp);
|
|
||||||
|
|
||||||
import gulptasksTranslations from "./translations.js";
|
|
||||||
import { BUILD_VARIANTS } from "./build_variants.js";
|
|
||||||
gulptasksTranslations(gulp);
|
|
||||||
|
|
||||||
///////////////////// BUILD TASKS /////////////////////
|
|
||||||
|
|
||||||
// Cleans up everything
|
|
||||||
gulp.task("utils.cleanBuildFolder", () => {
|
|
||||||
return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
|
||||||
});
|
|
||||||
gulp.task("utils.cleanBuildOutputFolder", () => {
|
|
||||||
return gulp.src(buildOuptutFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
|
||||||
});
|
|
||||||
gulp.task("utils.cleanBuildTempFolder", () => {
|
|
||||||
return gulp
|
|
||||||
.src(path.join("..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
|
|
||||||
.pipe(gulpClean({ force: true }));
|
|
||||||
});
|
|
||||||
gulp.task("utils.cleanImageBuildFolder", () => {
|
|
||||||
return gulp
|
|
||||||
.src(path.join("res_built"), { read: false, allowEmpty: true })
|
|
||||||
.pipe(gulpClean({ force: true }));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"utils.cleanup",
|
|
||||||
gulp.series("utils.cleanBuildFolder", "utils.cleanImageBuildFolder", "utils.cleanBuildTempFolder")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Requires no uncomitted files
|
|
||||||
gulp.task("utils.requireCleanWorkingTree", cb => {
|
|
||||||
let output = execSync("git status -su").toString("ascii").trim().replace(/\r/gi, "").split("\n");
|
|
||||||
|
|
||||||
// Filter files which are OK to be untracked
|
|
||||||
output = output
|
|
||||||
.map(x => x.replace(/[\r\n]+/gi, ""))
|
|
||||||
.filter(x => x.indexOf(".local.js") < 0)
|
|
||||||
.filter(x => x.length > 0);
|
|
||||||
if (output.length > 0) {
|
|
||||||
console.error("\n\nYou have unstaged changes, please commit everything first!");
|
|
||||||
console.error("Unstaged files:");
|
|
||||||
console.error(output.map(x => "'" + x + "'").join("\n"));
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("utils.copyAdditionalBuildFiles", cb => {
|
|
||||||
const additionalFolder = path.join("additional_build_files");
|
|
||||||
const additionalSrcGlobs = [
|
|
||||||
path.join(additionalFolder, "**/*.*"),
|
|
||||||
path.join(additionalFolder, "**/.*"),
|
|
||||||
path.join(additionalFolder, "**/*"),
|
|
||||||
];
|
|
||||||
|
|
||||||
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Starts a webserver on the built directory (useful for testing prod build)
|
|
||||||
gulp.task("main.webserver", () => {
|
|
||||||
return gulp.src(buildFolder).pipe(
|
|
||||||
gulpWebserver({
|
|
||||||
livereload: {
|
|
||||||
enable: true,
|
|
||||||
},
|
|
||||||
directoryListing: false,
|
|
||||||
open: true,
|
|
||||||
port: 3005,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @typedef {import("gulp").TaskFunction} TaskFunction
|
||||||
* @param {object} param0
|
* @typedef {TaskFunction | { [k: string]: Tasks }} Tasks
|
||||||
* @param {keyof typeof BUILD_VARIANTS} param0.version
|
|
||||||
*/
|
*/
|
||||||
function serveHTML({ version = "web-dev" }) {
|
|
||||||
browserSync.init({
|
|
||||||
server: [buildFolder, path.join(baseDir, "mod_examples")],
|
|
||||||
port: 3005,
|
|
||||||
ghostMode: {
|
|
||||||
clicks: false,
|
|
||||||
scroll: false,
|
|
||||||
location: false,
|
|
||||||
forms: false,
|
|
||||||
},
|
|
||||||
logLevel: "info",
|
|
||||||
logPrefix: "BS",
|
|
||||||
online: false,
|
|
||||||
xip: false,
|
|
||||||
notify: false,
|
|
||||||
reloadDebounce: 100,
|
|
||||||
reloadOnRestart: true,
|
|
||||||
watchEvents: ["add", "change"],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Watch .scss files, those trigger a css rebuild
|
/**
|
||||||
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
|
* @param {Tasks} tasks
|
||||||
|
* @param {string=} prefix
|
||||||
// Watch .html files, those trigger a html rebuild
|
*/
|
||||||
gulp.watch("../src/**/*.html", gulp.series("html.dev"));
|
function register(tasks, prefix) {
|
||||||
gulp.watch("./preloader/*.*", gulp.series("html.dev"));
|
if (tasks instanceof Function) {
|
||||||
|
gulp.task(prefix, tasks);
|
||||||
// Watch translations
|
return;
|
||||||
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
|
}
|
||||||
|
for (const [k, v] of Object.entries(tasks)) {
|
||||||
gulp.watch(
|
register(v, prefix == null ? k : `${prefix}.${k}`);
|
||||||
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
|
|
||||||
gulp.series("sounds.sfx", "sounds.copy")
|
|
||||||
);
|
|
||||||
gulp.watch(
|
|
||||||
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
|
|
||||||
gulp.series("sounds.music", "sounds.copy")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Watch resource files and copy them on change
|
|
||||||
gulp.watch(imgres.rawImageResourcesGlobs, gulp.series("imgres.buildAtlas"));
|
|
||||||
gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources"));
|
|
||||||
gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
|
|
||||||
|
|
||||||
// Watch .atlas files and recompile the atlas on change
|
|
||||||
gulp.watch("../res_built/atlas/*.atlas", gulp.series("imgres.atlasToJson"));
|
|
||||||
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
|
|
||||||
|
|
||||||
// Watch the build folder and reload when anything changed
|
|
||||||
const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"];
|
|
||||||
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (p) {
|
|
||||||
return gulp
|
|
||||||
.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep))
|
|
||||||
.pipe(browserSync.reload({ stream: true }));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.watch("../src/js/built-temp/*.json").on("change", function (p) {
|
|
||||||
return gulp
|
|
||||||
.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep))
|
|
||||||
.pipe(browserSync.reload({ stream: true }));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.series("js." + version + ".dev.watch")(() => true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre and postbuild
|
|
||||||
gulp.task("step.baseResources", gulp.series("imgres.allOptimized"));
|
|
||||||
gulp.task("step.deleteEmpty", cb => {
|
|
||||||
deleteEmpty.sync(buildFolder);
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
|
|
||||||
|
|
||||||
///////////////////// RUNNABLE TASKS /////////////////////
|
|
||||||
|
|
||||||
// Builds everything (dev)
|
|
||||||
gulp.task(
|
|
||||||
"build.prepare.dev",
|
|
||||||
gulp.series(
|
|
||||||
"utils.cleanup",
|
|
||||||
"utils.copyAdditionalBuildFiles",
|
|
||||||
"localConfig.findOrCreate",
|
|
||||||
"imgres.buildAtlas",
|
|
||||||
"imgres.atlasToJson",
|
|
||||||
"imgres.atlas",
|
|
||||||
"sounds.dev",
|
|
||||||
"imgres.copyImageResources",
|
|
||||||
"imgres.copyNonImageResources",
|
|
||||||
"translations.fullBuild",
|
|
||||||
"css.dev"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Builds everything for every variant
|
|
||||||
for (const variant in BUILD_VARIANTS) {
|
|
||||||
const data = BUILD_VARIANTS[variant];
|
|
||||||
const buildName = "build." + variant;
|
|
||||||
|
|
||||||
// build
|
|
||||||
gulp.task(
|
|
||||||
buildName + ".code",
|
|
||||||
gulp.series(
|
|
||||||
data.standalone ? "sounds.fullbuildHQ" : "sounds.fullbuild",
|
|
||||||
"translations.fullBuild",
|
|
||||||
"js." + variant + ".prod"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task(buildName + ".resourcesAndCode", gulp.parallel("step.baseResources", buildName + ".code"));
|
|
||||||
|
|
||||||
gulp.task(buildName + ".all", gulp.series(buildName + ".resourcesAndCode", "css.prod", "html.prod"));
|
|
||||||
|
|
||||||
gulp.task(buildName, gulp.series("utils.cleanup", buildName + ".all", "step.postbuild"));
|
|
||||||
|
|
||||||
// Tasks for creating packages. These packages are already distributable, but usually can be further
|
|
||||||
// wrapped in a different format (an installer for Windows, tarball for Linux, DMG for macOS).
|
|
||||||
if (data.standalone) {
|
|
||||||
const packageTasks = [
|
|
||||||
"win32-x64",
|
|
||||||
"win32-arm64",
|
|
||||||
"linux-x64",
|
|
||||||
"linux-arm64",
|
|
||||||
"darwin-x64",
|
|
||||||
"darwin-arm64",
|
|
||||||
"all",
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const task of packageTasks) {
|
|
||||||
gulp.task(
|
|
||||||
`package.${variant}.${task}`,
|
|
||||||
gulp.series(
|
|
||||||
"localConfig.findOrCreate",
|
|
||||||
`build.${variant}`,
|
|
||||||
"utils.cleanBuildOutputFolder",
|
|
||||||
`standalone.${variant}.prepare`,
|
|
||||||
`standalone.${variant}.package.${task}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serve
|
|
||||||
gulp.task(
|
|
||||||
"serve." + variant,
|
|
||||||
gulp.series("build.prepare.dev", "html.dev", () => serveHTML({ version: variant }))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deploying!
|
register(tasks);
|
||||||
gulp.task(
|
|
||||||
"deploy.staging",
|
|
||||||
gulp.series("utils.requireCleanWorkingTree", "build.web-shapezio-beta", "ftp.upload.staging")
|
|
||||||
);
|
|
||||||
gulp.task(
|
|
||||||
"deploy.prod",
|
|
||||||
gulp.series("utils.requireCleanWorkingTree", "build.web-shapezio", "ftp.upload.prod")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Default task (dev, localhost)
|
|
||||||
gulp.task("default", gulp.series("serve.standalone-steam"));
|
|
||||||
|
|||||||
144
gulp/html.js
144
gulp/html.js
@ -2,6 +2,8 @@ import { getRevision } from "./buildutils.js";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
import gulp from "gulp";
|
||||||
|
import { buildFolder } from "./config.js";
|
||||||
|
|
||||||
import gulpDom from "gulp-dom";
|
import gulpDom from "gulp-dom";
|
||||||
import gulpHtmlmin from "gulp-htmlmin";
|
import gulpHtmlmin from "gulp-htmlmin";
|
||||||
@ -20,32 +22,31 @@ function computeIntegrityHash(fullPath, algorithm = "sha256") {
|
|||||||
* html.dev
|
* html.dev
|
||||||
* html.prod
|
* html.prod
|
||||||
*/
|
*/
|
||||||
export default function gulptasksHTML(gulp, buildFolder) {
|
const commitHash = getRevision();
|
||||||
const commitHash = getRevision();
|
async function buildHtml({ integrity = true }) {
|
||||||
async function buildHtml({ integrity = true }) {
|
return gulp
|
||||||
return gulp
|
.src("../src/html/index.html")
|
||||||
.src("../src/html/index.html")
|
.pipe(
|
||||||
.pipe(
|
gulpDom(
|
||||||
gulpDom(
|
/** @this {Document} **/ function () {
|
||||||
/** @this {Document} **/ function () {
|
const document = this;
|
||||||
const document = this;
|
|
||||||
|
|
||||||
// Append css
|
// Append css
|
||||||
const css = document.createElement("link");
|
const css = document.createElement("link");
|
||||||
css.rel = "stylesheet";
|
css.rel = "stylesheet";
|
||||||
css.type = "text/css";
|
css.type = "text/css";
|
||||||
css.media = "none";
|
css.media = "none";
|
||||||
css.setAttribute("onload", "this.media='all'");
|
css.setAttribute("onload", "this.media='all'");
|
||||||
css.href = "main.css";
|
css.href = "main.css";
|
||||||
if (integrity) {
|
if (integrity) {
|
||||||
css.setAttribute(
|
css.setAttribute(
|
||||||
"integrity",
|
"integrity",
|
||||||
computeIntegrityHash(path.join(buildFolder, "main.css"))
|
computeIntegrityHash(path.join(buildFolder, "main.css"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
document.head.appendChild(css);
|
document.head.appendChild(css);
|
||||||
|
|
||||||
let fontCss = `
|
let fontCss = `
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "GameFont";
|
font-family: "GameFont";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@ -54,59 +55,54 @@ export default function gulptasksHTML(gulp, buildFolder) {
|
|||||||
src: url('res/fonts/GameFont.woff2') format("woff2");
|
src: url('res/fonts/GameFont.woff2') format("woff2");
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
let loadingCss =
|
let loadingCss =
|
||||||
fontCss + fs.readFileSync(path.join("preloader", "preloader.css")).toString();
|
fontCss + fs.readFileSync(path.join("preloader", "preloader.css")).toString();
|
||||||
|
|
||||||
const style = document.createElement("style");
|
const style = document.createElement("style");
|
||||||
style.setAttribute("type", "text/css");
|
style.setAttribute("type", "text/css");
|
||||||
style.textContent = loadingCss;
|
style.textContent = loadingCss;
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
let bodyContent = fs
|
let bodyContent = fs.readFileSync(path.join("preloader", "preloader.html")).toString();
|
||||||
.readFileSync(path.join("preloader", "preloader.html"))
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
const bundleScript = document.createElement("script");
|
const bundleScript = document.createElement("script");
|
||||||
bundleScript.type = "text/javascript";
|
bundleScript.type = "text/javascript";
|
||||||
bundleScript.src = "bundle.js";
|
bundleScript.src = "bundle.js";
|
||||||
if (integrity) {
|
if (integrity) {
|
||||||
bundleScript.setAttribute(
|
bundleScript.setAttribute(
|
||||||
"integrity",
|
"integrity",
|
||||||
computeIntegrityHash(path.join(buildFolder, "bundle.js"))
|
computeIntegrityHash(path.join(buildFolder, "bundle.js"))
|
||||||
);
|
);
|
||||||
}
|
|
||||||
document.head.appendChild(bundleScript);
|
|
||||||
|
|
||||||
document.body.innerHTML = bodyContent;
|
|
||||||
}
|
}
|
||||||
)
|
document.head.appendChild(bundleScript);
|
||||||
)
|
|
||||||
.pipe(
|
|
||||||
gulpHtmlmin({
|
|
||||||
caseSensitive: true,
|
|
||||||
collapseBooleanAttributes: true,
|
|
||||||
collapseInlineTagWhitespace: true,
|
|
||||||
collapseWhitespace: true,
|
|
||||||
preserveLineBreaks: true,
|
|
||||||
minifyJS: true,
|
|
||||||
minifyCSS: true,
|
|
||||||
quoteCharacter: '"',
|
|
||||||
useShortDoctype: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(gulpHtmlBeautify())
|
|
||||||
.pipe(gulpRename("index.html"))
|
|
||||||
.pipe(gulp.dest(buildFolder));
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.task("html.dev", () => {
|
document.body.innerHTML = bodyContent;
|
||||||
return buildHtml({
|
}
|
||||||
integrity: false,
|
)
|
||||||
});
|
)
|
||||||
});
|
.pipe(
|
||||||
gulp.task("html.prod", () => {
|
gulpHtmlmin({
|
||||||
return buildHtml({
|
caseSensitive: true,
|
||||||
integrity: true,
|
collapseBooleanAttributes: true,
|
||||||
});
|
collapseInlineTagWhitespace: true,
|
||||||
});
|
collapseWhitespace: true,
|
||||||
|
preserveLineBreaks: true,
|
||||||
|
minifyJS: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
quoteCharacter: '"',
|
||||||
|
useShortDoctype: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.pipe(gulpHtmlBeautify())
|
||||||
|
.pipe(gulpRename("index.html"))
|
||||||
|
.pipe(gulp.dest(buildFolder));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dev = () =>
|
||||||
|
buildHtml({
|
||||||
|
integrity: false,
|
||||||
|
});
|
||||||
|
export const prod = () =>
|
||||||
|
buildHtml({
|
||||||
|
integrity: true,
|
||||||
|
});
|
||||||
|
|||||||
@ -1,12 +1,19 @@
|
|||||||
import fs from "fs";
|
import fs from "fs/promises";
|
||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import atlasToJson from "./atlas2json.js";
|
import gulp from "gulp";
|
||||||
|
import { buildFolder } from "./config.js";
|
||||||
|
import atlas2Json from "./atlas2json.js";
|
||||||
|
|
||||||
import { execSync } from "child_process";
|
import childProcess from "child_process";
|
||||||
const execute = command =>
|
import { promisify } from "util";
|
||||||
execSync(command, {
|
const exec = promisify(childProcess.exec);
|
||||||
|
const execute = command => {
|
||||||
|
const promise = exec(command, {
|
||||||
encoding: "utf-8",
|
encoding: "utf-8",
|
||||||
});
|
});
|
||||||
|
promise.child.stderr.pipe(process.stderr);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
import gulpImagemin from "gulp-imagemin";
|
import gulpImagemin from "gulp-imagemin";
|
||||||
import imageminJpegtran from "imagemin-jpegtran";
|
import imageminJpegtran from "imagemin-jpegtran";
|
||||||
@ -15,182 +22,161 @@ import imageminPngquant from "imagemin-pngquant";
|
|||||||
import gulpIf from "gulp-if";
|
import gulpIf from "gulp-if";
|
||||||
import gulpCached from "gulp-cached";
|
import gulpCached from "gulp-cached";
|
||||||
import gulpClean from "gulp-clean";
|
import gulpClean from "gulp-clean";
|
||||||
|
import { nonImageResourcesGlobs, imageResourcesGlobs } from "./config.js";
|
||||||
// Globs for atlas resources
|
|
||||||
export const rawImageResourcesGlobs = ["../res_raw/atlas.json", "../res_raw/**/*.png"];
|
|
||||||
|
|
||||||
// Globs for non-ui resources
|
|
||||||
export const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
|
|
||||||
|
|
||||||
// Globs for ui resources
|
|
||||||
export const imageResourcesGlobs = [
|
|
||||||
"../res/**/*.png",
|
|
||||||
"../res/**/*.svg",
|
|
||||||
"../res/**/*.jpg",
|
|
||||||
"../res/**/*.gif",
|
|
||||||
];
|
|
||||||
|
|
||||||
// Link to download LibGDX runnable-texturepacker.jar
|
// Link to download LibGDX runnable-texturepacker.jar
|
||||||
const runnableTPSource =
|
const runnableTPSource =
|
||||||
"https://libgdx-nightlies.s3.eu-central-1.amazonaws.com/libgdx-runnables/runnable-texturepacker.jar";
|
"https://libgdx-nightlies.s3.eu-central-1.amazonaws.com/libgdx-runnables/runnable-texturepacker.jar";
|
||||||
|
|
||||||
export default function gulptasksImageResources(gulp, buildFolder) {
|
// Lossless options
|
||||||
// Lossless options
|
const minifyImagesOptsLossless = () => [
|
||||||
const minifyImagesOptsLossless = () => [
|
imageminJpegtran({
|
||||||
imageminJpegtran({
|
progressive: true,
|
||||||
progressive: true,
|
}),
|
||||||
}),
|
gulpImagemin.svgo({}),
|
||||||
gulpImagemin.svgo({}),
|
gulpImagemin.optipng({
|
||||||
gulpImagemin.optipng({
|
optimizationLevel: 3,
|
||||||
optimizationLevel: 3,
|
}),
|
||||||
}),
|
imageminGifsicle({
|
||||||
imageminGifsicle({
|
optimizationLevel: 3,
|
||||||
optimizationLevel: 3,
|
colors: 128,
|
||||||
colors: 128,
|
}),
|
||||||
}),
|
];
|
||||||
];
|
|
||||||
|
|
||||||
// Lossy options
|
// Lossy options
|
||||||
const minifyImagesOpts = () => [
|
const minifyImagesOpts = () => [
|
||||||
gulpImagemin.mozjpeg({
|
gulpImagemin.mozjpeg({
|
||||||
quality: 80,
|
quality: 80,
|
||||||
maxMemory: 1024 * 1024 * 8,
|
maxMemory: 1024 * 1024 * 8,
|
||||||
}),
|
}),
|
||||||
gulpImagemin.svgo({}),
|
gulpImagemin.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,
|
||||||
}),
|
}),
|
||||||
gulpImagemin.optipng({
|
gulpImagemin.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 /////////////////////
|
||||||
|
|
||||||
gulp.task("imgres.buildAtlas", cb => {
|
export async function buildAtlas() {
|
||||||
const config = JSON.stringify("../res_raw/atlas.json");
|
const config = JSON.stringify("../res_raw/atlas.json");
|
||||||
const source = JSON.stringify("../res_raw");
|
const source = JSON.stringify("../res_raw");
|
||||||
const dest = JSON.stringify("../res_built/atlas");
|
const dest = JSON.stringify("../res_built/atlas");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First check whether Java is installed
|
// First check whether Java is installed
|
||||||
execute("java -version");
|
await execute("java -version");
|
||||||
// Now check and try downloading runnable-texturepacker.jar (22MB)
|
// Now check and try downloading runnable-texturepacker.jar (22MB)
|
||||||
if (!fs.existsSync("./runnable-texturepacker.jar")) {
|
try {
|
||||||
const escapedLink = JSON.stringify(runnableTPSource);
|
await fs.access("./runnable-texturepacker.jar");
|
||||||
|
} catch {
|
||||||
try {
|
const escapedLink = JSON.stringify(runnableTPSource);
|
||||||
execute(`curl -o runnable-texturepacker.jar ${escapedLink}`);
|
|
||||||
} catch {
|
try {
|
||||||
throw new Error("Failed to download runnable-texturepacker.jar!");
|
execute(`curl -o runnable-texturepacker.jar ${escapedLink}`);
|
||||||
}
|
} catch {
|
||||||
}
|
throw new Error("Failed to download runnable-texturepacker.jar!");
|
||||||
|
}
|
||||||
execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`);
|
}
|
||||||
} catch {
|
|
||||||
console.warn("Building atlas failed. Java not found / unsupported version?");
|
await execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`);
|
||||||
}
|
} catch {
|
||||||
cb();
|
console.warn("Building atlas failed. Java not found / unsupported version?");
|
||||||
});
|
}
|
||||||
|
}
|
||||||
// Converts .atlas LibGDX files to JSON
|
|
||||||
gulp.task("imgres.atlasToJson", cb => {
|
// Converts .atlas LibGDX files to JSON
|
||||||
atlasToJson("../res_built/atlas");
|
export async function atlasToJson() {
|
||||||
cb();
|
atlas2Json("../res_built/atlas");
|
||||||
});
|
}
|
||||||
|
|
||||||
// Copies the atlas to the final destination
|
// Copies the atlas to the final destination
|
||||||
gulp.task("imgres.atlas", () => {
|
export function atlas() {
|
||||||
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
|
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
|
||||||
});
|
}
|
||||||
|
|
||||||
// Copies the atlas to the final destination after optimizing it (lossy compression)
|
// Copies the atlas to the final destination after optimizing it (lossy compression)
|
||||||
gulp.task("imgres.atlasOptimized", () => {
|
export function atlasOptimized() {
|
||||||
return gulp
|
return gulp
|
||||||
.src(["../res_built/atlas/*.png"])
|
.src(["../res_built/atlas/*.png"])
|
||||||
.pipe(
|
.pipe(
|
||||||
gulpIf(
|
gulpIf(
|
||||||
fname => fileMustBeLossless(fname.history[0]),
|
fname => fileMustBeLossless(fname.history[0]),
|
||||||
gulpImagemin(minifyImagesOptsLossless()),
|
gulpImagemin(minifyImagesOptsLossless()),
|
||||||
gulpImagemin(minifyImagesOpts())
|
gulpImagemin(minifyImagesOpts())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(resourcesDestFolder));
|
.pipe(gulp.dest(resourcesDestFolder));
|
||||||
});
|
}
|
||||||
|
|
||||||
//////////////////// RESOURCES //////////////////////
|
//////////////////// RESOURCES //////////////////////
|
||||||
|
|
||||||
// Copies all resources which are no ui resources
|
// Copies all resources which are no ui resources
|
||||||
gulp.task("imgres.copyNonImageResources", () => {
|
export function copyNonImageResources() {
|
||||||
return gulp.src(nonImageResourcesGlobs).pipe(gulp.dest(resourcesDestFolder));
|
return gulp.src(nonImageResourcesGlobs).pipe(gulp.dest(resourcesDestFolder));
|
||||||
});
|
}
|
||||||
|
|
||||||
// Copies all ui resources
|
// Copies all ui resources
|
||||||
gulp.task("imgres.copyImageResources", () => {
|
export function copyImageResources() {
|
||||||
return gulp
|
return gulp
|
||||||
.src(imageResourcesGlobs)
|
.src(imageResourcesGlobs)
|
||||||
|
.pipe(gulpCached("imgres.copyImageResources"))
|
||||||
.pipe(gulpCached("imgres.copyImageResources"))
|
.pipe(gulp.dest(path.join(resourcesDestFolder)));
|
||||||
.pipe(gulp.dest(path.join(resourcesDestFolder)));
|
}
|
||||||
});
|
|
||||||
|
// Copies all ui resources and optimizes them
|
||||||
// Copies all ui resources and optimizes them
|
export function copyImageResourcesOptimized() {
|
||||||
gulp.task("imgres.copyImageResourcesOptimized", () => {
|
return gulp
|
||||||
return gulp
|
.src(imageResourcesGlobs)
|
||||||
.src(imageResourcesGlobs)
|
.pipe(
|
||||||
.pipe(
|
gulpIf(
|
||||||
gulpIf(
|
fname => fileMustBeLossless(fname.history[0]),
|
||||||
fname => fileMustBeLossless(fname.history[0]),
|
gulpImagemin(minifyImagesOptsLossless()),
|
||||||
gulpImagemin(minifyImagesOptsLossless()),
|
gulpImagemin(minifyImagesOpts())
|
||||||
gulpImagemin(minifyImagesOpts())
|
)
|
||||||
)
|
)
|
||||||
)
|
.pipe(gulp.dest(path.join(resourcesDestFolder)));
|
||||||
.pipe(gulp.dest(path.join(resourcesDestFolder)));
|
}
|
||||||
});
|
|
||||||
|
// Copies all resources and optimizes them
|
||||||
// Copies all resources and optimizes them
|
export const allOptimized = gulp.parallel(
|
||||||
gulp.task(
|
gulp.series(buildAtlas, atlasToJson, atlasOptimized),
|
||||||
"imgres.allOptimized",
|
copyNonImageResources,
|
||||||
gulp.parallel(
|
copyImageResourcesOptimized
|
||||||
"imgres.buildAtlas",
|
);
|
||||||
"imgres.atlasToJson",
|
|
||||||
"imgres.atlasOptimized",
|
// Cleans up unused images which are instead inline into the css
|
||||||
"imgres.copyNonImageResources",
|
export function cleanupUnusedCssInlineImages() {
|
||||||
"imgres.copyImageResourcesOptimized"
|
return gulp
|
||||||
)
|
.src(
|
||||||
);
|
[
|
||||||
|
path.join(buildFolder, "res", "ui", "**", "*.png"),
|
||||||
// Cleans up unused images which are instead inline into the css
|
path.join(buildFolder, "res", "ui", "**", "*.jpg"),
|
||||||
gulp.task("imgres.cleanupUnusedCssInlineImages", () => {
|
path.join(buildFolder, "res", "ui", "**", "*.svg"),
|
||||||
return gulp
|
path.join(buildFolder, "res", "ui", "**", "*.gif"),
|
||||||
.src(
|
],
|
||||||
[
|
{ read: false }
|
||||||
path.join(buildFolder, "res", "ui", "**", "*.png"),
|
)
|
||||||
path.join(buildFolder, "res", "ui", "**", "*.jpg"),
|
.pipe(gulpIf(fname => fname.history[0].indexOf("noinline") < 0, gulpClean({ force: true })));
|
||||||
path.join(buildFolder, "res", "ui", "**", "*.svg"),
|
|
||||||
path.join(buildFolder, "res", "ui", "**", "*.gif"),
|
|
||||||
],
|
|
||||||
{ read: false }
|
|
||||||
)
|
|
||||||
.pipe(gulpIf(fname => fname.history[0].indexOf("noinline") < 0, gulpClean({ force: true })));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
77
gulp/js.js
77
gulp/js.js
@ -1,4 +1,6 @@
|
|||||||
|
import gulp from "gulp";
|
||||||
import { BUILD_VARIANTS } from "./build_variants.js";
|
import { BUILD_VARIANTS } from "./build_variants.js";
|
||||||
|
import { buildFolder, browserSync } from "./config.js";
|
||||||
|
|
||||||
import webpackConfig from "./webpack.config.js";
|
import webpackConfig from "./webpack.config.js";
|
||||||
import webpackProductionConfig from "./webpack.production.config.js";
|
import webpackProductionConfig from "./webpack.production.config.js";
|
||||||
@ -15,64 +17,69 @@ import gulpRename from "gulp-rename";
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default function gulptasksJS(gulp, buildFolder, browserSync) {
|
//// DEV
|
||||||
//// DEV
|
|
||||||
|
|
||||||
for (const variant in BUILD_VARIANTS) {
|
export default Object.fromEntries(
|
||||||
const data = BUILD_VARIANTS[variant];
|
Object.entries(BUILD_VARIANTS).map(([variant, data]) => {
|
||||||
|
function watch() {
|
||||||
gulp.task("js." + variant + ".dev.watch", () => {
|
return gulp
|
||||||
gulp.src("../src/js/main.js")
|
.src("../src/js/main.js")
|
||||||
.pipe(webpackStream(webpackConfig))
|
.pipe(webpackStream(webpackConfig))
|
||||||
.pipe(gulp.dest(buildFolder))
|
.pipe(gulp.dest(buildFolder))
|
||||||
.pipe(browserSync.stream());
|
.pipe(browserSync.stream());
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
return gulp
|
||||||
|
.src("../src/js/main.js")
|
||||||
|
.pipe(webpackStream(webpackConfig))
|
||||||
|
.pipe(gulp.dest(buildFolder));
|
||||||
|
}
|
||||||
|
|
||||||
|
const dev = {
|
||||||
|
watch,
|
||||||
|
build,
|
||||||
|
};
|
||||||
|
|
||||||
|
let prod;
|
||||||
if (!data.standalone) {
|
if (!data.standalone) {
|
||||||
// WEB
|
// WEB
|
||||||
|
|
||||||
gulp.task("js." + variant + ".dev", () => {
|
function transpiled() {
|
||||||
return gulp
|
|
||||||
.src("../src/js/main.js")
|
|
||||||
.pipe(webpackStream(webpackConfig))
|
|
||||||
.pipe(gulp.dest(buildFolder));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("js." + variant + ".prod.transpiled", () => {
|
|
||||||
return gulp
|
return gulp
|
||||||
.src("../src/js/main.js")
|
.src("../src/js/main.js")
|
||||||
.pipe(webpackStream(webpackProductionConfig))
|
.pipe(webpackStream(webpackProductionConfig))
|
||||||
.pipe(gulpRename("bundle-transpiled.js"))
|
.pipe(gulpRename("bundle-transpiled.js"))
|
||||||
.pipe(gulp.dest(buildFolder));
|
.pipe(gulp.dest(buildFolder));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task("js." + variant + ".prod.es6", () => {
|
function es6() {
|
||||||
return gulp
|
return gulp
|
||||||
.src("../src/js/main.js")
|
.src("../src/js/main.js")
|
||||||
.pipe(webpackStream(webpackProductionConfig))
|
.pipe(webpackStream(webpackProductionConfig))
|
||||||
.pipe(gulp.dest(buildFolder));
|
.pipe(gulp.dest(buildFolder));
|
||||||
});
|
}
|
||||||
gulp.task(
|
|
||||||
"js." + variant + ".prod",
|
|
||||||
|
|
||||||
// transpiled currently not used
|
prod = {
|
||||||
// gulp.parallel("js." + variant + ".prod.transpiled", "js." + variant + ".prod.es6")
|
transpiled,
|
||||||
gulp.parallel("js." + variant + ".prod.es6")
|
es6,
|
||||||
);
|
build:
|
||||||
|
// transpiled currently not used
|
||||||
|
// gulp.parallel("js." + variant + ".prod.transpiled", "js." + variant + ".prod.es6")
|
||||||
|
es6,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
// STANDALONE
|
// STANDALONE
|
||||||
gulp.task("js." + variant + ".dev", () => {
|
function build() {
|
||||||
return gulp
|
|
||||||
.src("../src/js/main.js")
|
|
||||||
.pipe(webpackStream(webpackConfig))
|
|
||||||
.pipe(gulp.dest(buildFolder));
|
|
||||||
});
|
|
||||||
gulp.task("js." + variant + ".prod", () => {
|
|
||||||
return gulp
|
return gulp
|
||||||
.src("../src/js/main.js")
|
.src("../src/js/main.js")
|
||||||
.pipe(webpackStream(webpackProductionConfig))
|
.pipe(webpackStream(webpackProductionConfig))
|
||||||
.pipe(gulp.dest(buildFolder));
|
.pipe(gulp.dest(buildFolder));
|
||||||
});
|
}
|
||||||
|
|
||||||
|
prod = { build };
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
return [variant, { dev, prod }];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
import fs from "fs";
|
import fs from "fs/promises";
|
||||||
|
|
||||||
const configTemplatePath = "../src/js/core/config.local.template.js";
|
const configTemplatePath = "../src/js/core/config.local.template.js";
|
||||||
const configPath = "../src/js/core/config.local.js";
|
const configPath = "../src/js/core/config.local.js";
|
||||||
|
|
||||||
export default function gulptasksLocalConfig(gulp) {
|
export async function findOrCreate() {
|
||||||
gulp.task("localConfig.findOrCreate", cb => {
|
try {
|
||||||
if (!fs.existsSync(configPath)) {
|
await fs.copyFile(configTemplatePath, configPath, fs.constants.COPYFILE_EXCL);
|
||||||
fs.copyFileSync(configTemplatePath, configPath);
|
} catch {}
|
||||||
}
|
|
||||||
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
229
gulp/sounds.js
229
gulp/sounds.js
@ -1,135 +1,132 @@
|
|||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import audiosprite from "gulp-audiosprite";
|
import gulp from "gulp";
|
||||||
|
import { buildFolder } from "./config.js";
|
||||||
|
|
||||||
|
import gulpAudiosprite from "gulp-audiosprite";
|
||||||
import gulpClean from "gulp-clean";
|
import gulpClean from "gulp-clean";
|
||||||
import gulpCache from "gulp-cache";
|
import gulpCache from "gulp-cache";
|
||||||
import gulpPlumber from "gulp-plumber";
|
import gulpPlumber from "gulp-plumber";
|
||||||
import gulpFluentFfmpeg from "gulp-fluent-ffmpeg";
|
import gulpFluentFfmpeg from "gulp-fluent-ffmpeg";
|
||||||
|
|
||||||
export default function gulptasksSounds(gulp, buildFolder) {
|
// Gather some basic infos
|
||||||
// Gather some basic infos
|
const soundsDir = path.join("..", "res_raw", "sounds");
|
||||||
const soundsDir = path.join("..", "res_raw", "sounds");
|
const builtSoundsDir = path.join("..", "res_built", "sounds");
|
||||||
const builtSoundsDir = path.join("..", "res_built", "sounds");
|
|
||||||
|
|
||||||
gulp.task("sounds.clear", () => {
|
export function clear() {
|
||||||
return gulp.src(builtSoundsDir, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
return gulp.src(builtSoundsDir, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
||||||
});
|
}
|
||||||
|
|
||||||
const filters = ["volume=0.2"];
|
const filters = ["volume=0.2"];
|
||||||
|
|
||||||
const fileCache = new gulpCache.Cache({
|
const fileCache = new gulpCache.Cache({
|
||||||
cacheDirName: "shapezio-precompiled-sounds",
|
cacheDirName: "shapezio-precompiled-sounds",
|
||||||
});
|
});
|
||||||
|
|
||||||
function getFileCacheValue(file) {
|
function getFileCacheValue(file) {
|
||||||
const { _isVinyl, base, cwd, contents, history, stat, path } = file;
|
const { _isVinyl, base, cwd, contents, history, stat, path } = file;
|
||||||
const encodedContents = Buffer.from(contents).toString("base64");
|
const encodedContents = Buffer.from(contents).toString("base64");
|
||||||
return { _isVinyl, base, cwd, contents: encodedContents, history, stat, path };
|
return { _isVinyl, base, cwd, contents: encodedContents, history, stat, path };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encodes the game music
|
// Encodes the game music
|
||||||
gulp.task("sounds.music", () => {
|
export function music() {
|
||||||
return gulp
|
return gulp
|
||||||
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
|
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
|
||||||
.pipe(gulpPlumber())
|
.pipe(gulpPlumber())
|
||||||
.pipe(
|
.pipe(
|
||||||
gulpCache(
|
gulpCache(
|
||||||
gulpFluentFfmpeg("mp3", function (cmd) {
|
|
||||||
return cmd
|
|
||||||
.audioBitrate(48)
|
|
||||||
.audioChannels(1)
|
|
||||||
.audioFrequency(22050)
|
|
||||||
.audioCodec("libmp3lame")
|
|
||||||
.audioFilters(["volume=0.15"]);
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "music",
|
|
||||||
fileCache,
|
|
||||||
value: getFileCacheValue,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Encodes the game music in high quality for the standalone
|
|
||||||
gulp.task("sounds.musicHQ", () => {
|
|
||||||
return gulp
|
|
||||||
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
|
|
||||||
.pipe(gulpPlumber())
|
|
||||||
.pipe(
|
|
||||||
gulpCache(
|
|
||||||
gulpFluentFfmpeg("mp3", function (cmd) {
|
|
||||||
return cmd
|
|
||||||
.audioBitrate(256)
|
|
||||||
.audioChannels(2)
|
|
||||||
.audioFrequency(44100)
|
|
||||||
.audioCodec("libmp3lame")
|
|
||||||
.audioFilters(["volume=0.15"]);
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "music-high-quality",
|
|
||||||
fileCache,
|
|
||||||
value: getFileCacheValue,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Encodes the ui sounds
|
|
||||||
gulp.task("sounds.sfxGenerateSprites", () => {
|
|
||||||
return gulp
|
|
||||||
.src([path.join(soundsDir, "sfx", "**", "*.wav"), path.join(soundsDir, "sfx", "**", "*.mp3")])
|
|
||||||
.pipe(gulpPlumber())
|
|
||||||
.pipe(
|
|
||||||
audiosprite({
|
|
||||||
format: "howler",
|
|
||||||
output: "sfx",
|
|
||||||
gap: 0.1,
|
|
||||||
export: "mp3",
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(gulp.dest(path.join(builtSoundsDir)));
|
|
||||||
});
|
|
||||||
gulp.task("sounds.sfxOptimize", () => {
|
|
||||||
return gulp
|
|
||||||
.src([path.join(builtSoundsDir, "sfx.mp3")])
|
|
||||||
.pipe(gulpPlumber())
|
|
||||||
.pipe(
|
|
||||||
gulpFluentFfmpeg("mp3", function (cmd) {
|
gulpFluentFfmpeg("mp3", function (cmd) {
|
||||||
return cmd
|
return cmd
|
||||||
.audioBitrate(128)
|
.audioBitrate(48)
|
||||||
.audioChannels(1)
|
.audioChannels(1)
|
||||||
.audioFrequency(22050)
|
.audioFrequency(22050)
|
||||||
.audioCodec("libmp3lame")
|
.audioCodec("libmp3lame")
|
||||||
.audioFilters(filters);
|
.audioFilters(["volume=0.15"]);
|
||||||
})
|
}),
|
||||||
|
{
|
||||||
|
name: "music",
|
||||||
|
fileCache,
|
||||||
|
value: getFileCacheValue,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(path.join(builtSoundsDir)));
|
)
|
||||||
});
|
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
|
||||||
gulp.task("sounds.sfxCopyAtlas", () => {
|
|
||||||
return gulp
|
|
||||||
.src([path.join(builtSoundsDir, "sfx.json")])
|
|
||||||
.pipe(gulp.dest(path.join("..", "src", "js", "built-temp")));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"sounds.sfx",
|
|
||||||
gulp.series("sounds.sfxGenerateSprites", "sounds.sfxOptimize", "sounds.sfxCopyAtlas")
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task("sounds.copy", () => {
|
|
||||||
return gulp
|
|
||||||
.src(path.join(builtSoundsDir, "**", "*.mp3"))
|
|
||||||
.pipe(gulpPlumber())
|
|
||||||
.pipe(gulp.dest(path.join(buildFolder, "res", "sounds")));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("sounds.buildall", gulp.parallel("sounds.music", "sounds.sfx"));
|
|
||||||
gulp.task("sounds.buildallHQ", gulp.parallel("sounds.musicHQ", "sounds.sfx"));
|
|
||||||
|
|
||||||
gulp.task("sounds.fullbuild", gulp.series("sounds.clear", "sounds.buildall", "sounds.copy"));
|
|
||||||
gulp.task("sounds.fullbuildHQ", gulp.series("sounds.clear", "sounds.buildallHQ", "sounds.copy"));
|
|
||||||
gulp.task("sounds.dev", gulp.series("sounds.buildall", "sounds.copy"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encodes the game music in high quality for the standalone
|
||||||
|
export function musicHQ() {
|
||||||
|
return gulp
|
||||||
|
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
|
||||||
|
.pipe(gulpPlumber())
|
||||||
|
.pipe(
|
||||||
|
gulpCache(
|
||||||
|
gulpFluentFfmpeg("mp3", function (cmd) {
|
||||||
|
return cmd
|
||||||
|
.audioBitrate(256)
|
||||||
|
.audioChannels(2)
|
||||||
|
.audioFrequency(44100)
|
||||||
|
.audioCodec("libmp3lame")
|
||||||
|
.audioFilters(["volume=0.15"]);
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "music-high-quality",
|
||||||
|
fileCache,
|
||||||
|
value: getFileCacheValue,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes the ui sounds
|
||||||
|
export function sfxGenerateSprites() {
|
||||||
|
return gulp
|
||||||
|
.src([path.join(soundsDir, "sfx", "**", "*.wav"), path.join(soundsDir, "sfx", "**", "*.mp3")])
|
||||||
|
.pipe(gulpPlumber())
|
||||||
|
.pipe(
|
||||||
|
gulpAudiosprite({
|
||||||
|
format: "howler",
|
||||||
|
output: "sfx",
|
||||||
|
gap: 0.1,
|
||||||
|
export: "mp3",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.pipe(gulp.dest(path.join(builtSoundsDir)));
|
||||||
|
}
|
||||||
|
export function sfxOptimize() {
|
||||||
|
return gulp
|
||||||
|
.src([path.join(builtSoundsDir, "sfx.mp3")])
|
||||||
|
.pipe(gulpPlumber())
|
||||||
|
.pipe(
|
||||||
|
gulpFluentFfmpeg("mp3", function (cmd) {
|
||||||
|
return cmd
|
||||||
|
.audioBitrate(128)
|
||||||
|
.audioChannels(1)
|
||||||
|
.audioFrequency(22050)
|
||||||
|
.audioCodec("libmp3lame")
|
||||||
|
.audioFilters(filters);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.pipe(gulp.dest(path.join(builtSoundsDir)));
|
||||||
|
}
|
||||||
|
export function sfxCopyAtlas() {
|
||||||
|
return gulp
|
||||||
|
.src([path.join(builtSoundsDir, "sfx.json")])
|
||||||
|
.pipe(gulp.dest(path.join("..", "src", "js", "built-temp")));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sfx = gulp.series(sfxGenerateSprites, sfxOptimize, sfxCopyAtlas);
|
||||||
|
|
||||||
|
export function copy() {
|
||||||
|
return gulp
|
||||||
|
.src(path.join(builtSoundsDir, "**", "*.mp3"))
|
||||||
|
.pipe(gulpPlumber())
|
||||||
|
.pipe(gulp.dest(path.join(buildFolder, "res", "sounds")));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildall = gulp.parallel(music, sfx);
|
||||||
|
export const buildallHQ = gulp.parallel(musicHQ, sfx);
|
||||||
|
|
||||||
|
export const fullbuild = gulp.series(clear, buildall, copy);
|
||||||
|
export const fullbuildHQ = gulp.series(clear, buildallHQ, copy);
|
||||||
|
export const dev = gulp.series(buildall, copy);
|
||||||
|
|||||||
@ -2,8 +2,11 @@ import packager from "electron-packager";
|
|||||||
import pj from "../electron/package.json" assert { type: "json" };
|
import pj from "../electron/package.json" assert { type: "json" };
|
||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import { getVersion } from "./buildutils.js";
|
import { getVersion } from "./buildutils.js";
|
||||||
import fs from "fs";
|
import fs from "fs/promises";
|
||||||
import { execSync } from "child_process";
|
import childProcess from "child_process";
|
||||||
|
import { promisify } from "util";
|
||||||
|
const exec = promisify(childProcess.exec);
|
||||||
|
import gulp from "gulp";
|
||||||
import { BUILD_VARIANTS } from "./build_variants.js";
|
import { BUILD_VARIANTS } from "./build_variants.js";
|
||||||
|
|
||||||
import gulpClean from "gulp-clean";
|
import gulpClean from "gulp-clean";
|
||||||
@ -11,121 +14,132 @@ import gulpClean from "gulp-clean";
|
|||||||
const platforms = /** @type {const} */ (["win32", "linux", "darwin"]);
|
const platforms = /** @type {const} */ (["win32", "linux", "darwin"]);
|
||||||
const architectures = /** @type {const} */ (["x64", "arm64"]);
|
const architectures = /** @type {const} */ (["x64", "arm64"]);
|
||||||
|
|
||||||
export default function gulptasksStandalone(gulp) {
|
export default Object.fromEntries(
|
||||||
for (const variant in BUILD_VARIANTS) {
|
Object.entries(BUILD_VARIANTS)
|
||||||
const variantData = BUILD_VARIANTS[variant];
|
.filter(([variant, variantData]) => variantData.standalone)
|
||||||
if (!variantData.standalone) {
|
.map(([variant, variantData]) => {
|
||||||
continue;
|
const tempDestDir = path.join("..", "build_output", variant);
|
||||||
}
|
const electronBaseDir = path.join("..", "electron");
|
||||||
const tempDestDir = path.join("..", "build_output", variant);
|
const tempDestBuildDir = path.join(tempDestDir, "built");
|
||||||
const taskPrefix = "standalone." + variant;
|
|
||||||
const electronBaseDir = path.join("..", "electron");
|
|
||||||
const tempDestBuildDir = path.join(tempDestDir, "built");
|
|
||||||
|
|
||||||
gulp.task(taskPrefix + ".prepare.cleanup", () => {
|
function cleanup() {
|
||||||
return gulp.src(tempDestDir, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
return gulp
|
||||||
});
|
.src(tempDestDir, { read: false, allowEmpty: true })
|
||||||
|
.pipe(gulpClean({ force: true }));
|
||||||
|
}
|
||||||
|
|
||||||
gulp.task(taskPrefix + ".prepare.copyPrefab", () => {
|
function copyPrefab() {
|
||||||
const requiredFiles = [
|
const requiredFiles = [
|
||||||
path.join(electronBaseDir, "node_modules", "**", "*.*"),
|
path.join(electronBaseDir, "node_modules", "**", "*.*"),
|
||||||
path.join(electronBaseDir, "node_modules", "**", ".*"),
|
path.join(electronBaseDir, "node_modules", "**", ".*"),
|
||||||
path.join(electronBaseDir, "favicon*"),
|
path.join(electronBaseDir, "favicon*"),
|
||||||
];
|
];
|
||||||
return gulp.src(requiredFiles, { base: electronBaseDir }).pipe(gulp.dest(tempDestBuildDir));
|
return gulp.src(requiredFiles, { base: electronBaseDir }).pipe(gulp.dest(tempDestBuildDir));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task(taskPrefix + ".prepare.writePackageJson", cb => {
|
async function writePackageJson() {
|
||||||
const packageJsonString = JSON.stringify(
|
const packageJsonString = JSON.stringify(
|
||||||
{
|
{
|
||||||
scripts: {
|
scripts: {
|
||||||
start: pj.scripts.start,
|
start: pj.scripts.start,
|
||||||
|
},
|
||||||
|
devDependencies: pj.devDependencies,
|
||||||
|
dependencies: pj.dependencies,
|
||||||
|
optionalDependencies: pj.optionalDependencies,
|
||||||
},
|
},
|
||||||
devDependencies: pj.devDependencies,
|
null,
|
||||||
dependencies: pj.dependencies,
|
4
|
||||||
optionalDependencies: pj.optionalDependencies,
|
);
|
||||||
},
|
|
||||||
null,
|
|
||||||
4
|
|
||||||
);
|
|
||||||
|
|
||||||
fs.writeFileSync(path.join(tempDestBuildDir, "package.json"), packageJsonString);
|
await fs.writeFile(path.join(tempDestBuildDir, "package.json"), packageJsonString);
|
||||||
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(taskPrefix + ".prepare.minifyCode", () => {
|
|
||||||
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(taskPrefix + ".prepare.copyGamefiles", () => {
|
|
||||||
return gulp.src("../build/**/*.*", { base: "../build" }).pipe(gulp.dest(tempDestBuildDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(taskPrefix + ".killRunningInstances", cb => {
|
|
||||||
try {
|
|
||||||
execSync("taskkill /F /IM shapezio.exe");
|
|
||||||
} catch (ex) {
|
|
||||||
console.warn("Failed to kill running instances, maybe none are up.");
|
|
||||||
}
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
taskPrefix + ".prepare",
|
|
||||||
gulp.series(
|
|
||||||
taskPrefix + ".killRunningInstances",
|
|
||||||
taskPrefix + ".prepare.cleanup",
|
|
||||||
taskPrefix + ".prepare.copyPrefab",
|
|
||||||
taskPrefix + ".prepare.writePackageJson",
|
|
||||||
taskPrefix + ".prepare.minifyCode",
|
|
||||||
taskPrefix + ".prepare.copyGamefiles"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {typeof platforms[number] | (typeof platforms[number])[]} platform
|
|
||||||
* @param {typeof architectures[number] | (typeof architectures[number])[]} arch
|
|
||||||
* @param {function():void} cb
|
|
||||||
*/
|
|
||||||
async function packageStandalone(platform, arch, cb) {
|
|
||||||
const appPaths = await packager({
|
|
||||||
dir: tempDestBuildDir,
|
|
||||||
appCopyright: "tobspr Games",
|
|
||||||
appVersion: getVersion(),
|
|
||||||
buildVersion: "1.0.0",
|
|
||||||
arch,
|
|
||||||
platform,
|
|
||||||
asar: true,
|
|
||||||
executableName: "shapezio",
|
|
||||||
icon: path.join(electronBaseDir, "favicon"),
|
|
||||||
name: "shapez",
|
|
||||||
out: tempDestDir,
|
|
||||||
overwrite: true,
|
|
||||||
appBundleId: "tobspr.shapezio." + variant,
|
|
||||||
appCategoryType: "public.app-category.games",
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Packages created:", appPaths);
|
|
||||||
for (const appPath of appPaths) {
|
|
||||||
fs.writeFileSync(path.join(appPath, "LICENSE"), fs.readFileSync(path.join("..", "LICENSE")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cb();
|
function minifyCode() {
|
||||||
}
|
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
|
||||||
|
}
|
||||||
|
|
||||||
for (const platform of platforms) {
|
function copyGamefiles() {
|
||||||
for (const arch of architectures) {
|
return gulp.src("../build/**/*.*", { base: "../build" }).pipe(gulp.dest(tempDestBuildDir));
|
||||||
gulp.task(taskPrefix + `.package.${platform}-${arch}`, cb =>
|
}
|
||||||
packageStandalone(platform, arch, cb)
|
|
||||||
|
async function killRunningInstances() {
|
||||||
|
try {
|
||||||
|
await exec("taskkill /F /IM shapezio.exe");
|
||||||
|
} catch (ex) {
|
||||||
|
console.warn("Failed to kill running instances, maybe none are up.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const prepare = {
|
||||||
|
cleanup,
|
||||||
|
copyPrefab,
|
||||||
|
writePackageJson,
|
||||||
|
minifyCode,
|
||||||
|
copyGamefiles,
|
||||||
|
all: gulp.series(
|
||||||
|
killRunningInstances,
|
||||||
|
cleanup,
|
||||||
|
copyPrefab,
|
||||||
|
writePackageJson,
|
||||||
|
minifyCode,
|
||||||
|
copyGamefiles
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {typeof platforms[number] | (typeof platforms[number])[]} platform
|
||||||
|
* @param {typeof architectures[number] | (typeof architectures[number])[]} arch
|
||||||
|
*/
|
||||||
|
async function packageStandalone(platform, arch) {
|
||||||
|
const appPaths = await packager({
|
||||||
|
dir: tempDestBuildDir,
|
||||||
|
appCopyright: "tobspr Games",
|
||||||
|
appVersion: getVersion(),
|
||||||
|
buildVersion: "1.0.0",
|
||||||
|
arch,
|
||||||
|
platform,
|
||||||
|
asar: true,
|
||||||
|
executableName: "shapezio",
|
||||||
|
icon: path.join(electronBaseDir, "favicon"),
|
||||||
|
name: "shapez",
|
||||||
|
out: tempDestDir,
|
||||||
|
overwrite: true,
|
||||||
|
appBundleId: "tobspr.shapezio." + variant,
|
||||||
|
appCategoryType: "public.app-category.games",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Packages created:", appPaths);
|
||||||
|
await Promise.all(
|
||||||
|
appPaths.map(async appPath => {
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(appPath, "LICENSE"),
|
||||||
|
await fs.readFile(path.join("..", "LICENSE"))
|
||||||
|
);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Review this hack forced by readonly types
|
const pack = {
|
||||||
gulp.task(taskPrefix + ".package.all", cb =>
|
...Object.fromEntries(
|
||||||
packageStandalone([...platforms], [...architectures], cb)
|
platforms.flatMap(platform =>
|
||||||
);
|
architectures.map(arch => [
|
||||||
}
|
`${platform}-${arch}`,
|
||||||
}
|
() => packageStandalone(platform, arch),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// TODO: Review this hack forced by readonly types
|
||||||
|
all: () => packageStandalone([...platforms], [...architectures]),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
variant,
|
||||||
|
{
|
||||||
|
killRunningInstances,
|
||||||
|
prepare,
|
||||||
|
package: pack,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|||||||
304
gulp/tasks.js
Normal file
304
gulp/tasks.js
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
import gulp from "gulp";
|
||||||
|
import path from "path/posix";
|
||||||
|
import pathNative from "path";
|
||||||
|
import delEmpty from "delete-empty";
|
||||||
|
import childProcess from "child_process";
|
||||||
|
import { promisify } from "util";
|
||||||
|
const exec = promisify(childProcess.exec);
|
||||||
|
import { BUILD_VARIANTS } from "./build_variants.js";
|
||||||
|
import {
|
||||||
|
baseDir,
|
||||||
|
buildFolder,
|
||||||
|
buildOutputFolder,
|
||||||
|
browserSync,
|
||||||
|
rawImageResourcesGlobs,
|
||||||
|
nonImageResourcesGlobs,
|
||||||
|
imageResourcesGlobs,
|
||||||
|
} from "./config.js";
|
||||||
|
|
||||||
|
// Load other plugins
|
||||||
|
import gulpClean from "gulp-clean";
|
||||||
|
import gulpWebserver from "gulp-webserver";
|
||||||
|
|
||||||
|
import * as imgres from "./image-resources.js";
|
||||||
|
import * as css from "./css.js";
|
||||||
|
import * as sounds from "./sounds.js";
|
||||||
|
import * as localConfig from "./local-config.js";
|
||||||
|
import js from "./js.js";
|
||||||
|
import * as html from "./html.js";
|
||||||
|
import * as ftp from "./ftp.js";
|
||||||
|
import * as docs from "./docs.js";
|
||||||
|
import standalone from "./standalone.js";
|
||||||
|
import * as translations from "./translations.js";
|
||||||
|
|
||||||
|
export { imgres, css, sounds, localConfig, js, html, ftp, docs, standalone, translations };
|
||||||
|
|
||||||
|
///////////////////// BUILD TASKS /////////////////////
|
||||||
|
|
||||||
|
// Cleans up everything
|
||||||
|
function cleanBuildFolder() {
|
||||||
|
return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
||||||
|
}
|
||||||
|
function cleanBuildOutputFolder() {
|
||||||
|
return gulp.src(buildOutputFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
|
||||||
|
}
|
||||||
|
function cleanBuildTempFolder() {
|
||||||
|
return gulp
|
||||||
|
.src(path.join("..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
|
||||||
|
.pipe(gulpClean({ force: true }));
|
||||||
|
}
|
||||||
|
function cleanImageBuildFolder() {
|
||||||
|
return gulp
|
||||||
|
.src(path.join("res_built"), { read: false, allowEmpty: true })
|
||||||
|
.pipe(gulpClean({ force: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const cleanup = gulp.series(cleanBuildFolder, cleanImageBuildFolder, cleanBuildTempFolder);
|
||||||
|
|
||||||
|
// Requires no uncomitted files
|
||||||
|
async function requireCleanWorkingTree() {
|
||||||
|
let output = (await exec("git status -su", { encoding: "buffer" })).stdout
|
||||||
|
.toString("ascii")
|
||||||
|
.trim()
|
||||||
|
.replace(/\r/gi, "")
|
||||||
|
.split("\n");
|
||||||
|
|
||||||
|
// Filter files which are OK to be untracked
|
||||||
|
output = output
|
||||||
|
.map(x => x.replace(/[\r\n]+/gi, ""))
|
||||||
|
.filter(x => x.indexOf(".local.js") < 0)
|
||||||
|
.filter(x => x.length > 0);
|
||||||
|
if (output.length > 0) {
|
||||||
|
console.error("\n\nYou have unstaged changes, please commit everything first!");
|
||||||
|
console.error("Unstaged files:");
|
||||||
|
console.error(output.map(x => "'" + x + "'").join("\n"));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyAdditionalBuildFiles() {
|
||||||
|
const additionalFolder = path.join("additional_build_files");
|
||||||
|
const additionalSrcGlobs = [
|
||||||
|
path.join(additionalFolder, "**/*.*"),
|
||||||
|
path.join(additionalFolder, "**/.*"),
|
||||||
|
path.join(additionalFolder, "**/*"),
|
||||||
|
];
|
||||||
|
|
||||||
|
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const utils = {
|
||||||
|
cleanBuildFolder,
|
||||||
|
cleanBuildOutputFolder,
|
||||||
|
cleanBuildTempFolder,
|
||||||
|
cleanImageBuildFolder,
|
||||||
|
cleanup,
|
||||||
|
requireCleanWorkingTree,
|
||||||
|
copyAdditionalBuildFiles,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Starts a webserver on the built directory (useful for testing prod build)
|
||||||
|
function webserver() {
|
||||||
|
return gulp.src(buildFolder).pipe(
|
||||||
|
gulpWebserver({
|
||||||
|
livereload: {
|
||||||
|
enable: true,
|
||||||
|
},
|
||||||
|
directoryListing: false,
|
||||||
|
open: true,
|
||||||
|
port: 3005,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} param0
|
||||||
|
* @param {keyof typeof BUILD_VARIANTS} param0.version
|
||||||
|
*/
|
||||||
|
function serveHTML({ version = "web-dev" }) {
|
||||||
|
browserSync.init({
|
||||||
|
server: [buildFolder, path.join(baseDir, "mod_examples")],
|
||||||
|
port: 3005,
|
||||||
|
ghostMode: {
|
||||||
|
clicks: false,
|
||||||
|
scroll: false,
|
||||||
|
location: false,
|
||||||
|
forms: false,
|
||||||
|
},
|
||||||
|
logLevel: "info",
|
||||||
|
logPrefix: "BS",
|
||||||
|
online: false,
|
||||||
|
xip: false,
|
||||||
|
notify: false,
|
||||||
|
reloadDebounce: 100,
|
||||||
|
reloadOnRestart: true,
|
||||||
|
watchEvents: ["add", "change"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Watch .scss files, those trigger a css rebuild
|
||||||
|
gulp.watch(["../src/**/*.scss"], css.dev);
|
||||||
|
|
||||||
|
// Watch .html files, those trigger a html rebuild
|
||||||
|
gulp.watch("../src/**/*.html", html.dev);
|
||||||
|
gulp.watch("./preloader/*.*", html.dev);
|
||||||
|
|
||||||
|
// Watch translations
|
||||||
|
gulp.watch("../translations/**/*.yaml", translations.convertToJson);
|
||||||
|
|
||||||
|
gulp.watch(
|
||||||
|
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
|
||||||
|
gulp.series(sounds.sfx, sounds.copy)
|
||||||
|
);
|
||||||
|
gulp.watch(
|
||||||
|
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
|
||||||
|
gulp.series(sounds.music, sounds.copy)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Watch resource files and copy them on change
|
||||||
|
gulp.watch(rawImageResourcesGlobs, imgres.buildAtlas);
|
||||||
|
gulp.watch(nonImageResourcesGlobs, imgres.copyNonImageResources);
|
||||||
|
gulp.watch(imageResourcesGlobs, imgres.copyImageResources);
|
||||||
|
|
||||||
|
// Watch .atlas files and recompile the atlas on change
|
||||||
|
gulp.watch("../res_built/atlas/*.atlas", imgres.atlasToJson);
|
||||||
|
gulp.watch("../res_built/atlas/*.json", imgres.atlas);
|
||||||
|
|
||||||
|
// Watch the build folder and reload when anything changed
|
||||||
|
const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"];
|
||||||
|
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", p =>
|
||||||
|
gulp
|
||||||
|
.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep))
|
||||||
|
.pipe(browserSync.reload({ stream: true }))
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.watch("../src/js/built-temp/*.json").on("change", p =>
|
||||||
|
gulp
|
||||||
|
.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep))
|
||||||
|
.pipe(browserSync.reload({ stream: true }))
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.series(js[version].dev.watch)(() => true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre and postbuild
|
||||||
|
const baseResources = imgres.allOptimized;
|
||||||
|
async function deleteEmpty() {
|
||||||
|
await delEmpty(buildFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const postbuild = gulp.series(imgres.cleanupUnusedCssInlineImages, deleteEmpty);
|
||||||
|
|
||||||
|
export const step = {
|
||||||
|
baseResources,
|
||||||
|
deleteEmpty,
|
||||||
|
postbuild,
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////// RUNNABLE TASKS /////////////////////
|
||||||
|
|
||||||
|
// Builds everything (dev)
|
||||||
|
const prepare = {
|
||||||
|
dev: gulp.series(
|
||||||
|
utils.cleanup,
|
||||||
|
utils.copyAdditionalBuildFiles,
|
||||||
|
localConfig.findOrCreate,
|
||||||
|
gulp.parallel(
|
||||||
|
gulp.series(imgres.buildAtlas, imgres.atlasToJson, imgres.atlas),
|
||||||
|
sounds.dev,
|
||||||
|
gulp.series(imgres.copyImageResources, css.dev),
|
||||||
|
imgres.copyNonImageResources,
|
||||||
|
translations.fullBuild
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("gulp").TaskFunction} TaskFunction
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const build =
|
||||||
|
/**
|
||||||
|
* @type {Record<string, {
|
||||||
|
* code: TaskFunction,
|
||||||
|
* resourcesAndCode: TaskFunction,
|
||||||
|
* all: TaskFunction,
|
||||||
|
* full: TaskFunction,
|
||||||
|
* }> & { prepare: typeof prepare }}
|
||||||
|
*/
|
||||||
|
({
|
||||||
|
prepare,
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* @type {Record<string, Record<string, TaskFunction>>}
|
||||||
|
*/
|
||||||
|
const pack = {};
|
||||||
|
export { pack as package };
|
||||||
|
/** @type {Record<string, TaskFunction>} */
|
||||||
|
export const serve = {};
|
||||||
|
|
||||||
|
// Builds everything for every variant
|
||||||
|
for (const variant in BUILD_VARIANTS) {
|
||||||
|
const data = BUILD_VARIANTS[variant];
|
||||||
|
|
||||||
|
// build
|
||||||
|
const code = gulp.series(
|
||||||
|
data.standalone ? sounds.fullbuildHQ : sounds.fullbuild,
|
||||||
|
translations.fullBuild,
|
||||||
|
js[variant].prod.build
|
||||||
|
);
|
||||||
|
|
||||||
|
const resourcesAndCode = gulp.parallel(step.baseResources, code);
|
||||||
|
|
||||||
|
const all = gulp.series(resourcesAndCode, css.prod, html.prod);
|
||||||
|
|
||||||
|
const full = gulp.series(utils.cleanup, all, step.postbuild);
|
||||||
|
|
||||||
|
build[variant] = { code, resourcesAndCode, all, full };
|
||||||
|
|
||||||
|
// Tasks for creating packages. These packages are already distributable, but usually can be further
|
||||||
|
// wrapped in a different format (an installer for Windows, tarball for Linux, DMG for macOS).
|
||||||
|
if (data.standalone) {
|
||||||
|
const packageTasks = [
|
||||||
|
"win32-x64",
|
||||||
|
"win32-arm64",
|
||||||
|
"linux-x64",
|
||||||
|
"linux-arm64",
|
||||||
|
"darwin-x64",
|
||||||
|
"darwin-arm64",
|
||||||
|
"all",
|
||||||
|
];
|
||||||
|
|
||||||
|
pack[variant] = {};
|
||||||
|
for (const task of packageTasks) {
|
||||||
|
pack[variant][task] = gulp.series(
|
||||||
|
localConfig.findOrCreate,
|
||||||
|
full,
|
||||||
|
utils.cleanBuildOutputFolder,
|
||||||
|
standalone[variant].prepare.all,
|
||||||
|
standalone[variant].package[task]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// serve
|
||||||
|
serve[variant] = gulp.series(build.prepare.dev, html.dev, () => serveHTML({ version: variant }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploying!
|
||||||
|
export const deploy = {
|
||||||
|
staging: gulp.series(
|
||||||
|
utils.requireCleanWorkingTree,
|
||||||
|
build["web-shapezio-beta"].full,
|
||||||
|
ftp.upload.staging.all
|
||||||
|
),
|
||||||
|
prod: gulp.series(utils.requireCleanWorkingTree, build["web-shapezio"].full, ftp.upload.prod.all),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const main = {
|
||||||
|
prepareDocs: docs.prepareDocs,
|
||||||
|
webserver,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default task (dev, localhost)
|
||||||
|
export default gulp.series(serve["standalone-steam"]);
|
||||||
@ -1,21 +1,20 @@
|
|||||||
import path from "path/posix";
|
import path from "path/posix";
|
||||||
import fs from "fs";
|
import fs from "fs/promises";
|
||||||
import gulpYaml from "gulp-yaml";
|
|
||||||
import YAML from "yaml";
|
import YAML from "yaml";
|
||||||
|
import gulp from "gulp";
|
||||||
|
|
||||||
import gulpPlumber from "gulp-plumber";
|
import gulpPlumber from "gulp-plumber";
|
||||||
|
import gulpYaml from "gulp-yaml";
|
||||||
|
|
||||||
const translationsSourceDir = path.join("..", "translations");
|
const translationsSourceDir = path.join("..", "translations");
|
||||||
const translationsJsonDir = path.join("..", "src", "js", "built-temp");
|
const translationsJsonDir = path.join("..", "src", "js", "built-temp");
|
||||||
|
|
||||||
export default function gulptasksTranslations(gulp) {
|
export function convertToJson() {
|
||||||
gulp.task("translations.convertToJson", () => {
|
return gulp
|
||||||
return gulp
|
.src(path.join(translationsSourceDir, "*.yaml"))
|
||||||
.src(path.join(translationsSourceDir, "*.yaml"))
|
.pipe(gulpPlumber())
|
||||||
.pipe(gulpPlumber())
|
.pipe(gulpYaml({ space: 2, safe: true }))
|
||||||
.pipe(gulpYaml({ space: 2, safe: true }))
|
.pipe(gulp.dest(translationsJsonDir));
|
||||||
.pipe(gulp.dest(translationsJsonDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("translations.fullBuild", gulp.series("translations.convertToJson"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fullBuild = convertToJson;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user