mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-08 18:44:00 +00:00
* initial modloader draft * modloader features * Refactor mods to use signals * Add support for modifying and registering new transltions * Minor adjustments * Support for string building ids for mods * Initial support for adding new buildings * Refactor how mods are loaded to resolve circular dependencies and prepare for future mod loading * Lazy Load mods to make sure all dependencies are loaded * Expose all exported members automatically to mods * Fix duplicate exports * Allow loading mods from standalone * update changelog * Fix mods folder incorrect path * Fix modloading in standalone * Fix sprites not getting replaced, update demo mod * Load dev mod via raw loader * Improve mod developing so mods are directly ready to be deployed, load mods from local file server * Proper mods ui * Allow mods to register game systems and draw stuff * Change mods path * Fix sprites not loading * Minor adjustments, closes #1333 * Add support for loading atlases via mods * Add support for loading mods from external sources in DEV * Add confirmation when loading mods * Fix circular dependency * Minor Keybindings refactor, add support for keybindings to mods, add support for dialogs to mods * Add some mod signals * refactor game loading states * Make shapez exports global * Start to make mods safer * Refactor file system electron event handling * Properly isolate electron renderer process * Update to latest electron * Show errors when loading mods * Update confirm dialgo * Minor restructure, start to add mod examples * Allow adding custom themesw * Add more examples and allow defining custom item processor operations * Add interface to register new buildings * Fixed typescript type errors (#1335) * Refactor building registry, make it easier for mods to add new buildings * Allow overriding existing methods * Add more examples and more features * More mod examples * Make mod loading simpler * Add example how to add custom drawings * Remove unused code * Minor modloader adjustments * Support for rotation variants in mods (was broken previously) * Allow mods to replace builtin sub shapes * Add helper methods to extend classes * Fix menu bar on mac os * Remember window state * Add support for paste signals * Add example how to add custom components and systems * Support for mod settings * Add example for adding a new item type * Update class extensions * Minor adjustments * Fix typo * Add notification blocks mod example * Add small tutorial * Update readme * Add better instructions * Update JSDoc for Replacing Methods (#1336) * upgraded types for overriding methods * updated comments Co-authored-by: Edward Badel <you@example.com> * Direction lock now indicates when there is a building inbetween * Fix mod examples * Fix linter error * Game state register (#1341) * Added a gamestate register helper Added a gamestate register helper * Update mod_interface.js * export build options * Fix runBeforeMethod and runAfterMethod * Minor game system code cleanup * Belt path drawing optimization * Fix belt path optimization * Belt drawing improvements, again * Do not render belts in statics disabled view * Allow external URL to load more than one mod (#1337) * Allow external URL to load more than one mod Instead of loading the text returned from the remote server, load a JSON object with a `mods` field, containing strings of all the mods. This lets us work on more than one mod at a time or without separate repos. This will break tooling such as `create-shapezio-mod` though. * Update modloader.js * Prettier fixes * Added link to create-shapezio-mod npm page (#1339) Added link to create-shapezio-mod npm page: https://www.npmjs.com/package/create-shapezio-mod * allow command line switch to load more than one mod (#1342) * Fixed class handle type (#1345) * Fixed class handle type * Fixed import game state * Minor adjustments * Refactor item acceptor to allow only single direction slots * Allow specifying minimumGameVersion * Add sandbox example * Replaced concatenated strings with template literals (#1347) * Mod improvements * Make wired pins component optional on the storage * Fix mod examples * Bind `this` for method overriding JSDoc (#1352) * fix entity debugger reaching HTML elements (#1353) * Store mods in savegame and show warning when it differs * Closes #1357 * Fix All Shapez Exports Being Const (#1358) * Allowed setting of variables inside webpack modules * remove console log * Fix stringification of things inside of eval Co-authored-by: Edward Badel <you@example.com> * Fix building placer intersection warning * Add example for storing data in the savegame * Fix double painter bug (#1349) * Add example on how to extend builtin buildings * update readme * Disable steam achievements when playing with mods * Update translations Co-authored-by: Thomas (DJ1TJOO) <44841260+DJ1TJOO@users.noreply.github.com> Co-authored-by: Bagel03 <70449196+Bagel03@users.noreply.github.com> Co-authored-by: Edward Badel <you@example.com> Co-authored-by: Emerald Block <69981203+EmeraldBlock@users.noreply.github.com> Co-authored-by: saile515 <63782477+saile515@users.noreply.github.com> Co-authored-by: Sense101 <67970865+Sense101@users.noreply.github.com>
308 lines
11 KiB
JavaScript
308 lines
11 KiB
JavaScript
import { globalConfig } from "../core/config";
|
|
import { DrawParameters } from "../core/draw_parameters";
|
|
import { getBuildingDataFromCode } from "./building_codes";
|
|
import { Entity } from "./entity";
|
|
import { MapChunk } from "./map_chunk";
|
|
import { GameRoot } from "./root";
|
|
import { THEME } from "./theme";
|
|
|
|
export const CHUNK_OVERLAY_RES = 3;
|
|
|
|
export const MOD_CHUNK_DRAW_HOOKS = {
|
|
backgroundLayerBefore: [],
|
|
backgroundLayerAfter: [],
|
|
|
|
foregroundDynamicBefore: [],
|
|
foregroundDynamicAfter: [],
|
|
|
|
staticBefore: [],
|
|
staticAfter: [],
|
|
};
|
|
|
|
export class MapChunkView extends MapChunk {
|
|
/**
|
|
*
|
|
* @param {GameRoot} root
|
|
* @param {number} x
|
|
* @param {number} y
|
|
*/
|
|
constructor(root, x, y) {
|
|
super(root, x, y);
|
|
|
|
/**
|
|
* Whenever something changes, we increase this number - so we know we need to redraw
|
|
*/
|
|
this.renderIteration = 0;
|
|
|
|
this.markDirty();
|
|
}
|
|
|
|
/**
|
|
* Marks this chunk as dirty, rerendering all caches
|
|
*/
|
|
markDirty() {
|
|
++this.renderIteration;
|
|
this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration;
|
|
this.root.map.getAggregateForChunk(this.x, this.y, true).markDirty(this.x, this.y);
|
|
}
|
|
|
|
/**
|
|
* Draws the background layer
|
|
* @param {DrawParameters} parameters
|
|
*/
|
|
drawBackgroundLayer(parameters) {
|
|
const systems = this.root.systemMgr.systems;
|
|
|
|
MOD_CHUNK_DRAW_HOOKS.backgroundLayerBefore.forEach(systemId =>
|
|
systems[systemId].drawChunk(parameters, this)
|
|
);
|
|
|
|
if (systems.zone) {
|
|
systems.zone.drawChunk(parameters, this);
|
|
}
|
|
|
|
if (this.root.gameMode.hasResources()) {
|
|
systems.mapResources.drawChunk(parameters, this);
|
|
}
|
|
|
|
systems.beltUnderlays.drawChunk(parameters, this);
|
|
systems.belt.drawChunk(parameters, this);
|
|
|
|
MOD_CHUNK_DRAW_HOOKS.backgroundLayerAfter.forEach(systemId =>
|
|
systems[systemId].drawChunk(parameters, this)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Draws the dynamic foreground layer
|
|
* @param {DrawParameters} parameters
|
|
*/
|
|
drawForegroundDynamicLayer(parameters) {
|
|
const systems = this.root.systemMgr.systems;
|
|
|
|
MOD_CHUNK_DRAW_HOOKS.foregroundDynamicBefore.forEach(systemId =>
|
|
systems[systemId].drawChunk(parameters, this)
|
|
);
|
|
|
|
systems.itemEjector.drawChunk(parameters, this);
|
|
systems.itemAcceptor.drawChunk(parameters, this);
|
|
systems.miner.drawChunk(parameters, this);
|
|
|
|
MOD_CHUNK_DRAW_HOOKS.foregroundDynamicAfter.forEach(systemId =>
|
|
systems[systemId].drawChunk(parameters, this)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Draws the static foreground layer
|
|
* @param {DrawParameters} parameters
|
|
*/
|
|
drawForegroundStaticLayer(parameters) {
|
|
const systems = this.root.systemMgr.systems;
|
|
|
|
MOD_CHUNK_DRAW_HOOKS.staticBefore.forEach(systemId => systems[systemId].drawChunk(parameters, this));
|
|
|
|
systems.staticMapEntities.drawChunk(parameters, this);
|
|
systems.lever.drawChunk(parameters, this);
|
|
systems.display.drawChunk(parameters, this);
|
|
systems.storage.drawChunk(parameters, this);
|
|
systems.constantProducer.drawChunk(parameters, this);
|
|
systems.goalAcceptor.drawChunk(parameters, this);
|
|
systems.itemProcessorOverlays.drawChunk(parameters, this);
|
|
|
|
MOD_CHUNK_DRAW_HOOKS.staticAfter.forEach(systemId => systems[systemId].drawChunk(parameters, this));
|
|
}
|
|
|
|
/**
|
|
* @param {DrawParameters} parameters
|
|
* @param {number} xoffs
|
|
* @param {number} yoffs
|
|
* @param {number} diameter
|
|
*/
|
|
drawOverlayPatches(parameters, xoffs, yoffs, diameter) {
|
|
for (let i = 0; i < this.patches.length; ++i) {
|
|
const patch = this.patches[i];
|
|
if (patch.item.getItemType() === "shape") {
|
|
const destX = xoffs + patch.pos.x * globalConfig.tileSize;
|
|
const destY = yoffs + patch.pos.y * globalConfig.tileSize;
|
|
patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {CanvasRenderingContext2D} context
|
|
* @param {number} w
|
|
* @param {number} h
|
|
* @param {number=} xoffs
|
|
* @param {number=} yoffs
|
|
*/
|
|
generateOverlayBuffer(context, w, h, xoffs, yoffs) {
|
|
context.fillStyle =
|
|
this.containedEntities.length > 0
|
|
? THEME.map.chunkOverview.filled
|
|
: THEME.map.chunkOverview.empty;
|
|
context.fillRect(xoffs, yoffs, w, h);
|
|
|
|
if (this.root.app.settings.getAllSettings().displayChunkBorders) {
|
|
context.fillStyle = THEME.map.chunkBorders;
|
|
context.fillRect(xoffs, yoffs, w, 1);
|
|
context.fillRect(xoffs, yoffs + 1, 1, h);
|
|
}
|
|
|
|
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
|
|
const lowerArray = this.lowerLayer[x];
|
|
const upperArray = this.contents[x];
|
|
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
|
|
const upperContent = upperArray[y];
|
|
if (upperContent) {
|
|
const staticComp = upperContent.components.StaticMapEntity;
|
|
const data = getBuildingDataFromCode(staticComp.code);
|
|
const metaBuilding = data.metaInstance;
|
|
|
|
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
|
|
staticComp.rotation,
|
|
data.rotationVariant,
|
|
data.variant,
|
|
upperContent
|
|
);
|
|
|
|
if (overlayMatrix) {
|
|
// Draw lower content first since it "shines" through
|
|
const lowerContent = lowerArray[y];
|
|
if (lowerContent) {
|
|
context.fillStyle = lowerContent.getBackgroundColorAsResource();
|
|
context.fillRect(
|
|
xoffs + x * CHUNK_OVERLAY_RES,
|
|
yoffs + y * CHUNK_OVERLAY_RES,
|
|
CHUNK_OVERLAY_RES,
|
|
CHUNK_OVERLAY_RES
|
|
);
|
|
}
|
|
|
|
context.fillStyle = metaBuilding.getSilhouetteColor(
|
|
data.variant,
|
|
data.rotationVariant
|
|
);
|
|
for (let dx = 0; dx < 3; ++dx) {
|
|
for (let dy = 0; dy < 3; ++dy) {
|
|
const isFilled = overlayMatrix[dx + dy * 3];
|
|
if (isFilled) {
|
|
context.fillRect(
|
|
xoffs + x * CHUNK_OVERLAY_RES + dx,
|
|
yoffs + y * CHUNK_OVERLAY_RES + dy,
|
|
1,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
} else {
|
|
context.fillStyle = metaBuilding.getSilhouetteColor(
|
|
data.variant,
|
|
data.rotationVariant
|
|
);
|
|
context.fillRect(
|
|
xoffs + x * CHUNK_OVERLAY_RES,
|
|
yoffs + y * CHUNK_OVERLAY_RES,
|
|
CHUNK_OVERLAY_RES,
|
|
CHUNK_OVERLAY_RES
|
|
);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const lowerContent = lowerArray[y];
|
|
if (lowerContent) {
|
|
context.fillStyle = lowerContent.getBackgroundColorAsResource();
|
|
context.fillRect(
|
|
xoffs + x * CHUNK_OVERLAY_RES,
|
|
yoffs + y * CHUNK_OVERLAY_RES,
|
|
CHUNK_OVERLAY_RES,
|
|
CHUNK_OVERLAY_RES
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.root.currentLayer === "wires") {
|
|
// Draw wires overlay
|
|
|
|
context.fillStyle = THEME.map.wires.overlayColor;
|
|
context.fillRect(xoffs, yoffs, w, h);
|
|
|
|
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
|
|
const wiresArray = this.wireContents[x];
|
|
for (let y = 0; y < globalConfig.mapChunkSize; ++y) {
|
|
const content = wiresArray[y];
|
|
if (!content) {
|
|
continue;
|
|
}
|
|
MapChunkView.drawSingleWiresOverviewTile({
|
|
context,
|
|
x: xoffs + x * CHUNK_OVERLAY_RES,
|
|
y: yoffs + y * CHUNK_OVERLAY_RES,
|
|
entity: content,
|
|
tileSizePixels: CHUNK_OVERLAY_RES,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {object} param0
|
|
* @param {CanvasRenderingContext2D} param0.context
|
|
* @param {number} param0.x
|
|
* @param {number} param0.y
|
|
* @param {Entity} param0.entity
|
|
* @param {number} param0.tileSizePixels
|
|
* @param {string=} param0.overrideColor Optionally override the color to be rendered
|
|
*/
|
|
static drawSingleWiresOverviewTile({ context, x, y, entity, tileSizePixels, overrideColor = null }) {
|
|
const staticComp = entity.components.StaticMapEntity;
|
|
const data = getBuildingDataFromCode(staticComp.code);
|
|
const metaBuilding = data.metaInstance;
|
|
const overlayMatrix = metaBuilding.getSpecialOverlayRenderMatrix(
|
|
staticComp.rotation,
|
|
data.rotationVariant,
|
|
data.variant,
|
|
entity
|
|
);
|
|
context.fillStyle =
|
|
overrideColor || metaBuilding.getSilhouetteColor(data.variant, data.rotationVariant);
|
|
if (overlayMatrix) {
|
|
for (let dx = 0; dx < 3; ++dx) {
|
|
for (let dy = 0; dy < 3; ++dy) {
|
|
const isFilled = overlayMatrix[dx + dy * 3];
|
|
if (isFilled) {
|
|
context.fillRect(
|
|
x + (dx * tileSizePixels) / CHUNK_OVERLAY_RES,
|
|
y + (dy * tileSizePixels) / CHUNK_OVERLAY_RES,
|
|
tileSizePixels / CHUNK_OVERLAY_RES,
|
|
tileSizePixels / CHUNK_OVERLAY_RES
|
|
);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
context.fillRect(x, y, tileSizePixels, tileSizePixels);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draws the wires layer
|
|
* @param {DrawParameters} parameters
|
|
*/
|
|
drawWiresForegroundLayer(parameters) {
|
|
const systems = this.root.systemMgr.systems;
|
|
systems.wire.drawChunk(parameters, this);
|
|
systems.staticMapEntities.drawWiresChunk(parameters, this);
|
|
systems.wiredPins.drawChunk(parameters, this);
|
|
}
|
|
}
|