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

Initial support for adding new buildings

This commit is contained in:
tobspr 2022-01-14 07:05:46 +01:00
parent 8777e4c6ea
commit 01b9bf561c
7 changed files with 165 additions and 20 deletions

View File

@ -1,6 +1,7 @@
import { globalConfig } from "../../core/config"; import { globalConfig } from "../../core/config";
import { DrawParameters } from "../../core/draw_parameters"; import { DrawParameters } from "../../core/draw_parameters";
import { Signal } from "../../core/signal"; import { Signal } from "../../core/signal";
import { MODS } from "../../mods/modloader";
import { KEYMAPPINGS } from "../key_action_mapper"; import { KEYMAPPINGS } from "../key_action_mapper";
import { MetaBuilding } from "../meta_building"; import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root"; import { GameRoot } from "../root";
@ -91,6 +92,7 @@ export class GameHUD {
const frag = document.createDocumentFragment(); const frag = document.createDocumentFragment();
for (const key in this.parts) { for (const key in this.parts) {
MODS.signals.hudElementInitialized.dispatch(this.parts[key]);
this.parts[key].createElements(frag); this.parts[key].createElements(frag);
} }
@ -98,6 +100,7 @@ export class GameHUD {
for (const key in this.parts) { for (const key in this.parts) {
this.parts[key].initialize(); this.parts[key].initialize();
MODS.signals.hudElementFinalized.dispatch(this.parts[key]);
} }
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this); this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);

View File

@ -1,4 +1,5 @@
import { gMetaBuildingRegistry } from "../../../core/global_registries"; import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { globalWarn } from "../../../core/logging";
import { STOP_PROPAGATION } from "../../../core/signal"; import { STOP_PROPAGATION } from "../../../core/signal";
import { makeDiv, safeModulo } from "../../../core/utils"; import { makeDiv, safeModulo } from "../../../core/utils";
import { MetaBlockBuilding } from "../../buildings/block"; import { MetaBlockBuilding } from "../../buildings/block";
@ -101,7 +102,12 @@ export class HUDBaseToolbar extends BaseHUDPart {
rawBinding = KEYMAPPINGS.buildings[metaBuilding.getId()]; rawBinding = KEYMAPPINGS.buildings[metaBuilding.getId()];
} }
const binding = actionMapper.getBinding(rawBinding); if (rawBinding) {
const binding = actionMapper.getBinding(rawBinding);
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
} else {
globalWarn("Building has no keybinding:", metaBuilding.getId());
}
const itemContainer = makeDiv( const itemContainer = makeDiv(
this.primaryBuildings.includes(allBuildings[i]) ? rowPrimary : rowSecondary, this.primaryBuildings.includes(allBuildings[i]) ? rowPrimary : rowSecondary,
@ -110,7 +116,6 @@ export class HUDBaseToolbar extends BaseHUDPart {
); );
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png"); itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
itemContainer.setAttribute("data-id", metaBuilding.getId()); itemContainer.setAttribute("data-id", metaBuilding.getId());
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
const icon = makeDiv(itemContainer, null, ["icon"]); const icon = makeDiv(itemContainer, null, ["icon"]);

View File

@ -126,12 +126,15 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
rawBinding = KEYMAPPINGS.buildings[metaBuilding.getId()]; rawBinding = KEYMAPPINGS.buildings[metaBuilding.getId()];
} }
const binding = this.root.keyMapper.getBinding(rawBinding); if (rawBinding) {
const binding = this.root.keyMapper.getBinding(rawBinding);
this.buildingInfoElements.hotkey.innerHTML = T.ingame.buildingPlacement.hotkeyLabel.replace( this.buildingInfoElements.hotkey.innerHTML = T.ingame.buildingPlacement.hotkeyLabel.replace(
"<key>", "<key>",
"<code class='keybinding'>" + binding.getKeyCodeString() + "</code>" "<code class='keybinding'>" + binding.getKeyCodeString() + "</code>"
); );
} else {
this.buildingInfoElements.hotkey.innerHTML = "";
}
this.buildingInfoElements.tutorialImage.setAttribute( this.buildingInfoElements.tutorialImage.setAttribute(
"data-icon", "data-icon",

View File

@ -205,18 +205,15 @@ export function initMetaBuildingRegistry() {
const id = metaBuilding.getId(); const id = metaBuilding.getId();
if (!["hub"].includes(id)) { if (!["hub"].includes(id)) {
if (!KEYMAPPINGS.buildings[id]) { if (!KEYMAPPINGS.buildings[id]) {
assertAlways( console.error(
false,
"Building " + id + " has no keybinding assigned! Add it to key_action_mapper.js" "Building " + id + " has no keybinding assigned! Add it to key_action_mapper.js"
); );
} }
if (!T.buildings[id]) { if (!T.buildings[id]) {
assertAlways(false, "Translation for building " + id + " missing!"); console.error("Translation for building " + id + " missing!");
} } else if (!T.buildings[id].default) {
console.error("Translation for building " + id + " missing (default variant)!");
if (!T.buildings[id].default) {
assertAlways(false, "Translation for building " + id + " missing (default variant)!");
} }
} }
}); });

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,17 @@
/* typehints:start */ /* typehints:start */
import { Application } from "../application";
import { ModLoader } from "./modloader"; import { ModLoader } from "./modloader";
import { MetaBuilding } from "../game/meta_building";
/* typehints:end */ /* typehints:end */
import { defaultBuildingVariant } from "../game/meta_building";
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites"; import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
import { enumShortcodeToSubShape, enumSubShape, enumSubShapeToShortcode } from "../game/shape_definition"; import { enumShortcodeToSubShape, enumSubShape, enumSubShapeToShortcode } from "../game/shape_definition";
import { Loader } from "../core/loader"; import { Loader } from "../core/loader";
import { LANGUAGES } from "../languages"; import { LANGUAGES } from "../languages";
import { matchDataRecursive, T } from "../translations"; import { matchDataRecursive, T } from "../translations";
import { registerBuildingVariant } from "../game/building_codes";
import { gMetaBuildingRegistry } from "../core/global_registries";
const LOG = createLogger("mod-interface"); const LOG = createLogger("mod-interface");
@ -113,4 +116,77 @@ export class ModInterface {
matchDataRecursive(T, translations, true); matchDataRecursive(T, translations, true);
} }
} }
/**
*
* @param {object} param0
* @param {typeof MetaBuilding} param0.metaClass
* @param {string=} param0.buildingIconBase64
* @param {({
* variant?: string;
* rotationVariant?: number;
* name: string;
* description: string;
* blueprintImageBase64?: string;
* regularImageBase64?: string;
* tutorialImageBase64?: string;
* }[])} param0.variantsAndRotations
*/
registerNewBuilding({ metaClass, variantsAndRotations, buildingIconBase64 }) {
const id = new /** @type {new () => MetaBuilding} */ (metaClass)().getId();
if (gMetaBuildingRegistry.hasId(id)) {
throw new Error("Tried to register building twice: " + id);
}
gMetaBuildingRegistry.register(metaClass);
T.buildings[id] = {};
variantsAndRotations.forEach(payload => {
const actualVariant = payload.variant || defaultBuildingVariant;
registerBuildingVariant(id, metaClass, actualVariant, payload.rotationVariant || 0);
T.buildings[id][actualVariant] = {
name: payload.name,
description: payload.description,
};
const buildingIdentifier =
id + (actualVariant === defaultBuildingVariant ? "" : "-" + actualVariant);
if (payload.regularImageBase64) {
this.registerSprite(
"sprites/buildings/" + buildingIdentifier + ".png",
payload.regularImageBase64
);
}
if (payload.blueprintImageBase64) {
this.registerSprite(
"sprites/blueprints/" + buildingIdentifier + ".png",
payload.blueprintImageBase64
);
}
if (payload.tutorialImageBase64) {
this.setBuildingTutorialImage(id, actualVariant, payload.tutorialImageBase64);
}
});
if (buildingIconBase64) {
this.setBuildingToolbarIcon(id, buildingIconBase64);
}
}
setBuildingToolbarIcon(buildingId, iconBase64) {
this.registerCss(`
[data-icon="building_icons/${buildingId}.png"] .icon {
background-image: url('${iconBase64}') !important;
}
`);
}
setBuildingTutorialImage(buildingId, variant, imageBase64) {
const buildingIdentifier = buildingId + (variant === defaultBuildingVariant ? "" : "-" + variant);
this.registerCss(`
[data-icon="building_tutorials/${buildingIdentifier}.png"] {
background-image: url('${imageBase64}') !important;
}
`);
}
} }

View File

@ -3,6 +3,7 @@ import { Signal } from "../core/signal";
import { DemoMod } from "./demo_mod"; import { DemoMod } from "./demo_mod";
import { Mod } from "./mod"; import { Mod } from "./mod";
import { ModInterface } from "./mod_interface"; import { ModInterface } from "./mod_interface";
import { BaseHUDPart } from "../game/hud/base_hud_part";
const LOG = createLogger("mods"); const LOG = createLogger("mods");
@ -25,6 +26,9 @@ export class ModLoader {
injectSprites: new Signal(), injectSprites: new Signal(),
preprocessTheme: /** @type {TypedSignal<[Object]>} */ (new Signal()), preprocessTheme: /** @type {TypedSignal<[Object]>} */ (new Signal()),
modifyLevelDefinitions: /** @type {TypedSignal<[Array[Object]]>} */ (new Signal()), modifyLevelDefinitions: /** @type {TypedSignal<[Array[Object]]>} */ (new Signal()),
hudElementInitialized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
hudElementFinalized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
}; };
this.registerMod(DemoMod); this.registerMod(DemoMod);