2020-09-19 06:51:28 +00:00
|
|
|
/* typehints:start */
|
|
|
|
|
import { DrawParameters } from "../core/draw_parameters";
|
|
|
|
|
import { Component } from "./component";
|
|
|
|
|
/* typehints:end */
|
|
|
|
|
|
|
|
|
|
import { GameRoot } from "./root";
|
|
|
|
|
import { globalConfig } from "../core/config";
|
|
|
|
|
import { enumDirectionToVector, enumDirectionToAngle } from "../core/vector";
|
|
|
|
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
|
|
|
|
import { EntityComponentStorage } from "./entity_components";
|
|
|
|
|
import { Loader } from "../core/loader";
|
|
|
|
|
import { drawRotatedSprite } from "../core/draw_utils";
|
|
|
|
|
import { gComponentRegistry } from "../core/global_registries";
|
2020-09-19 19:41:48 +00:00
|
|
|
import { getBuildingDataFromCode } from "./building_codes";
|
2020-09-19 06:51:28 +00:00
|
|
|
|
|
|
|
|
export class Entity extends BasicSerializableObject {
|
|
|
|
|
/**
|
|
|
|
|
* @param {GameRoot} root
|
|
|
|
|
*/
|
|
|
|
|
constructor(root) {
|
|
|
|
|
super();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle to the global game root
|
|
|
|
|
*/
|
|
|
|
|
this.root = root;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The components of the entity
|
|
|
|
|
*/
|
|
|
|
|
this.components = new EntityComponentStorage();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether this entity was registered on the @see EntityManager so far
|
|
|
|
|
*/
|
|
|
|
|
this.registered = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* On which layer this entity is
|
|
|
|
|
* @type {Layer}
|
|
|
|
|
*/
|
|
|
|
|
this.layer = "regular";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Internal entity unique id, set by the @see EntityManager
|
|
|
|
|
*/
|
|
|
|
|
this.uid = 0;
|
|
|
|
|
|
|
|
|
|
/* typehints:start */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stores if this entity is destroyed, set by the @see EntityManager
|
|
|
|
|
* @type {boolean} */
|
|
|
|
|
this.destroyed;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stores if this entity is queued to get destroyed in the next tick
|
|
|
|
|
* of the @see EntityManager
|
|
|
|
|
* @type {boolean} */
|
|
|
|
|
this.queuedForDestroy;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stores the reason why this entity was destroyed
|
|
|
|
|
* @type {string} */
|
|
|
|
|
this.destroyReason;
|
|
|
|
|
|
|
|
|
|
/* typehints:end */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static getId() {
|
|
|
|
|
return "Entity";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @see BasicSerializableObject.getSchema
|
|
|
|
|
* @returns {import("../savegame/serialization").Schema}
|
|
|
|
|
*/
|
|
|
|
|
static getSchema() {
|
|
|
|
|
return {
|
|
|
|
|
uid: types.uint,
|
|
|
|
|
components: types.keyValueMap(types.objData(gComponentRegistry), false),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-09-19 19:41:48 +00:00
|
|
|
* Returns a clone of this entity
|
2020-09-19 06:51:28 +00:00
|
|
|
*/
|
2020-09-19 19:41:48 +00:00
|
|
|
clone() {
|
|
|
|
|
const staticComp = this.components.StaticMapEntity;
|
|
|
|
|
const buildingData = getBuildingDataFromCode(staticComp.code);
|
|
|
|
|
|
|
|
|
|
const clone = buildingData.metaInstance.createEntity({
|
|
|
|
|
root: this.root,
|
|
|
|
|
origin: staticComp.origin,
|
|
|
|
|
originalRotation: staticComp.originalRotation,
|
|
|
|
|
rotation: staticComp.rotation,
|
|
|
|
|
rotationVariant: buildingData.rotationVariant,
|
|
|
|
|
variant: buildingData.variant,
|
|
|
|
|
});
|
|
|
|
|
|
2020-09-19 06:51:28 +00:00
|
|
|
for (const key in this.components) {
|
2020-09-19 19:41:48 +00:00
|
|
|
/** @type {Component} */ (this.components[key]).copyAdditionalStateTo(clone.components[key]);
|
2020-09-19 06:51:28 +00:00
|
|
|
}
|
2020-09-19 19:41:48 +00:00
|
|
|
|
2020-09-19 06:51:28 +00:00
|
|
|
return clone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds a new component, only possible until the entity is registered on the entity manager,
|
|
|
|
|
* after that use @see EntityManager.addDynamicComponent
|
|
|
|
|
* @param {Component} componentInstance
|
|
|
|
|
* @param {boolean} force Used by the entity manager. Internal parameter, do not change
|
|
|
|
|
*/
|
|
|
|
|
addComponent(componentInstance, force = false) {
|
|
|
|
|
if (!force && this.registered) {
|
|
|
|
|
this.root.entityMgr.attachDynamicComponent(this, componentInstance);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
assert(force || !this.registered, "Entity already registered, use EntityManager.addDynamicComponent");
|
|
|
|
|
const id = /** @type {typeof Component} */ (componentInstance.constructor).getId();
|
|
|
|
|
assert(!this.components[id], "Component already present");
|
|
|
|
|
this.components[id] = componentInstance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Removes a given component, only possible until the entity is registered on the entity manager,
|
|
|
|
|
* after that use @see EntityManager.removeDynamicComponent
|
|
|
|
|
* @param {typeof Component} componentClass
|
|
|
|
|
* @param {boolean} force
|
|
|
|
|
*/
|
|
|
|
|
removeComponent(componentClass, force = false) {
|
|
|
|
|
if (!force && this.registered) {
|
|
|
|
|
this.root.entityMgr.removeDynamicComponent(this, componentClass);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
assert(
|
|
|
|
|
force || !this.registered,
|
|
|
|
|
"Entity already registered, use EntityManager.removeDynamicComponent"
|
|
|
|
|
);
|
|
|
|
|
const id = componentClass.getId();
|
|
|
|
|
assert(this.components[id], "Component does not exist on entity");
|
|
|
|
|
delete this.components[id];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws the entity, to override use @see Entity.drawImpl
|
|
|
|
|
* @param {DrawParameters} parameters
|
|
|
|
|
*/
|
|
|
|
|
drawDebugOverlays(parameters) {
|
|
|
|
|
const context = parameters.context;
|
|
|
|
|
const staticComp = this.components.StaticMapEntity;
|
|
|
|
|
|
|
|
|
|
if (G_IS_DEV && staticComp && globalConfig.debug.showEntityBounds) {
|
|
|
|
|
if (staticComp) {
|
|
|
|
|
const transformed = staticComp.getTileSpaceBounds();
|
|
|
|
|
context.strokeStyle = "rgba(255, 0, 0, 0.5)";
|
|
|
|
|
context.lineWidth = 2;
|
|
|
|
|
// const boundsSize = 20;
|
|
|
|
|
context.beginPath();
|
|
|
|
|
context.rect(
|
|
|
|
|
transformed.x * globalConfig.tileSize,
|
|
|
|
|
transformed.y * globalConfig.tileSize,
|
|
|
|
|
transformed.w * globalConfig.tileSize,
|
|
|
|
|
transformed.h * globalConfig.tileSize
|
|
|
|
|
);
|
|
|
|
|
context.stroke();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (G_IS_DEV && staticComp && globalConfig.debug.showAcceptorEjectors) {
|
|
|
|
|
const ejectorComp = this.components.ItemEjector;
|
|
|
|
|
|
|
|
|
|
if (ejectorComp) {
|
|
|
|
|
const ejectorSprite = Loader.getSprite("sprites/debug/ejector_slot.png");
|
|
|
|
|
for (let i = 0; i < ejectorComp.slots.length; ++i) {
|
|
|
|
|
const slot = ejectorComp.slots[i];
|
|
|
|
|
const slotTile = staticComp.localTileToWorld(slot.pos);
|
|
|
|
|
const direction = staticComp.localDirectionToWorld(slot.direction);
|
|
|
|
|
const directionVector = enumDirectionToVector[direction];
|
|
|
|
|
const angle = Math.radians(enumDirectionToAngle[direction]);
|
|
|
|
|
|
|
|
|
|
context.globalAlpha = slot.item ? 1 : 0.2;
|
|
|
|
|
drawRotatedSprite({
|
|
|
|
|
parameters,
|
|
|
|
|
sprite: ejectorSprite,
|
|
|
|
|
x: (slotTile.x + 0.5 + directionVector.x * 0.37) * globalConfig.tileSize,
|
|
|
|
|
y: (slotTile.y + 0.5 + directionVector.y * 0.37) * globalConfig.tileSize,
|
|
|
|
|
angle,
|
|
|
|
|
size: globalConfig.tileSize * 0.25,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const acceptorComp = this.components.ItemAcceptor;
|
|
|
|
|
|
|
|
|
|
if (acceptorComp) {
|
|
|
|
|
const acceptorSprite = Loader.getSprite("sprites/misc/acceptor_slot.png");
|
|
|
|
|
for (let i = 0; i < acceptorComp.slots.length; ++i) {
|
|
|
|
|
const slot = acceptorComp.slots[i];
|
|
|
|
|
const slotTile = staticComp.localTileToWorld(slot.pos);
|
Mod Support - 1.5.0 Update (#1361)
* initial modloader draft
* modloader features
* Refactor mods to use signals
* Add support for modifying and registering new transltions
* Minor adjustments
* Support for string building ids for mods
* Initial support for adding new buildings
* Refactor how mods are loaded to resolve circular dependencies and prepare for future mod loading
* Lazy Load mods to make sure all dependencies are loaded
* Expose all exported members automatically to mods
* Fix duplicate exports
* Allow loading mods from standalone
* update changelog
* Fix mods folder incorrect path
* Fix modloading in standalone
* Fix sprites not getting replaced, update demo mod
* Load dev mod via raw loader
* Improve mod developing so mods are directly ready to be deployed, load mods from local file server
* Proper mods ui
* Allow mods to register game systems and draw stuff
* Change mods path
* Fix sprites not loading
* Minor adjustments, closes #1333
* Add support for loading atlases via mods
* Add support for loading mods from external sources in DEV
* Add confirmation when loading mods
* Fix circular dependency
* Minor Keybindings refactor, add support for keybindings to mods, add support for dialogs to mods
* Add some mod signals
* refactor game loading states
* Make shapez exports global
* Start to make mods safer
* Refactor file system electron event handling
* Properly isolate electron renderer process
* Update to latest electron
* Show errors when loading mods
* Update confirm dialgo
* Minor restructure, start to add mod examples
* Allow adding custom themesw
* Add more examples and allow defining custom item processor operations
* Add interface to register new buildings
* Fixed typescript type errors (#1335)
* Refactor building registry, make it easier for mods to add new buildings
* Allow overriding existing methods
* Add more examples and more features
* More mod examples
* Make mod loading simpler
* Add example how to add custom drawings
* Remove unused code
* Minor modloader adjustments
* Support for rotation variants in mods (was broken previously)
* Allow mods to replace builtin sub shapes
* Add helper methods to extend classes
* Fix menu bar on mac os
* Remember window state
* Add support for paste signals
* Add example how to add custom components and systems
* Support for mod settings
* Add example for adding a new item type
* Update class extensions
* Minor adjustments
* Fix typo
* Add notification blocks mod example
* Add small tutorial
* Update readme
* Add better instructions
* Update JSDoc for Replacing Methods (#1336)
* upgraded types for overriding methods
* updated comments
Co-authored-by: Edward Badel <you@example.com>
* Direction lock now indicates when there is a building inbetween
* Fix mod examples
* Fix linter error
* Game state register (#1341)
* Added a gamestate register helper
Added a gamestate register helper
* Update mod_interface.js
* export build options
* Fix runBeforeMethod and runAfterMethod
* Minor game system code cleanup
* Belt path drawing optimization
* Fix belt path optimization
* Belt drawing improvements, again
* Do not render belts in statics disabled view
* Allow external URL to load more than one mod (#1337)
* Allow external URL to load more than one mod
Instead of loading the text returned from the remote server, load a JSON object with a `mods` field, containing strings of all the mods. This lets us work on more than one mod at a time or without separate repos. This will break tooling such as `create-shapezio-mod` though.
* Update modloader.js
* Prettier fixes
* Added link to create-shapezio-mod npm page (#1339)
Added link to create-shapezio-mod npm page: https://www.npmjs.com/package/create-shapezio-mod
* allow command line switch to load more than one mod (#1342)
* Fixed class handle type (#1345)
* Fixed class handle type
* Fixed import game state
* Minor adjustments
* Refactor item acceptor to allow only single direction slots
* Allow specifying minimumGameVersion
* Add sandbox example
* Replaced concatenated strings with template literals (#1347)
* Mod improvements
* Make wired pins component optional on the storage
* Fix mod examples
* Bind `this` for method overriding JSDoc (#1352)
* fix entity debugger reaching HTML elements (#1353)
* Store mods in savegame and show warning when it differs
* Closes #1357
* Fix All Shapez Exports Being Const (#1358)
* Allowed setting of variables inside webpack modules
* remove console log
* Fix stringification of things inside of eval
Co-authored-by: Edward Badel <you@example.com>
* Fix building placer intersection warning
* Add example for storing data in the savegame
* Fix double painter bug (#1349)
* Add example on how to extend builtin buildings
* update readme
* Disable steam achievements when playing with mods
* Update translations
Co-authored-by: Thomas (DJ1TJOO) <44841260+DJ1TJOO@users.noreply.github.com>
Co-authored-by: Bagel03 <70449196+Bagel03@users.noreply.github.com>
Co-authored-by: Edward Badel <you@example.com>
Co-authored-by: Emerald Block <69981203+EmeraldBlock@users.noreply.github.com>
Co-authored-by: saile515 <63782477+saile515@users.noreply.github.com>
Co-authored-by: Sense101 <67970865+Sense101@users.noreply.github.com>
2022-02-01 15:35:49 +00:00
|
|
|
const direction = staticComp.localDirectionToWorld(slot.direction);
|
|
|
|
|
const directionVector = enumDirectionToVector[direction];
|
|
|
|
|
const angle = Math.radians(enumDirectionToAngle[direction] + 180);
|
|
|
|
|
context.globalAlpha = 0.4;
|
|
|
|
|
drawRotatedSprite({
|
|
|
|
|
parameters,
|
|
|
|
|
sprite: acceptorSprite,
|
|
|
|
|
x: (slotTile.x + 0.5 + directionVector.x * 0.37) * globalConfig.tileSize,
|
|
|
|
|
y: (slotTile.y + 0.5 + directionVector.y * 0.37) * globalConfig.tileSize,
|
|
|
|
|
angle,
|
|
|
|
|
size: globalConfig.tileSize * 0.25,
|
|
|
|
|
});
|
2020-09-19 06:51:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context.globalAlpha = 1;
|
|
|
|
|
}
|
|
|
|
|
// this.drawImpl(parameters);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///// Helper interfaces
|
|
|
|
|
|
|
|
|
|
///// Interface to override by subclasses
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* override, should draw the entity
|
|
|
|
|
* @param {DrawParameters} parameters
|
2022-02-15 07:31:47 +00:00
|
|
|
* @abstract
|
2020-09-19 06:51:28 +00:00
|
|
|
*/
|
|
|
|
|
drawImpl(parameters) {
|
|
|
|
|
abstract;
|
|
|
|
|
}
|
|
|
|
|
}
|