1
0
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:
teoxoy 2021-09-28 16:12:25 +02:00
parent d26c2dbb87
commit a6cb87c489
5 changed files with 119 additions and 41 deletions

View File

@ -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

View File

@ -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"
}
}
}

View File

@ -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,
}

View File

@ -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

View File

@ -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)
}