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

Minor fixes and adjustments for easier use

This commit is contained in:
Sense101 2021-07-07 10:15:26 +01:00
parent 900fcc8479
commit a0421ff14b
10 changed files with 186 additions and 138 deletions

BIN
res/ui/icons/upload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -1,4 +1,4 @@
#ingame_HUD_PuzzleEditorDownload {
#ingame_HUD_PuzzleImportExport {
position: absolute;
@include S(top, 35px);
left: 50%;
@ -17,12 +17,14 @@
transition-property: opacity, transform;
text-transform: uppercase;
@include PlainText;
@include S(width, 30px);
@include S(height, 30px);
@include S(width, 20px);
@include S(height, 20px);
margin: 8px 5px;
@include DarkThemeInvert;
opacity: 1;
&:hover {
opacity: 0.9 !important;
}
@ -31,7 +33,13 @@
transform: scale(0.95) !important;
}
& {
&.import {
/* @load-async */
background: uiResource("icons/upload.png") center center / D(15px) no-repeat;
//transform: rotate(180deg);
}
&.export {
/* @load-async */
background: uiResource("icons/download.png") center center / D(15px) no-repeat;
}

View File

@ -65,7 +65,7 @@
@import "ingame_hud/puzzle_play_settings";
@import "ingame_hud/puzzle_play_metadata";
@import "ingame_hud/puzzle_complete_notification";
@import "ingame_hud/puzzle_editor_download";
@import "ingame_hud/puzzle_import_export";
// prettier-ignore
$elements:
@ -85,7 +85,7 @@ ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay,
ingame_HUD_PuzzleBackToMenu,
ingame_HUD_PuzzleEditorReview,
ingame_HUD_PuzzleEditorDownload,
ingame_HUD_PuzzleImportExport,
ingame_HUD_PuzzleEditorControls,
ingame_HUD_PuzzleEditorTitle,
ingame_HUD_PuzzleEditorSettings,
@ -138,7 +138,7 @@ body.uiHidden {
#ingame_HUD_PuzzleEditorSettings,
#ingame_HUD_PuzzlePlaySettings,
#ingame_HUD_PuzzleEditorControls,
#ingame_HUD_PuzzleEditorDownload,
#ingame_HUD_PuzzleImportExport,
#ingame_HUD_PuzzlePlayMetadata,
#ingame_HUD_Notifications,
#ingame_HUD_TutorialHints,

View File

@ -302,8 +302,9 @@ export class HUDBaseToolbar extends BaseHUDPart {
/**
* @param {MetaBuilding} metaBuilding
* @param {boolean | null} force
*/
toggleBuildingLock(metaBuilding) {
toggleBuildingLock(metaBuilding, force = null) {
if (!this.visibilityCondition()) {
// Not active
return;
@ -315,7 +316,11 @@ export class HUDBaseToolbar extends BaseHUDPart {
}
const handle = this.buildingHandles[metaBuilding.getId()];
if (force != null) {
handle.puzzleLocked = force;
} else {
handle.puzzleLocked = !handle.puzzleLocked;
}
handle.element.classList.toggle("unlocked", !handle.puzzleLocked);
const entityManager = this.root.entityMgr;

View File

@ -1,37 +0,0 @@
import { ReadWriteProxy } from "../../../core/read_write_proxy";
import { generateFileDownload, makeDiv } from "../../../core/utils";
import { PuzzleSerializer } from "../../../savegame/puzzle_serializer";
import { T } from "../../../translations";
import { BaseHUDPart } from "../base_hud_part";
export class HUDPuzzleEditorDownload extends BaseHUDPart {
constructor(root) {
super(root);
}
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_PuzzleEditorDownload");
this.button = document.createElement("button");
this.button.classList.add("button");
this.element.appendChild(this.button);
this.trackClicks(this.button, () => {
const { ok } = this.root.hud.parts.dialogs.showWarning(
T.dialogs.puzzleDownload.title,
T.dialogs.puzzleDownload.desc,
["cancel", "ok:good:enter"]
);
ok.add(() => this.downloadPuzzle());
});
}
initialize() {}
downloadPuzzle() {
const serialized = new PuzzleSerializer().generateDumpFromGameRoot(this.root);
const data = ReadWriteProxy.serializeObject(serialized);
const filename = "puzzle.bin";
generateFileDownload(filename, data);
}
}

View File

@ -92,9 +92,8 @@ export class HUDPuzzleEditorSettings extends BaseHUDPart {
testButton.classList.toggle("disabled", false);
}, 140);
this.root.logic.performBulkOperation(() => {
for (const entity of this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
if (this.testMode) {
for (const entity of this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
this.storedSolution.push(entity.clone());
const metaBuilding = entity.components.StaticMapEntity.getMetaBuilding();
@ -111,26 +110,32 @@ export class HUDPuzzleEditorSettings extends BaseHUDPart {
) {
continue;
}
}
this.root.map.removeStaticEntity(entity);
this.root.entityMgr.destroyEntity(entity);
}
this.root.entityMgr.processDestroyList();
} else if (this.storedSolution.length) {
this.root.logic.performBulkOperation(() => {
this.root.logic.performImmutableOperation(() => {
for (const entity of this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
this.root.map.removeStaticEntity(entity);
this.root.entityMgr.destroyEntity(entity);
}
this.root.entityMgr.processDestroyList();
if (!this.testMode) {
for (const entity of this.storedSolution) {
const placedEntity = this.root.logic.tryPlaceEntity(entity);
for (const key in entity.components) {
/** @type {import("../../../core/global_registries").Component} */ (entity.components[
key
]).copyAdditionalStateTo(placedEntity.components[key]);
/** @type {import("../../../core/global_registries").Component} */ (entity
.components[key]).copyAdditionalStateTo(placedEntity.components[key]);
}
}
this.storedSolution = [];
}
});
});
}
}
trim() {

View File

@ -0,0 +1,118 @@
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { ReadWriteProxy } from "../../../core/read_write_proxy";
import { generateFileDownload, makeDiv, startFileChoose, waitNextFrame } from "../../../core/utils";
import { PuzzleSerializer } from "../../../savegame/puzzle_serializer";
import { T } from "../../../translations";
import { StaticMapEntityComponent } from "../../components/static_map_entity";
import { PuzzleGameMode } from "../../modes/puzzle";
import { BaseHUDPart } from "../base_hud_part";
export class HUDPuzzleImportExport extends BaseHUDPart {
constructor(root) {
super(root);
}
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_PuzzleImportExport");
this.importButton = document.createElement("button");
this.importButton.classList.add("button", "import");
this.element.appendChild(this.importButton);
this.exportButton = document.createElement("button");
this.exportButton.classList.add("button", "export");
this.element.appendChild(this.exportButton);
this.trackClicks(this.importButton, this.importPuzzle);
this.trackClicks(this.exportButton, () => {
const { yes } = this.root.hud.parts.dialogs.showWarning(
T.dialogs.puzzleExport.title,
T.dialogs.puzzleExport.desc,
["no", "yes:good:enter"]
);
yes.add(() => this.exportPuzzle());
});
}
initialize() {}
importPuzzle() {
startFileChoose(".bin").then(file => {
if (file) {
const closeLoader = this.root.hud.parts.dialogs.showLoadingDialog("Importing Puzzle");
waitNextFrame().then(() => {
const reader = new FileReader();
reader.addEventListener("load", event => {
const fileContents = String(event.target.result);
/** @type {import("../../../savegame/savegame_typedefs").PuzzleGameData} */
let gameData;
try {
gameData = ReadWriteProxy.deserializeObject(fileContents);
} catch (err) {
closeLoader();
this.root.hud.parts.dialogs.showWarning(T.global.error, String(err));
return;
}
const mode = /** @type {PuzzleGameMode} */ (this.root.gameMode);
let errorText;
try {
// set excluded buildings first so if we get an error we haven't removed buildings yet
const toolbar = this.root.hud.parts.buildingsToolbar;
const handles = toolbar.buildingHandles;
const ids = gMetaBuildingRegistry.getAllIds();
for (let i = 0; i < ids.length; ++i) {
const handle = handles[ids[i]];
if (handle && !toolbar.inRequiredBuildings(handle.metaBuilding)) {
const locked = gameData.excludedBuildings.includes(ids[i]);
toolbar.toggleBuildingLock(handle.metaBuilding, locked);
}
}
for (const entity of this.root.entityMgr.getAllWithComponent(
StaticMapEntityComponent
)) {
this.root.map.removeStaticEntity(entity);
this.root.entityMgr.destroyEntity(entity);
}
this.root.entityMgr.processDestroyList();
mode.zoneWidth = gameData.bounds.w;
mode.zoneHeight = gameData.bounds.h;
errorText = new PuzzleSerializer().deserializePuzzle(this.root, gameData);
} catch (ex) {
errorText = ex.message || ex;
}
if (errorText) {
this.root.hud.parts.dialogs.showWarning(
T.dialogs.puzzleLoadError.title,
T.dialogs.puzzleLoadError.desc + " " + errorText
);
} else {
this.root.hud.parts.dialogs.showInfo(
T.dialogs.puzzleImport.title,
T.dialogs.puzzleImport.desc
);
}
closeLoader();
});
reader.readAsText(file);
});
}
});
}
exportPuzzle() {
const serialized = new PuzzleSerializer().generateDumpFromGameRoot(this.root);
const data = ReadWriteProxy.serializeObject(serialized);
const filename = "puzzle.bin";
generateFileDownload(filename, data);
}
}

View File

@ -23,10 +23,7 @@ import { HUDPuzzleEditorControls } from "../hud/parts/puzzle_editor_controls";
import { HUDPuzzleEditorReview } from "../hud/parts/puzzle_editor_review";
import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings";
import { createLogger } from "../../core/logging";
import { PuzzleSerializer } from "../../savegame/puzzle_serializer";
import { T } from "../../translations";
import { gMetaBuildingRegistry } from "../../core/global_registries";
import { HUDPuzzleEditorDownload } from "../hud/parts/puzzle_editor_download";
import { HUDPuzzleImportExport } from "../hud/parts/puzzle_import_export";
const logger = createLogger("puzzle-edit");
@ -41,11 +38,8 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
/**
* @param {GameRoot} root
* @param {object} payload
* @param {import("../../savegame/savegame_typedefs").PuzzleGameData} payload.gameData
* @param {boolean} payload.startInTestMode
*/
constructor(root, { gameData = null, startInTestMode = false }) {
constructor(root) {
super(root);
this.hiddenBuildings = [
@ -70,57 +64,7 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls;
this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview;
this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings;
this.additionalHudParts.puzzleEditorDownload = HUDPuzzleEditorDownload;
this.gameData = gameData;
if (gameData) {
root.signals.postLoadHook.add(() => this.loadPuzzle(gameData), this);
}
this.startInTestMode = startInTestMode;
}
/**
* @param {import("../../savegame/savegame_typedefs").PuzzleGameData} puzzle
*/
loadPuzzle(puzzle) {
let errorText;
logger.log("Loading puzzle", puzzle);
// set zone and add buildings
try {
this.zoneWidth = puzzle.bounds.w;
this.zoneHeight = puzzle.bounds.h;
errorText = new PuzzleSerializer().deserializePuzzle(this.root, puzzle);
} catch (ex) {
errorText = ex.message || ex;
}
if (errorText) {
this.root.gameState.moveToState("PuzzleMenuState", {
error: {
title: T.dialogs.puzzleLoadError.title,
desc: T.dialogs.puzzleLoadError.desc + " " + errorText,
},
});
}
const toolbar = this.root.hud.parts.buildingsToolbar;
// lock excluded buildings
for (let i = 0; i < this.gameData.excludedBuildings.length; ++i) {
const id = this.gameData.excludedBuildings[i];
if (!gMetaBuildingRegistry.hasId(id)) {
continue;
}
toolbar.toggleBuildingLock(gMetaBuildingRegistry.findById(id));
}
if (this.startInTestMode) {
this.root.hud.parts.puzzleEditorSettings.toggleTestMode();
}
this.additionalHudParts.puzzleEditorDownload = HUDPuzzleImportExport;
}
getIsEditor() {

View File

@ -43,7 +43,6 @@ export class PuzzleMenuState extends TextualGameState {
<h1><button class="backButton"></button> ${this.getStateHeaderTitle()}</h1>
<div class="actions">
<button class="styledButton importPuzzle">Import</button>
<button class="styledButton loadPuzzle">${T.puzzleMenu.loadPuzzle}</button>
<button class="styledButton createPuzzle">+ ${T.puzzleMenu.createPuzzle}</button>
</div>
@ -390,7 +389,6 @@ export class PuzzleMenuState extends TextualGameState {
this.trackClicks(this.htmlElement.querySelector("button.createPuzzle"), () => this.createNewPuzzle());
this.trackClicks(this.htmlElement.querySelector("button.loadPuzzle"), () => this.loadPuzzle());
this.trackClicks(this.htmlElement.querySelector("button.importPuzzle"), () => this.importPuzzle());
}
createEmptySavegame() {

View File

@ -189,6 +189,8 @@ dialogs:
retry: Retry
continue: Continue
playOffline: Play Offline
yes: Yes
no: No
importSavegameError:
title: Import Error
@ -400,8 +402,13 @@ dialogs:
desc: >-
Are you sure you want to delete '<title>'? This can not be undone!
puzzleDownload:
title: Download Puzzle
puzzleImport:
title: Puzzle Imported
desc: >-
Your puzzle has been successfully imported.
puzzleExport:
title: Export Puzzle
desc: >-
Do you want to download this puzzle?