Files

465 lines
12 KiB
TypeScript

import { Type, Static } from "@sinclair/typebox";
import * as lib from "@clusterio/lib";
// Define the chart data structure
export const ChartDataSchema = Type.Object({
surface: Type.String(),
force: Type.String(),
chart_data: Type.String(),
});
export type ChartData = Static<typeof ChartDataSchema>;
// Define the SignalID structure (based on Factorio API)
export const SignalIDSchema = Type.Object({
type: Type.Optional(Type.String()), // SignalIDType, nil when reading for "item" type
name: Type.Optional(Type.String()), // Name of the prototype
quality: Type.Optional(Type.String()), // Quality name, defaults to "normal"
});
export type SignalID = Static<typeof SignalIDSchema>;
// Define the chart tag data structure
export const ChartTagDataSchema = Type.Object({
tag_number: Type.Number(),
start_tick: Type.Optional(Type.Number()),
end_tick: Type.Optional(Type.Number()),
force: Type.String(),
surface: Type.String(),
position: Type.Tuple([Type.Number(), Type.Number()]),
text: Type.String(),
icon: Type.Optional(SignalIDSchema),
last_user: Type.Optional(Type.String()),
});
export type ChartTagData = Static<typeof ChartTagDataSchema>;
export const RecipeDataSchema = Type.Object({
start_tick: Type.Optional(Type.Number()),
end_tick: Type.Optional(Type.Number()),
surface: Type.String(),
force: Type.String(),
position: Type.Tuple([Type.Number(), Type.Number()]),
recipe: Type.Optional(Type.String()),
icon: Type.Optional(SignalIDSchema),
});
export type RecipeData = Static<typeof RecipeDataSchema>;
export const PlayerDataSchema = Type.Object({
player_name: Type.String(),
surface: Type.String(),
x: Type.Number(), // tiles
y: Type.Number(), // tiles
sec: Type.Number(), // seconds since map started (⌊tick / 60⌋)
});
export type PlayerData = Static<typeof PlayerDataSchema>;
export const PlayerSessionEndDataSchema = Type.Object({
player_name: Type.String(),
surface: Type.String(),
});
export type PlayerSessionEndData = Static<typeof PlayerSessionEndDataSchema>;
/**
* PlayerPositionEvent: Used for both Factorio Instance -> Controller and Controller -> Web Clients
*
* Contains real-time player position data for live tracking and movement visualization.
* When sent from instance to controller: triggers storage in compressed binary format.
* When sent from controller to web clients: enables real-time player position updates.
*
* Data flow:
* - Lua module -> Instance plugin -> Controller plugin (for persistence)
* - Controller plugin -> Web UI plugin -> Canvas renderer (for live updates)
*/
export class PlayerPositionEvent {
declare ["constructor"]: typeof PlayerPositionEvent;
static type = "event" as const;
static src = ["instance", "controller"] as const;
static dst = ["controller", "control"] as const;
static plugin = "minimap" as const;
static permission = null;
constructor(
public instance_id: number,
public player_data: PlayerData,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"player_data": PlayerDataSchema,
});
static fromJSON(json: Static<typeof PlayerPositionEvent.jsonSchema>) {
return new this(
json.instance_id,
json.player_data
);
}
}
/**
* PlayerSessionEndEvent: Instance -> Controller
*
* Notifies controller that a player session has ended (disconnect).
*/
export class PlayerSessionEndEvent {
declare ["constructor"]: typeof PlayerSessionEndEvent;
static type = "event" as const;
static src = ["instance"] as const;
static dst = ["controller"] as const;
static plugin = "minimap" as const;
static permission = null;
constructor(
public instance_id: number,
public session_data: PlayerSessionEndData,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"session_data": PlayerSessionEndDataSchema,
});
static fromJSON(json: Static<typeof PlayerSessionEndEvent.jsonSchema>) {
return new this(
json.instance_id,
json.session_data
);
}
}
/**
* TileDataEvent: Used for both Factorio Instance -> Controller and Controller -> Web Clients
*
* Contains compressed RGB565 chart data from Factorio's internal mapping system.
* When sent from instance to controller: triggers storage in persistent tile files.
* When sent from controller to web clients: enables real-time minimap updates.
*
* Data flow:
* - Lua module -> Instance plugin -> Controller plugin (for persistence)
* - Controller plugin -> Web UI plugin -> Canvas renderer (for live updates)
*/
export class TileDataEvent {
declare ["constructor"]: typeof TileDataEvent;
static type = "event" as const;
static src = ["instance", "controller"] as const;
static dst = ["controller", "control"] as const;
static plugin = "minimap" as const;
static permission = null;
constructor(
public instance_id: number,
public surface: string,
public force: string,
public x: number,
public y: number,
public tick: number,
public chunk: ChartData,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"surface": Type.String(),
"force": Type.String(),
"x": Type.Number(),
"y": Type.Number(),
"tick": Type.Number(),
"chunk": ChartDataSchema,
});
static fromJSON(json: Static<typeof TileDataEvent.jsonSchema>) {
return new this(
json.instance_id,
json.surface,
json.force,
json.x,
json.y,
json.tick,
json.chunk
);
}
}
/**
* ChartTagDataEvent: Used for both Factorio Instance -> Controller and Controller -> Web Clients
*
* Contains chart tag information from Factorio's map tags.
* When sent from instance to controller: triggers storage for tag history and timelapse.
* When sent from controller to web clients: enables real-time tag updates.
*
* Data flow:
* - Lua module -> Instance plugin -> Controller plugin (for persistence)
* - Controller plugin -> Web UI plugin -> Tag renderer (for live updates)
*/
export class ChartTagDataEvent {
declare ["constructor"]: typeof ChartTagDataEvent;
static type = "event" as const;
static src = ["instance", "controller"] as const;
static dst = ["controller", "control"] as const;
static plugin = "minimap" as const;
static permission = null;
constructor(
public instance_id: number,
public tag_data: ChartTagData,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"tag_data": ChartTagDataSchema,
});
static fromJSON(json: Static<typeof ChartTagDataEvent.jsonSchema>) {
return new this(
json.instance_id,
json.tag_data
);
}
}
export class RecipeDataEvent {
declare ["constructor"]: typeof RecipeDataEvent;
static type = "event" as const;
static src = ["instance", "controller"] as const;
static dst = ["controller", "control"] as const;
static plugin = "minimap" as const;
static permission = null;
constructor(
public instance_id: number,
public recipe_data: RecipeData,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"recipe_data": RecipeDataSchema,
});
static fromJSON(json: Static<typeof RecipeDataEvent.jsonSchema>) {
return new this(
json.instance_id,
json.recipe_data
);
}
}
/**
* GetRawTileRequest: Request raw tile data from controller storage
*
* Returns base64-encoded tile data that can be processed in timelapse mode
* or for initial tile loading when canvas minimap starts up.
*/
export class GetRawTileRequest {
declare ["constructor"]: typeof GetRawTileRequest;
static type = "request" as const;
static src = "control" as const;
static dst = "controller" as const;
static plugin = "minimap" as const;
static permission = "minimap.view";
constructor(
public instance_id: number,
public surface: string,
public force: string,
public tile_x: number,
public tile_y: number,
public tick?: number,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"surface": Type.String(),
"force": Type.String(),
"tile_x": Type.Number(),
"tile_y": Type.Number(),
"tick": Type.Optional(Type.Number()),
});
static fromJSON(json: Static<typeof GetRawTileRequest.jsonSchema>) {
return new this(
json.instance_id,
json.surface,
json.force,
json.tile_x,
json.tile_y,
json.tick
);
}
static Response = lib.plainJson(Type.Object({
"tile_data": Type.Union([Type.String(), Type.Null()]), // Base64 encoded tile file or null if not found
}));
}
export class ClearMinimapSurfaceDataRequest {
declare ["constructor"]: typeof ClearMinimapSurfaceDataRequest;
static type = "request" as const;
static src = "control" as const;
static dst = "controller" as const;
static plugin = "minimap" as const;
static permission = "minimap.manage";
constructor(
public instance_id: number,
public surface: string,
public force?: string,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"surface": Type.String(),
"force": Type.Optional(Type.String()),
});
static fromJSON(json: Static<typeof ClearMinimapSurfaceDataRequest.jsonSchema>) {
return new this(
json.instance_id,
json.surface,
json.force
);
}
static Response = lib.plainJson(Type.Object({
"success": Type.Boolean(),
}));
}
export class ClearMinimapDataRequest {
declare ["constructor"]: typeof ClearMinimapDataRequest;
static type = "request" as const;
static src = "control" as const;
static dst = "controller" as const;
static plugin = "minimap" as const;
static permission = "minimap.manage";
static jsonSchema = Type.Object({});
static fromJSON(_: Static<typeof ClearMinimapDataRequest.jsonSchema>) {
return new this();
}
static Response = lib.plainJson(Type.Object({
"success": Type.Boolean(),
}));
}
/**
* GetChartTagsRequest: Request existing chart tags from controller storage
*
* Returns all saved chart tags for a specific instance/surface/force combination.
* Used to load existing chart tags when the web UI starts up or selection changes.
*/
export class GetChartTagsRequest {
declare ["constructor"]: typeof GetChartTagsRequest;
static type = "request" as const;
static src = "control" as const;
static dst = "controller" as const;
static plugin = "minimap" as const;
static permission = "minimap.view";
constructor(
public instance_id: number,
public surface: string,
public force: string,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"surface": Type.String(),
"force": Type.String(),
});
static fromJSON(json: Static<typeof GetChartTagsRequest.jsonSchema>) {
return new this(
json.instance_id,
json.surface,
json.force
);
}
static Response = lib.plainJson(Type.Object({
"chart_tags": Type.Array(ChartTagDataSchema),
}));
}
export class GetRawRecipeTileRequest {
declare ["constructor"]: typeof GetRawRecipeTileRequest;
static type = "request" as const;
static src = "control" as const;
static dst = "controller" as const;
static plugin = "minimap" as const;
static permission = "minimap.view";
constructor(
public instance_id: number,
public surface: string,
public force: string,
public tile_x: number,
public tile_y: number,
public tick?: number,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"surface": Type.String(),
"force": Type.String(),
"tile_x": Type.Number(),
"tile_y": Type.Number(),
"tick": Type.Optional(Type.Number()),
});
static fromJSON(json: Static<typeof GetRawRecipeTileRequest.jsonSchema>) {
return new this(
json.instance_id,
json.surface,
json.force,
json.tile_x,
json.tile_y,
json.tick
);
}
static Response = lib.plainJson(Type.Object({
"recipe_tile": Type.Union([Type.String(), Type.Null()]),
}));
}
/**
* GetPlayerPathRequest: Request compressed historical player path data from controller storage
*
* Returns binary compressed player position data for timeline playback.
* Used to load player movement history when opening timeline or specific player tracking.
*/
export class GetPlayerPathRequest {
declare ["constructor"]: typeof GetPlayerPathRequest;
static type = "request" as const;
static src = "control" as const;
static dst = "controller" as const;
static plugin = "minimap" as const;
static permission = "minimap.view";
constructor(
public instance_id: number,
public surface: string,
) { }
static jsonSchema = Type.Object({
"instance_id": Type.Number(),
"surface": Type.String(),
});
static fromJSON(json: Static<typeof GetPlayerPathRequest.jsonSchema>) {
return new this(
json.instance_id,
json.surface,
);
}
static Response = lib.plainJson(Type.Object({
"positions": Type.Union([Type.String(), Type.Null()]),
}));
}