mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Cleanup IS_DEMO flags and introduce Restriction Manager
This commit is contained in:
parent
81e7d96dd8
commit
fa27d1681f
@ -29,6 +29,7 @@ import { MobileWarningState } from "./states/mobile_warning";
|
|||||||
import { PreloadState } from "./states/preload";
|
import { PreloadState } from "./states/preload";
|
||||||
import { SettingsState } from "./states/settings";
|
import { SettingsState } from "./states/settings";
|
||||||
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
||||||
|
import { RestrictionManager } from "./core/restriction_manager";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
||||||
@ -70,6 +71,9 @@ export class Application {
|
|||||||
this.inputMgr = new InputDistributor(this);
|
this.inputMgr = new InputDistributor(this);
|
||||||
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
|
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
|
||||||
|
|
||||||
|
// Restrictions (Like demo etc)
|
||||||
|
this.restrictionMgr = new RestrictionManager(this);
|
||||||
|
|
||||||
// Platform dependent stuff
|
// Platform dependent stuff
|
||||||
|
|
||||||
/** @type {StorageInterface} */
|
/** @type {StorageInterface} */
|
||||||
|
@ -7,11 +7,6 @@ export const IS_DEBUG =
|
|||||||
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
||||||
window.location.search.indexOf("nodebug") < 0;
|
window.location.search.indexOf("nodebug") < 0;
|
||||||
|
|
||||||
export const IS_DEMO = queryParamOptions.fullVersion
|
|
||||||
? false
|
|
||||||
: (!G_IS_DEV && !G_IS_STANDALONE) ||
|
|
||||||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
|
|
||||||
|
|
||||||
export const SUPPORT_TOUCH = false;
|
export const SUPPORT_TOUCH = false;
|
||||||
|
|
||||||
const smoothCanvas = true;
|
const smoothCanvas = true;
|
||||||
|
@ -81,10 +81,6 @@ export class ReadWriteProxy {
|
|||||||
return this.writeAsync();
|
return this.writeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentData() {
|
|
||||||
return this.currentData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object} obj
|
* @param {object} obj
|
||||||
|
97
src/js/core/restriction_manager.js
Normal file
97
src/js/core/restriction_manager.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { Application } from "../application";
|
||||||
|
import { ExplainedResult } from "./explained_result";
|
||||||
|
import { queryParamOptions } from "./query_parameters";
|
||||||
|
import { ReadWriteProxy } from "./read_write_proxy";
|
||||||
|
|
||||||
|
export class RestrictionManager extends ReadWriteProxy {
|
||||||
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
constructor(app) {
|
||||||
|
super(app, "restriction-flags.bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- RW Proxy Impl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} data
|
||||||
|
*/
|
||||||
|
verify(data) {
|
||||||
|
return ExplainedResult.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
getDefaultData() {
|
||||||
|
return {
|
||||||
|
savegameV1119Imported: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
getCurrentVersion() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} data
|
||||||
|
*/
|
||||||
|
migrate(data) {
|
||||||
|
// Todo
|
||||||
|
return ExplainedResult.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- End RW Proxy Impl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the app is currently running as the limited version
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isLimitedVersion() {
|
||||||
|
return queryParamOptions.fullVersion
|
||||||
|
? false
|
||||||
|
: (!G_IS_DEV && !G_IS_STANDALONE) ||
|
||||||
|
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the app markets the standalone version on steam
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getIsStandaloneMarketingActive() {
|
||||||
|
return this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if exporting the base as a screenshot is possible
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getIsExportingScreenshotsPossible() {
|
||||||
|
return !this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of supported waypoints
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
getMaximumWaypoints() {
|
||||||
|
return this.isLimitedVersion() ? 2 : 1e20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the user has unlimited savegames
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getHasUnlimitedSavegames() {
|
||||||
|
return !this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the app has all settings available
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getHasExtendedSettings() {
|
||||||
|
return !this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
}
|
@ -681,3 +681,35 @@ export function fillInLinkIntoTranslation(translation, link) {
|
|||||||
.replace("<link>", "<a href='" + link + "' target='_blank'>")
|
.replace("<link>", "<a href='" + link + "' target='_blank'>")
|
||||||
.replace("</link>", "</a>");
|
.replace("</link>", "</a>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a file download
|
||||||
|
* @param {string} filename
|
||||||
|
* @param {string} text
|
||||||
|
*/
|
||||||
|
export function generateFileDownload(filename, text) {
|
||||||
|
var element = document.createElement("a");
|
||||||
|
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
|
||||||
|
element.setAttribute("download", filename);
|
||||||
|
|
||||||
|
element.style.display = "none";
|
||||||
|
document.body.appendChild(element);
|
||||||
|
|
||||||
|
element.click();
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a file chooser
|
||||||
|
* @param {string} acceptedType
|
||||||
|
*/
|
||||||
|
export function startFileChoose(acceptedType = ".bin") {
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.accept = acceptedType;
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
input.onchange = _ => resolve(input.files[0]);
|
||||||
|
input.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { globalConfig, IS_DEMO } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { RandomNumberGenerator } from "../core/rng";
|
import { RandomNumberGenerator } from "../core/rng";
|
||||||
import { clamp } from "../core/utils";
|
import { clamp } from "../core/utils";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
@ -281,11 +281,6 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DEMO && currentLevel >= 4) {
|
|
||||||
// DEMO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import { HUDKeybindingOverlay } from "./parts/keybinding_overlay";
|
|||||||
import { HUDUnlockNotification } from "./parts/unlock_notification";
|
import { HUDUnlockNotification } from "./parts/unlock_notification";
|
||||||
import { HUDGameMenu } from "./parts/game_menu";
|
import { HUDGameMenu } from "./parts/game_menu";
|
||||||
import { HUDShop } from "./parts/shop";
|
import { HUDShop } from "./parts/shop";
|
||||||
import { IS_MOBILE, globalConfig, IS_DEMO } from "../../core/config";
|
import { IS_MOBILE, globalConfig } from "../../core/config";
|
||||||
import { HUDMassSelector } from "./parts/mass_selector";
|
import { HUDMassSelector } from "./parts/mass_selector";
|
||||||
import { HUDVignetteOverlay } from "./parts/vignette_overlay";
|
import { HUDVignetteOverlay } from "./parts/vignette_overlay";
|
||||||
import { HUDStatistics } from "./parts/statistics";
|
import { HUDStatistics } from "./parts/statistics";
|
||||||
@ -116,7 +116,7 @@ export class GameHUD {
|
|||||||
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DEMO) {
|
if (this.root.app.restrictionMgr.getIsStandaloneMarketingActive()) {
|
||||||
this.parts.watermark = new HUDWatermark(this.root);
|
this.parts.watermark = new HUDWatermark(this.root);
|
||||||
this.parts.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
|
this.parts.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
|
||||||
this.parts.catMemes = new HUDCatMemes(this.root);
|
this.parts.catMemes = new HUDCatMemes(this.root);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
|
||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
|
||||||
import { IS_DEMO, globalConfig } from "../../../core/config";
|
|
||||||
import { T } from "../../../translations";
|
|
||||||
import { createLogger } from "../../../core/logging";
|
|
||||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
|
||||||
import { Vector } from "../../../core/vector";
|
|
||||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||||
|
import { globalConfig } from "../../../core/config";
|
||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
|
import { createLogger } from "../../../core/logging";
|
||||||
import { Rectangle } from "../../../core/rectangle";
|
import { Rectangle } from "../../../core/rectangle";
|
||||||
|
import { Vector } from "../../../core/vector";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||||
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
|
||||||
const logger = createLogger("screenshot_exporter");
|
const logger = createLogger("screenshot_exporter");
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startExport() {
|
startExport() {
|
||||||
if (IS_DEMO) {
|
if (!this.root.app.restrictionMgr.getIsExportingScreenshotsPossible()) {
|
||||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||||
import { globalConfig, IS_DEMO, THIRDPARTY_URLS } from "../../../core/config";
|
import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
|
||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
import { Loader } from "../../../core/loader";
|
import { Loader } from "../../../core/loader";
|
||||||
import { DialogWithForm } from "../../../core/modal_dialog_elements";
|
import { DialogWithForm } from "../../../core/modal_dialog_elements";
|
||||||
@ -302,7 +302,7 @@ export class HUDWaypoints extends BaseHUDPart {
|
|||||||
// Show info that you can have only N markers in the demo,
|
// Show info that you can have only N markers in the demo,
|
||||||
// actually show this *after* entering the name so you want the
|
// actually show this *after* entering the name so you want the
|
||||||
// standalone even more (I'm evil :P)
|
// standalone even more (I'm evil :P)
|
||||||
if (IS_DEMO && this.waypoints.length > 2) {
|
if (this.waypoints.length > this.root.app.restrictionMgr.getMaximumWaypoints()) {
|
||||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(
|
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(
|
||||||
"",
|
"",
|
||||||
T.dialogs.markerDemoLimit.desc
|
T.dialogs.markerDemoLimit.desc
|
||||||
|
@ -11,6 +11,7 @@ const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
|||||||
|
|
||||||
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
|
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
|
||||||
|
|
||||||
|
// @FIXME @TODO
|
||||||
const numEndgameUpgrades = !IS_DEMO ? 20 - fixedImprovements.length - 1 : 0;
|
const numEndgameUpgrades = !IS_DEMO ? 20 - fixedImprovements.length - 1 : 0;
|
||||||
|
|
||||||
function generateEndgameUpgrades() {
|
function generateEndgameUpgrades() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { globalConfig, IS_DEMO } from "../../core/config";
|
import { globalConfig } from "../../core/config";
|
||||||
import { smoothenDpi } from "../../core/dpi_manager";
|
import { smoothenDpi } from "../../core/dpi_manager";
|
||||||
import { DrawParameters } from "../../core/draw_parameters";
|
import { DrawParameters } from "../../core/draw_parameters";
|
||||||
import { drawSpriteClipped } from "../../core/draw_utils";
|
import { drawSpriteClipped } from "../../core/draw_utils";
|
||||||
|
@ -1,214 +1,202 @@
|
|||||||
import { globalConfig, IS_DEMO, IS_MOBILE } from "../../core/config";
|
import { globalConfig, IS_MOBILE } from "../../core/config";
|
||||||
import { createLogger } from "../../core/logging";
|
import { createLogger } from "../../core/logging";
|
||||||
import { queryParamOptions } from "../../core/query_parameters";
|
import { queryParamOptions } from "../../core/query_parameters";
|
||||||
import { clamp } from "../../core/utils";
|
import { clamp } from "../../core/utils";
|
||||||
import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
|
import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
|
||||||
import { NoAdProvider } from "../ad_providers/no_ad_provider";
|
import { NoAdProvider } from "../ad_providers/no_ad_provider";
|
||||||
import { PlatformWrapperInterface } from "../wrapper";
|
import { PlatformWrapperInterface } from "../wrapper";
|
||||||
import { StorageImplBrowser } from "./storage";
|
import { StorageImplBrowser } from "./storage";
|
||||||
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
|
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
|
||||||
|
|
||||||
const logger = createLogger("platform/browser");
|
const logger = createLogger("platform/browser");
|
||||||
|
|
||||||
export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||||
initialize() {
|
initialize() {
|
||||||
this.recaptchaTokenCallback = null;
|
this.recaptchaTokenCallback = null;
|
||||||
|
|
||||||
this.embedProvider = {
|
this.embedProvider = {
|
||||||
id: "shapezio-website",
|
id: "shapezio-website",
|
||||||
adProvider: NoAdProvider,
|
adProvider: NoAdProvider,
|
||||||
iframed: false,
|
iframed: false,
|
||||||
externalLinks: true,
|
externalLinks: true,
|
||||||
iogLink: true,
|
iogLink: true,
|
||||||
unlimitedSavegames: IS_DEMO ? false : true,
|
};
|
||||||
showDemoBadge: IS_DEMO,
|
|
||||||
};
|
if (!G_IS_STANDALONE && queryParamOptions.embedProvider) {
|
||||||
|
const providerId = queryParamOptions.embedProvider;
|
||||||
if (!G_IS_STANDALONE && queryParamOptions.embedProvider) {
|
this.embedProvider.iframed = true;
|
||||||
const providerId = queryParamOptions.embedProvider;
|
this.embedProvider.iogLink = false;
|
||||||
this.embedProvider.iframed = true;
|
|
||||||
this.embedProvider.iogLink = false;
|
switch (providerId) {
|
||||||
|
case "armorgames": {
|
||||||
switch (providerId) {
|
this.embedProvider.id = "armorgames";
|
||||||
case "armorgames": {
|
break;
|
||||||
this.embedProvider.id = "armorgames";
|
}
|
||||||
break;
|
|
||||||
}
|
case "iogames.space": {
|
||||||
|
this.embedProvider.id = "iogames.space";
|
||||||
case "iogames.space": {
|
this.embedProvider.iogLink = true;
|
||||||
this.embedProvider.id = "iogames.space";
|
break;
|
||||||
this.embedProvider.iogLink = true;
|
}
|
||||||
this.embedProvider.unlimitedSavegames = true;
|
|
||||||
this.embedProvider.showDemoBadge = false;
|
case "miniclip": {
|
||||||
break;
|
this.embedProvider.id = "miniclip";
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
case "miniclip": {
|
|
||||||
this.embedProvider.id = "miniclip";
|
case "gamedistribution": {
|
||||||
break;
|
this.embedProvider.id = "gamedistribution";
|
||||||
}
|
this.embedProvider.externalLinks = false;
|
||||||
|
this.embedProvider.adProvider = GamedistributionAdProvider;
|
||||||
case "gamedistribution": {
|
break;
|
||||||
this.embedProvider.id = "gamedistribution";
|
}
|
||||||
this.embedProvider.externalLinks = false;
|
|
||||||
this.embedProvider.adProvider = GamedistributionAdProvider;
|
case "kongregate": {
|
||||||
break;
|
this.embedProvider.id = "kongregate";
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
case "kongregate": {
|
|
||||||
this.embedProvider.id = "kongregate";
|
case "crazygames": {
|
||||||
break;
|
this.embedProvider.id = "crazygames";
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
case "crazygames": {
|
|
||||||
this.embedProvider.id = "crazygames";
|
default: {
|
||||||
break;
|
logger.error("Got unsupported embed provider:", providerId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
default: {
|
}
|
||||||
logger.error("Got unsupported embed provider:", providerId);
|
|
||||||
}
|
logger.log("Embed provider:", this.embedProvider.id);
|
||||||
}
|
|
||||||
}
|
return this.detectStorageImplementation()
|
||||||
|
.then(() => this.initializeAdProvider())
|
||||||
logger.log("Embed provider:", this.embedProvider.id);
|
.then(() => super.initialize());
|
||||||
|
}
|
||||||
return this.detectStorageImplementation()
|
|
||||||
.then(() => this.initializeAdProvider())
|
detectStorageImplementation() {
|
||||||
.then(() => super.initialize());
|
return new Promise(resolve => {
|
||||||
}
|
logger.log("Detecting storage");
|
||||||
|
|
||||||
detectStorageImplementation() {
|
if (!window.indexedDB) {
|
||||||
return new Promise(resolve => {
|
logger.log("Indexed DB not supported");
|
||||||
logger.log("Detecting storage");
|
this.app.storage = new StorageImplBrowser(this.app);
|
||||||
|
resolve();
|
||||||
if (!window.indexedDB) {
|
return;
|
||||||
logger.log("Indexed DB not supported");
|
}
|
||||||
this.app.storage = new StorageImplBrowser(this.app);
|
|
||||||
resolve();
|
// Try accessing the indexedb
|
||||||
return;
|
let request;
|
||||||
}
|
try {
|
||||||
|
request = window.indexedDB.open("indexeddb_feature_detection", 1);
|
||||||
// Try accessing the indexedb
|
} catch (ex) {
|
||||||
let request;
|
logger.warn("Error while opening indexed db:", ex);
|
||||||
try {
|
this.app.storage = new StorageImplBrowser(this.app);
|
||||||
request = window.indexedDB.open("indexeddb_feature_detection", 1);
|
resolve();
|
||||||
} catch (ex) {
|
return;
|
||||||
logger.warn("Error while opening indexed db:", ex);
|
}
|
||||||
this.app.storage = new StorageImplBrowser(this.app);
|
request.onerror = err => {
|
||||||
resolve();
|
logger.log("Indexed DB can *not* be accessed: ", err);
|
||||||
return;
|
logger.log("Using fallback to local storage");
|
||||||
}
|
this.app.storage = new StorageImplBrowser(this.app);
|
||||||
request.onerror = err => {
|
resolve();
|
||||||
logger.log("Indexed DB can *not* be accessed: ", err);
|
};
|
||||||
logger.log("Using fallback to local storage");
|
request.onsuccess = () => {
|
||||||
this.app.storage = new StorageImplBrowser(this.app);
|
logger.log("Indexed DB *can* be accessed");
|
||||||
resolve();
|
this.app.storage = new StorageImplBrowserIndexedDB(this.app);
|
||||||
};
|
resolve();
|
||||||
request.onsuccess = () => {
|
};
|
||||||
logger.log("Indexed DB *can* be accessed");
|
});
|
||||||
this.app.storage = new StorageImplBrowserIndexedDB(this.app);
|
}
|
||||||
resolve();
|
|
||||||
};
|
getId() {
|
||||||
});
|
return "browser@" + this.embedProvider.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHasUnlimitedSavegames() {
|
getUiScale() {
|
||||||
return this.embedProvider.unlimitedSavegames;
|
if (IS_MOBILE) {
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
getShowDemoBadges() {
|
|
||||||
return this.embedProvider.showDemoBadge;
|
const avgDims = Math.min(this.app.screenWidth, this.app.screenHeight);
|
||||||
}
|
return clamp((avgDims / 1000.0) * 1.9, 0.1, 10);
|
||||||
|
}
|
||||||
getId() {
|
|
||||||
return "browser@" + this.embedProvider.id;
|
getSupportsRestart() {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
getUiScale() {
|
|
||||||
if (IS_MOBILE) {
|
getTouchPanStrength() {
|
||||||
return 1;
|
return IS_MOBILE ? 1 : 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
const avgDims = Math.min(this.app.screenWidth, this.app.screenHeight);
|
openExternalLink(url, force = false) {
|
||||||
return clamp((avgDims / 1000.0) * 1.9, 0.1, 10);
|
logger.log("Opening external:", url);
|
||||||
}
|
if (force || this.embedProvider.externalLinks) {
|
||||||
|
window.open(url);
|
||||||
getSupportsRestart() {
|
} else {
|
||||||
return true;
|
// Do nothing
|
||||||
}
|
alert(
|
||||||
|
"This platform does not allow opening external links. You can play on https://shapez.io directly to open them.\n\nClicked Link: " +
|
||||||
getTouchPanStrength() {
|
url
|
||||||
return IS_MOBILE ? 1 : 0.5;
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
openExternalLink(url, force = false) {
|
|
||||||
logger.log("Opening external:", url);
|
performRestart() {
|
||||||
if (force || this.embedProvider.externalLinks) {
|
logger.log("Performing restart");
|
||||||
window.open(url);
|
window.location.reload(true);
|
||||||
} else {
|
}
|
||||||
// Do nothing
|
|
||||||
alert(
|
/**
|
||||||
"This platform does not allow opening external links. You can play on https://shapez.io directly to open them.\n\nClicked Link: " +
|
* Detects if there is an adblocker installed
|
||||||
url
|
* @returns {Promise<boolean>}
|
||||||
);
|
*/
|
||||||
}
|
detectAdblock() {
|
||||||
}
|
return Promise.race([
|
||||||
|
new Promise(resolve => {
|
||||||
performRestart() {
|
// If the request wasn't blocked within a very short period of time, this means
|
||||||
logger.log("Performing restart");
|
// the adblocker is not active and the request was actually made -> ignore it then
|
||||||
window.location.reload(true);
|
setTimeout(() => resolve(false), 30);
|
||||||
}
|
}),
|
||||||
|
new Promise(resolve => {
|
||||||
/**
|
fetch("https://googleads.g.doubleclick.net/pagead/id", {
|
||||||
* Detects if there is an adblocker installed
|
method: "HEAD",
|
||||||
* @returns {Promise<boolean>}
|
mode: "no-cors",
|
||||||
*/
|
})
|
||||||
detectAdblock() {
|
.then(res => {
|
||||||
return Promise.race([
|
resolve(false);
|
||||||
new Promise(resolve => {
|
})
|
||||||
// If the request wasn't blocked within a very short period of time, this means
|
.catch(err => {
|
||||||
// the adblocker is not active and the request was actually made -> ignore it then
|
resolve(true);
|
||||||
setTimeout(() => resolve(false), 30);
|
});
|
||||||
}),
|
}),
|
||||||
new Promise(resolve => {
|
]);
|
||||||
fetch("https://googleads.g.doubleclick.net/pagead/id", {
|
}
|
||||||
method: "HEAD",
|
|
||||||
mode: "no-cors",
|
initializeAdProvider() {
|
||||||
})
|
if (G_IS_DEV && !globalConfig.debug.testAds) {
|
||||||
.then(res => {
|
logger.log("Ads disabled in local environment");
|
||||||
resolve(false);
|
return Promise.resolve();
|
||||||
})
|
}
|
||||||
.catch(err => {
|
|
||||||
resolve(true);
|
// First, detect adblocker
|
||||||
});
|
return this.detectAdblock().then(hasAdblocker => {
|
||||||
}),
|
if (hasAdblocker) {
|
||||||
]);
|
logger.log("Adblock detected");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
initializeAdProvider() {
|
|
||||||
if (G_IS_DEV && !globalConfig.debug.testAds) {
|
const adProvider = this.embedProvider.adProvider;
|
||||||
logger.log("Ads disabled in local environment");
|
this.app.adProvider = new adProvider(this.app);
|
||||||
return Promise.resolve();
|
return this.app.adProvider.initialize().catch(err => {
|
||||||
}
|
logger.error("Failed to initialize ad provider, disabling ads:", err);
|
||||||
|
this.app.adProvider = new NoAdProvider(this.app);
|
||||||
// First, detect adblocker
|
});
|
||||||
return this.detectAdblock().then(hasAdblocker => {
|
});
|
||||||
if (hasAdblocker) {
|
}
|
||||||
logger.log("Adblock detected");
|
|
||||||
return;
|
exitApp() {
|
||||||
}
|
// Can not exit app
|
||||||
|
}
|
||||||
const adProvider = this.embedProvider.adProvider;
|
}
|
||||||
this.app.adProvider = new adProvider(this.app);
|
|
||||||
return this.app.adProvider.initialize().catch(err => {
|
|
||||||
logger.error("Failed to initialize ad provider, disabling ads:", err);
|
|
||||||
this.app.adProvider = new NoAdProvider(this.app);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
exitApp() {
|
|
||||||
// Can not exit app
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,65 +1,57 @@
|
|||||||
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
|
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
|
||||||
import { getIPCRenderer } from "../../core/utils";
|
import { getIPCRenderer } from "../../core/utils";
|
||||||
import { createLogger } from "../../core/logging";
|
import { createLogger } from "../../core/logging";
|
||||||
import { StorageImplElectron } from "./storage";
|
import { StorageImplElectron } from "./storage";
|
||||||
import { PlatformWrapperInterface } from "../wrapper";
|
import { PlatformWrapperInterface } from "../wrapper";
|
||||||
|
|
||||||
const logger = createLogger("electron-wrapper");
|
const logger = createLogger("electron-wrapper");
|
||||||
|
|
||||||
export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
|
export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
|
||||||
initialize() {
|
initialize() {
|
||||||
this.app.storage = new StorageImplElectron(this);
|
this.app.storage = new StorageImplElectron(this);
|
||||||
return PlatformWrapperInterface.prototype.initialize.call(this);
|
return PlatformWrapperInterface.prototype.initialize.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
getId() {
|
getId() {
|
||||||
return "electron";
|
return "electron";
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupportsRestart() {
|
getSupportsRestart() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
openExternalLink(url) {
|
openExternalLink(url) {
|
||||||
logger.log(this, "Opening external:", url);
|
logger.log(this, "Opening external:", url);
|
||||||
window.open(url, "about:blank");
|
window.open(url, "about:blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupportsAds() {
|
getSupportsAds() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHasUnlimitedSavegames() {
|
performRestart() {
|
||||||
return true;
|
logger.log(this, "Performing restart");
|
||||||
}
|
window.location.reload(true);
|
||||||
|
}
|
||||||
getShowDemoBadges() {
|
|
||||||
return false;
|
initializeAdProvider() {
|
||||||
}
|
return Promise.resolve();
|
||||||
|
}
|
||||||
performRestart() {
|
|
||||||
logger.log(this, "Performing restart");
|
getSupportsFullscreen() {
|
||||||
window.location.reload(true);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeAdProvider() {
|
setFullscreen(flag) {
|
||||||
return Promise.resolve();
|
getIPCRenderer().send("set-fullscreen", flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupportsFullscreen() {
|
getSupportsAppExit() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFullscreen(flag) {
|
exitApp() {
|
||||||
getIPCRenderer().send("set-fullscreen", flag);
|
logger.log(this, "Sending app exit signal");
|
||||||
}
|
getIPCRenderer().send("exit-app");
|
||||||
|
}
|
||||||
getSupportsAppExit() {
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
exitApp() {
|
|
||||||
logger.log(this, "Sending app exit signal");
|
|
||||||
getIPCRenderer().send("exit-app");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,7 @@ import { GameRoot } from "../game/root";
|
|||||||
|
|
||||||
import { newEmptyMap, clamp } from "../core/utils";
|
import { newEmptyMap, clamp } from "../core/utils";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { globalConfig, IS_DEMO } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
|
|
||||||
const logger = createLogger("sound");
|
const logger = createLogger("sound");
|
||||||
|
|
||||||
@ -29,7 +29,9 @@ export const SOUNDS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const MUSIC = {
|
export const MUSIC = {
|
||||||
theme: IS_DEMO ? "theme-short" : "theme-full",
|
// The theme always depends on the standalone only, even if running the full
|
||||||
|
// version in the browser
|
||||||
|
theme: G_IS_STANDALONE ? "theme-full" : "theme-short",
|
||||||
menu: "menu",
|
menu: "menu",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,142 +1,131 @@
|
|||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
import { Application } from "../application";
|
import { Application } from "../application";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { IS_MOBILE } from "../core/config";
|
import { IS_MOBILE } from "../core/config";
|
||||||
|
|
||||||
export class PlatformWrapperInterface {
|
export class PlatformWrapperInterface {
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
/** @type {Application} */
|
/** @type {Application} */
|
||||||
this.app = app;
|
this.app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {string} */
|
/** @returns {string} */
|
||||||
getId() {
|
getId() {
|
||||||
abstract;
|
abstract;
|
||||||
return "unknown-platform";
|
return "unknown-platform";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the UI scale, called on every resize
|
* Returns the UI scale, called on every resize
|
||||||
* @returns {number} */
|
* @returns {number} */
|
||||||
getUiScale() {
|
getUiScale() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
getSupportsRestart() {
|
getSupportsRestart() {
|
||||||
abstract;
|
abstract;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user has unlimited savegames
|
* Returns the strength of touch pans with the mouse
|
||||||
*/
|
*/
|
||||||
getHasUnlimitedSavegames() {
|
getTouchPanStrength() {
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getShowDemoBadges() {
|
/** @returns {Promise<void>} */
|
||||||
return false;
|
initialize() {
|
||||||
}
|
document.documentElement.classList.add("p-" + this.getId());
|
||||||
|
return Promise.resolve();
|
||||||
/**
|
}
|
||||||
* Returns the strength of touch pans with the mouse
|
|
||||||
*/
|
/**
|
||||||
getTouchPanStrength() {
|
* Should initialize the apps ad provider in case supported
|
||||||
return 1;
|
* @returns {Promise<void>}
|
||||||
}
|
*/
|
||||||
|
initializeAdProvider() {
|
||||||
/** @returns {Promise<void>} */
|
return Promise.resolve();
|
||||||
initialize() {
|
}
|
||||||
document.documentElement.classList.add("p-" + this.getId());
|
|
||||||
return Promise.resolve();
|
/**
|
||||||
}
|
* Should return the minimum supported zoom level
|
||||||
|
* @returns {number}
|
||||||
/**
|
*/
|
||||||
* Should initialize the apps ad provider in case supported
|
getMinimumZoom() {
|
||||||
* @returns {Promise<void>}
|
return 0.1 * this.getScreenScale();
|
||||||
*/
|
}
|
||||||
initializeAdProvider() {
|
|
||||||
return Promise.resolve();
|
/**
|
||||||
}
|
* Should return the maximum supported zoom level
|
||||||
|
* @returns {number}
|
||||||
/**
|
*/
|
||||||
* Should return the minimum supported zoom level
|
getMaximumZoom() {
|
||||||
* @returns {number}
|
return 3.5 * this.getScreenScale();
|
||||||
*/
|
}
|
||||||
getMinimumZoom() {
|
|
||||||
return 0.1 * this.getScreenScale();
|
getScreenScale() {
|
||||||
}
|
return Math.min(window.innerWidth, window.innerHeight) / 1024.0;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Should return the maximum supported zoom level
|
/**
|
||||||
* @returns {number}
|
* Should return if this platform supports ads at all
|
||||||
*/
|
*/
|
||||||
getMaximumZoom() {
|
getSupportsAds() {
|
||||||
return 3.5 * this.getScreenScale();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getScreenScale() {
|
/**
|
||||||
return Math.min(window.innerWidth, window.innerHeight) / 1024.0;
|
* Attempt to open an external url
|
||||||
}
|
* @param {string} url
|
||||||
|
* @param {boolean=} force Whether to always open the url even if not allowed
|
||||||
/**
|
*/
|
||||||
* Should return if this platform supports ads at all
|
openExternalLink(url, force = false) {
|
||||||
*/
|
abstract;
|
||||||
getSupportsAds() {
|
}
|
||||||
return false;
|
|
||||||
}
|
/**
|
||||||
|
* Attempt to restart the app
|
||||||
/**
|
*/
|
||||||
* Attempt to open an external url
|
performRestart() {
|
||||||
* @param {string} url
|
abstract;
|
||||||
* @param {boolean=} force Whether to always open the url even if not allowed
|
}
|
||||||
*/
|
|
||||||
openExternalLink(url, force = false) {
|
/**
|
||||||
abstract;
|
* Returns whether this platform supports a toggleable fullscreen
|
||||||
}
|
*/
|
||||||
|
getSupportsFullscreen() {
|
||||||
/**
|
return false;
|
||||||
* Attempt to restart the app
|
}
|
||||||
*/
|
|
||||||
performRestart() {
|
/**
|
||||||
abstract;
|
* Should set the apps fullscreen state to the desired state
|
||||||
}
|
* @param {boolean} flag
|
||||||
|
*/
|
||||||
/**
|
setFullscreen(flag) {
|
||||||
* Returns whether this platform supports a toggleable fullscreen
|
abstract;
|
||||||
*/
|
}
|
||||||
getSupportsFullscreen() {
|
|
||||||
return false;
|
/**
|
||||||
}
|
* Returns whether this platform supports quitting the app
|
||||||
|
*/
|
||||||
/**
|
getSupportsAppExit() {
|
||||||
* Should set the apps fullscreen state to the desired state
|
return false;
|
||||||
* @param {boolean} flag
|
}
|
||||||
*/
|
|
||||||
setFullscreen(flag) {
|
/**
|
||||||
abstract;
|
* Attempts to quit the app
|
||||||
}
|
*/
|
||||||
|
exitApp() {
|
||||||
/**
|
abstract;
|
||||||
* Returns whether this platform supports quitting the app
|
}
|
||||||
*/
|
|
||||||
getSupportsAppExit() {
|
/**
|
||||||
return false;
|
* Whether this platform supports a keyboard
|
||||||
}
|
*/
|
||||||
|
getSupportsKeyboard() {
|
||||||
/**
|
return !IS_MOBILE;
|
||||||
* Attempts to quit the app
|
}
|
||||||
*/
|
}
|
||||||
exitApp() {
|
|
||||||
abstract;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this platform supports a keyboard
|
|
||||||
*/
|
|
||||||
getSupportsKeyboard() {
|
|
||||||
return !IS_MOBILE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,8 +6,7 @@ import { ReadWriteProxy } from "../core/read_write_proxy";
|
|||||||
import { BoolSetting, EnumSetting, RangeSetting, BaseSetting } from "./setting_types";
|
import { BoolSetting, EnumSetting, RangeSetting, BaseSetting } from "./setting_types";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { ExplainedResult } from "../core/explained_result";
|
import { ExplainedResult } from "../core/explained_result";
|
||||||
import { THEMES, THEME, applyGameTheme } from "../game/theme";
|
import { THEMES, applyGameTheme } from "../game/theme";
|
||||||
import { IS_DEMO } from "../core/config";
|
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
import { LANGUAGES } from "../languages";
|
import { LANGUAGES } from "../languages";
|
||||||
|
|
||||||
@ -187,7 +186,9 @@ export const allApplicationSettings = [
|
|||||||
app.platformWrapper.setFullscreen(value);
|
app.platformWrapper.setFullscreen(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
!IS_DEMO
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/ app => app.restrictionMgr.getHasExtendedSettings()
|
||||||
),
|
),
|
||||||
|
|
||||||
new BoolSetting(
|
new BoolSetting(
|
||||||
@ -215,7 +216,9 @@ export const allApplicationSettings = [
|
|||||||
applyGameTheme(id);
|
applyGameTheme(id);
|
||||||
document.documentElement.setAttribute("data-theme", id);
|
document.documentElement.setAttribute("data-theme", id);
|
||||||
},
|
},
|
||||||
enabled: !IS_DEMO,
|
enabledCb: /**
|
||||||
|
* @param {Application} app
|
||||||
|
*/ app => app.restrictionMgr.getHasExtendedSettings(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new EnumSetting("autosaveInterval", {
|
new EnumSetting("autosaveInterval", {
|
||||||
@ -271,7 +274,9 @@ export const allApplicationSettings = [
|
|||||||
category: enumCategories.performance,
|
category: enumCategories.performance,
|
||||||
restartRequired: false,
|
restartRequired: false,
|
||||||
changeCb: (app, id) => {},
|
changeCb: (app, id) => {},
|
||||||
enabled: !IS_DEMO,
|
enabledCb: /**
|
||||||
|
* @param {Application} app
|
||||||
|
*/ app => app.restrictionMgr.getHasExtendedSettings(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new BoolSetting("lowQualityMapResources", enumCategories.performance, (app, value) => {}),
|
new BoolSetting("lowQualityMapResources", enumCategories.performance, (app, value) => {}),
|
||||||
@ -355,7 +360,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
* @returns {SettingsStorage}
|
* @returns {SettingsStorage}
|
||||||
*/
|
*/
|
||||||
getAllSettings() {
|
getAllSettings() {
|
||||||
return this.getCurrentData().settings;
|
return this.currentData.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,13 +13,13 @@ export class BaseSetting {
|
|||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @param {string} categoryId
|
* @param {string} categoryId
|
||||||
* @param {function(Application, any):void} changeCb
|
* @param {function(Application, any):void} changeCb
|
||||||
* @param {boolean} enabled
|
* @param {function(Application) : boolean=} enabledCb
|
||||||
*/
|
*/
|
||||||
constructor(id, categoryId, changeCb, enabled) {
|
constructor(id, categoryId, changeCb, enabledCb = null) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.categoryId = categoryId;
|
this.categoryId = categoryId;
|
||||||
this.changeCb = changeCb;
|
this.changeCb = changeCb;
|
||||||
this.enabled = enabled;
|
this.enabledCb = enabledCb;
|
||||||
|
|
||||||
/** @type {Application} */
|
/** @type {Application} */
|
||||||
this.app = null;
|
this.app = null;
|
||||||
@ -39,6 +39,7 @@ export class BaseSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Binds all parameters
|
||||||
* @param {Application} app
|
* @param {Application} app
|
||||||
* @param {HTMLElement} element
|
* @param {HTMLElement} element
|
||||||
* @param {any} dialogs
|
* @param {any} dialogs
|
||||||
@ -49,19 +50,37 @@ export class BaseSetting {
|
|||||||
this.dialogs = dialogs;
|
this.dialogs = dialogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHtml() {
|
/**
|
||||||
|
* Returns the HTML for this setting
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
getHtml(app) {
|
||||||
abstract;
|
abstract;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this setting is enabled and available
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
getIsAvailable(app) {
|
||||||
|
return this.enabledCb ? this.enabledCb(app) : true;
|
||||||
|
}
|
||||||
|
|
||||||
syncValueToElement() {
|
syncValueToElement() {
|
||||||
abstract;
|
abstract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to modify the setting
|
||||||
|
*/
|
||||||
modify() {
|
modify() {
|
||||||
abstract;
|
abstract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the dialog that a restart is required
|
||||||
|
*/
|
||||||
showRestartRequiredDialog() {
|
showRestartRequiredDialog() {
|
||||||
const { restart } = this.dialogs.showInfo(
|
const { restart } = this.dialogs.showInfo(
|
||||||
T.dialogs.restartRequired.title,
|
T.dialogs.restartRequired.title,
|
||||||
@ -74,6 +93,7 @@ export class BaseSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Validates the set value
|
||||||
* @param {any} value
|
* @param {any} value
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
@ -96,10 +116,10 @@ export class EnumSetting extends BaseSetting {
|
|||||||
iconPrefix = null,
|
iconPrefix = null,
|
||||||
changeCb = null,
|
changeCb = null,
|
||||||
magicValue = null,
|
magicValue = null,
|
||||||
enabled = true,
|
enabledCb = null,
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
super(id, category, changeCb, enabled);
|
super(id, category, changeCb, enabledCb);
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.valueGetter = valueGetter;
|
this.valueGetter = valueGetter;
|
||||||
@ -110,10 +130,14 @@ export class EnumSetting extends BaseSetting {
|
|||||||
this.magicValue = magicValue;
|
this.magicValue = magicValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHtml() {
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
getHtml(app) {
|
||||||
|
const available = this.getIsAvailable(app);
|
||||||
return `
|
return `
|
||||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
|
||||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
${available ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>${T.settings.labels[this.id].title}</label>
|
<label>${T.settings.labels[this.id].title}</label>
|
||||||
<div class="value enum" data-setting="${this.id}"></div>
|
<div class="value enum" data-setting="${this.id}"></div>
|
||||||
@ -180,14 +204,18 @@ export class EnumSetting extends BaseSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class BoolSetting extends BaseSetting {
|
export class BoolSetting extends BaseSetting {
|
||||||
constructor(id, category, changeCb = null, enabled = true) {
|
constructor(id, category, changeCb = null, enabledCb = null) {
|
||||||
super(id, category, changeCb, enabled);
|
super(id, category, changeCb, enabledCb);
|
||||||
}
|
}
|
||||||
|
|
||||||
getHtml() {
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
getHtml(app) {
|
||||||
|
const available = this.getIsAvailable(app);
|
||||||
return `
|
return `
|
||||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
|
||||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
${available ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>${T.settings.labels[this.id].title}</label>
|
<label>${T.settings.labels[this.id].title}</label>
|
||||||
@ -226,13 +254,13 @@ export class RangeSetting extends BaseSetting {
|
|||||||
id,
|
id,
|
||||||
category,
|
category,
|
||||||
changeCb = null,
|
changeCb = null,
|
||||||
enabled = true,
|
|
||||||
defaultValue = 1.0,
|
defaultValue = 1.0,
|
||||||
minValue = 0,
|
minValue = 0,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
stepSize = 0.0001
|
stepSize = 0.0001,
|
||||||
|
enabledCb = null
|
||||||
) {
|
) {
|
||||||
super(id, category, changeCb, enabled);
|
super(id, category, changeCb, enabledCb);
|
||||||
|
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
this.minValue = minValue;
|
this.minValue = minValue;
|
||||||
@ -240,10 +268,14 @@ export class RangeSetting extends BaseSetting {
|
|||||||
this.stepSize = stepSize;
|
this.stepSize = stepSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHtml() {
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
getHtml(app) {
|
||||||
|
const available = this.getIsAvailable(app);
|
||||||
return `
|
return `
|
||||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
|
||||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
${available ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>${T.settings.labels[this.id].title}</label>
|
<label>${T.settings.labels[this.id].title}</label>
|
||||||
|
@ -40,13 +40,6 @@ export class SavegameManager extends ReadWriteProxy {
|
|||||||
return 1002;
|
return 1002;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {SavegamesData}
|
|
||||||
*/
|
|
||||||
getCurrentData() {
|
|
||||||
return super.getCurrentData();
|
|
||||||
}
|
|
||||||
|
|
||||||
verify(data) {
|
verify(data) {
|
||||||
// TODO / FIXME!!!!
|
// TODO / FIXME!!!!
|
||||||
return ExplainedResult.good();
|
return ExplainedResult.good();
|
||||||
|
@ -1,179 +1,173 @@
|
|||||||
import { TextualGameState } from "../core/textual_game_state";
|
import { Dialog } from "../core/modal_dialog_elements";
|
||||||
import { SOUNDS } from "../platform/sound";
|
import { TextualGameState } from "../core/textual_game_state";
|
||||||
import { T } from "../translations";
|
import { getStringForKeyCode, KEYMAPPINGS } from "../game/key_action_mapper";
|
||||||
import { KEYMAPPINGS, getStringForKeyCode } from "../game/key_action_mapper";
|
import { SOUNDS } from "../platform/sound";
|
||||||
import { Dialog } from "../core/modal_dialog_elements";
|
import { T } from "../translations";
|
||||||
import { IS_DEMO } from "../core/config";
|
|
||||||
|
export class KeybindingsState extends TextualGameState {
|
||||||
export class KeybindingsState extends TextualGameState {
|
constructor() {
|
||||||
constructor() {
|
super("KeybindingsState");
|
||||||
super("KeybindingsState");
|
}
|
||||||
}
|
|
||||||
|
getStateHeaderTitle() {
|
||||||
getStateHeaderTitle() {
|
return T.keybindings.title;
|
||||||
return T.keybindings.title;
|
}
|
||||||
}
|
|
||||||
|
getMainContentHTML() {
|
||||||
getMainContentHTML() {
|
return `
|
||||||
return `
|
|
||||||
|
<div class="topEntries">
|
||||||
<div class="topEntries">
|
<span class="hint">${T.keybindings.hint}</span>
|
||||||
<span class="hint">${T.keybindings.hint}</span>
|
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
||||||
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="keybindings">
|
||||||
<div class="keybindings">
|
|
||||||
|
</div>
|
||||||
</div>
|
`;
|
||||||
`;
|
}
|
||||||
}
|
|
||||||
|
onEnter() {
|
||||||
onEnter() {
|
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
||||||
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
|
||||||
|
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
||||||
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
|
||||||
|
for (const category in KEYMAPPINGS) {
|
||||||
for (const category in KEYMAPPINGS) {
|
const categoryDiv = document.createElement("div");
|
||||||
const categoryDiv = document.createElement("div");
|
categoryDiv.classList.add("category");
|
||||||
categoryDiv.classList.add("category");
|
keybindingsElem.appendChild(categoryDiv);
|
||||||
keybindingsElem.appendChild(categoryDiv);
|
|
||||||
|
const labelDiv = document.createElement("strong");
|
||||||
const labelDiv = document.createElement("strong");
|
labelDiv.innerText = T.keybindings.categoryLabels[category];
|
||||||
labelDiv.innerText = T.keybindings.categoryLabels[category];
|
labelDiv.classList.add("categoryLabel");
|
||||||
labelDiv.classList.add("categoryLabel");
|
categoryDiv.appendChild(labelDiv);
|
||||||
categoryDiv.appendChild(labelDiv);
|
|
||||||
|
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||||
for (const keybindingId in KEYMAPPINGS[category]) {
|
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||||
const mapped = KEYMAPPINGS[category][keybindingId];
|
|
||||||
|
const elem = document.createElement("div");
|
||||||
const elem = document.createElement("div");
|
elem.classList.add("entry");
|
||||||
elem.classList.add("entry");
|
elem.setAttribute("data-keybinding", keybindingId);
|
||||||
elem.setAttribute("data-keybinding", keybindingId);
|
categoryDiv.appendChild(elem);
|
||||||
categoryDiv.appendChild(elem);
|
|
||||||
|
const title = document.createElement("span");
|
||||||
const title = document.createElement("span");
|
title.classList.add("title");
|
||||||
title.classList.add("title");
|
title.innerText = T.keybindings.mappings[keybindingId];
|
||||||
title.innerText = T.keybindings.mappings[keybindingId];
|
elem.appendChild(title);
|
||||||
elem.appendChild(title);
|
|
||||||
|
const mappingDiv = document.createElement("span");
|
||||||
const mappingDiv = document.createElement("span");
|
mappingDiv.classList.add("mapping");
|
||||||
mappingDiv.classList.add("mapping");
|
elem.appendChild(mappingDiv);
|
||||||
elem.appendChild(mappingDiv);
|
|
||||||
|
const editBtn = document.createElement("button");
|
||||||
const editBtn = document.createElement("button");
|
editBtn.classList.add("styledButton", "editKeybinding");
|
||||||
editBtn.classList.add("styledButton", "editKeybinding");
|
|
||||||
|
const resetBtn = document.createElement("button");
|
||||||
const resetBtn = document.createElement("button");
|
resetBtn.classList.add("styledButton", "resetKeybinding");
|
||||||
resetBtn.classList.add("styledButton", "resetKeybinding");
|
|
||||||
|
if (mapped.builtin) {
|
||||||
if (mapped.builtin) {
|
editBtn.classList.add("disabled");
|
||||||
editBtn.classList.add("disabled");
|
resetBtn.classList.add("disabled");
|
||||||
resetBtn.classList.add("disabled");
|
} else {
|
||||||
} else {
|
this.trackClicks(editBtn, () => this.editKeybinding(keybindingId));
|
||||||
this.trackClicks(editBtn, () => this.editKeybinding(keybindingId));
|
this.trackClicks(resetBtn, () => this.resetKeybinding(keybindingId));
|
||||||
this.trackClicks(resetBtn, () => this.resetKeybinding(keybindingId));
|
}
|
||||||
}
|
elem.appendChild(editBtn);
|
||||||
elem.appendChild(editBtn);
|
elem.appendChild(resetBtn);
|
||||||
elem.appendChild(resetBtn);
|
}
|
||||||
}
|
}
|
||||||
}
|
this.updateKeybindings();
|
||||||
this.updateKeybindings();
|
}
|
||||||
}
|
|
||||||
|
editKeybinding(id) {
|
||||||
editKeybinding(id) {
|
const dialog = new Dialog({
|
||||||
// if (IS_DEMO) {
|
app: this.app,
|
||||||
// this.dialogs.showFeatureRestrictionInfo(T.demo.features.customizeKeybindings);
|
title: T.dialogs.editKeybinding.title,
|
||||||
// return;
|
contentHTML: T.dialogs.editKeybinding.desc,
|
||||||
// }
|
buttons: ["cancel:good"],
|
||||||
|
type: "info",
|
||||||
const dialog = new Dialog({
|
});
|
||||||
app: this.app,
|
|
||||||
title: T.dialogs.editKeybinding.title,
|
dialog.inputReciever.keydown.add(({ keyCode, shift, alt, event }) => {
|
||||||
contentHTML: T.dialogs.editKeybinding.desc,
|
if (keyCode === 27) {
|
||||||
buttons: ["cancel:good"],
|
this.dialogs.closeDialog(dialog);
|
||||||
type: "info",
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
dialog.inputReciever.keydown.add(({ keyCode, shift, alt, event }) => {
|
if (event) {
|
||||||
if (keyCode === 27) {
|
event.preventDefault();
|
||||||
this.dialogs.closeDialog(dialog);
|
}
|
||||||
return;
|
|
||||||
}
|
if (event.target && event.target.tagName === "BUTTON" && keyCode === 1) {
|
||||||
|
return;
|
||||||
if (event) {
|
}
|
||||||
event.preventDefault();
|
|
||||||
}
|
if (
|
||||||
|
// Enter
|
||||||
if (event.target && event.target.tagName === "BUTTON" && keyCode === 1) {
|
keyCode === 13
|
||||||
return;
|
) {
|
||||||
}
|
// Ignore builtins
|
||||||
|
return;
|
||||||
if (
|
}
|
||||||
// Enter
|
|
||||||
keyCode === 13
|
this.app.settings.updateKeybindingOverride(id, keyCode);
|
||||||
) {
|
|
||||||
// Ignore builtins
|
this.dialogs.closeDialog(dialog);
|
||||||
return;
|
this.updateKeybindings();
|
||||||
}
|
});
|
||||||
|
|
||||||
this.app.settings.updateKeybindingOverride(id, keyCode);
|
dialog.inputReciever.backButton.add(() => {});
|
||||||
|
this.dialogs.internalShowDialog(dialog);
|
||||||
this.dialogs.closeDialog(dialog);
|
|
||||||
this.updateKeybindings();
|
this.app.sound.playUiSound(SOUNDS.dialogOk);
|
||||||
});
|
}
|
||||||
|
|
||||||
dialog.inputReciever.backButton.add(() => {});
|
updateKeybindings() {
|
||||||
this.dialogs.internalShowDialog(dialog);
|
const overrides = this.app.settings.getKeybindingOverrides();
|
||||||
|
for (const category in KEYMAPPINGS) {
|
||||||
this.app.sound.playUiSound(SOUNDS.dialogOk);
|
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||||
}
|
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||||
|
|
||||||
updateKeybindings() {
|
const container = this.htmlElement.querySelector("[data-keybinding='" + keybindingId + "']");
|
||||||
const overrides = this.app.settings.getKeybindingOverrides();
|
assert(container, "Container for keybinding not found: " + keybindingId);
|
||||||
for (const category in KEYMAPPINGS) {
|
|
||||||
for (const keybindingId in KEYMAPPINGS[category]) {
|
let keyCode = mapped.keyCode;
|
||||||
const mapped = KEYMAPPINGS[category][keybindingId];
|
if (overrides[keybindingId]) {
|
||||||
|
keyCode = overrides[keybindingId];
|
||||||
const container = this.htmlElement.querySelector("[data-keybinding='" + keybindingId + "']");
|
}
|
||||||
assert(container, "Container for keybinding not found: " + keybindingId);
|
|
||||||
|
const mappingDiv = container.querySelector(".mapping");
|
||||||
let keyCode = mapped.keyCode;
|
mappingDiv.innerHTML = getStringForKeyCode(keyCode);
|
||||||
if (overrides[keybindingId]) {
|
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
||||||
keyCode = overrides[keybindingId];
|
|
||||||
}
|
const resetBtn = container.querySelector("button.resetKeybinding");
|
||||||
|
resetBtn.classList.toggle("disabled", mapped.builtin || !overrides[keybindingId]);
|
||||||
const mappingDiv = container.querySelector(".mapping");
|
}
|
||||||
mappingDiv.innerHTML = getStringForKeyCode(keyCode);
|
}
|
||||||
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
}
|
||||||
|
|
||||||
const resetBtn = container.querySelector("button.resetKeybinding");
|
resetKeybinding(id) {
|
||||||
resetBtn.classList.toggle("disabled", mapped.builtin || !overrides[keybindingId]);
|
this.app.settings.resetKeybindingOverride(id);
|
||||||
}
|
this.updateKeybindings();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
resetBindings() {
|
||||||
resetKeybinding(id) {
|
const { reset } = this.dialogs.showWarning(
|
||||||
this.app.settings.resetKeybindingOverride(id);
|
T.dialogs.resetKeybindingsConfirmation.title,
|
||||||
this.updateKeybindings();
|
T.dialogs.resetKeybindingsConfirmation.desc,
|
||||||
}
|
["cancel:good", "reset:bad"]
|
||||||
|
);
|
||||||
resetBindings() {
|
|
||||||
const { reset } = this.dialogs.showWarning(
|
reset.add(() => {
|
||||||
T.dialogs.resetKeybindingsConfirmation.title,
|
this.app.settings.resetKeybindingOverrides();
|
||||||
T.dialogs.resetKeybindingsConfirmation.desc,
|
this.updateKeybindings();
|
||||||
["cancel:good", "reset:bad"]
|
|
||||||
);
|
this.dialogs.showInfo(T.dialogs.keybindingsResetOk.title, T.dialogs.keybindingsResetOk.desc);
|
||||||
|
});
|
||||||
reset.add(() => {
|
}
|
||||||
this.app.settings.resetKeybindingOverrides();
|
|
||||||
this.updateKeybindings();
|
getDefaultPreviousState() {
|
||||||
|
return "SettingsState";
|
||||||
this.dialogs.showInfo(T.dialogs.keybindingsResetOk.title, T.dialogs.keybindingsResetOk.desc);
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
getDefaultPreviousState() {
|
|
||||||
return "SettingsState";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import { GameState } from "../core/game_state";
|
|
||||||
import { cachebust } from "../core/cachebust";
|
import { cachebust } from "../core/cachebust";
|
||||||
import { A_B_TESTING_LINK_TYPE, globalConfig, IS_DEMO, THIRDPARTY_URLS } from "../core/config";
|
import { A_B_TESTING_LINK_TYPE, globalConfig, THIRDPARTY_URLS } from "../core/config";
|
||||||
|
import { GameState } from "../core/game_state";
|
||||||
|
import { DialogWithForm } from "../core/modal_dialog_elements";
|
||||||
|
import { FormElementInput } from "../core/modal_dialog_forms";
|
||||||
|
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||||
import {
|
import {
|
||||||
makeDiv,
|
|
||||||
makeButtonElement,
|
|
||||||
formatSecondsToTimeAgo,
|
formatSecondsToTimeAgo,
|
||||||
waitNextFrame,
|
generateFileDownload,
|
||||||
isSupportedBrowser,
|
isSupportedBrowser,
|
||||||
makeButton,
|
makeButton,
|
||||||
|
makeButtonElement,
|
||||||
|
makeDiv,
|
||||||
removeAllChildren,
|
removeAllChildren,
|
||||||
|
startFileChoose,
|
||||||
|
waitNextFrame,
|
||||||
} from "../core/utils";
|
} from "../core/utils";
|
||||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
|
||||||
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||||
import { T } from "../translations";
|
|
||||||
import { getApplicationSettingById } from "../profile/application_settings";
|
import { getApplicationSettingById } from "../profile/application_settings";
|
||||||
import { FormElementInput } from "../core/modal_dialog_forms";
|
import { T } from "../translations";
|
||||||
import { DialogWithForm } from "../core/modal_dialog_elements";
|
|
||||||
|
|
||||||
const trim = require("trim");
|
const trim = require("trim");
|
||||||
|
|
||||||
@ -24,23 +26,6 @@ const trim = require("trim");
|
|||||||
* @typedef {import("../profile/setting_types").EnumSetting} EnumSetting
|
* @typedef {import("../profile/setting_types").EnumSetting} EnumSetting
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a file download
|
|
||||||
* @param {string} filename
|
|
||||||
* @param {string} text
|
|
||||||
*/
|
|
||||||
function generateFileDownload(filename, text) {
|
|
||||||
var element = document.createElement("a");
|
|
||||||
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
|
|
||||||
element.setAttribute("download", filename);
|
|
||||||
|
|
||||||
element.style.display = "none";
|
|
||||||
document.body.appendChild(element);
|
|
||||||
|
|
||||||
element.click();
|
|
||||||
document.body.removeChild(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MainMenuState extends GameState {
|
export class MainMenuState extends GameState {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("MainMenuState");
|
super("MainMenuState");
|
||||||
@ -49,18 +34,16 @@ export class MainMenuState extends GameState {
|
|||||||
getInnerHTML() {
|
getInnerHTML() {
|
||||||
const bannerHtml = `
|
const bannerHtml = `
|
||||||
<h3>${T.demoBanners.title}</h3>
|
<h3>${T.demoBanners.title}</h3>
|
||||||
|
|
||||||
<p>${T.demoBanners.intro}</p>
|
<p>${T.demoBanners.intro}</p>
|
||||||
|
|
||||||
<a href="#" class="steamLink ${A_B_TESTING_LINK_TYPE}" target="_blank">Get the shapez.io standalone!</a>
|
<a href="#" class="steamLink ${A_B_TESTING_LINK_TYPE}" target="_blank">Get the shapez.io standalone!</a>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return `
|
const showDemoBadges = this.app.restrictionMgr.getIsStandaloneMarketingActive();
|
||||||
|
|
||||||
|
return `
|
||||||
<div class="topButtons">
|
<div class="topButtons">
|
||||||
<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>
|
<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>
|
||||||
<button class="settingsButton"></button>
|
<button class="settingsButton"></button>
|
||||||
|
|
||||||
${
|
${
|
||||||
G_IS_STANDALONE || G_IS_DEV
|
G_IS_STANDALONE || G_IS_DEV
|
||||||
? `
|
? `
|
||||||
@ -74,17 +57,14 @@ export class MainMenuState extends GameState {
|
|||||||
<source src="${cachebust("res/bg_render.webm")}" type="video/webm">
|
<source src="${cachebust("res/bg_render.webm")}" type="video/webm">
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
|
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
|
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
|
||||||
<span class="updateLabel">Wires update!</span>
|
<span class="updateLabel">Wires update!</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mainWrapper ${showDemoBadges ? "demo" : "noDemo"}">
|
||||||
<div class="mainWrapper ${IS_DEMO ? "demo" : "noDemo"}">
|
|
||||||
|
|
||||||
<div class="sideContainer">
|
<div class="sideContainer">
|
||||||
${IS_DEMO ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
|
${showDemoBadges ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mainContainer">
|
<div class="mainContainer">
|
||||||
@ -95,12 +75,9 @@ export class MainMenuState extends GameState {
|
|||||||
}
|
}
|
||||||
<div class="buttons"></div>
|
<div class="buttons"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
|
||||||
<a class="githubLink boxLink" target="_blank">
|
<a class="githubLink boxLink" target="_blank">
|
||||||
${T.mainMenu.openSourceHint}
|
${T.mainMenu.openSourceHint}
|
||||||
<span class="thirdpartyLogo githubLogo"></span>
|
<span class="thirdpartyLogo githubLogo"></span>
|
||||||
@ -123,32 +100,29 @@ export class MainMenuState extends GameState {
|
|||||||
"<author-link>",
|
"<author-link>",
|
||||||
'<a class="producerLink" target="_blank">Tobias Springer</a>'
|
'<a class="producerLink" target="_blank">Tobias Springer</a>'
|
||||||
)}</div>
|
)}</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the user to import a savegame
|
||||||
|
*/
|
||||||
requestImportSavegame() {
|
requestImportSavegame() {
|
||||||
if (
|
if (
|
||||||
IS_DEMO &&
|
|
||||||
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
||||||
!this.app.platformWrapper.getHasUnlimitedSavegames()
|
!this.app.restrictionMgr.getHasUnlimitedSavegames()
|
||||||
) {
|
) {
|
||||||
this.app.analytics.trackUiClick("importgame_slot_limit_show");
|
this.app.analytics.trackUiClick("importgame_slot_limit_show");
|
||||||
this.showSavegameSlotLimit();
|
this.showSavegameSlotLimit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var input = document.createElement("input");
|
// Create a 'fake' file-input to accept savegames
|
||||||
input.type = "file";
|
startFileChoose(".bin").then(file => {
|
||||||
input.accept = ".bin";
|
|
||||||
|
|
||||||
input.onchange = e => {
|
|
||||||
const file = input.files[0];
|
|
||||||
if (file) {
|
if (file) {
|
||||||
|
const closeLoader = this.dialogs.showLoadingDialog();
|
||||||
waitNextFrame().then(() => {
|
waitNextFrame().then(() => {
|
||||||
this.app.analytics.trackUiClick("import_savegame");
|
this.app.analytics.trackUiClick("import_savegame");
|
||||||
const closeLoader = this.dialogs.showLoadingDialog();
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener("load", event => {
|
reader.addEventListener("load", event => {
|
||||||
const contents = event.target.result;
|
const contents = event.target.result;
|
||||||
@ -194,8 +168,7 @@ export class MainMenuState extends GameState {
|
|||||||
reader.readAsText(file, "utf-8");
|
reader.readAsText(file, "utf-8");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
input.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackButton() {
|
onBackButton() {
|
||||||
@ -557,9 +530,8 @@ export class MainMenuState extends GameState {
|
|||||||
|
|
||||||
onPlayButtonClicked() {
|
onPlayButtonClicked() {
|
||||||
if (
|
if (
|
||||||
IS_DEMO &&
|
|
||||||
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
||||||
!this.app.platformWrapper.getHasUnlimitedSavegames()
|
!this.app.restrictionMgr.getHasUnlimitedSavegames()
|
||||||
) {
|
) {
|
||||||
this.app.analytics.trackUiClick("startgame_slot_limit_show");
|
this.app.analytics.trackUiClick("startgame_slot_limit_show");
|
||||||
this.showSavegameSlotLimit();
|
this.showSavegameSlotLimit();
|
||||||
|
@ -1,169 +1,169 @@
|
|||||||
import { TextualGameState } from "../core/textual_game_state";
|
import { TextualGameState } from "../core/textual_game_state";
|
||||||
import { formatSecondsToTimeAgo } from "../core/utils";
|
import { formatSecondsToTimeAgo } from "../core/utils";
|
||||||
import { allApplicationSettings, enumCategories } from "../profile/application_settings";
|
import { allApplicationSettings, enumCategories } from "../profile/application_settings";
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
|
|
||||||
export class SettingsState extends TextualGameState {
|
export class SettingsState extends TextualGameState {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("SettingsState");
|
super("SettingsState");
|
||||||
}
|
}
|
||||||
|
|
||||||
getStateHeaderTitle() {
|
getStateHeaderTitle() {
|
||||||
return T.settings.title;
|
return T.settings.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMainContentHTML() {
|
getMainContentHTML() {
|
||||||
return `
|
return `
|
||||||
|
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
${this.getCategoryButtonsHtml()}
|
${this.getCategoryButtonsHtml()}
|
||||||
|
|
||||||
${
|
${
|
||||||
this.app.platformWrapper.getSupportsKeyboard()
|
this.app.platformWrapper.getSupportsKeyboard()
|
||||||
? `
|
? `
|
||||||
<button class="styledButton categoryButton editKeybindings">
|
<button class="styledButton categoryButton editKeybindings">
|
||||||
${T.keybindings.title}
|
${T.keybindings.title}
|
||||||
</button>`
|
</button>`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="other">
|
<div class="other">
|
||||||
<button class="styledButton about">${T.about.title}</button>
|
<button class="styledButton about">${T.about.title}</button>
|
||||||
|
|
||||||
<div class="versionbar">
|
<div class="versionbar">
|
||||||
<div class="buildVersion">${T.global.loading} ...</div>
|
<div class="buildVersion">${T.global.loading} ...</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="categoryContainer">
|
<div class="categoryContainer">
|
||||||
${this.getSettingsHtml()}
|
${this.getSettingsHtml()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCategoryButtonsHtml() {
|
getCategoryButtonsHtml() {
|
||||||
return Object.keys(enumCategories)
|
return Object.keys(enumCategories)
|
||||||
.map(key => enumCategories[key])
|
.map(key => enumCategories[key])
|
||||||
.map(
|
.map(
|
||||||
category =>
|
category =>
|
||||||
`
|
`
|
||||||
<button class="styledButton categoryButton" data-category-btn="${category}">
|
<button class="styledButton categoryButton" data-category-btn="${category}">
|
||||||
${T.settings.categories[category]}
|
${T.settings.categories[category]}
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
.join("");
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
getSettingsHtml() {
|
getSettingsHtml() {
|
||||||
const categoriesHTML = {};
|
const categoriesHTML = {};
|
||||||
|
|
||||||
Object.keys(enumCategories).forEach(key => {
|
Object.keys(enumCategories).forEach(key => {
|
||||||
const catName = enumCategories[key];
|
const catName = enumCategories[key];
|
||||||
categoriesHTML[catName] = `<div class="category" data-category="${catName}">`;
|
categoriesHTML[catName] = `<div class="category" data-category="${catName}">`;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < allApplicationSettings.length; ++i) {
|
for (let i = 0; i < allApplicationSettings.length; ++i) {
|
||||||
const setting = allApplicationSettings[i];
|
const setting = allApplicationSettings[i];
|
||||||
|
|
||||||
categoriesHTML[setting.categoryId] += setting.getHtml();
|
categoriesHTML[setting.categoryId] += setting.getHtml(this.app);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.keys(categoriesHTML)
|
return Object.keys(categoriesHTML)
|
||||||
.map(k => categoriesHTML[k] + "</div>")
|
.map(k => categoriesHTML[k] + "</div>")
|
||||||
.join("");
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBuildText() {
|
renderBuildText() {
|
||||||
const labelVersion = this.htmlElement.querySelector(".buildVersion");
|
const labelVersion = this.htmlElement.querySelector(".buildVersion");
|
||||||
const lastBuildMs = new Date().getTime() - G_BUILD_TIME;
|
const lastBuildMs = new Date().getTime() - G_BUILD_TIME;
|
||||||
const lastBuildText = formatSecondsToTimeAgo(lastBuildMs / 1000.0);
|
const lastBuildText = formatSecondsToTimeAgo(lastBuildMs / 1000.0);
|
||||||
|
|
||||||
const version = T.settings.versionBadges[G_APP_ENVIRONMENT];
|
const version = T.settings.versionBadges[G_APP_ENVIRONMENT];
|
||||||
|
|
||||||
labelVersion.innerHTML = `
|
labelVersion.innerHTML = `
|
||||||
<span class='version'>
|
<span class='version'>
|
||||||
${G_BUILD_VERSION} @ ${version} @ ${G_BUILD_COMMIT_HASH}
|
${G_BUILD_VERSION} @ ${version} @ ${G_BUILD_COMMIT_HASH}
|
||||||
</span>
|
</span>
|
||||||
<span class='buildTime'>
|
<span class='buildTime'>
|
||||||
${T.settings.buildDate.replace("<at-date>", lastBuildText)}<br />
|
${T.settings.buildDate.replace("<at-date>", lastBuildText)}<br />
|
||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnter(payload) {
|
onEnter(payload) {
|
||||||
this.renderBuildText();
|
this.renderBuildText();
|
||||||
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
||||||
preventDefault: false,
|
preventDefault: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const keybindingsButton = this.htmlElement.querySelector(".editKeybindings");
|
const keybindingsButton = this.htmlElement.querySelector(".editKeybindings");
|
||||||
|
|
||||||
if (keybindingsButton) {
|
if (keybindingsButton) {
|
||||||
this.trackClicks(keybindingsButton, this.onKeybindingsClicked, { preventDefault: false });
|
this.trackClicks(keybindingsButton, this.onKeybindingsClicked, { preventDefault: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initSettings();
|
this.initSettings();
|
||||||
this.initCategoryButtons();
|
this.initCategoryButtons();
|
||||||
|
|
||||||
this.htmlElement.querySelector(".category").classList.add("active");
|
this.htmlElement.querySelector(".category").classList.add("active");
|
||||||
this.htmlElement.querySelector(".categoryButton").classList.add("active");
|
this.htmlElement.querySelector(".categoryButton").classList.add("active");
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveCategory(category) {
|
setActiveCategory(category) {
|
||||||
const previousCategory = this.htmlElement.querySelector(".category.active");
|
const previousCategory = this.htmlElement.querySelector(".category.active");
|
||||||
const previousCategoryButton = this.htmlElement.querySelector(".categoryButton.active");
|
const previousCategoryButton = this.htmlElement.querySelector(".categoryButton.active");
|
||||||
|
|
||||||
if (previousCategory.getAttribute("data-category") == category) {
|
if (previousCategory.getAttribute("data-category") == category) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
previousCategory.classList.remove("active");
|
previousCategory.classList.remove("active");
|
||||||
previousCategoryButton.classList.remove("active");
|
previousCategoryButton.classList.remove("active");
|
||||||
|
|
||||||
const newCategory = this.htmlElement.querySelector("[data-category='" + category + "']");
|
const newCategory = this.htmlElement.querySelector("[data-category='" + category + "']");
|
||||||
const newCategoryButton = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
const newCategoryButton = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
||||||
|
|
||||||
newCategory.classList.add("active");
|
newCategory.classList.add("active");
|
||||||
newCategoryButton.classList.add("active");
|
newCategoryButton.classList.add("active");
|
||||||
}
|
}
|
||||||
|
|
||||||
initSettings() {
|
initSettings() {
|
||||||
allApplicationSettings.forEach(setting => {
|
allApplicationSettings.forEach(setting => {
|
||||||
/** @type {HTMLElement} */
|
/** @type {HTMLElement} */
|
||||||
const element = this.htmlElement.querySelector("[data-setting='" + setting.id + "']");
|
const element = this.htmlElement.querySelector("[data-setting='" + setting.id + "']");
|
||||||
setting.bind(this.app, element, this.dialogs);
|
setting.bind(this.app, element, this.dialogs);
|
||||||
setting.syncValueToElement();
|
setting.syncValueToElement();
|
||||||
this.trackClicks(
|
this.trackClicks(
|
||||||
element,
|
element,
|
||||||
() => {
|
() => {
|
||||||
setting.modify();
|
setting.modify();
|
||||||
},
|
},
|
||||||
{ preventDefault: false }
|
{ preventDefault: false }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initCategoryButtons() {
|
initCategoryButtons() {
|
||||||
Object.keys(enumCategories).forEach(key => {
|
Object.keys(enumCategories).forEach(key => {
|
||||||
const category = enumCategories[key];
|
const category = enumCategories[key];
|
||||||
const button = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
const button = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
||||||
this.trackClicks(
|
this.trackClicks(
|
||||||
button,
|
button,
|
||||||
() => {
|
() => {
|
||||||
this.setActiveCategory(category);
|
this.setActiveCategory(category);
|
||||||
},
|
},
|
||||||
{ preventDefault: false }
|
{ preventDefault: false }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onAboutClicked() {
|
onAboutClicked() {
|
||||||
this.moveToStateAddGoBack("AboutState");
|
this.moveToStateAddGoBack("AboutState");
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeybindingsClicked() {
|
onKeybindingsClicked() {
|
||||||
this.moveToStateAddGoBack("KeybindingsState");
|
this.moveToStateAddGoBack("KeybindingsState");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user