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;
|
let trackProduction = true;
|
||||||
|
|
||||||
// DO SOME MAGIC
|
// 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) {
|
let nextSlot = processorComp.nextOutputSlot++ % availableSlots;
|
||||||
// SPLITTER
|
for (let i = 0; i < items.length; ++i) {
|
||||||
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()) {
|
|
||||||
outItems.push({
|
outItems.push({
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
item: items[i].item,
|
||||||
requiredSlot: i,
|
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)
|
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
|
||||||
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.shapeActionCutQuad(inputDefinition);
|
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||||
|
const definition = cutDefinitions[i];
|
||||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
if (!definition.isEntirelyEmpty()) {
|
||||||
const definition = cutDefinitions[i];
|
outItems.push({
|
||||||
if (!definition.isEntirelyEmpty()) {
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||||
outItems.push({
|
requiredSlot: i,
|
||||||
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
|
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
|
||||||
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 rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition);
|
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||||
outItems.push({
|
const definition = cutDefinitions[i];
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
if (!definition.isEntirelyEmpty()) {
|
||||||
});
|
outItems.push({
|
||||||
break;
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||||
}
|
requiredSlot: i,
|
||||||
|
});
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
// ROTATER
|
||||||
shapeItem.definition,
|
case enumItemProcessorTypes.rotater: {
|
||||||
/** @type {[string, string, string, string]} */ (colors)
|
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||||
);
|
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||||
|
const inputDefinition = inputItem.definition;
|
||||||
|
|
||||||
outItems.push({
|
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
inputDefinition
|
||||||
});
|
);
|
||||||
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({
|
outItems.push({
|
||||||
item,
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||||
requiredSlot: 1,
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = network.currentValue;
|
// ROTATER (CCW)
|
||||||
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
|
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({
|
outItems.push({
|
||||||
item,
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||||
requiredSlot: 0,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
outItems.push({
|
|
||||||
item,
|
|
||||||
requiredSlot: 1,
|
|
||||||
});
|
});
|
||||||
|
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
|
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(
|
||||||
case enumItemProcessorTypes.reader: {
|
inputDefinition
|
||||||
// Pass through the item
|
);
|
||||||
const item = itemsBySlot[0].item;
|
outItems.push({
|
||||||
outItems.push({ item });
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||||
|
});
|
||||||
// Track the item
|
break;
|
||||||
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;
|
// STACKER
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
case enumItemProcessorTypes.stacker: {
|
||||||
assertAlways(false, "Unkown item processor type: " + processorComp.type);
|
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
|
// Track produced items
|
||||||
|
@ -10,6 +10,7 @@ import { initDrawUtils } from "./core/draw_utils";
|
|||||||
import { initItemRegistry } from "./game/item_registry";
|
import { initItemRegistry } from "./game/item_registry";
|
||||||
import { initMetaBuildingRegistry } from "./game/meta_building_registry";
|
import { initMetaBuildingRegistry } from "./game/meta_building_registry";
|
||||||
import { initGameSpeedRegistry } from "./game/game_speed_registry";
|
import { initGameSpeedRegistry } from "./game/game_speed_registry";
|
||||||
|
import { initMods } from "./GeoZ/main";
|
||||||
|
|
||||||
const logger = createLogger("main");
|
const logger = createLogger("main");
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ console.log("%cDEVCODE BUILT IN", "color: #f77");
|
|||||||
|
|
||||||
logSection("Boot Process", "#f9a825");
|
logSection("Boot Process", "#f9a825");
|
||||||
|
|
||||||
|
initMods();
|
||||||
initDrawUtils();
|
initDrawUtils();
|
||||||
initComponentRegistry();
|
initComponentRegistry();
|
||||||
initItemRegistry();
|
initItemRegistry();
|
||||||
@ -91,4 +93,4 @@ function bootApp() {
|
|||||||
app.boot();
|
app.boot();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", bootApp);
|
window.addEventListener("load", bootApp);
|
Loading…
Reference in New Issue
Block a user