mirror of
				https://github.com/tobspr/shapez.io.git
				synced 2025-06-13 13:04:03 +00:00 
			
		
		
		
	Allow exporting whole bases, closes #137
This commit is contained in:
		
							parent
							
								
									fca216b3c5
								
							
						
					
					
						commit
						7e745fd0ce
					
				@ -10,6 +10,7 @@ import {
 | 
			
		||||
    Math_atan2,
 | 
			
		||||
    Math_sin,
 | 
			
		||||
    Math_cos,
 | 
			
		||||
    Math_ceil,
 | 
			
		||||
} from "./builtins";
 | 
			
		||||
 | 
			
		||||
const tileSize = globalConfig.tileSize;
 | 
			
		||||
@ -303,13 +304,21 @@ export class Vector {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Computes componentwise floor and return a new vector
 | 
			
		||||
     * Computes componentwise floor and returns a new vector
 | 
			
		||||
     * @returns {Vector}
 | 
			
		||||
     */
 | 
			
		||||
    floor() {
 | 
			
		||||
        return new Vector(Math_floor(this.x), Math_floor(this.y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Computes componentwise ceil and returns a new vector
 | 
			
		||||
     * @returns {Vector}
 | 
			
		||||
     */
 | 
			
		||||
    ceil() {
 | 
			
		||||
        return new Vector(Math_ceil(this.x), Math_ceil(this.y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Computes componentwise round and return a new vector
 | 
			
		||||
     * @returns {Vector}
 | 
			
		||||
 | 
			
		||||
@ -409,7 +409,7 @@ export class GameCore {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (G_IS_DEV) {
 | 
			
		||||
            root.map.drawStaticEntities(params);
 | 
			
		||||
            root.map.drawStaticEntityDebugOverlays(params);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // END OF GAME CONTENT
 | 
			
		||||
 | 
			
		||||
@ -136,7 +136,7 @@ export class Entity extends BasicSerializableObject {
 | 
			
		||||
     * Draws the entity, to override use @see Entity.drawImpl
 | 
			
		||||
     * @param {DrawParameters} parameters
 | 
			
		||||
     */
 | 
			
		||||
    draw(parameters) {
 | 
			
		||||
    drawDebugOverlays(parameters) {
 | 
			
		||||
        const context = parameters.context;
 | 
			
		||||
        const staticComp = this.components.StaticMapEntity;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,10 @@
 | 
			
		||||
import { GameRoot } from "../root";
 | 
			
		||||
/* typehints:end */
 | 
			
		||||
 | 
			
		||||
/* dev:start */
 | 
			
		||||
import { TrailerMaker } from "./trailer_maker";
 | 
			
		||||
/* dev:end */
 | 
			
		||||
 | 
			
		||||
import { Signal } from "../../core/signal";
 | 
			
		||||
import { DrawParameters } from "../../core/draw_parameters";
 | 
			
		||||
import { HUDProcessingOverlay } from "./parts/processing_overlay";
 | 
			
		||||
@ -29,10 +33,7 @@ import { HUDModalDialogs } from "./parts/modal_dialogs";
 | 
			
		||||
import { HUDPartTutorialHints } from "./parts/tutorial_hints";
 | 
			
		||||
import { HUDWaypoints } from "./parts/waypoints";
 | 
			
		||||
import { HUDInteractiveTutorial } from "./parts/interactive_tutorial";
 | 
			
		||||
 | 
			
		||||
/* dev:start */
 | 
			
		||||
import { TrailerMaker } from "./trailer_maker";
 | 
			
		||||
/* dev:end */
 | 
			
		||||
import { HUDScreenshotExporter } from "./parts/screenshot_exporter";
 | 
			
		||||
 | 
			
		||||
export class GameHUD {
 | 
			
		||||
    /**
 | 
			
		||||
@ -66,6 +67,7 @@ export class GameHUD {
 | 
			
		||||
            // betaOverlay: new HUDBetaOverlay(this.root),
 | 
			
		||||
            debugInfo: new HUDDebugInfo(this.root),
 | 
			
		||||
            dialogs: new HUDModalDialogs(this.root),
 | 
			
		||||
            screenshotExporter: new HUDScreenshotExporter(this.root),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.signals = {
 | 
			
		||||
 | 
			
		||||
@ -57,12 +57,6 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
 | 
			
		||||
                <label>${T.ingame.keybindingsOverlay.selectBuildings}</label>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="binding noPlacementOnly">
 | 
			
		||||
                <code class="keybinding">${getKeycode(KEYMAPPINGS.massSelect.pasteLastBlueprint)}</code>
 | 
			
		||||
                <label>${T.ingame.keybindingsOverlay.pasteLastBlueprint}</label>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <div class="binding placementOnly">
 | 
			
		||||
                <code class="keybinding leftMouse"></code>
 | 
			
		||||
                <label>${T.ingame.keybindingsOverlay.placeBuilding}</label>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										105
									
								
								src/js/game/hud/parts/screenshot_exporter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/js/game/hud/parts/screenshot_exporter.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,105 @@
 | 
			
		||||
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 { Math_max, Math_min } from "../../../core/builtins";
 | 
			
		||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
 | 
			
		||||
import { DrawParameters } from "../../../core/draw_parameters";
 | 
			
		||||
import { Rectangle } from "../../../core/rectangle";
 | 
			
		||||
 | 
			
		||||
const logger = createLogger("screenshot_exporter");
 | 
			
		||||
 | 
			
		||||
export class HUDScreenshotExporter extends BaseHUDPart {
 | 
			
		||||
    createElements() {}
 | 
			
		||||
 | 
			
		||||
    initialize() {
 | 
			
		||||
        this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.exportScreenshot).add(this.startExport, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    startExport() {
 | 
			
		||||
        if (IS_DEMO) {
 | 
			
		||||
            this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const { ok } = this.root.hud.parts.dialogs.showInfo(
 | 
			
		||||
            T.dialogs.exportScreenshotWarning.title,
 | 
			
		||||
            T.dialogs.exportScreenshotWarning.desc,
 | 
			
		||||
            ["cancel:good", "ok:bad"]
 | 
			
		||||
        );
 | 
			
		||||
        ok.add(this.doExport, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doExport() {
 | 
			
		||||
        logger.log("Starting export ...");
 | 
			
		||||
 | 
			
		||||
        // Find extends
 | 
			
		||||
        const staticEntities = this.root.entityMgr.getAllWithComponent(StaticMapEntityComponent);
 | 
			
		||||
 | 
			
		||||
        const minTile = new Vector(0, 0);
 | 
			
		||||
        const maxTile = new Vector(0, 0);
 | 
			
		||||
        for (let i = 0; i < staticEntities.length; ++i) {
 | 
			
		||||
            const bounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds();
 | 
			
		||||
            minTile.x = Math_min(minTile.x, bounds.x);
 | 
			
		||||
            minTile.y = Math_min(minTile.y, bounds.y);
 | 
			
		||||
 | 
			
		||||
            maxTile.x = Math_max(maxTile.x, bounds.x + bounds.w);
 | 
			
		||||
            maxTile.y = Math_max(maxTile.y, bounds.y + bounds.h);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const minChunk = minTile.divideScalar(globalConfig.mapChunkSize).floor();
 | 
			
		||||
        const maxChunk = maxTile.divideScalar(globalConfig.mapChunkSize).ceil();
 | 
			
		||||
 | 
			
		||||
        const dimensions = maxChunk.sub(minChunk);
 | 
			
		||||
        logger.log("Dimensions:", dimensions);
 | 
			
		||||
 | 
			
		||||
        const chunkSizePixels = 128;
 | 
			
		||||
        const chunkScale = chunkSizePixels / (globalConfig.mapChunkSize * globalConfig.tileSize);
 | 
			
		||||
        logger.log("Scale:", chunkScale);
 | 
			
		||||
 | 
			
		||||
        logger.log("Allocating buffer, if the factory grew too big it will crash here");
 | 
			
		||||
        const [canvas, context] = makeOffscreenBuffer(
 | 
			
		||||
            dimensions.x * chunkSizePixels,
 | 
			
		||||
            dimensions.y * chunkSizePixels,
 | 
			
		||||
            {
 | 
			
		||||
                smooth: true,
 | 
			
		||||
                reusable: false,
 | 
			
		||||
                label: "export-buffer",
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        logger.log("Got buffer, rendering now ...");
 | 
			
		||||
 | 
			
		||||
        const visibleRect = new Rectangle(
 | 
			
		||||
            minChunk.x * globalConfig.mapChunkSize * globalConfig.tileSize,
 | 
			
		||||
            minChunk.y * globalConfig.mapChunkSize * globalConfig.tileSize,
 | 
			
		||||
            dimensions.x * globalConfig.mapChunkSize * globalConfig.tileSize,
 | 
			
		||||
            dimensions.y * globalConfig.mapChunkSize * globalConfig.tileSize
 | 
			
		||||
        );
 | 
			
		||||
        const parameters = new DrawParameters({
 | 
			
		||||
            context,
 | 
			
		||||
            visibleRect,
 | 
			
		||||
            desiredAtlasScale: "1",
 | 
			
		||||
            root: this.root,
 | 
			
		||||
            zoomLevel: chunkScale,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        context.scale(chunkScale, chunkScale);
 | 
			
		||||
        context.translate(-visibleRect.x, -visibleRect.y);
 | 
			
		||||
 | 
			
		||||
        // Render all relevant chunks
 | 
			
		||||
        this.root.map.drawBackground(parameters);
 | 
			
		||||
        this.root.map.drawForeground(parameters);
 | 
			
		||||
 | 
			
		||||
        // Offer export
 | 
			
		||||
        logger.log("Rendered buffer, exporting ...");
 | 
			
		||||
        const image = canvas.toDataURL("image/png");
 | 
			
		||||
        const link = document.createElement("a");
 | 
			
		||||
        link.download = "base.png";
 | 
			
		||||
        link.href = image;
 | 
			
		||||
        link.click();
 | 
			
		||||
        logger.log("Done!");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -24,7 +24,8 @@ export const KEYMAPPINGS = {
 | 
			
		||||
        menuOpenStats: { keyCode: key("G") },
 | 
			
		||||
 | 
			
		||||
        toggleHud: { keyCode: 113 }, // F2
 | 
			
		||||
        toggleFPSInfo: { keyCode: 115 }, // F1
 | 
			
		||||
        exportScreenshot: { keyCode: 114 }, // F3
 | 
			
		||||
        toggleFPSInfo: { keyCode: 115 }, // F4
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    navigation: {
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@ export class MapView extends BaseMap {
 | 
			
		||||
     * Draws all static entities like buildings etc.
 | 
			
		||||
     * @param {DrawParameters} drawParameters
 | 
			
		||||
     */
 | 
			
		||||
    drawStaticEntities(drawParameters) {
 | 
			
		||||
    drawStaticEntityDebugOverlays(drawParameters) {
 | 
			
		||||
        const cullRange = drawParameters.visibleRect.toTileCullRectangle();
 | 
			
		||||
        const top = cullRange.top();
 | 
			
		||||
        const right = cullRange.right();
 | 
			
		||||
@ -90,7 +90,7 @@ export class MapView extends BaseMap {
 | 
			
		||||
                if (content) {
 | 
			
		||||
                    let isBorder = x <= left - 1 || x >= right + 1 || y <= top - 1 || y >= bottom + 1;
 | 
			
		||||
                    if (!isBorder) {
 | 
			
		||||
                        content.draw(drawParameters);
 | 
			
		||||
                        content.drawDebugOverlays(drawParameters);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -260,6 +260,10 @@ dialogs:
 | 
			
		||||
    markerDemoLimit:
 | 
			
		||||
        desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers!
 | 
			
		||||
 | 
			
		||||
    exportScreenshotWarning:
 | 
			
		||||
        title: Export screenshot
 | 
			
		||||
        desc: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game!
 | 
			
		||||
 | 
			
		||||
ingame:
 | 
			
		||||
    # This is shown in the top left corner and displays useful keybindings in
 | 
			
		||||
    # every situation
 | 
			
		||||
@ -698,6 +702,7 @@ keybindings:
 | 
			
		||||
 | 
			
		||||
        toggleHud: Toggle HUD
 | 
			
		||||
        toggleFPSInfo: Toggle FPS and Debug Info
 | 
			
		||||
        exportScreenshot: Export whole Base as Image
 | 
			
		||||
        belt: *belt
 | 
			
		||||
        splitter: *splitter
 | 
			
		||||
        underground_belt: *underground_belt
 | 
			
		||||
@ -739,5 +744,6 @@ demo:
 | 
			
		||||
        importingGames: Importing savegames
 | 
			
		||||
        oneGameLimit: Limited to one savegame
 | 
			
		||||
        customizeKeybindings: Customizing Keybindings
 | 
			
		||||
        exportingBase: Exporting whole Base as Image
 | 
			
		||||
 | 
			
		||||
    settingNotAvailable: Not available in the demo.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user