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; position: absolute;
@include S(top, 35px); @include S(top, 35px);
left: 50%; left: 50%;
@ -17,12 +17,14 @@
transition-property: opacity, transform; transition-property: opacity, transform;
text-transform: uppercase; text-transform: uppercase;
@include PlainText; @include PlainText;
@include S(width, 30px); @include S(width, 20px);
@include S(height, 30px); @include S(height, 20px);
margin: 8px 5px;
@include DarkThemeInvert; @include DarkThemeInvert;
opacity: 1; opacity: 1;
&:hover { &:hover {
opacity: 0.9 !important; opacity: 0.9 !important;
} }
@ -31,7 +33,13 @@
transform: scale(0.95) !important; 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 */ /* @load-async */
background: uiResource("icons/download.png") center center / D(15px) no-repeat; 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_settings";
@import "ingame_hud/puzzle_play_metadata"; @import "ingame_hud/puzzle_play_metadata";
@import "ingame_hud/puzzle_complete_notification"; @import "ingame_hud/puzzle_complete_notification";
@import "ingame_hud/puzzle_editor_download"; @import "ingame_hud/puzzle_import_export";
// prettier-ignore // prettier-ignore
$elements: $elements:
@ -85,7 +85,7 @@ ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay, ingame_HUD_KeybindingOverlay,
ingame_HUD_PuzzleBackToMenu, ingame_HUD_PuzzleBackToMenu,
ingame_HUD_PuzzleEditorReview, ingame_HUD_PuzzleEditorReview,
ingame_HUD_PuzzleEditorDownload, ingame_HUD_PuzzleImportExport,
ingame_HUD_PuzzleEditorControls, ingame_HUD_PuzzleEditorControls,
ingame_HUD_PuzzleEditorTitle, ingame_HUD_PuzzleEditorTitle,
ingame_HUD_PuzzleEditorSettings, ingame_HUD_PuzzleEditorSettings,
@ -138,7 +138,7 @@ body.uiHidden {
#ingame_HUD_PuzzleEditorSettings, #ingame_HUD_PuzzleEditorSettings,
#ingame_HUD_PuzzlePlaySettings, #ingame_HUD_PuzzlePlaySettings,
#ingame_HUD_PuzzleEditorControls, #ingame_HUD_PuzzleEditorControls,
#ingame_HUD_PuzzleEditorDownload, #ingame_HUD_PuzzleImportExport,
#ingame_HUD_PuzzlePlayMetadata, #ingame_HUD_PuzzlePlayMetadata,
#ingame_HUD_Notifications, #ingame_HUD_Notifications,
#ingame_HUD_TutorialHints, #ingame_HUD_TutorialHints,

View File

@ -302,8 +302,9 @@ export class HUDBaseToolbar extends BaseHUDPart {
/** /**
* @param {MetaBuilding} metaBuilding * @param {MetaBuilding} metaBuilding
* @param {boolean | null} force
*/ */
toggleBuildingLock(metaBuilding) { toggleBuildingLock(metaBuilding, force = null) {
if (!this.visibilityCondition()) { if (!this.visibilityCondition()) {
// Not active // Not active
return; return;
@ -315,7 +316,11 @@ export class HUDBaseToolbar extends BaseHUDPart {
} }
const handle = this.buildingHandles[metaBuilding.getId()]; const handle = this.buildingHandles[metaBuilding.getId()];
handle.puzzleLocked = !handle.puzzleLocked; if (force != null) {
handle.puzzleLocked = force;
} else {
handle.puzzleLocked = !handle.puzzleLocked;
}
handle.element.classList.toggle("unlocked", !handle.puzzleLocked); handle.element.classList.toggle("unlocked", !handle.puzzleLocked);
const entityManager = this.root.entityMgr; 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,45 +92,50 @@ export class HUDPuzzleEditorSettings extends BaseHUDPart {
testButton.classList.toggle("disabled", false); testButton.classList.toggle("disabled", false);
}, 140); }, 140);
this.root.logic.performBulkOperation(() => { if (this.testMode) {
for (const entity of this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) { for (const entity of this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
if (this.testMode) { this.storedSolution.push(entity.clone());
this.storedSolution.push(entity.clone());
const metaBuilding = entity.components.StaticMapEntity.getMetaBuilding(); const metaBuilding = entity.components.StaticMapEntity.getMetaBuilding();
const goalComp = entity.components.GoalAcceptor; const goalComp = entity.components.GoalAcceptor;
if (goalComp) { if (goalComp) {
goalComp.clear(); goalComp.clear();
continue; continue;
} }
if ( if (
[MetaConstantProducerBuilding, MetaBlockBuilding] [MetaConstantProducerBuilding, MetaBlockBuilding]
.map(metaClass => gMetaBuildingRegistry.findByClass(metaClass).id) .map(metaClass => gMetaBuildingRegistry.findByClass(metaClass).id)
.includes(metaBuilding.id) .includes(metaBuilding.id)
) { ) {
continue; continue;
}
} }
this.root.map.removeStaticEntity(entity); this.root.map.removeStaticEntity(entity);
this.root.entityMgr.destroyEntity(entity); this.root.entityMgr.destroyEntity(entity);
} }
this.root.entityMgr.processDestroyList(); this.root.entityMgr.processDestroyList();
} else if (this.storedSolution.length) {
if (!this.testMode) { this.root.logic.performBulkOperation(() => {
for (const entity of this.storedSolution) { this.root.logic.performImmutableOperation(() => {
const placedEntity = this.root.logic.tryPlaceEntity(entity); for (const entity of this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
this.root.map.removeStaticEntity(entity);
for (const key in entity.components) { this.root.entityMgr.destroyEntity(entity);
/** @type {import("../../../core/global_registries").Component} */ (entity.components[
key
]).copyAdditionalStateTo(placedEntity.components[key]);
} }
} this.root.entityMgr.processDestroyList();
this.storedSolution = [];
} 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]);
}
}
this.storedSolution = [];
});
});
}
} }
trim() { 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 { HUDPuzzleEditorReview } from "../hud/parts/puzzle_editor_review";
import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings"; import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings";
import { createLogger } from "../../core/logging"; import { createLogger } from "../../core/logging";
import { PuzzleSerializer } from "../../savegame/puzzle_serializer"; import { HUDPuzzleImportExport } from "../hud/parts/puzzle_import_export";
import { T } from "../../translations";
import { gMetaBuildingRegistry } from "../../core/global_registries";
import { HUDPuzzleEditorDownload } from "../hud/parts/puzzle_editor_download";
const logger = createLogger("puzzle-edit"); const logger = createLogger("puzzle-edit");
@ -41,11 +38,8 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
/** /**
* @param {GameRoot} root * @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); super(root);
this.hiddenBuildings = [ this.hiddenBuildings = [
@ -70,57 +64,7 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls; this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls;
this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview; this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview;
this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings; this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings;
this.additionalHudParts.puzzleEditorDownload = HUDPuzzleEditorDownload; this.additionalHudParts.puzzleEditorDownload = HUDPuzzleImportExport;
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();
}
} }
getIsEditor() { getIsEditor() {

View File

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

View File

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