1
0
mirror of https://github.com/barthuijgen/factorio-sites.git synced 2025-03-26 22:20:08 +02:00

Merge pull request #5 from barthuijgen/dev

Merge dev to master
This commit is contained in:
Bart 2021-03-10 22:55:09 +01:00 committed by GitHub
commit c4851e9b49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
122 changed files with 3703 additions and 406 deletions

View File

1
.gitignore vendored
View File

@ -45,4 +45,3 @@ Thumbs.db
.local.env
.env
local.readme.md
.yalc

View File

@ -0,0 +1,4 @@
*.md
tsconfig.json
/src
rollup.config.js

21
.yalc/@fbe/editor/dist/Editor.d.ts vendored Normal file
View File

@ -0,0 +1,21 @@
import { Blueprint, IOilOutpostSettings } from './core/Blueprint';
import { GridPattern } from './containers/BlueprintContainer';
export declare class Editor {
init(canvas: HTMLCanvasElement): Promise<void>;
setRendererSize(width: number, height: number): void;
get moveSpeed(): number;
set moveSpeed(speed: number);
get gridColor(): number;
set gridColor(color: number);
get gridPattern(): GridPattern;
set gridPattern(pattern: GridPattern);
get quickbarItems(): string[];
set quickbarItems(items: string[]);
get oilOutpostSettings(): IOilOutpostSettings;
set oilOutpostSettings(settings: IOilOutpostSettings);
get debug(): boolean;
set debug(debug: boolean);
getPicture(): Promise<Blob>;
loadBlueprint(bp: Blueprint): Promise<void>;
private registerActions;
}

View File

@ -0,0 +1,6 @@
import * as PIXI from 'pixi.js';
export declare class DebugContainer extends PIXI.Container {
x: number;
y: number;
constructor();
}

View File

@ -0,0 +1,13 @@
import { Entity } from '../core/Entity';
import { Panel } from './controls/Panel';
export declare class EntityInfoPanel extends Panel {
private title;
private m_EntityName;
private m_entityInfo;
private m_RecipeContainer;
private m_RecipeIOContainer;
constructor();
updateVisualization(entity?: Entity): void;
protected setPosition(): void;
private findNearbyBeacons;
}

View File

@ -0,0 +1,11 @@
import { Dialog } from './controls/Dialog';
export declare class InventoryDialog extends Dialog {
private readonly m_InventoryGroups;
private readonly m_InventoryItems;
private readonly m_RecipeLabel;
private readonly m_RecipeContainer;
private m_hoveredItem;
constructor(title?: string, itemsFilter?: string[], selectedCallBack?: (selectedItem: string) => void);
protected setPosition(): void;
private updateRecipeVisualization;
}

View File

@ -0,0 +1,15 @@
import { Panel } from './controls/Panel';
export declare class QuickbarPanel extends Panel {
private iWidth;
private iHeight;
private rows;
private slots;
private slotsContainer;
constructor(rows?: number, itemNames?: string[]);
private static createTriangleButton;
generateSlots(itemNames?: string[]): void;
bindKeyToSlot(slot: number): void;
changeActiveQuickbar(): void;
serialize(): string[];
protected setPosition(): void;
}

View File

@ -0,0 +1,16 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../core/Entity';
import { QuickbarPanel } from './QuickbarPanel';
export declare class UIContainer extends PIXI.Container {
private debugContainer;
quickbarPanel: QuickbarPanel;
private entityInfoPanel;
private dialogsContainer;
private paintIconContainer;
constructor();
updateEntityInfoPanel(entity: Entity): void;
addPaintIcon(icon: PIXI.DisplayObject): void;
set showDebuggingLayer(visible: boolean);
createEditor(entity: Entity): void;
createInventory(title?: string, itemsFilter?: string[], selectedCallBack?: (selectedItem: string) => void): void;
}

View File

@ -0,0 +1,18 @@
import * as PIXI from 'pixi.js';
export declare class Button extends PIXI.Container {
private readonly m_Background;
private readonly m_Active;
private readonly m_Hover;
private m_Content;
private m_Data;
constructor(width?: number, height?: number, border?: number);
get active(): boolean;
set active(active: boolean);
get content(): PIXI.DisplayObject;
set content(content: PIXI.DisplayObject);
get data(): unknown;
set data(value: unknown);
protected get background(): number;
protected get hover(): number;
protected get pressed(): boolean;
}

View File

@ -0,0 +1,11 @@
import * as PIXI from 'pixi.js';
export declare class Checkbox extends PIXI.Container {
private static readonly CHECK_POLYGON;
private m_Checkbox;
private m_Hover;
private m_Checked;
constructor(checked?: boolean, text?: string);
private static drawGraphic;
get checked(): boolean;
set checked(checked: boolean);
}

View File

@ -0,0 +1,15 @@
import * as PIXI from 'pixi.js';
import { Panel } from './Panel';
export declare abstract class Dialog extends Panel {
protected static s_openDialogs: Dialog[];
constructor(width: number, height: number, title?: string);
static closeLast(): void;
static closeAll(): void;
static anyOpen(): boolean;
static isOpen<T extends Dialog>(dialog: T): boolean;
protected static capitalize(text: string): string;
protected setPosition(): void;
close(): void;
protected addLabel(x?: number, y?: number, text?: string, style?: PIXI.TextStyle): PIXI.Text;
protected addLine(x: number, y: number, width: number, height: number, border?: number): PIXI.Graphics;
}

View File

@ -0,0 +1,10 @@
import * as PIXI from 'pixi.js';
export declare class Enable extends PIXI.Container {
private readonly m_TextText;
private readonly m_HoverText;
private readonly m_ActiveText;
private m_Active;
constructor(active: boolean, text: string);
get active(): boolean;
set active(value: boolean);
}

View File

@ -0,0 +1,10 @@
import * as PIXI from 'pixi.js';
export declare abstract class Panel extends PIXI.Container {
private readonly m_Background;
private _setPosition;
constructor(width: number, height: number, background?: number, alpha?: number, border?: number);
destroy(): void;
get width(): number;
get height(): number;
protected abstract setPosition(): void;
}

View File

@ -0,0 +1,18 @@
import * as PIXI from 'pixi.js';
export declare class Slider extends PIXI.Container {
private static readonly SLIDER_WIDTH;
private static readonly SLIDER_HEIGHT;
private readonly m_SliderButton;
private readonly m_SliderValue;
private m_Dragging;
private m_Dragpoint;
private p_Value;
constructor(value?: number);
get value(): number;
set value(value: number);
private updateButtonPosition;
private updateSliderValue;
private readonly onButtonDragStart;
private readonly onButtonDragMove;
private readonly onButtonDragEnd;
}

View File

@ -0,0 +1,6 @@
import { Button } from './Button';
export declare class Slot extends Button {
get hover(): number;
get pressed(): boolean;
constructor(width?: number, height?: number, border?: number);
}

View File

@ -0,0 +1,10 @@
import * as PIXI from 'pixi.js';
export declare class Switch extends PIXI.Container {
private readonly m_Button;
private readonly m_Values;
private m_Value;
constructor(values: string[], value?: string);
get value(): string;
set value(value: string);
private updateButtonPosition;
}

View File

@ -0,0 +1,20 @@
import * as PIXI from 'pixi.js';
export declare class Textbox extends PIXI.Container {
private readonly m_Background;
private readonly m_Active;
private readonly m_Text;
private readonly m_Length;
private readonly m_Filter;
private readonly m_CaretGraphic;
private p_CaretPosition;
private m_MouseInside;
constructor(width: number, text?: string, length?: number, filter?: string);
get text(): string;
set text(text: string);
private get caretPosition();
private set caretPosition(value);
private instertCharacter;
private removeCharacter;
private readonly onPointerUp;
private readonly keyPressedCallback;
}

View File

@ -0,0 +1,19 @@
import * as PIXI from 'pixi.js';
import { IngredientOrResult, ColorWithAlpha } from '../../core/factorioData';
declare function ShadeColor(color: number, percent: number): number;
declare function DrawRectangle(width: number, height: number, background: number, alpha?: number, border?: number, pressed?: boolean): PIXI.Graphics;
declare function DrawControlFace(w: number, h: number, f: number, c: number, a: number, p0: number, p1: number, p2: number, p3: number): PIXI.Graphics;
declare function CreateIcon(itemName: string, maxSize?: number, setAnchor?: boolean, darkBackground?: boolean): PIXI.DisplayObject;
declare function CreateIconWithAmount(host: PIXI.Container, x: number, y: number, name: string, amount: number): void;
declare function CreateRecipe(host: PIXI.Container, x: number, y: number, ingredients: IngredientOrResult[], results: IngredientOrResult[], time: number): void;
declare function applyTint(s: PIXI.Sprite, tint: ColorWithAlpha): void;
declare const _default: {
ShadeColor: typeof ShadeColor;
DrawRectangle: typeof DrawRectangle;
DrawControlFace: typeof DrawControlFace;
CreateIcon: typeof CreateIcon;
CreateIconWithAmount: typeof CreateIconWithAmount;
CreateRecipe: typeof CreateRecipe;
applyTint: typeof applyTint;
};
export default _default;

View File

@ -0,0 +1,5 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class BeaconEditor extends Editor {
constructor(entity: Entity);
}

View File

@ -0,0 +1,7 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class ChestEditor extends Editor {
private readonly m_Amount;
private m_Filter;
constructor(entity: Entity);
}

View File

@ -0,0 +1,16 @@
import { Entity } from '../../core/Entity';
import { Dialog } from '../controls/Dialog';
import { Preview } from './components/Preview';
import { Recipe } from './components/Recipe';
import { Modules } from './components/Modules';
import { Filters } from './components/Filters';
export declare abstract class Editor extends Dialog {
protected readonly m_Entity: Entity;
protected readonly m_Preview: Preview;
constructor(width: number, height: number, entity: Entity);
protected addRecipe(x?: number, y?: number): Recipe;
protected addModules(x?: number, y?: number): Modules;
protected addFilters(x?: number, y?: number, amount?: boolean): Filters;
protected onEntityChange(event: string, fn: (...args: any[]) => void): void;
destroy(): void;
}

View File

@ -0,0 +1,5 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class InserterEditor extends Editor {
constructor(entity: Entity);
}

View File

@ -0,0 +1,5 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class MachineEditor extends Editor {
constructor(entity: Entity);
}

View File

@ -0,0 +1,5 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class MiningEditor extends Editor {
constructor(entity: Entity);
}

View File

@ -0,0 +1,5 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class SplitterEditor extends Editor {
constructor(entity: Entity);
}

View File

@ -0,0 +1,5 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare class TempEditor extends Editor {
constructor(entity: Entity);
}

View File

@ -0,0 +1,15 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../../../core/Entity';
export declare class Filters extends PIXI.Container {
private readonly m_Entity;
private readonly m_Amount;
private m_Filters;
constructor(entity: Entity, amount?: boolean);
private onEntityChange;
destroy(opts?: boolean | PIXI.IDestroyOptions): void;
updateFilter(index: number, count: number): void;
getFilterCount(index: number): number;
private m_UpdateFilters;
private m_UpdateSlots;
private readonly onSlotPointerDown;
}

View File

@ -0,0 +1,11 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../../../core/Entity';
export declare class Modules extends PIXI.Container {
private readonly m_Entity;
private readonly m_Modules;
constructor(entity: Entity);
private onEntityChange;
destroy(opts?: boolean | PIXI.IDestroyOptions): void;
private updateContent;
private onSlotPointerDown;
}

View File

@ -0,0 +1,12 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../../../core/Entity';
export declare class Preview extends PIXI.Container {
private readonly m_Entity;
private readonly m_Size;
private m_Preview;
constructor(entity: Entity, size: number);
private onEntityChange;
destroy(opts?: boolean | PIXI.IDestroyOptions): void;
private generatePreview;
private readonly onEntityChanged;
}

View File

@ -0,0 +1,11 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../../../core/Entity';
import { Slot } from '../../controls/Slot';
export declare class Recipe extends Slot {
private readonly m_Entity;
constructor(entity: Entity);
private onEntityChange;
destroy(opts?: boolean | PIXI.IDestroyOptions): void;
private updateContent;
private onSlotPointerDown;
}

View File

@ -0,0 +1,3 @@
import { Entity } from '../../core/Entity';
import { Editor } from './Editor';
export declare function createEditor(entity: Entity): Editor;

183
.yalc/@fbe/editor/dist/UI/style.d.ts vendored Normal file
View File

@ -0,0 +1,183 @@
import { TextStyle } from 'pixi.js';
declare const colors: {
text: {
title: number;
normal: number;
link: number;
accent: number;
};
controls: {
button: {
border: number;
background: {
color: number;
alpha: number;
};
hover: {
color: number;
alpha: number;
};
active: {
color: number;
alpha: number;
};
};
checkbox: {
foreground: {
color: number;
};
background: {
color: number;
alpha: number;
};
checkmark: {
color: number;
alpha: number;
};
hover: {
color: number;
alpha: number;
};
};
enable: {
text: {
color: number;
};
hover: {
color: number;
};
active: {
color: number;
};
};
panel: {
background: {
color: number;
alpha: number;
border: number;
};
};
slider: {
slidebar: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
button: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
hover: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
value: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
};
slot: {
hover: {
color: number;
};
};
switch: {
background: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
hover: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
line: {
color: number;
p0: number;
p1: number;
p2: number;
p3: number;
};
};
textbox: {
foreground: {
color: number;
};
background: {
color: number;
alpha: number;
};
active: {
color: number;
alpha: number;
};
};
};
dialog: {
background: {
color: number;
alpha: number;
border: number;
};
line: {
background: {
color: number;
alpha: number;
border: number;
};
};
};
editor: {
sprite: {
background: {
color: number;
alpha: number;
};
};
};
quickbar: {
background: {
color: number;
alpha: number;
border: number;
};
};
};
declare const styles: {
controls: {
checkbox: TextStyle;
enable: {
text: TextStyle;
hover: TextStyle;
active: TextStyle;
};
textbox: TextStyle;
};
dialog: {
title: TextStyle;
label: TextStyle;
};
icon: {
amount: TextStyle;
};
debug: {
text: TextStyle;
};
};
export { colors, styles };

35
.yalc/@fbe/editor/dist/actions.d.ts vendored Normal file
View File

@ -0,0 +1,35 @@
import keyboardJS from 'keyboardjs';
declare function initActions(canvas: HTMLCanvasElement): void;
declare function passtroughAllEvents(cb: (e: keyboardJS.KeyEvent) => boolean): void;
declare class Action {
readonly name: string;
private readonly defaultKeyCombo;
private m_active;
private m_keyCombo;
private handlers;
private _pressed;
constructor(name: string, defaultKeyCombo: string);
get prettyName(): string;
private get active();
private set active(value);
get keyCombo(): string;
set keyCombo(value: string);
get pressed(): boolean;
get usesDefaultKeyCombo(): boolean;
resetKeyCombo(): void;
bind(opts: {
press?: (e: keyboardJS.KeyEvent) => void;
release?: (e: keyboardJS.KeyEvent) => void;
once?: boolean;
repeat?: boolean;
}): void;
call(): void;
}
declare function registerAction(name: string, keyCombo: string): Action;
declare function callAction(name: string): void;
declare function isActionActive(name: string): boolean;
declare function forEachAction(cb: (action: Action, actionName: string) => void): void;
declare function resetKeybinds(): void;
declare function importKeybinds(keybinds: Record<string, string>): void;
declare function exportKeybinds(changedOnly?: boolean): Record<string, string>;
export { initActions, passtroughAllEvents, registerAction, callAction, isActionActive, forEachAction, resetKeybinds, importKeybinds, exportKeybinds, };

View File

@ -0,0 +1,17 @@
import * as PIXI from 'pixi.js';
import { Blueprint } from '../core/Blueprint';
import { UIContainer } from '../UI/UIContainer';
import { BlueprintContainer } from '../containers/BlueprintContainer';
declare function waitForLoader(): Promise<void>;
declare function getTexture(path: string, x?: number, y?: number, w?: number, h?: number): PIXI.Texture;
declare const _default: {
debug: boolean;
hr: boolean;
BPC: BlueprintContainer;
UI: UIContainer;
app: PIXI.Application;
bp: Blueprint;
getTexture: typeof getTexture;
waitForLoader: typeof waitForLoader;
};
export default _default;

23
.yalc/@fbe/editor/dist/common/util.d.ts vendored Normal file
View File

@ -0,0 +1,23 @@
declare const _default: {
duplicate: <T>(obj: T) => T;
getRandomInt: (min: number, max: number) => number;
getRandomItem: <T_1>(array: T_1[]) => T_1;
getRelativeDirection: (position: IPoint) => 0 | 2 | 4 | 6;
rotatePointBasedOnDir: (p: IPoint | number[], dir: number) => IPoint;
transformConnectionPosition: (position: IPoint, direction: number) => IPoint;
switchSizeBasedOnDirection: (size: {
width: number;
height: number;
}, direction: number) => IPoint;
intToDir: (i: number) => "north" | "east" | "south" | "west";
nearestPowerOf2: (n: number) => number;
uniqueInArray: <T_2>(array: T_2[]) => T_2[];
equalArrays: <T_3>(array1: T_3[], array2: T_3[]) => boolean;
areObjectsEquivalent: <T_4 extends Record<string, any>>(a: T_4, b: T_4) => boolean;
areArraysEquivalent: <T_5>(a: T_5[], b: T_5[]) => boolean;
timer: (name: string) => {
stop: () => void;
};
objectHasOwnProperty: (obj: Record<string, unknown>, key: string) => boolean;
};
export default _default;

View File

@ -0,0 +1,88 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../core/Entity';
import { Blueprint } from '../core/Blueprint';
import { EntitySprite } from './EntitySprite';
import { WiresContainer } from './WiresContainer';
import { UnderlayContainer } from './UnderlayContainer';
import { EntityContainer } from './EntityContainer';
import { OverlayContainer } from './OverlayContainer';
import { PaintContainer } from './PaintContainer';
import { GridData } from './GridData';
export declare type GridPattern = 'checker' | 'grid';
export declare enum EditorMode {
NONE = 0,
EDIT = 1,
PAINT = 2,
PAN = 3,
COPY = 4,
DELETE = 5
}
export declare class BlueprintContainer extends PIXI.Container {
private readonly chunks;
private readonly chunkOffset;
private readonly size;
private readonly anchor;
private readonly viewport;
private _moveSpeed;
private _gridColor;
private _gridPattern;
private _mode;
readonly bp: Blueprint;
readonly gridData: GridData;
private grid;
private readonly chunkGrid;
private readonly tileSprites;
private readonly tilePaintSlot;
readonly underlayContainer: UnderlayContainer;
private readonly entitySprites;
readonly wiresContainer: WiresContainer;
readonly overlayContainer: OverlayContainer;
private readonly entityPaintSlot;
hoverContainer: EntityContainer;
paintContainer: PaintContainer;
private _entityForCopyData;
private copyModeEntities;
private deleteModeEntities;
private copyModeUpdateFn;
private deleteModeUpdateFn;
viewportCulling: boolean;
readonly interactive = true;
readonly interactiveChildren = false;
readonly hitArea: PIXI.Rectangle;
constructor(bp: Blueprint);
get entityForCopyData(): Entity;
copyEntitySettings(): void;
pasteEntitySettings(): void;
getViewportScale(): number;
toWorld(x: number, y: number): [number, number];
render(renderer: PIXI.Renderer): void;
get mode(): EditorMode;
private setMode;
enterCopyMode(): void;
exitCopyMode(cancel?: boolean): void;
enterDeleteMode(): void;
exitDeleteMode(cancel?: boolean): void;
enterPanMode(): void;
exitPanMode(): void;
zoom(zoomIn?: boolean): void;
private get isPointerInside();
private updateHoverContainer;
get moveSpeed(): number;
set moveSpeed(speed: number);
get gridColor(): number;
set gridColor(color: number);
get gridPattern(): GridPattern;
set gridPattern(pattern: GridPattern);
private generateGrid;
private generateChunkGrid;
initBP(): void;
destroy(): void;
addEntitySprites(entitySprites: EntitySprite[], sort?: boolean): void;
addTileSprites(tileSprites: EntitySprite[]): void;
private sortEntities;
transparentEntities(bool?: boolean): void;
centerViewport(): void;
getBlueprintBounds(): PIXI.Rectangle;
getPicture(): Promise<Blob>;
spawnPaintContainer(itemNameOrEntities: string | Entity[], direction?: number): void;
}

View File

@ -0,0 +1,43 @@
import * as PIXI from 'pixi.js';
import { EventEmitter } from 'eventemitter3';
interface IOptions {
maxSize: number;
alpha: boolean;
scaleMode: PIXI.SCALE_MODES;
padding: number;
extrude: boolean;
testBoxes: boolean;
show: boolean;
}
export declare class DynamicSpritesheet extends EventEmitter {
private testBoxes;
private maxSize;
private padding;
private show;
private extrude;
private maxLoading;
private baseTextures;
private entries;
private canvasesDiv;
private packer;
private loading;
private nrOfBinsOnLastRepack;
private textureToEntry;
private rendering;
private rerender;
private firstRender;
private alpha;
private subtextures;
private waitingQueue;
constructor(options?: Partial<IOptions>);
progress(tick: (loaded: number, total: number) => void): void;
awaitSprites(): Promise<void>;
private add;
get(filename: string, x?: number, y?: number, width?: number, height?: number): PIXI.Texture;
getSubtexture(mainTexture: PIXI.Texture, filename: string, x: number, y: number, width: number, height: number): PIXI.Texture;
onAllLoaded(textures: PIXI.Texture[]): Promise<void>;
render(): Promise<void>;
private randomColor;
private extrudeEntry;
}
export {};

View File

@ -0,0 +1,26 @@
import { CursorBoxType } from '../core/factorioData';
import { Entity } from '../core/Entity';
export declare class EntityContainer {
static readonly mappings: Map<number, EntityContainer>;
private static _updateGroups;
private static get updateGroups();
private visualizationArea;
private entityInfo;
private entitySprites;
private cursorBoxContainer;
private undergroundLine;
private readonly m_Entity;
constructor(entity: Entity, sort?: boolean);
private static generateUpdateGroups;
get entity(): Entity;
get position(): IPoint;
set cursorBox(type: CursorBoxType);
private createUndergroundLine;
private destroyUndergroundLine;
private updateUndergroundLine;
private redrawEntityInfo;
pointerOverEventHandler(): void;
pointerOutEventHandler(): void;
private redrawSurroundingEntities;
redraw(ignoreConnections?: boolean, sort?: boolean): void;
}

View File

@ -0,0 +1,37 @@
import * as PIXI from 'pixi.js';
import { Entity } from '../core/Entity';
import { PositionGrid } from '../core/PositionGrid';
import { ISpriteData } from '../core/spriteDataBuilder';
interface IEntityData {
name: string;
type?: string;
direction?: number;
position?: IPoint;
generateConnector?: boolean;
directionType?: string;
operator?: string;
assemblerCraftsWithFluid?: boolean;
assemblerPipeDirection?: string;
trainStopColor?: {
r: number;
g: number;
b: number;
a: number;
};
chemicalPlantDontConnectOutput?: boolean;
modules?: string[];
}
export declare class EntitySprite extends PIXI.Sprite {
private static nextID;
private id;
zIndex: number;
private zOrder;
cachedBounds: [number, number, number, number];
private readonly entityPos;
constructor(texture: PIXI.Texture, data: ISpriteData, position?: IPoint);
private static getNextID;
static getParts(entity: IEntityData | Entity, position?: IPoint, positionGrid?: PositionGrid): EntitySprite[];
static compareFn(a: EntitySprite, b: EntitySprite): number;
private cacheBounds;
}
export {};

View File

@ -0,0 +1,23 @@
import { EventEmitter } from 'eventemitter3';
import { BlueprintContainer } from './BlueprintContainer';
export declare class GridData extends EventEmitter {
private readonly bpc;
private _x;
private _y;
private _x16;
private _y16;
private _x32;
private _y32;
private lastMousePosX;
private lastMousePosY;
constructor(bpc: BlueprintContainer);
get x(): number;
get y(): number;
get x16(): number;
get y16(): number;
get x32(): number;
get y32(): number;
destroy(): void;
recalculate(): void;
private update;
}

View File

@ -0,0 +1,10 @@
import * as PIXI from 'pixi.js';
import { EntitySprite } from './EntitySprite';
import { BlueprintContainer } from './BlueprintContainer';
export declare class OptimizedContainer extends PIXI.Container {
private bpc;
children: EntitySprite[];
constructor(bpc: BlueprintContainer);
updateTransform(): void;
render(renderer: PIXI.Renderer): void;
}

View File

@ -0,0 +1,23 @@
import * as PIXI from 'pixi.js';
import { CursorBoxType } from '../core/factorioData';
import { Entity } from '../core/Entity';
import { BlueprintContainer } from './BlueprintContainer';
export declare class OverlayContainer extends PIXI.Container {
private readonly bpc;
private readonly entityInfos;
private readonly cursorBoxes;
private readonly undergroundLines;
private readonly selectionArea;
private copyCursorBox;
private selectionAreaUpdateFn;
constructor(bpc: BlueprintContainer);
static createEntityInfo(entity: Entity, position: IPoint): PIXI.Container;
createCopyCursorBox(): void;
destroyCopyCursorBox(): void;
toggleEntityInfoVisibility(): void;
createEntityInfo(entity: Entity, position: IPoint): PIXI.Container;
createCursorBox(position: IPoint, size: IPoint, type?: CursorBoxType): PIXI.Container;
createUndergroundLine(name: string, position: IPoint, direction: number, searchDirection: number): PIXI.Container;
showSelectionArea(color: number): void;
hideSelectionArea(): void;
}

View File

@ -0,0 +1,19 @@
import { Entity } from '../core/Entity';
import { EntitySprite } from './EntitySprite';
import { PaintContainer } from './PaintContainer';
import { BlueprintContainer } from './BlueprintContainer';
export declare class PaintBlueprintContainer extends PaintContainer {
private readonly bp;
private readonly entities;
children: EntitySprite[];
constructor(bpc: BlueprintContainer, entities: Entity[]);
hide(): void;
show(): void;
destroy(): void;
getItemName(): string;
rotate(): void;
moveAtCursor(): void;
protected redraw(): void;
placeEntityContainer(): void;
removeContainerUnder(): void;
}

View File

@ -0,0 +1,24 @@
import { Entity } from '../core/Entity';
import { Blueprint } from '../core/Blueprint';
import { EntitySprite } from './EntitySprite';
import { BlueprintContainer } from './BlueprintContainer';
import { PaintBlueprintContainer } from './PaintBlueprintContainer';
export declare class PaintBlueprintEntityContainer {
private readonly pbpc;
private readonly bpc;
private readonly bp;
private readonly entity;
private readonly visualizationArea;
readonly entitySprites: EntitySprite[];
private undergroundLine;
constructor(pbpc: PaintBlueprintContainer, bpc: BlueprintContainer, bp: Blueprint, entity: Entity);
private get entityPosition();
private get position();
destroy(): void;
private checkBuildable;
private updateUndergroundLine;
private destroyUndergroundLine;
moveAtCursor(): void;
removeContainerUnder(): void;
placeEntityContainer(): Entity;
}

View File

@ -0,0 +1,23 @@
import * as PIXI from 'pixi.js';
import { BlueprintContainer } from './BlueprintContainer';
export declare abstract class PaintContainer extends PIXI.Container {
protected readonly bpc: BlueprintContainer;
private readonly icon;
private _blocked;
private tint;
protected constructor(bpc: BlueprintContainer, name: string);
protected get blocked(): boolean;
protected set blocked(value: boolean);
hide(): void;
show(): void;
destroy(): void;
protected getGridPosition(): IPoint;
protected setNewPosition(size: IPoint): void;
private readonly updateIconPos;
abstract getItemName(): string;
abstract rotate(ccw?: boolean): void;
protected abstract redraw(): void;
abstract moveAtCursor(): void;
abstract removeContainerUnder(): void;
abstract placeEntityContainer(): void;
}

View File

@ -0,0 +1,23 @@
import { PaintContainer } from './PaintContainer';
import { BlueprintContainer } from './BlueprintContainer';
export declare class PaintEntityContainer extends PaintContainer {
private visualizationArea;
private directionType;
private direction;
private undergroundLine;
constructor(bpc: BlueprintContainer, name: string, direction: number);
private get size();
hide(): void;
show(): void;
destroy(): void;
getItemName(): string;
private checkBuildable;
private updateUndergroundBeltRotation;
private updateUndergroundLine;
private destroyUndergroundLine;
rotate(ccw?: boolean): void;
protected redraw(): void;
moveAtCursor(): void;
removeContainerUnder(): void;
placeEntityContainer(): void;
}

View File

@ -0,0 +1,18 @@
import { PaintContainer } from './PaintContainer';
import { BlueprintContainer } from './BlueprintContainer';
export declare class PaintTileContainer extends PaintContainer {
private static size;
constructor(bpc: BlueprintContainer, name: string);
private static getTilePositions;
hide(): void;
show(): void;
destroy(): void;
getItemName(): string;
increaseSize(): void;
decreaseSize(): void;
rotate(): void;
protected redraw(): void;
moveAtCursor(): void;
removeContainerUnder(): void;
placeEntityContainer(): void;
}

View File

@ -0,0 +1,8 @@
import { Tile } from '../core/Tile';
import { EntitySprite } from './EntitySprite';
export declare class TileContainer {
private readonly tileSprites;
constructor(tile: Tile);
static generateSprite(name: string, x: number, y: number): EntitySprite;
static generateSprites(name: string, position: IPoint, positions: IPoint[]): EntitySprite[];
}

View File

@ -0,0 +1,16 @@
import * as PIXI from 'pixi.js';
import { VisualizationArea } from './VisualizationArea';
export declare class UnderlayContainer extends PIXI.Container {
private active;
private readonly logistics0;
private readonly logistics1;
private readonly poles;
private readonly beacons;
private readonly drills;
private readonly dummyVisualizationArea;
constructor();
private static getDataForVisualizationArea;
activateRelatedAreas(entityName: string): void;
deactivateActiveAreas(): void;
create(entityName: string, position: IPoint): VisualizationArea;
}

View File

@ -0,0 +1,28 @@
import * as PIXI from 'pixi.js';
export declare class Viewport {
private size;
private viewPortSize;
private anchor;
private maxZoom;
private dirty;
private positionX;
private positionY;
private scaleX;
private scaleY;
private scaleCenterX;
private scaleCenterY;
private origTransform;
private transform;
constructor(size: IPoint, viewPortSize: IPoint, anchor: IPoint, maxZoom: number);
private _updateMatrix;
centerViewPort(focusObjectSize: IPoint, offset: IPoint): void;
update(): boolean;
getTransform(): PIXI.Matrix;
setSize(x: number, y: number): void;
setPosition(posX: number, posY: number): void;
zoomBy(deltaX: number, deltaY?: number): void;
translateBy(deltaX: number, deltaY: number): void;
setCurrentScale(newScale: number): void;
getCurrentScale(): number;
setScaleCenter(posX: number, posY: number): void;
}

View File

@ -0,0 +1,11 @@
import * as PIXI from 'pixi.js';
export declare class VisualizationArea {
static ALPHA: number;
private readonly sprites;
constructor(sprites: PIXI.Sprite[]);
destroy(): void;
show(): void;
hide(): void;
highlight(): void;
moveTo(position: IPoint): void;
}

View File

@ -0,0 +1,17 @@
import * as PIXI from 'pixi.js';
import { Blueprint } from '../core/Blueprint';
import { IConnection } from '../core/WireConnections';
export declare class WiresContainer extends PIXI.Container {
private readonly bp;
private connectionToSprite;
constructor(bp: Blueprint);
private static createWire;
connect(hash: string, connection: IConnection): void;
disconnect(hash: string, connection: IConnection): void;
add(hash: string, connection: IConnection): void;
remove(hash: string): void;
update(entityNumber: number): void;
private updateConnectedEntities;
private redrawEntityConnections;
private getWireSprite;
}

View File

@ -0,0 +1,59 @@
import { EventEmitter } from 'eventemitter3';
import { Entity } from './Entity';
import { WireConnections } from './WireConnections';
import { PositionGrid } from './PositionGrid';
import { History } from './History';
import { Tile } from './Tile';
interface IOilOutpostSettings extends Record<string, string | boolean | number> {
DEBUG: boolean;
PUMPJACK_MODULE: string;
MIN_GAP_BETWEEN_UNDERGROUNDS: number;
BEACONS: boolean;
MIN_AFFECTED_ENTITIES: number;
BEACON_MODULE: string;
}
declare const oilOutpostSettings: IOilOutpostSettings;
declare const getFactorioVersion: (main?: number, major?: number, minor?: number) => number;
declare class OurMap<K, V> extends Map<K, V> {
constructor(values?: V[], mapFn?: (value: V) => K);
isEmpty(): boolean;
valuesArray(): V[];
find(predicate: (value: V, key: K) => boolean): V;
filter(predicate: (value: V, key: K) => boolean): V[];
}
interface IEntityData extends Omit<BPS.IEntity, 'entity_number'> {
entity_number?: number;
}
export declare class Blueprint extends EventEmitter {
name: string;
private readonly icons;
readonly wireConnections: WireConnections;
readonly entityPositionGrid: PositionGrid;
readonly entities: OurMap<number, Entity>;
readonly tiles: OurMap<string, Tile>;
readonly history: History;
private readonly description?;
private readonly schedules?;
private readonly absolute_snapping?;
private readonly snap_to_grid?;
private readonly position_relative_to_grid?;
private m_nextEntityNumber;
constructor(data?: Partial<BPS.IBlueprint>);
createEntity(rawData: IEntityData, connectPowerPole?: boolean): Entity;
removeEntity(entity: Entity): void;
removeEntities(entities: Entity[]): void;
fastReplaceEntity(name: string, direction: number, position: IPoint): boolean;
private onCreateOrRemoveEntity;
createTiles(name: string, positions: IPoint[]): void;
removeTiles(positions: IPoint[]): void;
private onCreateOrRemoveTile;
private get nextEntityNumber();
getFirstRailRelatedEntity(): Entity;
isEmpty(): boolean;
private getCenter;
generatePipes(): string;
private generateIcons;
private processRawEntities;
serialize(): BPS.IBlueprint;
}
export { oilOutpostSettings, getFactorioVersion, IOilOutpostSettings };

16
.yalc/@fbe/editor/dist/core/Book.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
import { Blueprint } from './Blueprint';
declare class Book {
private _active;
private _activeIndex;
private readonly blueprints;
private readonly label?;
private readonly description?;
private readonly icons?;
constructor(data: BPS.IBlueprintBook);
get activeIndex(): number;
get lastBookIndex(): number;
private saveActiveBlueprint;
selectBlueprint(index?: number): Blueprint;
serialize(): BPS.IBlueprintBook;
}
export { Book };

75
.yalc/@fbe/editor/dist/core/Entity.d.ts vendored Normal file
View File

@ -0,0 +1,75 @@
import { EventEmitter } from 'eventemitter3';
import { Entity as FD_Entity } from './factorioData';
import { Blueprint } from './Blueprint';
export interface IFilter {
index: number;
name: string;
count?: number;
}
export declare class Entity extends EventEmitter {
private readonly m_rawEntity;
private readonly m_BP;
constructor(rawEntity: BPS.IEntity, blueprint: Blueprint);
static getItemName(name: string): string;
destroy(): void;
get Blueprint(): Blueprint;
get entityNumber(): number;
get name(): string;
get type(): string;
get entityData(): FD_Entity;
get size(): IPoint;
get position(): IPoint;
set position(position: IPoint);
get maxWireDistance(): number;
moveBy(offset: IPoint): void;
get direction(): number;
set direction(direction: number);
get directionType(): 'input' | 'output';
set directionType(type: 'input' | 'output');
get recipe(): string;
set recipe(recipe: string);
get acceptedRecipes(): string[];
get moduleSlots(): number;
get acceptedModules(): string[];
get acceptedFilters(): string[];
get modules(): string[];
set modules(modules: string[]);
get filterSlots(): number;
get filters(): IFilter[];
set filters(list: IFilter[]);
get splitterInputPriority(): string;
set splitterInputPriority(priority: string);
get splitterOutputPriority(): string;
set splitterOutputPriority(priority: string);
private get splitterFilter();
private set splitterFilter(value);
get filterMode(): 'whitelist' | 'blacklist';
set filterMode(filterMode: 'whitelist' | 'blacklist');
private get inserterFilters();
private set inserterFilters(value);
private get logisticChestFilters();
private set logisticChestFilters(value);
private get infinityChestFilters();
private get infinityPipeFilters();
get requestFromBufferChest(): boolean;
set requestFromBufferChest(request: boolean);
get inserterStackSize(): number;
get constantCombinatorFilters(): BPS.IConstantCombinatorFilter[];
get deciderCombinatorConditions(): BPS.IDeciderCondition;
get arithmeticCombinatorConditions(): BPS.IArithmeticCondition;
get generateConnector(): boolean;
private get connectToLogisticNetwork();
private get hasConnections();
get chemicalPlantDontConnectOutput(): boolean;
get trainStopColor(): BPS.IColor;
get operator(): string;
private get canBeRotated();
rotate(ccw?: boolean, rotateOpposingUB?: boolean): void;
canPasteSettings(sourceEntity: Entity): boolean;
pasteSettings(sourceEntity: Entity): void;
get assemblerCraftsWithFluid(): boolean;
get mayCraftWithFluid(): boolean;
get assemblerPipeDirection(): 'input' | 'output';
getWireConnectionPoint(color: string, side: number, direction?: number): number[];
serialize(entNrWhitelist?: Set<number>): BPS.IEntity;
}

View File

@ -0,0 +1,37 @@
declare enum HistoryValue {
New = 0,
Old = 1
}
declare class Action<V> {
readonly oldValue: V;
readonly newValue: V;
readonly text: string;
private readonly applyFn;
private readonly emits;
private readonly history;
applyImmediate: boolean;
constructor(history: History, oldValue: V, newValue: V, text: string, applyFn: (value: V) => void);
commit(): this;
apply(value?: HistoryValue): void;
onDone(f: (newValue: V, oldValue: V) => void): Action<V>;
}
export declare class History {
logging: boolean;
private readonly MAX_HISTORY_LENGTH;
private readonly MIN_HISTORY_LENGTH;
private transactionCount;
private historyIndex;
private activeTransaction;
private transactionHistory;
reset(): void;
updateValue<T, V>(target: T, path: string[], value: V, text: string): Action<V>;
updateMap<K, V>(target: Map<K, V>, key: K, value: V, text: string): Action<V>;
undo(): boolean;
redo(): boolean;
startTransaction(text?: string, applyImmediate?: boolean): boolean;
commitTransaction(): boolean;
private GetValue;
private SetValue;
private DeleteValue;
}
export {};

View File

@ -0,0 +1,33 @@
import { Blueprint } from './Blueprint';
import { Entity } from './Entity';
interface IArea {
x: number;
y: number;
w: number;
h: number;
}
interface INeighbourData extends IPoint {
relDir: number;
entity: Entity;
}
export declare class PositionGrid {
private bp;
private grid;
constructor(bp: Blueprint);
private tileDataAction;
getEntityAtPosition(x: number, y: number): Entity;
setTileData(entity: Entity, position?: IPoint): void;
removeTileData(entity: Entity, position?: IPoint): void;
canMoveTo(entity: Entity, newPosition: IPoint): boolean;
isAreaAvalible(name: string, pos: IPoint, direction?: number): boolean;
checkFastReplaceableGroup(name: string, direction: number, pos: IPoint): Entity;
checkSameEntityAndDifferentDirection(name: string, direction: number, pos: IPoint): Entity;
getOpposingEntity(name: string, direction: number, position: IPoint, searchDirection: number, maxDistance: number): number;
sharesCell(area: IArea): boolean;
isAreaEmpty(area: IArea): boolean;
findInArea(area: IArea, fn: (entity: Entity) => boolean): Entity;
getEntitiesInArea(area: IArea): Entity[];
getSurroundingEntities(area: IArea): Entity[];
getNeighbourData(point: IPoint): INeighbourData[];
}
export {};

13
.yalc/@fbe/editor/dist/core/Tile.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
import { EventEmitter } from 'eventemitter3';
export declare class Tile extends EventEmitter {
private readonly _name;
private readonly _x;
private readonly _y;
constructor(name: string, x: number, y: number);
static getItemName(name: string): string;
get name(): string;
get x(): number;
get y(): number;
get hash(): string;
destroy(): void;
}

View File

@ -0,0 +1,8 @@
import { IConnection } from './WireConnections';
export declare class WireConnectionMap extends Map<string, IConnection> {
private entNrToConnHash;
getEntityConnectionHashes(entityNumber: number): string[];
getEntityConnections(entityNumber: number): IConnection[];
set(hash: string, connection: IConnection): this;
delete(hash: string): boolean;
}

View File

@ -0,0 +1,37 @@
import { EventEmitter } from 'eventemitter3';
import { Blueprint } from './Blueprint';
export interface IConnection {
color: string;
entityNumber1: number;
entityNumber2: number;
entitySide1: number;
entitySide2: number;
}
export declare class WireConnections extends EventEmitter {
private bp;
private readonly connections;
constructor(bp: Blueprint);
private static hash;
static deserialize(entityNumber: number, connections: BPS.IConnection, neighbours: number[]): IConnection[];
static serialize(entityNumber: number, connections: IConnection[], getType: (entityNumber: number) => string, entNrWhitelist?: Set<number>): {
connections: BPS.IConnection;
neighbours: number[];
};
private static toPoleConnection;
create(connection: IConnection): void;
private remove;
private onCreateOrRemoveConnection;
get(hash: string): IConnection;
forEach(fn: (value: IConnection, key: string) => void): void;
createEntityConnections(entityNumber: number, connections: BPS.IConnection, neighbours: number[]): void;
removeEntityConnections(entityNumber: number): void;
getEntityConnectionHashes(entityNumber: number): string[];
getEntityConnections(entityNumber: number): IConnection[];
serializeConnectionData(entityNumber: number, entNrWhitelist?: Set<number>): {
connections: BPS.IConnection;
neighbours: number[];
};
connectPowerPole(entityNumber: number): void;
generatePowerPoleWires(): void;
getPowerPoleDirection(entityNumber: number): number;
}

View File

@ -0,0 +1,19 @@
import Ajv from 'ajv';
import { Blueprint } from './Blueprint';
import { Book } from './Book';
declare class CorruptedBlueprintStringError {
error: unknown;
constructor(error: unknown);
}
declare class ModdedBlueprintError {
errors: Ajv.ErrorObject[];
constructor(errors: Ajv.ErrorObject[]);
}
declare class TrainBlueprintError {
errors: Ajv.ErrorObject[];
constructor(errors: Ajv.ErrorObject[]);
}
declare function decodeToBlueprint(str: string): Promise<Blueprint>;
declare function encode(bpOrBook: Blueprint | Book): Promise<string>;
declare function getBlueprintOrBookFromSource(source: string): Promise<Blueprint | Book>;
export { ModdedBlueprintError, TrainBlueprintError, CorruptedBlueprintStringError, encode, getBlueprintOrBookFromSource, decodeToBlueprint, };

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
import { IVisualization } from './index';
export declare function generateBeacons(entities: {
position: IPoint;
size: number;
effect: boolean;
}[], minAffectedEntities?: number): {
beacons: {
name: string;
position: IPoint;
}[];
info: {
totalBeacons: number;
effectsGiven: number;
};
visualizations: IVisualization[];
};

View File

@ -0,0 +1,10 @@
import { generatePipes } from './pipe';
import { generateBeacons } from './beacon';
import { generatePoles } from './pole';
export interface IVisualization {
path: IPoint[];
size: number;
alpha: number;
color?: number;
}
export { generatePipes, generateBeacons, generatePoles };

View File

@ -0,0 +1,22 @@
import { IVisualization } from './index';
declare function generatePipes(pumpjacks: {
entity_number: number;
position: IPoint;
}[], minGapBetweenUndergrounds?: number): {
pumpjacksToRotate: {
entity_number: number;
direction: number;
}[];
pipes: {
name: string;
position: IPoint;
direction: number;
}[];
info: {
nrOfPipes: number;
nrOfUPipes: number;
nrOfPipesReplacedByUPipes: number;
};
visualizations: IVisualization[];
};
export { generatePipes };

View File

@ -0,0 +1,15 @@
import { IVisualization } from './index';
export declare function generatePoles(entities: {
position: IPoint;
size: number;
power: boolean;
}[]): {
poles: {
name: string;
position: IPoint;
}[];
info: {
totalPoles: number;
};
visualizations: IVisualization[];
};

View File

@ -0,0 +1,17 @@
declare const _default: {
hashPoint: (p: IPoint) => string;
equalPoints: <T extends IPoint>(a: T) => (b: T) => boolean;
uniqPoints: <T_1 extends IPoint>(list: T_1[]) => T_1[];
arrayToPoint: (array: number[]) => IPoint;
pointToArray: (point: IPoint) => number[];
manhattenDistance: (p0: IPoint, p1: IPoint) => number;
euclideanDistance: (p0: IPoint, p1: IPoint) => number;
pointInCircle: (point: IPoint, origin: IPoint, r: number) => boolean;
pointsToLines: <T_2 extends IPoint>(nodes: T_2[]) => T_2[][];
pointsToTriangles: <T_3 extends IPoint>(nodes: T_3[]) => T_3[][];
range: (from: number, to: number) => number[];
getAngle: (cX: number, cY: number, pX: number, pY: number) => number;
getReflectedPoint: (p: IPoint, lp0: IPoint, lp1: IPoint) => IPoint;
findSide: (p: IPoint, lp0: IPoint, lp1: IPoint) => number;
};
export default _default;

View File

@ -0,0 +1,43 @@
import { PositionGrid } from './PositionGrid';
interface IDrawData {
hr: boolean;
dir: number;
name: string;
positionGrid: PositionGrid;
position: IPoint;
generateConnector: boolean;
assemblerPipeDirection: string;
dirType: string;
operator: string;
assemblerCraftsWithFluid: boolean;
trainStopColor: {
r: number;
g: number;
b: number;
a: number;
};
chemicalPlantDontConnectOutput: boolean;
modules: string[];
}
interface ISpriteData {
filename: string;
width: number;
height: number;
scale?: number;
x?: number;
y?: number;
shift?: number[];
tint?: {
r: number;
g: number;
b: number;
a: number;
};
anchorX?: number;
anchorY?: number;
squishY?: number;
rotAngle?: number;
}
declare function getSpriteData(data: IDrawData): ISpriteData[];
declare function getBeltWireConnectionIndex(positionGrid: PositionGrid, position: IPoint, dir: number): 0 | 1 | 2 | 3 | 4 | 5 | 6;
export { ISpriteData, getSpriteData, getBeltWireConnectionIndex };

18
.yalc/@fbe/editor/dist/index.d.ts vendored Normal file
View File

@ -0,0 +1,18 @@
import { Book } from './core/Book';
import { Blueprint } from './core/Blueprint';
import { GridPattern } from './containers/BlueprintContainer';
import { registerAction, callAction, forEachAction, resetKeybinds, importKeybinds, exportKeybinds } from './actions';
import { Editor } from './Editor';
import FD from './core/factorioData';
export * from './core/bpString';
export { Editor, Book, Blueprint, GridPattern, FD };
declare const _default: {
registerAction: typeof registerAction;
callAction: typeof callAction;
forEachAction: typeof forEachAction;
resetKeybinds: typeof resetKeybinds;
importKeybinds: typeof importKeybinds;
exportKeybinds: typeof exportKeybinds;
waitForLoader: () => Promise<void>;
};
export default _default;

330
.yalc/@fbe/editor/dist/index.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
{
"name": "@fbe/editor",
"version": "1.0.0+4ce98ad6",
"description": "A Factorio blueprint editor and renderer webapp",
"author": "Teoxoy",
"license": "MIT",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "git://github.com/Teoxoy/factorio-blueprint-editor.git"
},
"bugs": "https://github.com/Teoxoy/factorio-blueprint-editor/issues",
"homepage": "https://github.com/Teoxoy/factorio-blueprint-editor",
"dependencies": {
"@pixi/basis": "^6.0.0-rc.2",
"ajv": "^6.12.2",
"delaunator": "^4.0.1",
"eventemitter3": "^4.0.4",
"keyboardjs": "^2.5.1",
"maxrects-packer": "^2.6.0",
"pako": "^1.0.11",
"pathfinding": "^0.4.18",
"pixi.js": "^6.0.0-rc.2"
},
"yalcSig": "4ce98ad61ee9927a6bee4eb976d9403a"
}

View File

@ -0,0 +1 @@
4ce98ad61ee9927a6bee4eb976d9403a

View File

@ -127,7 +127,7 @@ export const functionPubSubHandler: PubSubHandler = async (message, _context, ca
await saveBlueprintImage(blueprint.image_hash, min_image, "300");
log(`Saved image with image hash ${blueprint.image_hash}`);
await saveBlueprintImage(blueprint.image_hash, image, "original");
// await saveBlueprintImage(blueprint.image_hash, image, "original");
callback();
} catch (reason) {

View File

@ -11,6 +11,7 @@ import { renderImage } from "./image-renderer";
export async function subscribeToPubSub() {
const topic = getBlueprintImageRequestTopic();
if (!topic) throw Error("PubSub Topic not found");
const [subscription] = await topic
.subscription("blueprint-image-function-app", {
flowControl: { allowExcessMessages: false, maxMessages: 1, maxExtension: 3600 },

View File

@ -6,10 +6,11 @@ module.exports = {
images: {
domains: ["storage.googleapis.com"],
},
assetPrefix: process.env.ASSET_PREFIX ? process.env.ASSET_PREFIX : "",
webpack(config, options) {
const { dev, isServer } = options;
// Do not run type checking twice:
// Do not run type checking twice
if (dev && isServer) {
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
config.plugins.push(new ForkTsCheckerWebpackPlugin());

View File

@ -0,0 +1,2 @@
-- AddForeignKey
ALTER TABLE "blueprint_page" ADD FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@ -60,6 +60,7 @@ model blueprint_page {
blueprint_book blueprint_book? @relation(fields: [blueprint_book_id], references: [id])
blueprint blueprint? @relation(fields: [blueprint_id], references: [id])
user_favorites user_favorites[]
user user? @relation(fields: [user_id], references: [id])
}
model session {
@ -92,6 +93,7 @@ model user {
updated_at DateTime @updatedAt
session session[]
user_favorites user_favorites[]
blueprint_pages blueprint_page[]
}
model user_favorites {

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,59 @@
import parser, { Tag } from "bbcode-to-react";
import { FactorioIcon } from "./FactorioIcon";
class ImgTag extends Tag {
toReact() {
const content = this.getContent(true);
const img = (this.params as any).img;
const [type, item] = img.split("/");
if (type === "item") {
return (
<>
<FactorioIcon type={type} icon={item} size={20} />
{content && <span>{content}</span>}
</>
);
}
return null;
}
}
class ItemTag extends Tag {
toReact() {
const content = this.getContent(true);
const item = (this.params as any).item;
if (item) {
return (
<>
<FactorioIcon type="item" icon={item} size={20} />
{content && <span>{content}</span>}
</>
);
}
return null;
}
}
class VirtualSignalTag extends Tag {
toReact() {
const signal = (this.params as any)["virtual-signal"];
const content = this.getContent(true);
if (signal) {
return (
<>
<FactorioIcon type="signal" icon={signal} size={20} />
{content && <span>{content}</span>}
</>
);
}
return null;
}
}
parser.registerTag("img", ImgTag as any);
parser.registerTag("item", ItemTag as any);
parser.registerTag("virtual-signal", VirtualSignalTag as any);
export const BBCode: React.FC<{ code: string }> = ({ code }) => {
return <>{parser.toReact(code)}</>;
};

View File

@ -68,8 +68,7 @@ export const BlueprintLink: React.FC<BlueprintLinkProps> = ({
type = "tile",
}) => {
const [imageError, setImageError] = useState(false);
const onImageError = (error: unknown) => {
console.log(error);
const onImageError = () => {
setImageError(true);
};

View File

@ -1,8 +1,8 @@
import { css } from "@emotion/react";
import Link from "next/link";
import BBCode from "bbcode-to-react";
import { FactorioIcon } from "./FactorioIcon";
import { ChildTreeBlueprintBookEnriched } from "@factorio-sites/web-utils";
import { FactorioIcon } from "./FactorioIcon";
import { BBCode } from "./BBCode";
const componentStyles = css`
.blueprint,
@ -50,7 +50,9 @@ export const BookChildTree: React.FC<BookChildTreeProps> = ({
size={20}
/>
))}
<span className="label">{BBCode.toReact(blueprint_book.name || "")}</span>
<span className="label">
<BBCode code={blueprint_book.name || ""} />
</span>
</a>
</Link>
<div css={{ marginLeft: `20px` }}>
@ -58,15 +60,18 @@ export const BookChildTree: React.FC<BookChildTreeProps> = ({
return child.type === "blueprint" ? (
<Link key={child.id} href={`${base_url}?selected=${child.id}`}>
<a className={"blueprint" + (selected_id === child.id ? " active" : "")}>
{child.icons.map((icon, index) => (
<FactorioIcon
key={index}
type={icon.signal.type}
icon={icon.signal.name}
size={20}
/>
))}
<span className="label"> {BBCode.toReact(child.name || "")}</span>
{child.icons &&
child.icons.map((icon, index) => (
<FactorioIcon
key={index}
type={icon.signal.type}
icon={icon.signal.name}
size={20}
/>
))}
<span className="label">
<BBCode code={child.name || ""} />
</span>
</a>
</Link>
) : child.type === "blueprint_book" ? (

View File

@ -4,10 +4,9 @@ import { MdCheck, MdClose } from "react-icons/md";
const SUCCESS_ICON_DURATION = 2000;
export const CopyButton: React.FC<Omit<ButtonProps, "children"> & { content: string }> = ({
content,
...props
}) => {
export const CopyButton: React.FC<
Omit<ButtonProps, "children"> & { content: string; label?: string }
> = ({ content, label, ...props }) => {
const [loading, setLoading] = useState(false);
const [icon, setIcon] = useState<"red" | "green" | null>(null);
@ -47,7 +46,7 @@ export const CopyButton: React.FC<Omit<ButtonProps, "children"> & { content: str
});
}}
>
copy
{label || "copy"}
</Button>
);
};

View File

@ -1,7 +1,7 @@
import { IconSignalTypes } from "@factorio-sites/types";
interface FactorioIconProps {
type: IconSignalTypes;
type: IconSignalTypes | "signal";
icon: string;
size: number;
}
@ -12,6 +12,11 @@ function getUrlByType(type: FactorioIconProps["type"], icon: string) {
return `https://storage.googleapis.com/factorio-blueprints-assets/factorio/graphics/icons/${icon}.png`;
case "fluid":
return `https://storage.googleapis.com/factorio-blueprints-assets/factorio/graphics/icons/fluid/${icon}.png`;
case "signal":
return `https://storage.googleapis.com/factorio-blueprints-assets/factorio/graphics/icons/signal/${icon.replace(
/-/,
"_"
)}.png`;
case "virtual":
return null;
default:

View File

@ -1,9 +1,8 @@
import React, { useEffect, useState } from "react";
import { Box, Heading, Flex, Text, Input, InputGroup, InputLeftElement } from "@chakra-ui/react";
import React, { useState } from "react";
import { Box, Heading, Flex, Text } from "@chakra-ui/react";
import Link from "next/link";
import { useRouter } from "next/router";
import { useAuth } from "../providers/auth";
import { MdSearch } from "react-icons/md";
const MenuItem: React.FC<{ href: string }> = ({ children, href }) => (
<Link href={href} passHref>
@ -20,13 +19,8 @@ export const Header: React.FC = (props) => {
const auth = useAuth();
const router = useRouter();
const [show, setShow] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const handleToggle = () => setShow(!show);
useEffect(() => {
setSearchQuery((router.query.q as string) || "");
}, [router.query.q]);
return (
<Flex
as="header"
@ -46,14 +40,12 @@ export const Header: React.FC = (props) => {
</Link>
</Heading>
</Flex>
<Box display={{ base: "block", md: "none" }} onClick={handleToggle}>
<svg fill="white" width="12px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<title>Menu</title>
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" />
</svg>
</Box>
<Box
as="nav"
display={{

View File

@ -1,9 +1,28 @@
import { css } from "@emotion/react";
import { parseBlueprintStringClient } from "@factorio-sites/web-utils";
import { useEffect, useRef, useState } from "react";
type FBE = typeof import("@fbe/editor");
type Editor = InstanceType<FBE["Editor"]>;
const editorCss = css`
position: relative;
.error {
position: absolute;
top: 10%;
left: 10%;
background: rgba(0, 0, 0, 0.5);
padding: 10px 20px;
border-radius: 40px;
width: 450px;
text-align: center;
h3 {
font-size: 30px;
}
}
`;
interface ImageEditorProps {
string: string;
}
@ -13,6 +32,7 @@ export const ImageEditor: React.FC<ImageEditorProps> = ({ string }) => {
// const [image, setImage] = useState<string | undefined>();
const FbeRef = useRef<FBE>();
const editorRef = useRef<Editor>();
const [renderError, setRenderError] = useState(false);
const [editorLoaded, setEditorLoaded] = useState(false);
// Load editor async, it does not work server side
@ -30,35 +50,8 @@ export const ImageEditor: React.FC<ImageEditorProps> = ({ string }) => {
editorRef.current = editor;
setEditorLoaded(true);
})();
}, []);
useEffect(() => {
(async () => {
if (!parseBlueprintStringClient(string)) {
return;
}
const FBE = FbeRef.current;
const editor = editorRef.current;
if (!editorLoaded || !FBE || !editor) return;
const bpOrBook = await FBE.getBlueprintOrBookFromSource(string);
const blueprint = bpOrBook instanceof FBE.Book ? bpOrBook.selectBlueprint(0) : bpOrBook;
await editor.loadBlueprint(blueprint);
// await FBE.default.waitForLoader();
// Wait a little extra, sometimes even after textures are loaded it neeeds a moment to render
// await new Promise((resolve) => setTimeout(resolve, 10));
// const picture = await editor.getPicture();
// setImage(URL.createObjectURL(picture));
})();
}, [string, editorLoaded]);
window.addEventListener(
"resize",
() => {
const resizeFn = () => {
if (!canvasRef.current || !editorRef.current) return;
canvasRef.current.style.width = "100%";
canvasRef.current.style.height = "auto";
@ -66,12 +59,55 @@ export const ImageEditor: React.FC<ImageEditorProps> = ({ string }) => {
canvasRef.current.offsetWidth,
canvasRef.current.offsetHeight
);
},
false
);
};
window.addEventListener("resize", resizeFn, false);
return () => window.removeEventListener("resize", resizeFn);
}, []);
useEffect(() => {
(async () => {
try {
setRenderError(false);
if (!parseBlueprintStringClient(string)) {
return;
}
const FBE = FbeRef.current;
const editor = editorRef.current;
if (!editorLoaded || !FBE || !editor) return;
const bp = await FBE.decodeToBlueprint(string);
await editor.loadBlueprint(bp);
// await FBE.default.waitForLoader();
// Wait a little extra, sometimes even after textures are loaded it neeeds a moment to render
// await new Promise((resolve) => setTimeout(resolve, 10));
// const picture = await editor.getPicture();
// setImage(URL.createObjectURL(picture));
} catch (reason) {
setRenderError(true);
if (Array.isArray(reason.errors)) {
return console.error("Blueprint string not supported by FBE", reason.errors);
}
console.error("Failed to render blueprint", reason);
}
})();
}, [string, editorLoaded]);
return (
<div>
<div css={editorCss}>
{renderError && (
<div className="error">
<h3>Failed to render blueprint</h3>
<p>
This happens when there are modded entities or in some cases blueprint properties that
FBE does not yet support
</p>
</div>
)}
<canvas id="pbe" ref={canvasRef} style={{ width: "100%", height: "auto" }} />
{/* <img src={image} alt="blueprint" style={{ width: "500px" }}></img> */}
</div>

View File

@ -0,0 +1,12 @@
import Link from "next/link";
import { Image } from "@chakra-ui/react";
export const SteamLogin: React.FC = () => {
return (
<Link href={`/api/openid/steam`}>
<a>
<Image src="https://steamcdn-a.akamaihd.net/steamcommunity/public/images/steamworks_docs/english/sits_large_noborder.png" />
</a>
</Link>
);
};

View File

@ -53,11 +53,9 @@ const BlueprintsApp = ({
<AuthContext.Provider value={auth.data?.auth || null}>
<Global styles={globalStyles} />
<Head>
<title>Welcome to blueprints!</title>
<link
href="https://cdn.factorio.com/assets/fonts/titillium-web.css"
rel="stylesheet"
></link>
<title>Factorio Blueprints</title>
<link rel="shortcut icon" href="/favicon.png" />
<link href="https://cdn.factorio.com/assets/fonts/titillium-web.css" rel="stylesheet" />
</Head>
<div>
{!auth.loading && (

View File

@ -96,21 +96,26 @@ export const Index: NextPage = () => {
</Box>
<Box>
<ul css={listCss}>
<li>Make a good tags list</li>
<li>Add a "copy url" button</li>
<li>Fix "auhor" field in blueprint pages and filter blueprints by user</li>
<li>Add book preview when creating blueprints</li>
<li>Improve modded blueprint support in FBE</li>
<li>Improve blueprint title icon (bbcode) support</li>
<li>Make entity/recipe/item dropdown be based on blueprint data in the site</li>
<li>Add a Wysiwyg editor for descriptions</li>
<li>Change thumbnail generation method to be more reliable</li>
<li>Add tag fixing moderators role</li>
<li>Add a landing page on steam sign up to change username before submitting</li>
<li>Add tracking of blueprint views</li>
<li>Add blueprint history</li>
<li className="strike">Add creating new blueprints</li>
<li className="strike">Add search</li>
<li>Add a landing page on steam sign up to change username before submitting</li>
<li>Add book preview when creating blueprints</li>
<li className="strike">Add blueprint tags</li>
<li className="strike">Expand search with tags</li>
<li>Add tracking of blueprint views</li>
<li className="strike">Add favorites</li>
<li className="strike">Add sorting by views/favorites</li>
<li className="strike">Add thumbnails</li>
<li>Change thumbnail generation method to be more reliable</li>
<li>Add tag fixing moderators</li>
<li>Improve modded blueprint support</li>
<li>Add blueprint title icon support</li>
<li>Add blueprint history</li>
<li className="strike">
Add search filter for blueprint entities/recipes without manual tagging
</li>

View File

@ -9,6 +9,8 @@ import { parseDatabaseError } from "../../../utils/api.utils";
import { apiHandler } from "../../../utils/api-handler";
const handler = apiHandler(async (req, res, { session }) => {
if (req.method !== "POST") return res.status(400).json({ error: "method must be POST" });
if (!session) {
return res.status(401).json({ status: "Not authenticated" });
}
@ -70,3 +72,11 @@ const handler = apiHandler(async (req, res, { session }) => {
});
export default handler;
export const config = {
api: {
bodyParser: {
sizeLimit: "2mb",
},
},
};

View File

@ -4,6 +4,8 @@ import { parseDatabaseError } from "../../../utils/api.utils";
import { apiHandler } from "../../../utils/api-handler";
const handler = apiHandler(async (req, res, { session }) => {
if (req.method !== "POST") return res.status(400).json({ error: "method must be POST" });
if (!session) {
return res.status(401).json({ status: "Not authenticated" });
}

View File

@ -16,9 +16,11 @@ const handler: NextApiHandler = apiHandler(async (req, res) => {
const blueprintImageRequestTopic = getBlueprintImageRequestTopic();
if (blueprintPage.blueprint_id) {
blueprintImageRequestTopic.publishJSON({
blueprintId: blueprintPage.blueprint_id,
});
if (blueprintImageRequestTopic) {
blueprintImageRequestTopic.publishJSON({
blueprintId: blueprintPage.blueprint_id,
});
}
return res.json({ blueprint_id: blueprintPage.blueprint_id });
} else if (blueprintPage.blueprint_book_id) {
const blueprintBook = await getBlueprintBookById(blueprintPage.blueprint_book_id);
@ -26,9 +28,11 @@ const handler: NextApiHandler = apiHandler(async (req, res) => {
const firstBlueprintId = getFirstBlueprintFromChildTree(blueprintBook.child_tree);
const firstBlueprint = await getBlueprintById(firstBlueprintId);
if (!firstBlueprint) throw new ApiError(500, "Failed to find blueprint");
blueprintImageRequestTopic.publishJSON({
blueprintId: firstBlueprintId,
});
if (blueprintImageRequestTopic) {
blueprintImageRequestTopic.publishJSON({
blueprintId: firstBlueprintId,
});
}
return res.json({ blueprint_id: firstBlueprintId });
}
});

View File

@ -0,0 +1,63 @@
import { NextApiHandler } from "next";
import { getBlueprintPageById, getBlueprintStringByHash, prisma } from "@factorio-sites/database";
import { parseBlueprintString } from "@factorio-sites/node-utils";
import { apiHandler, ApiError } from "../../../utils/api-handler";
import { ChildTree } from "@factorio-sites/types";
const validateBlueprintBook = async (blueprint_book_id: string) => {
const book = await prisma.blueprint_book.findUnique({
where: { id: blueprint_book_id },
include: {
blueprint_books: true,
blueprints: true,
},
});
if (!book) return false;
const string = await getBlueprintStringByHash(book.blueprint_hash);
if (!string) {
throw new ApiError(500, "failed to fetch string", { id: book.id, hash: book.blueprint_hash });
}
const { data } = await parseBlueprintString(string);
if (!data.blueprint_book || !book.child_tree) return;
const child_tree = (book.child_tree as unknown) as ChildTree;
data.blueprint_book?.blueprints.forEach((data_bp, index) => {
console.log(data_bp);
console.log(child_tree[index]);
});
return true;
};
const DISABLED = true;
const handler: NextApiHandler = apiHandler(async (req, res) => {
if (DISABLED) throw new ApiError(400, "disabled");
if (!req.query.id) throw new ApiError(400, "No id in query");
if (!req.query.type) throw new ApiError(400, "No type in query");
if (req.query.type === "page") {
const blueprintPage = await getBlueprintPageById(req.query.id as string);
if (!blueprintPage) return res.status(404).json({ error: "Blueprint page not found" });
console.log(`Validate page ${blueprintPage.id}`);
if (blueprintPage.blueprint_id) {
return res.json({ valid: true });
}
if (blueprintPage.blueprint_book_id) {
const valid = await validateBlueprintBook(blueprintPage.blueprint_book_id);
return res.json({ valid });
}
} else if (req.query.type === "book") {
const valid = await validateBlueprintBook(req.query.id as string);
return res.json({ valid });
}
return res.json({ valid: true });
});
export default handler;

View File

@ -1,16 +0,0 @@
import { NextApiHandler } from "next";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { init, prisma } from "@factorio-sites/database";
const handler: NextApiHandler = async (_, res) => {
await init();
if (process.env.NODE_ENV === "development") {
const bp = await prisma.blueprint.findFirst({ where: { id: "uuid" } });
console.log({ bp });
}
res.status(200).end("db sync");
};
export default handler;

View File

@ -1,25 +1,40 @@
import { NextApiHandler } from "next";
const BLOCKED_HEADERS = [
"content-encoding",
"connection",
"server",
"transfer-encoding",
"vary",
"report-to",
"nel",
"expect-ct",
"set-cookie",
"cache-control",
"expires",
];
const handler: NextApiHandler = async (req, res) => {
const path = req.query.proxy ? (req.query.proxy as string[]).join("/") : "";
// console.log("[fbe-proxy]", path);
const result = await fetch(
"https://static-fbe.teoxoy.com/file/factorio-blueprint-editor/" + path
);
res.setHeader("Access-Control-Allow-Origin", "*");
result.headers.forEach((val, key) => {
if (
!res.hasHeader(key) &&
!["content-encoding", "connection", "server", "transfer-encoding", "vary"].includes(key)
!BLOCKED_HEADERS.includes(key) &&
!key.startsWith("x-") &&
!key.startsWith("cf-")
) {
res.setHeader(key, val);
}
});
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("cache-control", "max-age=108000");
if (result.headers.get("content-type") === "application/octet-stream") {
const output = Buffer.from(await result.arrayBuffer());
res.end(output);

View File

@ -7,11 +7,13 @@ import {
hasBlueprintImage,
} from "@factorio-sites/database";
import { Blueprint } from "@factorio-sites/types";
import { apiHandler } from "../../utils/api-handler";
const DISABLED = true;
const getOneMessage = async (): Promise<Blueprint> => {
const topic = getBlueprintImageRequestTopic();
if (!topic) throw Error("Pubsub TOPIC not found");
const [subscription] = await topic
.subscription("blueprint-image-function-app", {
flowControl: { allowExcessMessages: false, maxMessages: 1 },
@ -44,7 +46,7 @@ const getOneMessage = async (): Promise<Blueprint> => {
});
};
const handler: NextApiHandler = async (req, res) => {
const handler: NextApiHandler = apiHandler(async (req, res) => {
if (DISABLED) return res.status(400).send("Method not availablee");
// Allow the url to be used in the blueprint editor
@ -67,6 +69,6 @@ const handler: NextApiHandler = async (req, res) => {
string: string,
})
);
};
});
export default handler;

View File

@ -7,6 +7,7 @@ import {
import { NextApiHandler } from "next";
import { fetchSteamProfile, steamAuthenticate } from "../../../utils/openid_steam";
import { setUserToken } from "@factorio-sites/node-utils";
import { apiHandler } from "../../../utils/api-handler";
export const COOKIE_SESSION_NAME = "session-token";
export const COOKIE_SESSION_OPTIONS = {
@ -16,13 +17,11 @@ export const COOKIE_SESSION_OPTIONS = {
sameSite: "strict" as const,
};
const handler: NextApiHandler = async (req, res) => {
const handler: NextApiHandler = apiHandler(async (req, res, { ip, useragent, url }) => {
console.log({ return_url: req.url });
if (!req.url) return;
const steam_id = await steamAuthenticate(req.url);
const ip = (req.headers["x-forwarded-for"] || (req as any).ip) as string;
const useragent = req.headers["user-agent"] as string;
const steam_id = await steamAuthenticate(req.url, url);
console.log({ steam_id, useragent, ip });
await init();
@ -52,9 +51,9 @@ const handler: NextApiHandler = async (req, res) => {
res.setHeader("content-type", "text/html");
return res.status(200).end(`
<html><head>
<meta http-equiv="refresh" content="0;url=${process.env.BASE_URL}" />
<meta http-equiv="refresh" content="0;url=/" />
</head></html>
`);
};
});
export default handler;

View File

@ -2,21 +2,24 @@ import { NextApiHandler } from "next";
import cookie from "cookie";
import { getSteamRedirectUrl } from "../../../utils/openid_steam";
import { COOKIE_SESSION_NAME } from "./return";
import { apiHandler, ApiError } from "../../../utils/api-handler";
const handler: NextApiHandler = async (req, res) => {
const handler: NextApiHandler = apiHandler(async (req, res, { url }) => {
try {
const cookies = cookie.parse(req.headers.cookie || "");
if (cookies[COOKIE_SESSION_NAME]) {
return res.status(400).json({ error: "User already logged in" });
throw new ApiError(400, "User already logged in");
}
const url = await getSteamRedirectUrl();
res.setHeader("location", url);
const steam_url = await getSteamRedirectUrl(url);
res.setHeader("location", steam_url);
res.status(302).end();
} catch (reason) {
console.error("creating steam redirect failed", reason);
res.status(500).end("Failed to authenticate with steam, please go back and try again.");
throw new ApiError(500, "Failed to authenticate with steam, please go back and try again.");
}
};
});
export default handler;

View File

@ -1,20 +1,17 @@
import { NextApiHandler } from "next";
import { getBlueprintStringByHash } from "@factorio-sites/database";
import { apiHandler } from "../../../utils/api-handler";
const handler: NextApiHandler = async (req, res) => {
const handler: NextApiHandler = apiHandler(async (req, res) => {
if (!req.query.hash) {
return res.status(400).end("No string hash provided");
}
const blueprintString = await getBlueprintStringByHash(req.query.hash as string);
// Allow the url to be used in the blueprint editor
if (req.headers.origin === "https://teoxoy.github.io") {
res.setHeader("Access-Control-Allow-Origin", "https://teoxoy.github.io");
}
res.setHeader("Cache-Control", "public, max-age=86400");
res.setHeader("Content-Type", "text/plain");
res.status(200).end(blueprintString);
};
});
export default handler;

Some files were not shown because too many files have changed in this diff Show More