mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
192 lines
5.5 KiB
TypeScript
192 lines
5.5 KiB
TypeScript
import type { Control } from "@clusterio/web_ui";
|
|
import {
|
|
GetChartTagsRequest,
|
|
GetPlayerPathRequest,
|
|
GetRawRecipeTileRequest,
|
|
GetRawTileRequest,
|
|
type TileDataEvent,
|
|
type ChartTagDataEvent,
|
|
type RecipeDataEvent,
|
|
type PlayerPositionEvent,
|
|
} from "../../messages";
|
|
import type {
|
|
ChartTagDataWithInstance,
|
|
MinimapActiveView,
|
|
MinimapDataSource,
|
|
MinimapViewBounds,
|
|
} from "../minimap-data-source";
|
|
|
|
interface MinimapWebPlugin {
|
|
setInstanceSurfaceFilters?(filters: Array<{ instanceId: number; surface: string }> | null): Promise<void> | void;
|
|
setInstanceSurfaceFilter?(instanceId: number | null, surface: string | null): Promise<void> | void;
|
|
onTileUpdate(callback: (event: TileDataEvent) => void): void;
|
|
offTileUpdate(callback: (event: TileDataEvent) => void): void;
|
|
onChartTagUpdate(callback: (event: ChartTagDataEvent) => void): void;
|
|
offChartTagUpdate(callback: (event: ChartTagDataEvent) => void): void;
|
|
onRecipeUpdate(callback: (event: RecipeDataEvent) => void): void;
|
|
offRecipeUpdate(callback: (event: RecipeDataEvent) => void): void;
|
|
onPlayerPositionUpdate(callback: (event: PlayerPositionEvent) => void): void;
|
|
offPlayerPositionUpdate(callback: (event: PlayerPositionEvent) => void): void;
|
|
}
|
|
|
|
const decodeBase64ToBytes = (base64: string): Uint8Array => {
|
|
const binary = atob(base64);
|
|
const bytes = new Uint8Array(binary.length);
|
|
for (let i = 0; i < binary.length; i++) {
|
|
bytes[i] = binary.charCodeAt(i);
|
|
}
|
|
return bytes;
|
|
};
|
|
|
|
export class SingleInstanceDataSource implements MinimapDataSource {
|
|
private control: Control;
|
|
private plugin: MinimapWebPlugin | null = null;
|
|
private instanceId: number | null = null;
|
|
private surface = "nauvis";
|
|
private force = "player";
|
|
private activeInstances: number[] = [];
|
|
|
|
constructor(control: Control) {
|
|
this.control = control;
|
|
this.plugin = control.plugins.get("minimap") as MinimapWebPlugin | undefined ?? null;
|
|
}
|
|
|
|
setInstance(instanceId: number | null): void {
|
|
this.instanceId = instanceId;
|
|
this.updateFilters();
|
|
}
|
|
|
|
setSurfaceForce(surface: string, force: string): void {
|
|
this.surface = surface;
|
|
this.force = force;
|
|
this.updateFilters();
|
|
}
|
|
|
|
setActiveView(_bounds: MinimapViewBounds): MinimapActiveView {
|
|
const nextActive = this.instanceId !== null ? [this.instanceId] : [];
|
|
const changed = nextActive.length !== this.activeInstances.length
|
|
|| nextActive.some((id, index) => id !== this.activeInstances[index]);
|
|
if (changed) {
|
|
this.activeInstances = nextActive;
|
|
}
|
|
return { changed, activeInstanceIds: [...this.activeInstances] };
|
|
}
|
|
|
|
isReady(): boolean {
|
|
return this.instanceId !== null;
|
|
}
|
|
|
|
async getTileData(tileX: number, tileY: number, tick?: number | null): Promise<Uint8Array | null> {
|
|
if (this.instanceId === null) {
|
|
return null;
|
|
}
|
|
const response = await this.control.send(new GetRawTileRequest(
|
|
this.instanceId,
|
|
this.surface,
|
|
this.force,
|
|
tileX,
|
|
tileY,
|
|
tick ?? undefined,
|
|
));
|
|
if (!response.tile_data) {
|
|
return null;
|
|
}
|
|
return decodeBase64ToBytes(response.tile_data);
|
|
}
|
|
|
|
async getRecipeTileData(tileX: number, tileY: number, tick?: number | null): Promise<Uint8Array | null> {
|
|
if (this.instanceId === null) {
|
|
return null;
|
|
}
|
|
const response = await this.control.send(new GetRawRecipeTileRequest(
|
|
this.instanceId,
|
|
this.surface,
|
|
this.force,
|
|
tileX,
|
|
tileY,
|
|
tick ?? undefined,
|
|
));
|
|
if (!response.recipe_tile) {
|
|
return null;
|
|
}
|
|
return decodeBase64ToBytes(response.recipe_tile);
|
|
}
|
|
|
|
async getChartTags(): Promise<ChartTagDataWithInstance[]> {
|
|
if (this.instanceId === null) {
|
|
return [];
|
|
}
|
|
const response = await this.control.send(new GetChartTagsRequest(
|
|
this.instanceId,
|
|
this.surface,
|
|
this.force,
|
|
));
|
|
return response.chart_tags.map(tag => ({
|
|
...tag,
|
|
instance_id: this.instanceId as number,
|
|
}));
|
|
}
|
|
|
|
async getPlayerPaths(): Promise<Array<{ instanceId: number; data: Uint8Array }>> {
|
|
if (this.instanceId === null) {
|
|
return [];
|
|
}
|
|
const response = await this.control.send(new GetPlayerPathRequest(
|
|
this.instanceId,
|
|
this.surface,
|
|
));
|
|
if (!response.positions) {
|
|
return [];
|
|
}
|
|
return [{ instanceId: this.instanceId, data: decodeBase64ToBytes(response.positions) }];
|
|
}
|
|
|
|
onTileUpdate(callback: (event: TileDataEvent) => void): () => void {
|
|
this.plugin?.onTileUpdate(callback);
|
|
return () => {
|
|
this.plugin?.offTileUpdate(callback);
|
|
};
|
|
}
|
|
|
|
onChartTagUpdate(callback: (event: ChartTagDataEvent) => void): () => void {
|
|
this.plugin?.onChartTagUpdate(callback);
|
|
return () => {
|
|
this.plugin?.offChartTagUpdate(callback);
|
|
};
|
|
}
|
|
|
|
onRecipeUpdate(callback: (event: RecipeDataEvent) => void): () => void {
|
|
this.plugin?.onRecipeUpdate(callback);
|
|
return () => {
|
|
this.plugin?.offRecipeUpdate(callback);
|
|
};
|
|
}
|
|
|
|
onPlayerPositionUpdate(callback: (event: PlayerPositionEvent) => void): () => void {
|
|
this.plugin?.onPlayerPositionUpdate(callback);
|
|
return () => {
|
|
this.plugin?.offPlayerPositionUpdate(callback);
|
|
};
|
|
}
|
|
|
|
private updateFilters() {
|
|
if (!this.plugin) {
|
|
return;
|
|
}
|
|
if (this.instanceId === null) {
|
|
if (this.plugin.setInstanceSurfaceFilters) {
|
|
this.plugin.setInstanceSurfaceFilters(null);
|
|
} else if (this.plugin.setInstanceSurfaceFilter) {
|
|
this.plugin.setInstanceSurfaceFilter(null, null);
|
|
}
|
|
return;
|
|
}
|
|
const filters = [{ instanceId: this.instanceId, surface: this.surface }];
|
|
if (this.plugin.setInstanceSurfaceFilters) {
|
|
this.plugin.setInstanceSurfaceFilters(filters);
|
|
} else if (this.plugin.setInstanceSurfaceFilter) {
|
|
this.plugin.setInstanceSurfaceFilter(this.instanceId, this.surface);
|
|
}
|
|
}
|
|
}
|