mirror of
https://github.com/teoxoy/factorio-blueprint-editor.git
synced 2025-03-27 21:39:03 +02:00
support books containing upgrade and deconstruction planners
This commit is contained in:
parent
d26c2dbb87
commit
a6cb87c489
@ -1,17 +1,9 @@
|
||||
import { Blueprint, getFactorioVersion } from './Blueprint'
|
||||
|
||||
interface IBP {
|
||||
blueprint?: BPS.IBlueprint
|
||||
blueprint_book?: BPS.IBlueprintBook
|
||||
}
|
||||
|
||||
class Book {
|
||||
private _active: Blueprint
|
||||
private _activeIndex: number
|
||||
private readonly blueprints: {
|
||||
blueprint?: BPS.IBlueprint
|
||||
blueprint_book?: BPS.IBlueprintBook
|
||||
}[]
|
||||
private readonly blueprints: BPS.IBlueprintBookEntry[]
|
||||
|
||||
private readonly label?: string
|
||||
private readonly description?: string
|
||||
@ -20,7 +12,7 @@ class Book {
|
||||
public constructor(data: BPS.IBlueprintBook) {
|
||||
if (data) {
|
||||
this._activeIndex = getFlattenedActiveIndex(data.blueprints, data.active_index)
|
||||
this.blueprints = data.blueprints
|
||||
this.blueprints = data.blueprints || []
|
||||
this.label = data.label
|
||||
this.description = data.description
|
||||
this.icons = data.icons
|
||||
@ -78,36 +70,72 @@ class Book {
|
||||
}
|
||||
}
|
||||
|
||||
function countNestedBlueprints(bps: IBP[]): number {
|
||||
return bps.reduce(
|
||||
(count, { blueprint_book }) =>
|
||||
count + (blueprint_book ? countNestedBlueprints(blueprint_book.blueprints) : 1),
|
||||
0
|
||||
)
|
||||
function countNestedBlueprints(
|
||||
bps: BPS.IBlueprintBookEntry[] = [],
|
||||
includePlanners = false
|
||||
): number {
|
||||
return bps.reduce((count, { blueprint, blueprint_book }) => {
|
||||
if (blueprint_book) {
|
||||
return count + countNestedBlueprints(blueprint_book.blueprints, includePlanners)
|
||||
} else if (blueprint || includePlanners) {
|
||||
return count + 1
|
||||
} else {
|
||||
return count
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function getFlattenedActiveIndex(bps: IBP[], active_index: number): number {
|
||||
return bps.reduce((aI, { blueprint_book }, i) => {
|
||||
if (blueprint_book && i < active_index) {
|
||||
return aI + countNestedBlueprints(blueprint_book.blueprints) - 1
|
||||
function getFlattenedActiveIndex(
|
||||
bps: BPS.IBlueprintBookEntry[] = [],
|
||||
active_index: number
|
||||
): number {
|
||||
{
|
||||
const { upgrade_planner, deconstruction_planner, blueprint_book } = bps[active_index]
|
||||
|
||||
if (
|
||||
upgrade_planner ||
|
||||
deconstruction_planner ||
|
||||
(blueprint_book && countNestedBlueprints(blueprint_book.blueprints) === 0)
|
||||
) {
|
||||
return 0
|
||||
}
|
||||
if (blueprint_book && i === active_index) {
|
||||
return (
|
||||
aI + getFlattenedActiveIndex(blueprint_book.blueprints, blueprint_book.active_index)
|
||||
)
|
||||
}
|
||||
|
||||
let res = active_index
|
||||
|
||||
for (let i = 0; i < active_index; i++) {
|
||||
const { upgrade_planner, deconstruction_planner, blueprint_book } = bps[i]
|
||||
|
||||
if (blueprint_book) {
|
||||
res += countNestedBlueprints(blueprint_book.blueprints) - 1
|
||||
} else if (upgrade_planner || deconstruction_planner) {
|
||||
res -= 1
|
||||
}
|
||||
return aI
|
||||
}, active_index)
|
||||
}
|
||||
|
||||
const { blueprint_book } = bps[active_index]
|
||||
|
||||
if (blueprint_book) {
|
||||
res += getFlattenedActiveIndex(blueprint_book.blueprints, blueprint_book.active_index)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
function getBlueprintAtFlattenedActiveIndex(bps: IBP[], index: number): BPS.IBlueprint {
|
||||
const search = (bps: IBP[], index: number): number | BPS.IBlueprint => {
|
||||
function getBlueprintAtFlattenedActiveIndex(
|
||||
bps: BPS.IBlueprintBookEntry[],
|
||||
index: number
|
||||
): BPS.IBlueprint {
|
||||
const search = (
|
||||
bps: BPS.IBlueprintBookEntry[] = [],
|
||||
index: number
|
||||
): number | BPS.IBlueprint => {
|
||||
let i = index
|
||||
for (const { blueprint, blueprint_book } of bps) {
|
||||
if (blueprint) {
|
||||
if (i === 0) return blueprint
|
||||
i -= 1
|
||||
} else {
|
||||
} else if (blueprint_book) {
|
||||
const ret = search(blueprint_book.blueprints, i)
|
||||
if (typeof ret === 'number') {
|
||||
i = ret
|
||||
@ -123,7 +151,11 @@ function getBlueprintAtFlattenedActiveIndex(bps: IBP[], index: number): BPS.IBlu
|
||||
return typeof ret === 'number' ? undefined : ret
|
||||
}
|
||||
|
||||
function saveBlueprint(bps: IBP[], index: number, bp: BPS.IBlueprint): [number, number] {
|
||||
function saveBlueprint(
|
||||
bps: BPS.IBlueprintBookEntry[] = [],
|
||||
index: number,
|
||||
bp: BPS.IBlueprint
|
||||
): [number, number] {
|
||||
let i = index
|
||||
for (let j = 0; j < bps.length; j++) {
|
||||
const { blueprint, blueprint_book } = bps[j]
|
||||
@ -133,7 +165,7 @@ function saveBlueprint(bps: IBP[], index: number, bp: BPS.IBlueprint): [number,
|
||||
return [undefined, j]
|
||||
}
|
||||
i -= 1
|
||||
} else {
|
||||
} else if (blueprint_book) {
|
||||
const [newI, activeIndex] = saveBlueprint(blueprint_book.blueprints, i, bp)
|
||||
if (newI === undefined) {
|
||||
blueprint_book.active_index = activeIndex
|
||||
|
@ -664,7 +664,7 @@
|
||||
},
|
||||
"blueprint_book": {
|
||||
"type": "object",
|
||||
"required": ["version", "item", "active_index", "blueprints"],
|
||||
"required": ["version", "item", "active_index"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"version": { "type": "integer" },
|
||||
@ -691,11 +691,23 @@
|
||||
},
|
||||
"blueprint_book": {
|
||||
"$ref": "blueprintSchema.json#/definitions/blueprint_book"
|
||||
},
|
||||
"upgrade_planner": {
|
||||
"$ref": "blueprintSchema.json#/definitions/upgrade_planner"
|
||||
},
|
||||
"deconstruction_planner": {
|
||||
"$ref": "blueprintSchema.json#/definitions/deconstruction_planner"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"upgrade_planner": {
|
||||
"type": "object"
|
||||
},
|
||||
"deconstruction_planner": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,10 @@ class CorruptedBlueprintStringError {
|
||||
}
|
||||
}
|
||||
|
||||
class BookWithNoBlueprintsError {
|
||||
public error = 'Blueprint book contains no blueprints!'
|
||||
}
|
||||
|
||||
class ModdedBlueprintError {
|
||||
public errors: Ajv.ErrorObject[]
|
||||
public constructor(errors: Ajv.ErrorObject[]) {
|
||||
@ -97,9 +101,23 @@ function decode(str: string): Promise<Blueprint | Book> {
|
||||
}).then((data: { blueprint?: BPS.IBlueprint; blueprint_book?: BPS.IBlueprintBook }) => {
|
||||
console.log(data)
|
||||
if (validate(data)) {
|
||||
return data.blueprint_book === undefined
|
||||
? new Blueprint(data.blueprint)
|
||||
: new Book(data.blueprint_book)
|
||||
if (data.blueprint_book === undefined) {
|
||||
return new Blueprint(data.blueprint)
|
||||
} else {
|
||||
const hasBlueprint = (entries: BPS.IBlueprintBookEntry[] = []): boolean => {
|
||||
for (const entry of entries) {
|
||||
if (entry.blueprint) return true
|
||||
if (entry.blueprint_book && hasBlueprint(entry.blueprint_book.blueprints))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if (hasBlueprint(data.blueprint_book.blueprints)) {
|
||||
return new Book(data.blueprint_book)
|
||||
} else {
|
||||
throw new BookWithNoBlueprintsError()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const errors = validate.errors
|
||||
const trainEntityNames = new Set(['locomotive', 'cargo_wagon', 'fluid_wagon'])
|
||||
@ -198,6 +216,7 @@ export {
|
||||
ModdedBlueprintError,
|
||||
TrainBlueprintError,
|
||||
CorruptedBlueprintStringError,
|
||||
BookWithNoBlueprintsError,
|
||||
encode,
|
||||
getBlueprintOrBookFromSource,
|
||||
}
|
||||
|
14
packages/editor/src/global.d.ts
vendored
14
packages/editor/src/global.d.ts
vendored
@ -338,15 +338,19 @@ declare namespace BPS {
|
||||
position_relative_to_grid?: IPoint
|
||||
}
|
||||
|
||||
interface IBlueprintBookEntry {
|
||||
index: number
|
||||
blueprint?: IBlueprint
|
||||
blueprint_book?: IBlueprintBook
|
||||
upgrade_planner?: Record<string, unknown>
|
||||
deconstruction_planner?: Record<string, unknown>
|
||||
}
|
||||
|
||||
interface IBlueprintBook {
|
||||
version: number
|
||||
item: 'blueprint_book'
|
||||
active_index: number
|
||||
blueprints: {
|
||||
index: number
|
||||
blueprint?: IBlueprint
|
||||
blueprint_book?: IBlueprintBook
|
||||
}[]
|
||||
blueprints?: IBlueprintBookEntry[]
|
||||
|
||||
label?: string
|
||||
description?: string
|
||||
|
@ -9,6 +9,7 @@ import EDITOR, {
|
||||
TrainBlueprintError,
|
||||
ModdedBlueprintError,
|
||||
CorruptedBlueprintStringError,
|
||||
BookWithNoBlueprintsError,
|
||||
encode,
|
||||
getBlueprintOrBookFromSource,
|
||||
} from '@fbe/editor'
|
||||
@ -267,7 +268,12 @@ function createErrorMessage(text: string, error: unknown, timeout = 10000): void
|
||||
})
|
||||
}
|
||||
function createBPImportError(
|
||||
error: Error | TrainBlueprintError | ModdedBlueprintError | CorruptedBlueprintStringError
|
||||
error:
|
||||
| Error
|
||||
| TrainBlueprintError
|
||||
| ModdedBlueprintError
|
||||
| CorruptedBlueprintStringError
|
||||
| BookWithNoBlueprintsError
|
||||
): void {
|
||||
if (error instanceof TrainBlueprintError) {
|
||||
createErrorMessage(
|
||||
@ -293,5 +299,10 @@ function createBPImportError(
|
||||
return
|
||||
}
|
||||
|
||||
if (error instanceof BookWithNoBlueprintsError) {
|
||||
createErrorMessage(`${error.error} If you think this is a mistake:`, error.error)
|
||||
return
|
||||
}
|
||||
|
||||
createErrorMessage('Blueprint string could not be loaded.', error)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user