1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

GeoZ base

Working Buildings base
This commit is contained in:
Exund 2020-09-09 02:30:35 +02:00
parent 76a05a5776
commit 3b4417ba0b
10 changed files with 908 additions and 257 deletions

237
src/js/GeoZ/main.js Normal file
View File

@ -0,0 +1,237 @@
import { MetaModBuilding } from "./mod_building";
import { ModComponent } from "./mod_component";
import { ModItem } from "./mod_item";
import { ModProcessor } from "./mod_processor";
import { ModSystem, ModSystemWithFilter } from "./mod_system";
import { gComponentRegistry, gItemRegistry, gMetaBuildingRegistry } from "../core/global_registries";
import { GameSystemManager } from "../game/game_system_manager";
import { GameCore } from "../game/core";
import { createLogger } from "../core/logging";
import { registerBuildingVariant } from "../game/building_codes";
import { supportedBuildings } from "../game/hud/parts/buildings_toolbar";
import { KEYMAPPINGS, key } from "../game/key_action_mapper";
import { T } from "../translations";
export { MetaModBuilding } from "./mod_building";
export { ModComponent } from "./mod_component";
export { ModItem } from "./mod_item";
export { ModProcessor } from "./mod_processor";
export { ModSystem, ModSystemWithFilter } from "./mod_system";
/**
* @typedef {Object} Mod
* @property {String} name
* @property {Array<typeof MetaModBuilding>=} buildings
* @property {Array<typeof ModComponent>=} components
* @property {Array<typeof ModItem>=} items
* @property {Array<typeof ModProcessor>=} processors
* @property {Array<typeof ModSystem | typeof ModSystemWithFilter>=} systems
*/
const logger = createLogger("GeoZ");
/** @type {Array<Mod>} */
export const Mods = [];
/** @type {Array<typeof ModComponent>} */
export const ModComponents = [];
/** @type {Array<typeof ModSystem | typeof ModSystemWithFilter>} */
export const ModSystems = [];
/** @type {Object.<string, typeof ModProcessor>} */
export const ModProcessors = {};
/** @type {Array<typeof ModItem>} */
export const ModItems = [];
/** @type {Array<typeof MetaModBuilding>} */
export const ModBuildings = [];
const GameSystemManager_internalInitSystems_original = GameSystemManager.prototype.internalInitSystems;
GameSystemManager.prototype.internalInitSystems = function () {
GameSystemManager_internalInitSystems_original.call(this);
for (const system of ModSystems) {
//add(system.getId(), system);
const before = system.getUpdateBefore();
const after = system.getUpdateAfter();
const system_id = system.getId();
let override = false;
if (this.systems[system_id]) {
logger.log(
`⚠️ WARNING ⚠️ A system with the ID "${system_id}" already exists and will be overriden`
);
override = true;
}
this.systems[system_id] = new system(this.root);
if (!override) {
if (before) {
const i = this.systemUpdateOrder.indexOf(before);
if (i !== -1) {
this.systemUpdateOrder.splice(i, 0, system_id);
continue;
}
logger.log(
`⚠️ WARNING ⚠️ System "${before}" not found and so system "${system_id}" can't be updated before it`
);
}
if (after) {
const i = this.systemUpdateOrder.indexOf(after);
if (i !== -1) {
this.systemUpdateOrder.splice(i + 1, 0, system_id);
continue;
}
logger.log(
`⚠️ WARNING ⚠️ System "${after}" not found and so system "${system_id}" can't be updated after it`
);
}
}
if (!this.systemUpdateOrder.includes(system_id)) {
this.systemUpdateOrder.push(system_id);
}
if (override) {
logger.log(`System "${system_id}" update order : ${this.systemUpdateOrder.indexOf(system_id)}`);
}
}
};
// @ts-ignore
const webpack_require = require.context("../", true, /\.js$/);
const GeoZ = {
Classes: {
MetaModBuilding,
ModComponent,
ModItem,
ModProcessor,
ModSystem,
ModSystemWithFilter,
},
require(module) {
return webpack_require(`./${module}.js`);
},
};
export async function initMods() {
const style = "font-size: 35px; font-family: Arial;font-weight: bold; padding: 10px 0;";
console.log(
`%cGeo%cZ%c modloader\nby %cExund\n`,
`${style} color: #aaa;`,
`${style} color: #7f7;`,
`${style} color: #aaa; font-size: 15px;`,
"color: #ff4300"
);
// @ts-ignore
window.GeoZ = GeoZ;
// @ts-ignore
const local_mods = require.context("./mods", true, /.*\.mod\.js/i);
for (let key of local_mods.keys()) {
let mod = /** @type {Mod} */ (local_mods(key).default);
if (mod.name) {
Mods.push(mod);
}
}
const local_mods_count = Mods.length;
logger.log(`${local_mods_count} local mods found`);
/** @type {Array<string>} */
let external_mods = [];
let storage = localStorage.getItem("mods.external");
if (storage) {
external_mods = JSON.parse(storage);
}
for (const url of external_mods) {
let temp = await fetch(url);
const text = await temp.text();
const mod = /** @type {Mod} */ (eval(text));
if (mod.name) {
Mods.push(mod);
}
}
const external_mods_count = Mods.length - local_mods_count;
logger.log(`${external_mods_count} external mods found`);
for (const mod of Mods) {
let mod_infos = `${mod.name} : `;
if (mod.components) {
mod_infos += `${mod.components.length} components, `;
for (const component of mod.components) {
ModComponents.push(component);
gComponentRegistry.register(component);
}
}
if (mod.systems) {
mod_infos += `${mod.systems.length} systems, `;
for (const system of mod.systems) {
ModSystems.push(system);
}
}
if (mod.processors) {
mod_infos += `${mod.processors.length} processors, `;
for (const processor of mod.processors) {
ModProcessors[processor.getType()] = processor;
}
}
if (mod.items) {
mod_infos += `${mod.items.length} items, `;
for (const item of mod.items) {
ModItems.push(item);
gItemRegistry.register(item);
}
}
if (mod.buildings) {
mod_infos += `${mod.buildings.length} buildings, `;
for (const building of mod.buildings) {
ModBuildings.push(building);
gMetaBuildingRegistry.register(building);
const base_id = building.getId();
registerBuildingVariant(base_id, building);
for (const variant of building.getVariants()) {
registerBuildingVariant(`${base_id}-${variant}`, building);
}
supportedBuildings.push(building);
KEYMAPPINGS.buildings[base_id] = { keyCode: key(building.getKeybinding()) };
const translations = building.getTranslations();
T.keybindings.mappings[base_id] = translations.keybinding;
T.buildings[base_id] = {};
for (const variant in translations.variants) {
T.buildings[base_id][variant] = translations.variants[variant];
}
}
}
logger.log(mod_infos);
}
for (const categoryId in KEYMAPPINGS) {
for (const mappingId in KEYMAPPINGS[categoryId]) {
KEYMAPPINGS[categoryId][mappingId].id = mappingId;
}
}
logger.log(`${Mods.length} mods loaded`);
}

138
src/js/GeoZ/mod_building.js Normal file
View File

@ -0,0 +1,138 @@
import { MetaBuilding, defaultBuildingVariant } from "../game/meta_building";
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
import { atlasFiles } from "../core/atlas_definitions";
import { getFileAsDataURI } from "./mod_utils";
import { Loader } from "../core/loader";
/**
* @typedef {{
* url: string
* width: number
* height: number
* }} ExternalSpriteMeta
*/
/**
* @typedef {{
* name: string,
* description: string
* }} BuildingVariantTranslation
*/
/**
* @typedef {{
* variants: {[x: string]: BuildingVariantTranslation, default: BuildingVariantTranslation},
* keybinding: string
* }} BuildingTranlsations
*/
export class MetaModBuilding extends MetaBuilding {
/**
* Returns the building IDs
* @returns {String}
*/
static getId() {
abstract;
return "";
}
/**
* Returns the building variants IDs
* @returns {Array<String>}
*/
static getVariants() {
return [];
}
/**
* Returns the building keybinding
* @returns {String}
*/
static getKeybinding() {
abstract;
return "";
}
/**
* Returns the building translations
* @returns {BuildingTranlsations}
*/
static getTranslations() {
abstract;
return {variants: { default: { name: "", description: ""} }, keybinding: ""};
}
/**
* @param {string} id
*/
constructor(id) {
super(id);
/** @type {Object<string, AtlasSprite>} */
this.cachedSprites = {};
}
/**
* Returns the sprite for a given variant
* @param {number} rotationVariant
* @param {string} variant
* @returns {AtlasSprite}
*/
getSprite(rotationVariant, variant) {
const sprite_id =
this.id + (variant === defaultBuildingVariant ? "" : "-" + variant) + "-" + rotationVariant;
if (this.cachedSprites[sprite_id]) {
return this.cachedSprites[sprite_id];
}
const sprite = new AtlasSprite(sprite_id);
const meta = this.getSpriteMeta(rotationVariant, variant);
const scales = atlasFiles.map(af => af.meta.scale);
for (const res of scales) {
sprite.linksByResolution[res] = Loader.spriteNotFoundSprite.linksByResolution[res];
}
getFileAsDataURI(meta.url).then(data => {
const img = document.createElement("img");
img.src = data;
const link = new SpriteAtlasLink({
atlas: img,
packOffsetX: 0,
packOffsetY: 0,
packedX: 0,
packedY: 0,
packedW: meta.width,
packedH: meta.height,
w: meta.width,
h: meta.width,
});
for (const res of scales) {
sprite.linksByResolution[res] = link;
}
});
return sprite;
}
getBlueprintSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
return this.getSprite(rotationVariant, variant);
}
getPreviewSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
return this.getSprite(rotationVariant, variant);
}
/**
* Returns the sprite metadata for a given variant
* @param {number} rotationVariant
* @param {string} variant
* @returns {ExternalSpriteMeta}
*/
getSpriteMeta(rotationVariant, variant) {
abstract;
return { url: "", width: 0, height: 0 };
}
}

View File

@ -0,0 +1,13 @@
import { Component } from "../game/component";
export class ModComponent extends Component {
static getId() {
const className = this.prototype.constructor.name;
let id = className;
const i = className.lastIndexOf("Component");
if(i !== -1) {
id = id.slice(0, i);
}
return id;
}
}

5
src/js/GeoZ/mod_item.js Normal file
View File

@ -0,0 +1,5 @@
import { BaseItem } from "../game/base_item";
export class ModItem extends BaseItem {
}

View File

@ -0,0 +1,51 @@
import { Entity } from "../game/entity";
import { ItemProcessorSystem } from "../game/systems/item_processor";
import { BaseItem } from "../game/base_item";
/**
* @typedef {{
* items: Array<BaseItem>,
* itemsBySlot: Array<{ item: BaseItem, sourceSlot: number }>,
* itemsRaw: Array<{ item: BaseItem, sourceSlot: number }>,
* entity: Entity,
* outItems: Array<{item: BaseItem, requiredSlot?: number, preferredSlot?: number}>,
* system: ItemProcessorSystem
* }} ProcessorParameters
*/
export class ModProcessor {
/**
* @returns {String}
*/
static getType() {
return this.prototype.constructor.name;
}
/**
* @returns {Number}
*/
static getBaseSpeed() {
abstract;
return 0;
}
/**
* Checks whether it's possible to process something
* @param {Entity} entity
* @returns {Boolean}
*/
static canProcess(entity) {
abstract;
return false;
}
/**
* Process ther current item
* @param {ProcessorParameters} param0
* @returns {Boolean} Whether to track the production towards the analytics
*/
static process({}) {
abstract;
return false;
}
}

121
src/js/GeoZ/mod_system.js Normal file
View File

@ -0,0 +1,121 @@
import { GameSystem } from "../game/game_system";
import { GameSystemWithFilter } from "../game/game_system_with_filter";
import { GameRoot } from "../game/root";
import { Component } from "../game/component";
/**
* @typedef {
"belt"
| "itemEjector"
| "mapResources"
| "miner"
| "itemProcessor"
| "undergroundBelt"
| "hub"
| "staticMapEntities"
| "itemAcceptor"
| "storage"
| "wiredPins"
| "beltUnderlays"
| "wire"
| "constantSignal"
| "logicGate"
| "lever"
| "display"
| "itemProcessorOverlays"
| "beltReader"
| ""
* } VanillaSystemId
*/
export class ModSystem extends GameSystem {
/**
* @returns {String} Mod system ID
*/
static getId() {
//abstract;
const className = this.prototype.constructor.name;
let id = className;
const i = className.lastIndexOf("System");
if(i !== -1) {
id = id.slice(0, i);
}
id = id[0].toLowerCase() + id.slice(1);
return id;
}
/**
* Before which vanilla system should this system update
* @returns {VanillaSystemId}
*/
static getUpdateBefore() {
return "";
}
/**
* After which vanilla system should this system update
* @returns {VanillaSystemId}
*/
static getUpdateAfter() {
return "";
}
/**
* @param {GameRoot} root
*/
constructor(root) {
super(root);
}
}
export class ModSystemWithFilter extends GameSystemWithFilter {
/**
* @returns {String} Mod system ID
*/
static getId() {
//abstract;
const className = this.prototype.constructor.name;
let id = className;
const i = className.lastIndexOf("System");
if(i !== -1) {
id = id.slice(0, i);
}
id = id[0].toLowerCase() + id.slice(1);
return id;
}
/**
* Before which vanilla system should this system update
* @returns {VanillaSystemId}
*/
static getUpdateBefore() {
return "";
}
/**
* After which vanilla system should this system update
* @returns {VanillaSystemId}
*/
static getUpdateAfter() {
return "";
}
/**
* @returns {Array<typeof Component>}
*/
static getRequiredComponents() {
abstract;
return [];
}
/**
* Constructs a new game system with the given component filter. It will process
* all entities which have *all* of the passed components
* @param {GameRoot} root
*/
constructor(root) {
super(root, []);
this.requiredComponents = /** @type {Array<typeof Component>} */ (Object.getPrototypeOf(this).getRequiredComponents());
this.requiredComponentIds = this.requiredComponents.map(component => component.getId());
}
}

16
src/js/GeoZ/mod_utils.js Normal file
View File

@ -0,0 +1,16 @@
/**
* Returns a file as a data URI
* @param {string} url
* @returns {Promise<String>}
*/
export function getFileAsDataURI(url) {
return fetch(url)
.then(response => response.blob())
.then(blob => {
return new Promise((resolve) => {
var reader = new FileReader() ;
reader.onload = function() { resolve(this.result.toString()) } ; // <--- `this.result` contains a base64 data URI
reader.readAsDataURL(blob) ;
});
});
}

View File

@ -0,0 +1,51 @@
import * as GeoZ from "../../main";
import { Vector } from "../../../core/vector";
import { Entity } from "../../../game/entity";
class MetaTestBuilding extends GeoZ.MetaModBuilding {
static getId() {
return "test";
}
static getKeybinding() {
return "0";
}
static getTranslations() {
return {
variants: {
default: {
name: "Test",
description: "Test GeoZ building"
}
},
keybinding: "Test"
};
}
constructor() {
super("test");
}
getSilhouetteColor() {
return "#ff00ff";
}
getDimensions() {
return new Vector(1, 1);
}
getSpriteMeta() {
return {url:"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/wires/boolean_false.png", width: 64, height: 64};
}
setupEntityComponents() {}
}
/**@type {GeoZ.Mod}*/
const test = {
name: "test",
buildings: [MetaTestBuilding]
};
export default test;

View File

@ -251,292 +251,309 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
let trackProduction = true;
// DO SOME MAGIC
const ModProcessors = require("../../GeoZ/main").ModProcessors;
if (ModProcessors[processorComp.type]) {
trackProduction = ModProcessors[processorComp.type].process({
items: itemsBySlot.map(e => e.item),
itemsBySlot,
itemsRaw: items,
entity,
outItems,
system: this,
});
} else {
switch (processorComp.type) {
// SPLITTER
case enumItemProcessorTypes.splitterWires:
case enumItemProcessorTypes.splitter: {
trackProduction = false;
const availableSlots = entity.components.ItemEjector.slots.length;
switch (processorComp.type) {
// SPLITTER
case enumItemProcessorTypes.splitterWires:
case enumItemProcessorTypes.splitter: {
trackProduction = false;
const availableSlots = entity.components.ItemEjector.slots.length;
let nextSlot = processorComp.nextOutputSlot++ % availableSlots;
for (let i = 0; i < items.length; ++i) {
outItems.push({
item: items[i].item,
preferredSlot: (nextSlot + i) % availableSlots,
});
}
break;
}
// CUTTER
case enumItemProcessorTypes.cutter: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition;
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
for (let i = 0; i < cutDefinitions.length; ++i) {
const definition = cutDefinitions[i];
if (!definition.isEntirelyEmpty()) {
let nextSlot = processorComp.nextOutputSlot++ % availableSlots;
for (let i = 0; i < items.length; ++i) {
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
requiredSlot: i,
item: items[i].item,
preferredSlot: (nextSlot + i) % availableSlots,
});
}
break;
}
break;
}
// CUTTER
case enumItemProcessorTypes.cutter: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition;
// CUTTER (Quad)
case enumItemProcessorTypes.cutterQuad: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition;
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
for (let i = 0; i < cutDefinitions.length; ++i) {
const definition = cutDefinitions[i];
if (!definition.isEntirelyEmpty()) {
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
requiredSlot: i,
});
for (let i = 0; i < cutDefinitions.length; ++i) {
const definition = cutDefinitions[i];
if (!definition.isEntirelyEmpty()) {
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
requiredSlot: i,
});
}
}
break;
}
break;
}
// CUTTER (Quad)
case enumItemProcessorTypes.cutterQuad: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition;
// ROTATER
case enumItemProcessorTypes.rotater: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
});
break;
}
// ROTATER (CCW)
case enumItemProcessorTypes.rotaterCCW: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(inputDefinition);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
});
break;
}
// ROTATER (FL)
case enumItemProcessorTypes.rotaterFL: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(inputDefinition);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
});
break;
}
// STACKER
case enumItemProcessorTypes.stacker: {
const lowerItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const upperItem = /** @type {ShapeItem} */ (itemsBySlot[1].item);
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
lowerItem.definition,
upperItem.definition
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition),
});
break;
}
// TRASH
case enumItemProcessorTypes.trash: {
// Well this one is easy .. simply do nothing with the item
break;
}
// MIXER
case enumItemProcessorTypes.mixer: {
// Find both colors and combine them
const item1 = /** @type {ColorItem} */ (items[0].item);
const item2 = /** @type {ColorItem} */ (items[1].item);
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
const color1 = item1.color;
const color2 = item2.color;
// Try finding mixer color, and if we can't mix it we simply return the same color
const mixedColor = enumColorMixingResults[color1][color2];
let resultColor = color1;
if (mixedColor) {
resultColor = mixedColor;
}
outItems.push({
item: COLOR_ITEM_SINGLETONS[resultColor],
});
break;
}
// PAINTER
case enumItemProcessorTypes.painter: {
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const colorItem = /** @type {ColorItem} */ (itemsBySlot[1].item);
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem.definition,
colorItem.color
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
});
break;
}
// PAINTER (DOUBLE)
case enumItemProcessorTypes.painterDouble: {
const shapeItem1 = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const shapeItem2 = /** @type {ShapeItem} */ (itemsBySlot[1].item);
const colorItem = /** @type {ColorItem} */ (itemsBySlot[2].item);
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
assert(colorItem instanceof ColorItem, "Input for painter is not a color");
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem1.definition,
colorItem.color
);
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem2.definition,
colorItem.color
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1),
});
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2),
});
break;
}
// PAINTER (QUAD)
case enumItemProcessorTypes.painterQuad: {
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
/** @type {Array<enumColors>} */
const colors = [null, null, null, null];
for (let i = 0; i < 4; ++i) {
if (itemsBySlot[i + 1]) {
colors[i] = /** @type {ColorItem} */ (itemsBySlot[i + 1].item).color;
for (let i = 0; i < cutDefinitions.length; ++i) {
const definition = cutDefinitions[i];
if (!definition.isEntirelyEmpty()) {
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
requiredSlot: i,
});
}
}
break;
}
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
shapeItem.definition,
/** @type {[string, string, string, string]} */ (colors)
);
// ROTATER
case enumItemProcessorTypes.rotater: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
});
break;
}
// FILTER
case enumItemProcessorTypes.filter: {
// TODO
trackProduction = false;
const item = itemsBySlot[0].item;
const network = entity.components.WiredPins.slots[0].linkedNetwork;
if (!network || !network.currentValue) {
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(
inputDefinition
);
outItems.push({
item,
requiredSlot: 1,
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
});
break;
}
const value = network.currentValue;
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
// ROTATER (CCW)
case enumItemProcessorTypes.rotaterCCW: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(
inputDefinition
);
outItems.push({
item,
requiredSlot: 0,
});
} else {
outItems.push({
item,
requiredSlot: 1,
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
});
break;
}
break;
}
// ROTATER (FL)
case enumItemProcessorTypes.rotaterFL: {
const inputItem = /** @type {ShapeItem} */ (items[0].item);
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
// READER
case enumItemProcessorTypes.reader: {
// Pass through the item
const item = itemsBySlot[0].item;
outItems.push({ item });
// Track the item
const readerComp = entity.components.BeltReader;
readerComp.lastItemTimes.push(this.root.time.now());
readerComp.lastItem = item;
break;
}
// HUB
case enumItemProcessorTypes.hub: {
trackProduction = false;
const hubComponent = entity.components.Hub;
assert(hubComponent, "Hub item processor has no hub component");
for (let i = 0; i < items.length; ++i) {
const item = /** @type {ShapeItem} */ (items[i].item);
this.root.hubGoals.handleDefinitionDelivered(item.definition);
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(
inputDefinition
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
});
break;
}
break;
}
// STACKER
default:
assertAlways(false, "Unkown item processor type: " + processorComp.type);
case enumItemProcessorTypes.stacker: {
const lowerItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const upperItem = /** @type {ShapeItem} */ (itemsBySlot[1].item);
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
lowerItem.definition,
upperItem.definition
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition),
});
break;
}
// TRASH
case enumItemProcessorTypes.trash: {
// Well this one is easy .. simply do nothing with the item
break;
}
// MIXER
case enumItemProcessorTypes.mixer: {
// Find both colors and combine them
const item1 = /** @type {ColorItem} */ (items[0].item);
const item2 = /** @type {ColorItem} */ (items[1].item);
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
const color1 = item1.color;
const color2 = item2.color;
// Try finding mixer color, and if we can't mix it we simply return the same color
const mixedColor = enumColorMixingResults[color1][color2];
let resultColor = color1;
if (mixedColor) {
resultColor = mixedColor;
}
outItems.push({
item: COLOR_ITEM_SINGLETONS[resultColor],
});
break;
}
// PAINTER
case enumItemProcessorTypes.painter: {
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const colorItem = /** @type {ColorItem} */ (itemsBySlot[1].item);
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem.definition,
colorItem.color
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
});
break;
}
// PAINTER (DOUBLE)
case enumItemProcessorTypes.painterDouble: {
const shapeItem1 = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const shapeItem2 = /** @type {ShapeItem} */ (itemsBySlot[1].item);
const colorItem = /** @type {ColorItem} */ (itemsBySlot[2].item);
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
assert(colorItem instanceof ColorItem, "Input for painter is not a color");
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem1.definition,
colorItem.color
);
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem2.definition,
colorItem.color
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1),
});
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2),
});
break;
}
// PAINTER (QUAD)
case enumItemProcessorTypes.painterQuad: {
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
/** @type {Array<enumColors>} */
const colors = [null, null, null, null];
for (let i = 0; i < 4; ++i) {
if (itemsBySlot[i + 1]) {
colors[i] = /** @type {ColorItem} */ (itemsBySlot[i + 1].item).color;
}
}
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
shapeItem.definition,
/** @type {[string, string, string, string]} */ (colors)
);
outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
});
break;
}
// FILTER
case enumItemProcessorTypes.filter: {
// TODO
trackProduction = false;
const item = itemsBySlot[0].item;
const network = entity.components.WiredPins.slots[0].linkedNetwork;
if (!network || !network.currentValue) {
outItems.push({
item,
requiredSlot: 1,
});
break;
}
const value = network.currentValue;
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
outItems.push({
item,
requiredSlot: 0,
});
} else {
outItems.push({
item,
requiredSlot: 1,
});
}
break;
}
// READER
case enumItemProcessorTypes.reader: {
// Pass through the item
const item = itemsBySlot[0].item;
outItems.push({ item });
// Track the item
const readerComp = entity.components.BeltReader;
readerComp.lastItemTimes.push(this.root.time.now());
readerComp.lastItem = item;
break;
}
// HUB
case enumItemProcessorTypes.hub: {
trackProduction = false;
const hubComponent = entity.components.Hub;
assert(hubComponent, "Hub item processor has no hub component");
for (let i = 0; i < items.length; ++i) {
const item = /** @type {ShapeItem} */ (items[i].item);
this.root.hubGoals.handleDefinitionDelivered(item.definition);
}
break;
}
default:
assertAlways(false, "Unkown item processor type: " + processorComp.type);
}
}
// Track produced items

View File

@ -10,6 +10,7 @@ import { initDrawUtils } from "./core/draw_utils";
import { initItemRegistry } from "./game/item_registry";
import { initMetaBuildingRegistry } from "./game/meta_building_registry";
import { initGameSpeedRegistry } from "./game/game_speed_registry";
import { initMods } from "./GeoZ/main";
const logger = createLogger("main");
@ -77,6 +78,7 @@ console.log("%cDEVCODE BUILT IN", "color: #f77");
logSection("Boot Process", "#f9a825");
initMods();
initDrawUtils();
initComponentRegistry();
initItemRegistry();
@ -91,4 +93,4 @@ function bootApp() {
app.boot();
}
window.addEventListener("load", bootApp);
window.addEventListener("load", bootApp);