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:
parent
76a05a5776
commit
3b4417ba0b
237
src/js/GeoZ/main.js
Normal file
237
src/js/GeoZ/main.js
Normal 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
138
src/js/GeoZ/mod_building.js
Normal 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 };
|
||||
}
|
||||
}
|
13
src/js/GeoZ/mod_component.js
Normal file
13
src/js/GeoZ/mod_component.js
Normal 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
5
src/js/GeoZ/mod_item.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { BaseItem } from "../game/base_item";
|
||||
|
||||
export class ModItem extends BaseItem {
|
||||
|
||||
}
|
51
src/js/GeoZ/mod_processor.js
Normal file
51
src/js/GeoZ/mod_processor.js
Normal 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
121
src/js/GeoZ/mod_system.js
Normal 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
16
src/js/GeoZ/mod_utils.js
Normal 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) ;
|
||||
});
|
||||
});
|
||||
}
|
51
src/js/GeoZ/mods/test/test.mod.js
Normal file
51
src/js/GeoZ/mods/test/test.mod.js
Normal 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;
|
@ -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
|
||||
|
@ -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);
|
Loading…
Reference in New Issue
Block a user