mirror of
https://github.com/teoxoy/factorio-blueprint-editor.git
synced 2025-09-04 17:09:30 +00:00
reformat files
via `npm run format:fix`
This commit is contained in:
4
.github/ISSUE_TEMPLATE/--bug-report.md
vendored
4
.github/ISSUE_TEMPLATE/--bug-report.md
vendored
@@ -29,8 +29,8 @@ If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
@@ -14,10 +14,10 @@ You can file new issues by selecting from our [new issue templates](https://gith
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [git](https://git-scm.com/)
|
||||
- [node](https://nodejs.org/en/)
|
||||
- [vscode](https://code.visualstudio.com/)
|
||||
- [rust](https://rust-lang.org)
|
||||
- [git](https://git-scm.com/)
|
||||
- [node](https://nodejs.org/en/)
|
||||
- [vscode](https://code.visualstudio.com/)
|
||||
- [rust](https://rust-lang.org)
|
||||
|
||||
### Note
|
||||
|
||||
|
16
README.md
16
README.md
@@ -17,14 +17,14 @@ Example blueprint book: https://fbe.teoxoy.com/?source=https://pastebin.com/Xp9u
|
||||
|
||||
# Features
|
||||
|
||||
- rendering and editing blueprints
|
||||
- history (undo/redo)
|
||||
- copy and delete selections
|
||||
- import blueprints and books from multiple sources (direct bp string, pastebin, hastebin, gist, gitlab, factorioprints, factorio.school, google docs)
|
||||
- generating blueprint images
|
||||
- oil outpost generator
|
||||
- customizable keybinds
|
||||
- "creative" entities
|
||||
- rendering and editing blueprints
|
||||
- history (undo/redo)
|
||||
- copy and delete selections
|
||||
- import blueprints and books from multiple sources (direct bp string, pastebin, hastebin, gist, gitlab, factorioprints, factorio.school, google docs)
|
||||
- generating blueprint images
|
||||
- oil outpost generator
|
||||
- customizable keybinds
|
||||
- "creative" entities
|
||||
|
||||
# Contributing
|
||||
|
||||
|
@@ -127,11 +127,11 @@ export class Editor {
|
||||
}
|
||||
|
||||
public haveBlueprint(): boolean {
|
||||
return !G.bp.isEmpty();
|
||||
return !G.bp.isEmpty()
|
||||
}
|
||||
|
||||
public async appendBlueprint(bp: Blueprint): Promise<void> {
|
||||
const result = bp.entities.valuesArray().map(e => new Entity(e.rawEntity, G.BPC.bp));
|
||||
const result = bp.entities.valuesArray().map(e => new Entity(e.rawEntity, G.BPC.bp))
|
||||
|
||||
G.BPC.spawnPaintContainer(result, 0)
|
||||
}
|
||||
@@ -180,7 +180,7 @@ export class Editor {
|
||||
|
||||
registerAction('focus', 'f').bind({ press: () => G.BPC.centerViewport() })
|
||||
|
||||
function doRotate(ccw: boolean): void {
|
||||
function doRotate(ccw: boolean): void {
|
||||
if (G.BPC.mode === EditorMode.EDIT) {
|
||||
G.BPC.hoverContainer.entity.rotate(ccw, true)
|
||||
} else if (G.BPC.mode === EditorMode.PAINT) {
|
||||
@@ -194,9 +194,11 @@ export class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
function doFlip(vertical: boolean): void {
|
||||
if (G.BPC.mode === EditorMode.PAINT
|
||||
&& G.BPC.paintContainer.canFlipOrRotateByCopying()) {
|
||||
function doFlip(vertical: boolean): void {
|
||||
if (
|
||||
G.BPC.mode === EditorMode.PAINT &&
|
||||
G.BPC.paintContainer.canFlipOrRotateByCopying()
|
||||
) {
|
||||
try {
|
||||
const copies = G.BPC.paintContainer.flippedEntities(vertical)
|
||||
G.BPC.paintContainer.destroy()
|
||||
@@ -212,19 +214,19 @@ export class Editor {
|
||||
}
|
||||
|
||||
registerAction('rotate', 'r').bind({
|
||||
press: () => doRotate(false)
|
||||
press: () => doRotate(false),
|
||||
})
|
||||
|
||||
registerAction('reverseRotate', 'shift+r').bind({
|
||||
press: () => doRotate(true)
|
||||
press: () => doRotate(true),
|
||||
})
|
||||
|
||||
registerAction('flipHorizontal', 'shift+f').bind({
|
||||
press: () => doFlip(false)
|
||||
press: () => doFlip(false),
|
||||
})
|
||||
|
||||
registerAction('flipVertical', 'shift+g').bind({
|
||||
press: () => doFlip(true)
|
||||
press: () => doFlip(true),
|
||||
})
|
||||
|
||||
registerAction('pipette', 'q').bind({
|
||||
|
@@ -81,7 +81,12 @@ export class InventoryDialog extends Dialog {
|
||||
if (itemsFilter === undefined) {
|
||||
const itemData = FD.items[item.name]
|
||||
if (!itemData) continue
|
||||
if (!itemData.place_result && !itemData.place_as_tile && !itemData.wire_count) continue
|
||||
if (
|
||||
!itemData.place_result &&
|
||||
!itemData.place_as_tile &&
|
||||
!itemData.wire_count
|
||||
)
|
||||
continue
|
||||
// needed for robots/trains/cars
|
||||
if (itemData.place_result && !FD.entities[itemData.place_result]) continue
|
||||
} else {
|
||||
|
@@ -14,8 +14,8 @@ const Point = (p: IPoint | number[]): IPoint => {
|
||||
}
|
||||
|
||||
/** Computes a weighted sum of vectors. Weights are preceding their corresponding vector, and equal to 1 if not specified */
|
||||
const sumprod = (...args: (number | (number[]|IPoint))[]): IPoint => {
|
||||
const ans: IPoint = {x:0, y:0}
|
||||
const sumprod = (...args: (number | (number[] | IPoint))[]): IPoint => {
|
||||
const ans: IPoint = { x: 0, y: 0 }
|
||||
let coef: number = undefined
|
||||
for (let arg of args) {
|
||||
if (typeof arg === 'number') {
|
||||
@@ -27,7 +27,7 @@ const sumprod = (...args: (number | (number[]|IPoint))[]): IPoint => {
|
||||
ans.y += (coef ?? 1) * arg.y
|
||||
coef = undefined
|
||||
}
|
||||
if (coef !== undefined) throw new TypeError("weights should be followed by a vector")
|
||||
if (coef !== undefined) throw new TypeError('weights should be followed by a vector')
|
||||
return ans
|
||||
}
|
||||
|
||||
|
@@ -62,7 +62,8 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
)
|
||||
|
||||
private _moveSpeed = Number(localStorage.getItem('moveSpeed') ?? 10)
|
||||
private _gridColor = (localStorage.getItem('darkTheme') ?? 'true') === 'true' ? 0x303030 : 0xc9c9c9
|
||||
private _gridColor =
|
||||
(localStorage.getItem('darkTheme') ?? 'true') === 'true' ? 0x303030 : 0xc9c9c9
|
||||
private _gridPattern: GridPattern = (localStorage.getItem('pattern') ?? 'grid') as GridPattern
|
||||
private _limitWireReach = (localStorage.getItem('limitWireReach') ?? 'true') === 'true'
|
||||
private _mode: EditorMode = EditorMode.NONE
|
||||
@@ -446,7 +447,7 @@ export class BlueprintContainer extends PIXI.Container {
|
||||
|
||||
const entity = this.bp.entityPositionGrid.getEntityAtPosition({
|
||||
x: this.gridData.x32,
|
||||
y: this.gridData.y32
|
||||
y: this.gridData.y32,
|
||||
})
|
||||
const eC = entity ? EntityContainer.mappings.get(entity.entityNumber) : undefined
|
||||
|
||||
|
@@ -55,7 +55,7 @@ export class GridData extends EventEmitter {
|
||||
return this._constrained
|
||||
}
|
||||
|
||||
public set constrained(constrained: boolean) {
|
||||
public set constrained(constrained: boolean) {
|
||||
this._constrained = constrained
|
||||
this._constrainTo = undefined
|
||||
}
|
||||
@@ -77,14 +77,19 @@ export class GridData extends EventEmitter {
|
||||
return false
|
||||
}
|
||||
|
||||
if (element.startsWith(`_${ this._constrainTo}`)) {
|
||||
if (element.startsWith(`_${this._constrainTo}`)) {
|
||||
const sign = Math.sign(target - this[element])
|
||||
this[element] += sign
|
||||
return this[element] != target
|
||||
}
|
||||
}
|
||||
|
||||
private updateValuesWithConstraints(x16: number, y16: number, x32: number, y32: number): boolean {
|
||||
private updateValuesWithConstraints(
|
||||
x16: number,
|
||||
y16: number,
|
||||
x32: number,
|
||||
y32: number
|
||||
): boolean {
|
||||
let anythingChanged = false
|
||||
if (this.constrainMove('_x16', x16)) anythingChanged = true
|
||||
if (this.constrainMove('_y16', y16)) anythingChanged = true
|
||||
|
@@ -301,7 +301,7 @@ export class OverlayContainer extends PIXI.Container {
|
||||
case 6:
|
||||
position.x += offset
|
||||
}
|
||||
const arrow = createArrow(util.sumprod(64,position), type)
|
||||
const arrow = createArrow(util.sumprod(64, position), type)
|
||||
if (entity.type === 'boiler' && type === 2) {
|
||||
arrow.rotation = 0.5 * Math.PI
|
||||
}
|
||||
|
@@ -89,11 +89,17 @@ export class PaintBlueprintContainer extends PaintContainer {
|
||||
}
|
||||
|
||||
public logDataForComparison(): void {
|
||||
const withOutNums = [...this.entities.keys()].map(e => ({...e.rawEntity, entity_number: undefined}))
|
||||
withOutNums.sort((a, b) => Math.sign(b.position.y - a.position.y) || Math.sign(b.position.x - a.position.x))
|
||||
const withOutNums = [...this.entities.keys()].map(e => ({
|
||||
...e.rawEntity,
|
||||
entity_number: undefined,
|
||||
}))
|
||||
withOutNums.sort(
|
||||
(a, b) =>
|
||||
Math.sign(b.position.y - a.position.y) || Math.sign(b.position.x - a.position.x)
|
||||
)
|
||||
console.log(withOutNums)
|
||||
}
|
||||
|
||||
|
||||
public canFlipOrRotateByCopying(): boolean {
|
||||
return true
|
||||
}
|
||||
@@ -115,7 +121,6 @@ export class PaintBlueprintContainer extends PaintContainer {
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
public moveAtCursor(): void {
|
||||
if (!this.visible) return
|
||||
|
||||
@@ -164,16 +169,14 @@ export class PaintBlueprintContainer extends PaintContainer {
|
||||
this.bp.wireConnections
|
||||
.getEntityConnections(oldID)
|
||||
.filter(connection =>
|
||||
connection.cps.every(cp =>
|
||||
oldEntIDToNewEntID.has(cp.entityNumber)
|
||||
)
|
||||
connection.cps.every(cp => oldEntIDToNewEntID.has(cp.entityNumber))
|
||||
)
|
||||
.map(connection => ({
|
||||
...connection,
|
||||
cps: connection.cps.map(cp => ({
|
||||
...cp,
|
||||
entityNumber: oldEntIDToNewEntID.get(cp.entityNumber),
|
||||
}))
|
||||
})),
|
||||
}))
|
||||
.forEach(conn => this.bpc.bp.wireConnections.create(conn))
|
||||
}
|
||||
|
@@ -32,13 +32,13 @@ export class PaintBlueprintEntityContainer {
|
||||
|
||||
this.entitySprites = EntitySprite.getParts(
|
||||
this.entity,
|
||||
util.sumprod(32,this.entity.position),
|
||||
util.sumprod(32, this.entity.position),
|
||||
this.bp.entityPositionGrid
|
||||
)
|
||||
}
|
||||
|
||||
private get entityPosition(): IPoint {
|
||||
return util.sumprod(1/32,this.pbpc, this.entity.position)
|
||||
return util.sumprod(1 / 32, this.pbpc, this.entity.position)
|
||||
}
|
||||
|
||||
private get position(): IPoint {
|
||||
|
@@ -131,7 +131,7 @@ export class PaintEntityContainer extends PaintContainer {
|
||||
}
|
||||
|
||||
public canFlipOrRotateByCopying(): boolean {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
protected redraw(): void {
|
||||
|
@@ -69,7 +69,7 @@ export class PaintTileContainer extends PaintContainer {
|
||||
}
|
||||
|
||||
public canFlipOrRotateByCopying(): boolean {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
protected redraw(): void {
|
||||
@@ -95,9 +95,7 @@ export class PaintTileContainer extends PaintContainer {
|
||||
const position = this.getGridPosition()
|
||||
|
||||
this.bpc.bp.removeTiles(
|
||||
PaintTileContainer.getTilePositions().map(p =>
|
||||
util.sumprod(p, position)
|
||||
)
|
||||
PaintTileContainer.getTilePositions().map(p => util.sumprod(p, position))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -108,9 +106,7 @@ export class PaintTileContainer extends PaintContainer {
|
||||
|
||||
this.bpc.bp.createTiles(
|
||||
this.name,
|
||||
PaintTileContainer.getTilePositions().map(p =>
|
||||
util.sumprod(p, position)
|
||||
)
|
||||
PaintTileContainer.getTilePositions().map(p => util.sumprod(p, position))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -8,15 +8,15 @@ import { PaintContainer } from './PaintContainer'
|
||||
import { BlueprintContainer } from './BlueprintContainer'
|
||||
|
||||
export class PaintWireContainer extends PaintContainer {
|
||||
private color? : string
|
||||
private cp? : IConnectionPoint? = undefined
|
||||
private color?: string
|
||||
private cp?: IConnectionPoint? = undefined
|
||||
/** This is only a reference */
|
||||
private cursorBox: PIXI.Container
|
||||
|
||||
public constructor(bpc: BlueprintContainer, name: string) {
|
||||
super(bpc, name)
|
||||
|
||||
this.color = name.split("_",1)[0]
|
||||
this.color = name.split('_', 1)[0]
|
||||
this.cp = undefined
|
||||
|
||||
this.moveAtCursor()
|
||||
@@ -58,9 +58,12 @@ export class PaintWireContainer extends PaintContainer {
|
||||
const entity = this.bpc.bp.entityPositionGrid.getEntityAtPosition(cursor_position)
|
||||
if (entity === undefined) return undefined
|
||||
const ec = EntityContainer.mappings.get(entity.entityNumber)
|
||||
|
||||
const cp = this.bpc.bp.entityPositionGrid.getConnectionPointAtPosition(cursor_position, this.color)
|
||||
|
||||
|
||||
const cp = this.bpc.bp.entityPositionGrid.getConnectionPointAtPosition(
|
||||
cursor_position,
|
||||
this.color
|
||||
)
|
||||
|
||||
let connectionsReach = true
|
||||
if (this.cp && G.BPC.limitWireReach) {
|
||||
connectionsReach &&= U.pointInCircle(
|
||||
@@ -76,9 +79,7 @@ export class PaintWireContainer extends PaintContainer {
|
||||
this.cursorBox = this.bpc.overlayContainer.createCursorBox(
|
||||
ec.position,
|
||||
entity.size,
|
||||
cp === undefined ? 'not_allowed'
|
||||
: (!connectionsReach) ? 'not_allowed'
|
||||
: 'regular'
|
||||
cp === undefined ? 'not_allowed' : !connectionsReach ? 'not_allowed' : 'regular'
|
||||
)
|
||||
if (connectionsReach) return cp
|
||||
}
|
||||
@@ -94,22 +95,22 @@ export class PaintWireContainer extends PaintContainer {
|
||||
// entity?.rotate(ccw, true)
|
||||
|
||||
/** Non-standard behavior: cycle between colors */
|
||||
if (this.name === "red_wire") this.name = "green_wire"
|
||||
else if (this.name === "green_wire") this.name = "red_wire"
|
||||
this.color = this.name.split("_",1)[0]
|
||||
if (this.name === 'red_wire') this.name = 'green_wire'
|
||||
else if (this.name === 'green_wire') this.name = 'red_wire'
|
||||
this.color = this.name.split('_', 1)[0]
|
||||
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
public canFlipOrRotateByCopying(): boolean {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
protected redraw(): void {
|
||||
this.updatecursorBox()
|
||||
this.bpc.wiresContainer.remove('paint-wire')
|
||||
if (this.cp) {
|
||||
const connection : IConnection = {
|
||||
const connection: IConnection = {
|
||||
color: this.color,
|
||||
cps: [this.cp, { position: this.getGridPosition() }],
|
||||
}
|
||||
@@ -131,7 +132,7 @@ export class PaintWireContainer extends PaintContainer {
|
||||
if (this.cp?.entityNumber === undefined) {
|
||||
this.cp = cp
|
||||
} else {
|
||||
const connection : IConnection = {
|
||||
const connection: IConnection = {
|
||||
color: this.color,
|
||||
cps: [this.cp, cp],
|
||||
}
|
||||
@@ -158,7 +159,7 @@ export class PaintWireContainer extends PaintContainer {
|
||||
if (this.cp?.entityNumber === undefined) {
|
||||
this.cp = cp
|
||||
} else {
|
||||
const connection : IConnection = {
|
||||
const connection: IConnection = {
|
||||
color: this.color,
|
||||
cps: [this.cp, cp],
|
||||
}
|
||||
|
@@ -13,7 +13,12 @@ export class WiresContainer extends PIXI.Container {
|
||||
this.bp = bp
|
||||
}
|
||||
|
||||
private static createWire(p1: IPoint, p2: IPoint, color: string, connectionsReach = true): PIXI.Graphics {
|
||||
private static createWire(
|
||||
p1: IPoint,
|
||||
p2: IPoint,
|
||||
color: string,
|
||||
connectionsReach = true
|
||||
): PIXI.Graphics {
|
||||
const wire = new PIXI.Graphics()
|
||||
|
||||
const minX = Math.min(p1.x, p2.x)
|
||||
@@ -32,7 +37,7 @@ export class WiresContainer extends PIXI.Container {
|
||||
wire.lineStyle({
|
||||
width: 1.5,
|
||||
color: colorMap[color],
|
||||
alpha: (connectionsReach ? 1 : 0.3),
|
||||
alpha: connectionsReach ? 1 : 0.3,
|
||||
})
|
||||
wire.moveTo(0, 0)
|
||||
|
||||
@@ -99,7 +104,9 @@ export class WiresContainer extends PIXI.Container {
|
||||
|
||||
for (const conn of connections) {
|
||||
const entNr =
|
||||
entityNumber === conn.cps[0].entityNumber ? conn.cps[1].entityNumber : conn.cps[0].entityNumber
|
||||
entityNumber === conn.cps[0].entityNumber
|
||||
? conn.cps[1].entityNumber
|
||||
: conn.cps[0].entityNumber
|
||||
const ec = EntityContainer.mappings.get(entNr)
|
||||
if (ec.entity.type === 'electric_pole') {
|
||||
ec.redraw()
|
||||
@@ -161,7 +168,10 @@ export class WiresContainer extends PIXI.Container {
|
||||
const connectionsReach = U.pointInCircle(
|
||||
getPos(connection.cps[0]),
|
||||
getPos(connection.cps[1]),
|
||||
Math.min(Infinity, ...connection.cps.map(getMaxWireDistance).filter(d => d !== undefined))
|
||||
Math.min(
|
||||
Infinity,
|
||||
...connection.cps.map(getMaxWireDistance).filter(d => d !== undefined)
|
||||
)
|
||||
)
|
||||
|
||||
return WiresContainer.createWire(
|
||||
|
@@ -476,21 +476,27 @@ class Blueprint extends EventEmitter {
|
||||
.filter(vis => vis.length)
|
||||
.forEach((vis, i) => {
|
||||
vis.forEach((v, j, arr) => {
|
||||
setTimeout(() => {
|
||||
const tint = v.color ? v.color : 0xffffff * Math.random()
|
||||
v.path.forEach((p, k) => {
|
||||
setTimeout(() => {
|
||||
const s = new PIXI.Sprite(PIXI.Texture.WHITE)
|
||||
s.tint = tint
|
||||
s.anchor.set(0.5)
|
||||
s.alpha = v.alpha
|
||||
s.width = v.size
|
||||
s.height = v.size
|
||||
s.position.set(p.x * 32, p.y * 32)
|
||||
G.BPC.wiresContainer.addChild(s)
|
||||
}, k * (timePerVis / arr.length / v.path.length))
|
||||
})
|
||||
}, j * (timePerVis / arr.length) + i * timePerVis)
|
||||
setTimeout(
|
||||
() => {
|
||||
const tint = v.color ? v.color : 0xffffff * Math.random()
|
||||
v.path.forEach((p, k) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
const s = new PIXI.Sprite(PIXI.Texture.WHITE)
|
||||
s.tint = tint
|
||||
s.anchor.set(0.5)
|
||||
s.alpha = v.alpha
|
||||
s.width = v.size
|
||||
s.height = v.size
|
||||
s.position.set(p.x * 32, p.y * 32)
|
||||
G.BPC.wiresContainer.addChild(s)
|
||||
},
|
||||
k * (timePerVis / arr.length / v.path.length)
|
||||
)
|
||||
})
|
||||
},
|
||||
j * (timePerVis / arr.length) + i * timePerVis
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@@ -72,7 +72,7 @@ export class Entity extends EventEmitter {
|
||||
}
|
||||
|
||||
public get rawEntity(): BPS.IEntity {
|
||||
return this.m_rawEntity;
|
||||
return this.m_rawEntity
|
||||
}
|
||||
|
||||
/** Entity size */
|
||||
@@ -93,20 +93,25 @@ export class Entity extends EventEmitter {
|
||||
// Check if the new position breaks any valid entity connections
|
||||
const connectionsBreak = this.m_BP.wireConnections
|
||||
.getEntityConnections(this.entityNumber)
|
||||
.map(c => (c.cps[0].entityNumber === this.entityNumber ? c.cps[1].entityNumber : c.cps[0].entityNumber))
|
||||
.map(c =>
|
||||
c.cps[0].entityNumber === this.entityNumber
|
||||
? c.cps[1].entityNumber
|
||||
: c.cps[0].entityNumber
|
||||
)
|
||||
.map(otherEntityNumer => this.m_BP.entities.get(otherEntityNumer))
|
||||
.some(e =>
|
||||
// Make sure that a reaching connection is not broken
|
||||
U.pointInCircle(
|
||||
e.position,
|
||||
this.position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
) &&
|
||||
!U.pointInCircle(
|
||||
e.position,
|
||||
position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
)
|
||||
.some(
|
||||
e =>
|
||||
// Make sure that a reaching connection is not broken
|
||||
U.pointInCircle(
|
||||
e.position,
|
||||
this.position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
) &&
|
||||
!U.pointInCircle(
|
||||
e.position,
|
||||
position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
)
|
||||
)
|
||||
if (G.BPC.limitWireReach && connectionsBreak) return
|
||||
|
||||
@@ -130,16 +135,20 @@ export class Entity extends EventEmitter {
|
||||
|
||||
public connectionsReach(position?: IPoint): boolean {
|
||||
return this.m_BP.wireConnections
|
||||
.getEntityConnections(this.entityNumber)
|
||||
.map(c => (c.cps[0].entityNumber === this.entityNumber ? c.cps[1].entityNumber : c.cps[0].entityNumber))
|
||||
.map(otherEntityNumer => this.m_BP.entities.get(otherEntityNumer))
|
||||
.every(e =>
|
||||
U.pointInCircle(
|
||||
e.position,
|
||||
position ?? this.position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
.getEntityConnections(this.entityNumber)
|
||||
.map(c =>
|
||||
c.cps[0].entityNumber === this.entityNumber
|
||||
? c.cps[1].entityNumber
|
||||
: c.cps[0].entityNumber
|
||||
)
|
||||
.map(otherEntityNumer => this.m_BP.entities.get(otherEntityNumer))
|
||||
.every(e =>
|
||||
U.pointInCircle(
|
||||
e.position,
|
||||
position ?? this.position,
|
||||
Math.min(e.maxWireDistance, this.maxWireDistance)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
public moveBy(offset: IPoint): void {
|
||||
@@ -580,21 +589,20 @@ export class Entity extends EventEmitter {
|
||||
|
||||
public getRotatedCopy(ccw = false): Entity {
|
||||
const position = ccw
|
||||
? {x: this.m_rawEntity.position.y, y: -this.m_rawEntity.position.x}
|
||||
: {x: -this.m_rawEntity.position.y, y: this.m_rawEntity.position.x}
|
||||
? { x: this.m_rawEntity.position.y, y: -this.m_rawEntity.position.x }
|
||||
: { x: -this.m_rawEntity.position.y, y: this.m_rawEntity.position.x }
|
||||
const direction = this.constrainDirection((this.direction + (ccw ? 6 : 2)) % 8)
|
||||
const updatedRawEntity = {...this.m_rawEntity, position, direction}
|
||||
const updatedRawEntity = { ...this.m_rawEntity, position, direction }
|
||||
if (direction === 0) delete updatedRawEntity.direction
|
||||
|
||||
return new Entity(updatedRawEntity, this.m_BP);
|
||||
return new Entity(updatedRawEntity, this.m_BP)
|
||||
}
|
||||
|
||||
private constrainDirection(direction: number): number {
|
||||
const pr = this.entityData.possible_rotations
|
||||
let canRotate = pr !== undefined
|
||||
|
||||
if (this.type === 'assembling_machine')
|
||||
canRotate = this.assemblerCraftsWithFluid
|
||||
if (this.type === 'assembling_machine') canRotate = this.assemblerCraftsWithFluid
|
||||
if (canRotate) {
|
||||
if (!pr.includes(direction)) {
|
||||
if (direction === 4 && pr.includes(0)) {
|
||||
@@ -612,10 +620,8 @@ export class Entity extends EventEmitter {
|
||||
}
|
||||
|
||||
private changePriority(priority?: 'left' | 'right'): 'left' | 'right' | undefined {
|
||||
if (priority === 'left')
|
||||
return 'right'
|
||||
else if (priority === 'right')
|
||||
return 'left'
|
||||
if (priority === 'left') return 'right'
|
||||
else if (priority === 'right') return 'left'
|
||||
return priority
|
||||
}
|
||||
|
||||
@@ -626,49 +632,65 @@ export class Entity extends EventEmitter {
|
||||
// Straight rail: 1, 2, 7, 0, 5, 2, 3, 0
|
||||
// Vert: 1-3, 2-2, 7-5, 0-0
|
||||
// Horz: 1-7, 3-5
|
||||
const translation_map: {[key: string]: {[vert: string]: number[]}} = {
|
||||
'curved_rail': {true: [5, 4, 3, 2, 1, 0, 7, 6], false: [1, 0, 7, 6, 5, 4, 3, 2] },
|
||||
'straight_rail': {true: [0, 3, 2, 1, 4, 7, 6, 5], false: [0, 7, 2, 5, 4, 3, 6, 1]},
|
||||
'default': {true: [4, 1, 2, 3, 0, 5, 6, 7], false: [0, 1, 6, 3, 4, 5, 2, 7]}
|
||||
const translation_map: { [key: string]: { [vert: string]: number[] } } = {
|
||||
curved_rail: { true: [5, 4, 3, 2, 1, 0, 7, 6], false: [1, 0, 7, 6, 5, 4, 3, 2] },
|
||||
straight_rail: { true: [0, 3, 2, 1, 4, 7, 6, 5], false: [0, 7, 2, 5, 4, 3, 6, 1] },
|
||||
default: { true: [4, 1, 2, 3, 0, 5, 6, 7], false: [0, 1, 6, 3, 4, 5, 2, 7] },
|
||||
}
|
||||
|
||||
const non_flip_entities = ['chemical_plant', 'oil_refinery', 'train_stop', 'rail_chain_signal', 'rail_signal']
|
||||
const non_flip_entities = [
|
||||
'chemical_plant',
|
||||
'oil_refinery',
|
||||
'train_stop',
|
||||
'rail_chain_signal',
|
||||
'rail_signal',
|
||||
]
|
||||
|
||||
if (non_flip_entities.includes(this.name))
|
||||
throw new IllegalFlipError(`${this.name } cannot be flipped`);
|
||||
throw new IllegalFlipError(`${this.name} cannot be flipped`)
|
||||
|
||||
const translation = this.name in translation_map ? translation_map[this.name] : translation_map.default
|
||||
const direction = this.name === 'storage_tank'
|
||||
? (2 - this.direction)
|
||||
: this.constrainDirection(translation[String(vertical)][this.direction])
|
||||
const translation =
|
||||
this.name in translation_map ? translation_map[this.name] : translation_map.default
|
||||
const direction =
|
||||
this.name === 'storage_tank'
|
||||
? 2 - this.direction
|
||||
: this.constrainDirection(translation[String(vertical)][this.direction])
|
||||
|
||||
let input_priority = this.m_rawEntity.input_priority
|
||||
let output_priority = this.m_rawEntity.output_priority
|
||||
|
||||
if ((vertical && (direction === 2 || direction === 4))
|
||||
|| (!vertical && (direction === 0 || direction === 6))) {
|
||||
if (
|
||||
(vertical && (direction === 2 || direction === 4)) ||
|
||||
(!vertical && (direction === 0 || direction === 6))
|
||||
) {
|
||||
input_priority = this.changePriority(input_priority)
|
||||
output_priority = this.changePriority(output_priority)
|
||||
}
|
||||
|
||||
const position = vertical
|
||||
? {x: this.m_rawEntity.position.x, y: -this.m_rawEntity.position.y}
|
||||
: {x: -this.m_rawEntity.position.x, y: this.m_rawEntity.position.y}
|
||||
const updatedRawEntity = {...this.m_rawEntity, direction, position, input_priority, output_priority}
|
||||
if (direction === 0) delete updatedRawEntity.direction
|
||||
? { x: this.m_rawEntity.position.x, y: -this.m_rawEntity.position.y }
|
||||
: { x: -this.m_rawEntity.position.x, y: this.m_rawEntity.position.y }
|
||||
const updatedRawEntity = {
|
||||
...this.m_rawEntity,
|
||||
direction,
|
||||
position,
|
||||
input_priority,
|
||||
output_priority,
|
||||
}
|
||||
if (direction === 0) delete updatedRawEntity.direction
|
||||
|
||||
return new Entity(updatedRawEntity, this.m_BP);
|
||||
return new Entity(updatedRawEntity, this.m_BP)
|
||||
}
|
||||
|
||||
private rotateDir(ccw: boolean): number {
|
||||
if (!this.canBeRotated) return this.direction
|
||||
const pr = this.entityData.possible_rotations
|
||||
return pr[
|
||||
(pr.indexOf(this.direction) +
|
||||
(this.size.x !== this.size.y || this.type === 'underground_belt' ? 2 : 1) *
|
||||
(ccw ? 3 : 1)) %
|
||||
pr.length
|
||||
]
|
||||
(pr.indexOf(this.direction) +
|
||||
(this.size.x !== this.size.y || this.type === 'underground_belt' ? 2 : 1) *
|
||||
(ccw ? 3 : 1)) %
|
||||
pr.length
|
||||
]
|
||||
}
|
||||
|
||||
public rotate(ccw = false, rotateOpposingUB = false): void {
|
||||
@@ -895,23 +917,26 @@ export class Entity extends EventEmitter {
|
||||
): number[][] {
|
||||
const e = this.entityData
|
||||
const size_box = [
|
||||
[-e.size.width/2, -e.size.height/2],
|
||||
[+e.size.width/2, +e.size.height/2],
|
||||
[-e.size.width / 2, -e.size.height / 2],
|
||||
[+e.size.width / 2, +e.size.height / 2],
|
||||
]
|
||||
// use size_box for cell-wise selection, use e.selection_box for "true" selection
|
||||
if (side===1 && e.connection_points?.[direction/2].wire[color]) return size_box
|
||||
if (side===1 && e.circuit_wire_connection_point?.wire[color]) return size_box
|
||||
if (side===1 && e.circuit_wire_connection_points?.[direction/2].wire[color]) return size_box
|
||||
if (side===1 && e.input_connection_points?.[direction/2].wire[color]) return e.input_connection_bounding_box
|
||||
if (side===2 && e.output_connection_points?.[direction/2].wire[color]) return e.output_connection_bounding_box
|
||||
if (side===1 && e.left_wire_connection_point?.wire[color]) {
|
||||
if (side === 1 && e.connection_points?.[direction / 2].wire[color]) return size_box
|
||||
if (side === 1 && e.circuit_wire_connection_point?.wire[color]) return size_box
|
||||
if (side === 1 && e.circuit_wire_connection_points?.[direction / 2].wire[color])
|
||||
return size_box
|
||||
if (side === 1 && e.input_connection_points?.[direction / 2].wire[color])
|
||||
return e.input_connection_bounding_box
|
||||
if (side === 2 && e.output_connection_points?.[direction / 2].wire[color])
|
||||
return e.output_connection_bounding_box
|
||||
if (side === 1 && e.left_wire_connection_point?.wire[color]) {
|
||||
const box = util.duplicate(size_box)
|
||||
box[1][0] = (box[0][0]+box[1][0])/2
|
||||
box[1][0] = (box[0][0] + box[1][0]) / 2
|
||||
return box
|
||||
}
|
||||
if (side===2 && e.right_wire_connection_point?.wire[color]) {
|
||||
if (side === 2 && e.right_wire_connection_point?.wire[color]) {
|
||||
const box = util.duplicate(size_box)
|
||||
box[0][0] = (box[0][0]+box[1][0])/2
|
||||
box[0][0] = (box[0][0] + box[1][0]) / 2
|
||||
return box
|
||||
}
|
||||
}
|
||||
@@ -923,11 +948,11 @@ export class Entity extends EventEmitter {
|
||||
): IPoint[] {
|
||||
const box = this.getWire_connection_box(color, side, direction)
|
||||
if (box === undefined) return undefined
|
||||
let bbox : IPoint[] = box.map(util.Point)
|
||||
let bbox: IPoint[] = box.map(util.Point)
|
||||
bbox = bbox.map(p => util.rotatePointBasedOnDir(p, direction))
|
||||
bbox = [
|
||||
{x: Math.min(...bbox.map(p => p.x)), y: Math.min(...bbox.map(p => p.y))},
|
||||
{x: Math.max(...bbox.map(p => p.x)), y: Math.max(...bbox.map(p => p.y))},
|
||||
{ x: Math.min(...bbox.map(p => p.x)), y: Math.min(...bbox.map(p => p.y)) },
|
||||
{ x: Math.max(...bbox.map(p => p.x)), y: Math.max(...bbox.map(p => p.y)) },
|
||||
]
|
||||
return bbox
|
||||
}
|
||||
|
@@ -71,11 +71,11 @@ export class PositionGrid {
|
||||
public getConnectionPointAtPosition(position: IPoint, color: string): IConnectionPoint {
|
||||
const entity = this.getEntityAtPosition(position)
|
||||
if (entity === undefined) return undefined
|
||||
const rel_position = util.sumprod(position, -1,entity.position)
|
||||
const rel_position = util.sumprod(position, -1, entity.position)
|
||||
for (let side = 1; side <= 10; side++) {
|
||||
const bbox = entity.getWireConnectionBoundingBox(color, side)
|
||||
if (bbox === undefined) break // no more sides expected for that color
|
||||
const rel_bbox = bbox.map(b => util.sumprod(rel_position, -1,b))
|
||||
if (bbox === undefined) break // no more sides expected for that color
|
||||
const rel_bbox = bbox.map(b => util.sumprod(rel_position, -1, b))
|
||||
if (Object.values(rel_bbox[0]).some(v => v < 0)) continue
|
||||
if (Object.values(rel_bbox[1]).some(v => v > 0)) continue
|
||||
return {
|
||||
|
@@ -27,7 +27,9 @@ export class WireConnections extends EventEmitter {
|
||||
}
|
||||
|
||||
private static hash(conn: IConnection): string {
|
||||
const cps = conn.cps.sort((cp1,cp2) => cp1.entityNumber-cp2.entityNumber || cp1.entitySide-cp2.entitySide)
|
||||
const cps = conn.cps.sort(
|
||||
(cp1, cp2) => cp1.entityNumber - cp2.entityNumber || cp1.entitySide - cp2.entitySide
|
||||
)
|
||||
const [firstE, secondE] = cps.map(cp => cp.entityNumber)
|
||||
const [firstS, secondS] = cps.map(cp => cp.entitySide)
|
||||
return `${conn.color}-${firstE}-${secondE}-${firstS}-${secondS}`
|
||||
@@ -51,13 +53,13 @@ export class WireConnections extends EventEmitter {
|
||||
cps: [
|
||||
{
|
||||
entityNumber: entityNumber,
|
||||
entitySide: Number(side)
|
||||
entitySide: Number(side),
|
||||
},
|
||||
{
|
||||
entityNumber: data.entity_id,
|
||||
entitySide: data.circuit_id || 1
|
||||
}
|
||||
]
|
||||
entitySide: data.circuit_id || 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -73,13 +75,13 @@ export class WireConnections extends EventEmitter {
|
||||
cps: [
|
||||
{
|
||||
entityNumber: entityNumber,
|
||||
entitySide: Number(side.slice(2, 3)) + 1
|
||||
entitySide: Number(side.slice(2, 3)) + 1,
|
||||
},
|
||||
{
|
||||
entityNumber: data.entity_id,
|
||||
entitySide: 1
|
||||
}
|
||||
]
|
||||
entitySide: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -159,13 +161,13 @@ export class WireConnections extends EventEmitter {
|
||||
cps: [
|
||||
{
|
||||
entityNumber: entityNumber1,
|
||||
entitySide: 1
|
||||
entitySide: 1,
|
||||
},
|
||||
{
|
||||
entityNumber: entityNumber2,
|
||||
entitySide: 1
|
||||
}
|
||||
]
|
||||
entitySide: 1,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +386,9 @@ export class WireConnections extends EventEmitter {
|
||||
|
||||
public getPowerPoleDirection(entityNumber: number): number {
|
||||
const connections = this.getEntityConnections(entityNumber).map(conn =>
|
||||
entityNumber === conn.cps[0].entityNumber ? conn.cps[1].entityNumber : conn.cps[0].entityNumber
|
||||
entityNumber === conn.cps[0].entityNumber
|
||||
? conn.cps[1].entityNumber
|
||||
: conn.cps[0].entityNumber
|
||||
)
|
||||
if (connections.length === 0) return 0
|
||||
|
||||
|
@@ -126,8 +126,8 @@ function decode(str: string): Promise<Blueprint | Book> {
|
||||
throw hasTrain()
|
||||
? new TrainBlueprintError(errors)
|
||||
: isModded()
|
||||
? new ModdedBlueprintError(errors)
|
||||
: errors
|
||||
? new ModdedBlueprintError(errors)
|
||||
: errors
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -1077,7 +1077,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
h: size.y,
|
||||
})
|
||||
.filter(e => e.name === 'gate')
|
||||
.map(e => util.sumprod(e.position, -1,data.position))
|
||||
.map(e => util.sumprod(e.position, -1, data.position))
|
||||
// Rotate relative to mid point
|
||||
.map(p => util.rotatePointBasedOnDir(p, dir).y)
|
||||
// Remove duplicates
|
||||
@@ -1306,7 +1306,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
if (data.dir === 0 && data.positionGrid) {
|
||||
const wall = data.positionGrid.getEntityAtPosition({
|
||||
x: data.position.x,
|
||||
y: data.position.y + 1
|
||||
y: data.position.y + 1,
|
||||
})
|
||||
if (wall && wall.name === 'stone_wall') {
|
||||
return [...getBaseSprites(), e.wall_patch.layers[0]]
|
||||
@@ -1459,9 +1459,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
|
||||
const belt0Parts = getBeltSprites(
|
||||
e.belt_animation_set,
|
||||
data.positionGrid
|
||||
? util.sumprod(data.position, b0Offset)
|
||||
: b0Offset,
|
||||
data.positionGrid ? util.sumprod(data.position, b0Offset) : b0Offset,
|
||||
data.dir,
|
||||
data.positionGrid,
|
||||
true,
|
||||
@@ -1471,9 +1469,7 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
|
||||
const belt1Parts = getBeltSprites(
|
||||
e.belt_animation_set,
|
||||
data.positionGrid
|
||||
? util.sumprod(data.position, b1Offset)
|
||||
: b1Offset,
|
||||
data.positionGrid ? util.sumprod(data.position, b1Offset) : b1Offset,
|
||||
data.dir,
|
||||
data.positionGrid,
|
||||
true,
|
||||
@@ -1573,8 +1569,8 @@ function generateGraphics(e: FD_Entity): (data: IDrawData) => SpriteData[] {
|
||||
? structure.direction_in_side_loading.sheet
|
||||
: structure.direction_out_side_loading.sheet
|
||||
: isInput
|
||||
? structure.direction_in.sheet
|
||||
: structure.direction_out.sheet,
|
||||
? structure.direction_in.sheet
|
||||
: structure.direction_out.sheet,
|
||||
'x',
|
||||
'width',
|
||||
dir / 2
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
@@ -91,7 +91,7 @@ for (const p of params) {
|
||||
let changeBookForIndexSelector: (bpOrBook: Book | Blueprint) => void
|
||||
|
||||
editor
|
||||
.init(CANVAS, (text: string) => createToast({text, type: 'error', timeout: 3000}))
|
||||
.init(CANVAS, (text: string) => createToast({ text, type: 'error', timeout: 3000 }))
|
||||
.then(() => {
|
||||
if (localStorage.getItem('quickbarItemNames')) {
|
||||
const quickbarItems = JSON.parse(localStorage.getItem('quickbarItemNames'))
|
||||
@@ -195,13 +195,14 @@ function registerActions(): void {
|
||||
|
||||
EDITOR.registerAction('appendBlueprint', 'shift+modifier+v').bind({
|
||||
press: () => {
|
||||
navigator.clipboard.readText()
|
||||
navigator.clipboard
|
||||
.readText()
|
||||
.then(getBlueprintOrBookFromSource)
|
||||
.then(bp => editor.appendBlueprint(bp instanceof Book ? bp.selectBlueprint(0) : bp))
|
||||
.catch(error => {
|
||||
createBPImportError(error)
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
EDITOR.registerAction('generateOilOutpost', 'g').bind({
|
||||
|
@@ -96,7 +96,7 @@ export function initSettingsPane(
|
||||
}
|
||||
editor.debug = debug
|
||||
})
|
||||
|
||||
|
||||
if (localStorage.getItem('limitWireReach')) {
|
||||
const limitWireReach = localStorage.getItem('limitWireReach') === 'true'
|
||||
editor.limitWireReach = limitWireReach
|
||||
|
Reference in New Issue
Block a user