From 5208d9affdc8384b0ae1d51d7d096f86a6ca1e67 Mon Sep 17 00:00:00 2001 From: Adam <897017+aSemy@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:51:15 +0100 Subject: [PATCH] - make each event update have a key/data interface - separate .d.ts file for event updates - fix initialisation of global items --- .../events-mod/src/main/typescript/control.ts | 31 +-- .../kafkatorio-schema/object-data.d.ts | 27 +++ .../generated/kafkatorio-schema/schema.d.ts | 93 --------- .../generated/kafkatorio-schema/update.d.ts | 134 +++++++++++++ .../typescript/main/cache/EventDataCache.ts | 84 ++++---- .../typescript/main/cache/cacheChecker.ts | 33 +--- .../main/commands/kafkatorioCommands.ts | 19 +- .../typescript/main/events/eventTypeCheck.ts | 2 +- .../main/typescript/main/events/mapEvents.ts | 27 ++- .../main/events/registerHandlers.ts | 1 + .../src/main/typescript/main/global-init.ts | 15 ++ .../src/main/typescript/main/queue/queue.ts | 31 +-- .../events/schema/factorioEventUpdates.kt | 187 +++++++++++++----- .../adamko/kafkatorio/events/schema/kt2ts.kt | 33 +++- 14 files changed, 451 insertions(+), 266 deletions(-) create mode 100644 modules/events-mod/src/main/typescript/generated/kafkatorio-schema/update.d.ts create mode 100644 modules/events-mod/src/main/typescript/main/global-init.ts diff --git a/modules/events-mod/src/main/typescript/control.ts b/modules/events-mod/src/main/typescript/control.ts index f97e909..13ddeb1 100644 --- a/modules/events-mod/src/main/typescript/control.ts +++ b/modules/events-mod/src/main/typescript/control.ts @@ -1,16 +1,17 @@ import {emitConfigurationUpdate} from "./main/config-update/handleConfigurationUpdate"; import {emitPrototypes} from "./main/config-update/prototypes"; -import {Queue} from "./main/queue/queue"; -import {EventDataCache} from "./main/cache/EventDataCache"; +import {initGlobal} from "./main/global-init"; require("./main/events/registerHandlers") +require("./main/events/playerEvents") +require("./main/events/mapEvents") require("./main/commands/kafkatorioCommands") require("./main/cache/cacheChecker") script.on_configuration_changed((data: ConfigurationChangedData) => { // runs whenever the version of the base game, or a mod, changes - reInitGlobal() + initGlobal(true) emitConfigurationUpdate(data) emitPrototypes() }) @@ -18,27 +19,5 @@ script.on_configuration_changed((data: ConfigurationChangedData) => { script.on_init(() => { // runs only once (when the mod is first added to the save) - initGlobal() + initGlobal(true) }) - - -function initGlobal() { - log("Initialising Kafkatorio Global variables...") - - Queue.init() - EventDataCache.init() - - log("Finished initialising Kafkatorio Global variables") -} - -function reInitGlobal() { - log("Re-initialising Kafkatorio Global variables...") - - global.MOD_VERSION = script.active_mods[script.mod_name] - global.FACTORIO_VERSION = script.active_mods["base"] - - Queue.reset() - EventDataCache.reset() - - log("Finished re-initialising Kafkatorio Global variables") -} diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts index 9313d83..62bb0c4 100644 --- a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts @@ -6,6 +6,33 @@ interface FactorioObjectData { objectName: ObjectName; } +interface PlayerData extends FactorioObjectData, FactorioLuaControl { + associatedCharactersUnitNumbers: uint[]; + characterUnitNumber: uint | null; + chatColour: Colour; + colour: Colour; + force: uint; + lastOnline: uint; + name: string; + objectName: ObjectName; + position: MapEntityPosition; + surface: uint; +} + +interface EntityData extends FactorioObjectData, FactorioLuaControl { + active: boolean; + force: uint; + health: double | null; + healthRatio: double; + name: string; + objectName: ObjectName; + playerIndex: uint | null; + position: MapEntityPosition; + surface: uint; + type: string; + unitNumber: uint | null; +} + interface SurfaceData extends FactorioObjectData { daytime: double; index: uint; diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts index e200e6e..ca76f05 100644 --- a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts @@ -7,19 +7,6 @@ interface KafkatorioPacket { packetType: PacketType; } -type FactorioEventUpdateType = "PLAYER" | "MAP_CHUNK" | "ENTITY"; - -interface FactorioEventUpdate { - updateType: FactorioEventUpdateType; -} - -interface FactorioEventUpdatePacket extends KafkatorioPacket { - modVersion: string; - packetType: PacketType; - tick: uint; - update: FactorioEventUpdate; -} - interface FactorioEvent extends KafkatorioPacket { data: FactorioObjectData; eventType: string; @@ -46,33 +33,6 @@ interface Colour { red: float; } -interface PlayerData extends FactorioObjectData, FactorioLuaControl { - associatedCharactersUnitNumbers: uint[]; - characterUnitNumber: uint | null; - chatColour: Colour; - colour: Colour; - force: uint; - lastOnline: uint; - name: string; - objectName: ObjectName; - position: MapEntityPosition; - surface: uint; -} - -interface EntityData extends FactorioObjectData, FactorioLuaControl { - active: boolean; - force: uint; - health: double | null; - healthRatio: double; - name: string; - objectName: ObjectName; - playerIndex: uint | null; - position: MapEntityPosition; - surface: uint; - type: string; - unitNumber: uint | null; -} - interface MapTilePosition { x: int; y: int; @@ -99,56 +59,3 @@ interface EntityIdentifiers { type: string; unitNumber: uint | null; } - -interface PlayerUpdate extends FactorioEventUpdate { - afkTime: uint | null; - bannedReason: string | null; - characterUnitNumber: uint | null; - chatColour: Colour | null; - colour: Colour | null; - diedCause: EntityIdentifiers | null; - disconnectReason: string | null; - forceIndex: uint | null; - index: uint; - isAdmin: boolean | null; - isConnected: boolean | null; - isRemoved: boolean | null; - isShowOnMap: boolean | null; - isSpectator: boolean | null; - kickedReason: string | null; - lastOnline: uint | null; - name: string | null; - onlineTime: uint | null; - position: MapEntityPosition | null; - surfaceIndex: uint | null; - tag: string | null; - ticksToRespawn: uint | null; - updateType: FactorioEventUpdateType; -} - -interface EntityUpdate extends FactorioEventUpdate, EntityIdentifiers { - chunkPosition: MapChunkPosition | null; - graphicsVariation: number | null; - health: float | null; - isActive: boolean | null; - isRotatable: boolean | null; - lastUser: int | null; - localisedDescription: string | null; - localisedName: string | null; - name: string; - prototype: string | null; - type: string; - unitNumber: uint; - updateType: FactorioEventUpdateType; -} - -interface MapChunkUpdate extends FactorioEventUpdate { - chunkPosition: MapChunkPosition; - force: uint | null; - isDeleted: boolean | null; - player: uint | null; - robot: EntityIdentifiers | null; - surfaceIndex: uint; - tiles: Map | null; - updateType: FactorioEventUpdateType; -} diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/update.d.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/update.d.ts new file mode 100644 index 0000000..1d6898d --- /dev/null +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/update.d.ts @@ -0,0 +1,134 @@ +// Generated by TypeScriptGenerator - do not edit this file manually + +type FactorioEventUpdateType = "PLAYER" | "MAP_CHUNK" | "ENTITY"; + +interface FactorioEventUpdateKey { + updateType: FactorioEventUpdateType; +} + +interface FactorioEventUpdateData { + updateType: FactorioEventUpdateType; +} + +interface FactorioEventUpdate extends FactorioEventUpdateKey, FactorioEventUpdateData { + updateType: FactorioEventUpdateType; +} + +interface FactorioEventUpdatePacket extends KafkatorioPacket { + modVersion: string; + packetType: PacketType; + tick: uint; + update: FactorioEventUpdate; +} + +interface PlayerUpdateKey extends FactorioEventUpdateKey { + index: uint; +} + +interface PlayerUpdateData extends FactorioEventUpdateData { + afkTime: uint | null; + bannedReason: string | null; + characterUnitNumber: uint | null; + chatColour: Colour | null; + colour: Colour | null; + diedCause: EntityIdentifiers | null; + disconnectReason: string | null; + forceIndex: uint | null; + isAdmin: boolean | null; + isConnected: boolean | null; + isRemoved: boolean | null; + isShowOnMap: boolean | null; + isSpectator: boolean | null; + kickedReason: string | null; + lastOnline: uint | null; + name: string | null; + onlineTime: uint | null; + position: MapEntityPosition | null; + surfaceIndex: uint | null; + tag: string | null; + ticksToRespawn: uint | null; +} + +interface PlayerUpdate extends FactorioEventUpdate, PlayerUpdateKey, PlayerUpdateData { + afkTime: uint | null; + bannedReason: string | null; + characterUnitNumber: uint | null; + chatColour: Colour | null; + colour: Colour | null; + diedCause: EntityIdentifiers | null; + disconnectReason: string | null; + forceIndex: uint | null; + index: uint; + isAdmin: boolean | null; + isConnected: boolean | null; + isRemoved: boolean | null; + isShowOnMap: boolean | null; + isSpectator: boolean | null; + kickedReason: string | null; + lastOnline: uint | null; + name: string | null; + onlineTime: uint | null; + position: MapEntityPosition | null; + surfaceIndex: uint | null; + tag: string | null; + ticksToRespawn: uint | null; + updateType: FactorioEventUpdateType; +} + +interface EntityUpdateKey extends EntityIdentifiers, FactorioEventUpdateKey { + name: string; + type: string; + unitNumber: uint; +} + +interface EntityUpdateData extends FactorioEventUpdateData { + chunkPosition: MapChunkPosition | null; + graphicsVariation: number | null; + health: float | null; + isActive: boolean | null; + isRotatable: boolean | null; + lastUser: int | null; + localisedDescription: string | null; + localisedName: string | null; + prototype: string | null; +} + +interface EntityUpdate extends FactorioEventUpdate, EntityIdentifiers, EntityUpdateKey, EntityUpdateData { + chunkPosition: MapChunkPosition | null; + graphicsVariation: number | null; + health: float | null; + isActive: boolean | null; + isRotatable: boolean | null; + lastUser: int | null; + localisedDescription: string | null; + localisedName: string | null; + name: string; + prototype: string | null; + type: string; + unitNumber: uint; + updateType: FactorioEventUpdateType; +} + +interface MapChunkUpdateKey extends FactorioEventUpdateKey { + chunkPosition: MapChunkPosition; + surfaceIndex: uint; +} + +interface MapChunkUpdateData extends FactorioEventUpdateData { + force: uint | null; + isDeleted: boolean | null; + player: uint | null; + robot: EntityIdentifiers | null; + tiles: MapTile[] | null; +} + +interface MapChunkUpdate extends FactorioEventUpdate, MapChunkUpdateKey, MapChunkUpdateData { + chunkPosition: MapChunkPosition; + force: uint | null; + isDeleted: boolean | null; + player: uint | null; + robot: EntityIdentifiers | null; + surfaceIndex: uint; + tiles: MapTile[] | null; + updateType: FactorioEventUpdateType; +} diff --git a/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts b/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts index 4caddfa..a26e5b1 100644 --- a/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts +++ b/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts @@ -1,32 +1,34 @@ -import {ExcludeNullKeys, NonNullableKeys} from "../types"; +import {NonNullableKeys} from "../types"; export namespace EventDataCache { declare const global: { cache: LuaTable, CacheEntry>, - DEFAULT_CACHE_DURATION_TICKS2: Record, + defaultCacheDurationTicks: Record, } - export function reset() { - log("Resetting EventDataCache") - global.cache = new LuaTable, CacheEntry>() - } + export function init(force?: boolean) { + const isAnythingUndefined = global.cache == undefined || + global.defaultCacheDurationTicks == undefined - export function init() { - if (typeof global.cache == undefined) { - log("Initialising EventDataCache") - reset() + log(`Initialising EventDataCache (force=${force}, isAnythingUndefined=${isAnythingUndefined})...`) - global.DEFAULT_CACHE_DURATION_TICKS2 = { - "PLAYER": 30, // 0.5 seconds - "MAP_CHUNK": 60 * 15, // ~ 15 seconds - "ENTITY": 60 * 2, // ~2 seconds - "default": 60 + if (force == true || isAnythingUndefined) { + log("Initialising global.cache") + global.cache = new LuaTable, CacheEntry>() + + log("Initialising global.DEFAULT_CACHE_DURATION_TICKS") + global.defaultCacheDurationTicks = { + "PLAYER": 60, // 1 second + "MAP_CHUNK": 60 * 30, // 30 seconds + "ENTITY": 60 * 2, // 2 seconds + "default": 60 * 5, // 5 seconds } } + log(`Finished initialising EventDataCache`) } @@ -73,7 +75,7 @@ export namespace EventDataCache { */ export function setExpiration( key: CacheKey, - expirationDurationTicks?: uint, + expirationDurationTicks: uint, ) { const entry = getCacheEntry(key) if (entry != undefined) { @@ -82,11 +84,12 @@ export namespace EventDataCache { } - export function extractExpired(): Array> { - const expiredData: Array> = [] + export function extractExpired(): Array { + const expiredData: Array = [] for (let [key, entry] of global.cache) { - if (entry.isExpired()) { - expiredData.push(entry.data) + if (isExpired(entry)) { + const update: FactorioEventUpdate = {...key, ...entry.data} + expiredData.push(update) global.cache.delete(key) } } @@ -114,7 +117,7 @@ export namespace EventDataCache { key: CacheKey, mutate: CacheDataMutator, ): CacheEntry { - // @ts-ignore // TODO remove ts-ignore for "not assignable to type" + // @ts-ignore // TODO resolve ts-ignore for "not assignable to type" const data: CacheData = {updateType: key.updateType} mutate(data) let entry: CacheEntry = new CacheEntry(data) @@ -123,24 +126,35 @@ export namespace EventDataCache { } - /** Map a {@link FactorioEventUpdateType} to a {@link FactorioEventUpdate} DTO */ - type ConvertUpdateType = - TYPE extends "PLAYER" ? PlayerUpdate : - TYPE extends "MAP_CHUNK" ? MapChunkUpdate : - TYPE extends "ENTITY" ? EntityUpdate : + // /** Map a {@link FactorioEventUpdateType} to a {@link FactorioEventUpdate} DTO */ + // type ConvertUpdateType = + // TYPE extends "PLAYER" ? PlayerUpdate : + // TYPE extends "MAP_CHUNK" ? MapChunkUpdate : + // TYPE extends "ENTITY" ? EntityUpdate : + // never + + type ConvertKeyType = + TYPE extends "PLAYER" ? PlayerUpdateKey : + TYPE extends "MAP_CHUNK" ? MapChunkUpdateKey : + TYPE extends "ENTITY" ? EntityUpdateKey : + never + type ConvertKeyData = + TYPE extends "PLAYER" ? PlayerUpdateData : + TYPE extends "MAP_CHUNK" ? MapChunkUpdateData : + TYPE extends "ENTITY" ? EntityUpdateData : never /** Only include the non-null properties, and make `updateType` specific */ export type CacheKey = CacheTyped - & Omit>, "updateType"> + & Omit, "updateType"> /** Exclude {@link CacheKey} fields, and make `updateType` specific */ export type CacheData = CacheTyped - & NonNullableKeys, keyof CacheKey | "updateType">>> + & NonNullableKeys, "updateType">>> export type CacheTyped = { @@ -163,17 +177,15 @@ export namespace EventDataCache { expirationDurationTicks?: uint, ) { this.data = data - if (expirationDurationTicks != undefined) { - this.expirationDurationTicks = expirationDurationTicks - } + this.expirationDurationTicks = expirationDurationTicks } + } - isExpired(): boolean { - const cacheDuration = - this.expirationDurationTicks ?? global.DEFAULT_CACHE_DURATION_TICKS2[this.data.updateType] - return game.tick - this.lastUpdatedTick > cacheDuration - } + function isExpired(entry: CacheEntry): boolean { + const expiryDuration = + entry.expirationDurationTicks ?? global.defaultCacheDurationTicks[entry.data.updateType] + return game.tick - entry.lastUpdatedTick > expiryDuration } diff --git a/modules/events-mod/src/main/typescript/main/cache/cacheChecker.ts b/modules/events-mod/src/main/typescript/main/cache/cacheChecker.ts index 119046d..9a7e056 100644 --- a/modules/events-mod/src/main/typescript/main/cache/cacheChecker.ts +++ b/modules/events-mod/src/main/typescript/main/cache/cacheChecker.ts @@ -4,7 +4,7 @@ import {emitPacket} from "../emitKafkatorioPacket"; /** Every 0.1 seconds */ script.on_nth_tick(6, (nthTick: NthTickEventData) => { - const cachedEvents: Array> = EventDataCache.extractExpired() + const cachedEvents: Array = EventDataCache.extractExpired() if (cachedEvents.length > 0) { log(`nth tick ${nthTick.tick} has ${cachedEvents.length} events`) @@ -22,34 +22,3 @@ script.on_nth_tick(6, (nthTick: NthTickEventData) => { } } }) - -// -// function createEntityUpdate(cacheKey: EntityCacheKey, events: EventName[]): EntityUpdate | null { -// -// -// return null -// } -// -// interface EntityUpdate { -// name: string -// -// unit_number: uint -// -// unhandledEvents?: string[] -// -// chunkPosition: MapChunkPosition -// graphics_variation?: uint8 -// health?: float -// isActive?: boolean -// isRotatable?: boolean -// last_user?: uint -// localised_description?: string -// localised_name?: string -// prototype?: string -// -// // ghost_localised_description?: string -// // ghost_localised_name?: string -// // ghost_name?: string -// // ghost_prototype?: string -// // ghost_unit_number?: uint -// } diff --git a/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts b/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts index 3cc2c79..9b5faba 100644 --- a/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts +++ b/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts @@ -1,5 +1,6 @@ import {emitPrototypes} from "../config-update/prototypes"; import {Queue} from "../queue/queue"; +import {initGlobal} from "../global-init"; import floor = math.floor; @@ -8,18 +9,20 @@ commands.add_command( "kafkatorio innit bruv", (e: CustomCommandData) => { - let player = (e.player_index != null) ? game.get_player(e.player_index) : null + const player = (e.player_index != null) ? game.get_player(e.player_index) : null - if (e.parameter == undefined) { + const paramUppercase = e.parameter?.toUpperCase() + + if (paramUppercase == undefined) { if (player != null) { player.print("no parameter") } // do nothing - } else if ("PROTOTYPES" == e.parameter.toUpperCase()) { + } else if ("PROTOTYPES" == paramUppercase) { emitPrototypes() - } else if (e.parameter.toUpperCase().startsWith("CHUNKS")) { + } else if (paramUppercase.startsWith("CHUNKS")) { - let size = e.parameter.split(" ")?.[1] ?? null + let size = paramUppercase.split(" ")?.[1] ?? null let radius = (size != null) ? parseInt(size) : 1 if (e.player_index != undefined) { @@ -60,10 +63,8 @@ commands.add_command( } } } - } else if ("QUEUE_RESET" == e.parameter.toUpperCase()) { - Queue.reset() - } else if ("QUEUE_INIT" == e.parameter.toUpperCase()) { - Queue.init() + } else if (paramUppercase.startsWith("INIT_GLOBAL")) { + initGlobal(paramUppercase.startsWith("INIT_GLOBAL FORCE")) } } ) diff --git a/modules/events-mod/src/main/typescript/main/events/eventTypeCheck.ts b/modules/events-mod/src/main/typescript/main/events/eventTypeCheck.ts index e3769f2..4321eb3 100644 --- a/modules/events-mod/src/main/typescript/main/events/eventTypeCheck.ts +++ b/modules/events-mod/src/main/typescript/main/events/eventTypeCheck.ts @@ -1,5 +1,5 @@ -function isEventType( +export function isEventType( eventData: EventData, type: ED extends CustomInputEvent ? string : EventId ): eventData is ED { diff --git a/modules/events-mod/src/main/typescript/main/events/mapEvents.ts b/modules/events-mod/src/main/typescript/main/events/mapEvents.ts index 5744703..bb8b58c 100644 --- a/modules/events-mod/src/main/typescript/main/events/mapEvents.ts +++ b/modules/events-mod/src/main/typescript/main/events/mapEvents.ts @@ -1,4 +1,5 @@ import {EventDataCache} from "../cache/EventDataCache"; +import {isEventType} from "./eventTypeCheck"; import CacheKey = EventDataCache.CacheKey; import CacheData = EventDataCache.CacheData; @@ -24,12 +25,17 @@ function mapTilesUpdateDebounce( }, data => { if (data.tiles == undefined) { - data.tiles = new Map() + data.tiles = [] } for (const tile of tiles) { - const position: MapTilePosition = {x: tile.position.x, y: tile.position.y} - data.tiles.set(position, tile.name) + data.tiles.push( + { + x: tile.position.x, + y: tile.position.y, + proto: tile.name, + } + ) } if (updater != undefined) { @@ -58,6 +64,8 @@ function getSurface(surfaceIndex: uint): LuaSurface | undefined { script.on_event( defines.events.on_chunk_generated, (e: OnChunkGeneratedEvent) => { + log(`on_chunk_generated ${e.tick}`) + let tiles = getTiles(e.surface, e.area) mapTilesUpdateDebounce(e.surface, e.position, tiles) } @@ -66,6 +74,7 @@ script.on_event( script.on_event( defines.events.on_chunk_charted, (e: OnChunkChartedEvent) => { + log(`on_chunk_charted ${e.tick}`) const surface = getSurface(e.surface_index) if (surface == undefined) { @@ -82,6 +91,7 @@ script.on_event( script.on_event( defines.events.script_raised_set_tiles, (e: ScriptRaisedSetTilesEvent) => { + log(`script_raised_set_tiles ${e.tick}`) const surface = getSurface(e.surface_index) if (surface == undefined) { @@ -164,8 +174,14 @@ function onBuildTileEvent(event: OnPlayerBuiltTileEvent | OnRobotBuiltTileEvent) } } -script.on_event(defines.events.on_player_built_tile, (e: OnPlayerBuiltTileEvent) => onBuildTileEvent(e)) -script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) => onBuildTileEvent(e)) +script.on_event(defines.events.on_player_built_tile, (e: OnPlayerBuiltTileEvent) => { + log(`on_player_built_tile ${e.tick}`) + onBuildTileEvent(e) +}) +script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) => { + log(`on_robot_built_tile ${e.tick}`) + onBuildTileEvent(e) +}) // script.on_event( // defines.events.on_player_mined_tile, @@ -187,6 +203,7 @@ script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) = script.on_event( defines.events.on_pre_chunk_deleted, (e: OnPreChunkDeletedEvent) => { + log(`on_pre_chunk_deleted ${e.tick}`) const surface = getSurface(e.surface_index) if (surface == undefined) { diff --git a/modules/events-mod/src/main/typescript/main/events/registerHandlers.ts b/modules/events-mod/src/main/typescript/main/events/registerHandlers.ts index 763aae5..d059674 100644 --- a/modules/events-mod/src/main/typescript/main/events/registerHandlers.ts +++ b/modules/events-mod/src/main/typescript/main/events/registerHandlers.ts @@ -7,6 +7,7 @@ import { } from "./handlers"; import {Queue} from "../queue/queue"; import {EventName} from "../types"; +import {isEventType} from "./eventTypeCheck"; const mapEventIdToName = new LuaTable() diff --git a/modules/events-mod/src/main/typescript/main/global-init.ts b/modules/events-mod/src/main/typescript/main/global-init.ts new file mode 100644 index 0000000..920549b --- /dev/null +++ b/modules/events-mod/src/main/typescript/main/global-init.ts @@ -0,0 +1,15 @@ +import {Queue} from "./queue/queue"; +import {EventDataCache} from "./cache/EventDataCache"; + + +export function initGlobal(force: boolean = false) { + log(`Initialising Kafkatorio Global variables (force=${force})...`) + + global.MOD_VERSION = script.active_mods[script.mod_name] + global.FACTORIO_VERSION = script.active_mods["base"] + + Queue.init(true) + EventDataCache.init(true) + + log("Finished initialising Kafkatorio Global variables") +} diff --git a/modules/events-mod/src/main/typescript/main/queue/queue.ts b/modules/events-mod/src/main/typescript/main/queue/queue.ts index 6483642..95fd0cd 100644 --- a/modules/events-mod/src/main/typescript/main/queue/queue.ts +++ b/modules/events-mod/src/main/typescript/main/queue/queue.ts @@ -10,24 +10,27 @@ export namespace Queue { } - export function init() { - if (global.store == undefined) { - log("initialising EventQueue") - reset() + export function init(force?: boolean) { + + const isAnythingUndefined = global.store == undefined || + global.size == undefined || + global.head == undefined || + global.tail == undefined + + log(`Initialising EventQueue globals (force=${force}, isAnythingUndefined=${isAnythingUndefined})`) + + if (force == true || isAnythingUndefined) { + global.store = {} + global.head = null + global.tail = null + global.size = 0 } + + log(`Finished initialising EventQueue`) } - export function reset() { - log("Resetting EventQueue") - global.store = {} - global.head = null - global.tail = null - global.size = 0 - } - - - export function size(): uint { + export function size(): uint | undefined { return global.size } diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt index 61b85bc..c88f0e2 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt @@ -1,5 +1,6 @@ package dev.adamko.kafkatorio.events.schema +import dev.adamko.kafkatorio.events.schema.FactorioEventUpdate.FactorioEventUpdateType import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.EncodeDefault import kotlinx.serialization.Serializable @@ -22,11 +23,24 @@ class FactorioEventUpdatePacket( } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +sealed interface FactorioEventUpdateKey { + val updateType: FactorioEventUpdateType +} + + +sealed interface FactorioEventUpdateData { + val updateType: FactorioEventUpdateType +} + + @Serializable(with = FactorioEventUpdate.Companion.JsonSerializer::class) -sealed class FactorioEventUpdate { +sealed class FactorioEventUpdate : FactorioEventUpdateKey, FactorioEventUpdateData { @EncodeDefault - abstract val updateType: FactorioEventUpdateType + abstract override val updateType: FactorioEventUpdateType @Serializable enum class FactorioEventUpdateType { @@ -61,7 +75,7 @@ sealed class FactorioEventUpdate { return when (type) { FactorioEventUpdateType.PLAYER -> PlayerUpdate.serializer() - FactorioEventUpdateType.MAP_CHUNK -> TODO() + FactorioEventUpdateType.MAP_CHUNK -> MapChunkUpdate.serializer() FactorioEventUpdateType.ENTITY -> EntityUpdate.serializer() } } @@ -71,75 +85,154 @@ sealed class FactorioEventUpdate { } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +sealed interface PlayerUpdateKey : FactorioEventUpdateKey { + val index: PlayerIndex +} + + +sealed interface PlayerUpdateData : FactorioEventUpdateData { + val characterUnitNumber: UnitNumber? + val chatColour: Colour? + val colour: Colour? + val name: String? + + val afkTime: Tick? + val ticksToRespawn: Tick? + val forceIndex: ForceIndex? + val isAdmin: Boolean? + val isConnected: Boolean? + val isShowOnMap: Boolean? + val isSpectator: Boolean? + val lastOnline: Tick? + val onlineTime: Tick? + val position: MapEntityPosition? + val surfaceIndex: SurfaceIndex? + val tag: String? + val diedCause: EntityIdentifiers? + + val bannedReason: String? + val kickedReason: String? + val disconnectReason: String? + /** `true` when a player is removed (deleted) from the game */ + val isRemoved: Boolean? +} + + @Serializable data class PlayerUpdate( - val index: PlayerIndex, + override val index: PlayerIndex, - val characterUnitNumber: UnitNumber? = null, - val chatColour: Colour? = null, - val colour: Colour? = null, - val name: String? = null, + override val characterUnitNumber: UnitNumber? = null, + override val chatColour: Colour? = null, + override val colour: Colour? = null, + override val name: String? = null, - val afkTime: Tick? = null, - val ticksToRespawn: Tick? = null, - val forceIndex: ForceIndex? = null, - val isAdmin: Boolean? = null, - val isConnected: Boolean? = null, - val isShowOnMap: Boolean? = null, - val isSpectator: Boolean? = null, - val lastOnline: Tick? = null, - val onlineTime: Tick? = null, - val position: MapEntityPosition? = null, - val surfaceIndex: SurfaceIndex? = null, - val tag: String? = null, - val diedCause: EntityIdentifiers? = null, + override val afkTime: Tick? = null, + override val ticksToRespawn: Tick? = null, + override val forceIndex: ForceIndex? = null, + override val isAdmin: Boolean? = null, + override val isConnected: Boolean? = null, + override val isShowOnMap: Boolean? = null, + override val isSpectator: Boolean? = null, + override val lastOnline: Tick? = null, + override val onlineTime: Tick? = null, + override val position: MapEntityPosition? = null, + override val surfaceIndex: SurfaceIndex? = null, + override val tag: String? = null, + override val diedCause: EntityIdentifiers? = null, - val bannedReason: String? = null, - val kickedReason: String? = null, - val disconnectReason: String? = null, + override val bannedReason: String? = null, + override val kickedReason: String? = null, + override val disconnectReason: String? = null, /** `true` when a player is removed (deleted) from the game */ - val isRemoved: Boolean? = null, -) : FactorioEventUpdate() { + override val isRemoved: Boolean? = null, +) : FactorioEventUpdate(), PlayerUpdateKey, PlayerUpdateData { @EncodeDefault override val updateType: FactorioEventUpdateType = FactorioEventUpdateType.PLAYER } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +sealed interface EntityUpdateKey : EntityIdentifiers, FactorioEventUpdateKey { + /** A [unitNumber] is required for caching */ + override val unitNumber: UnitNumber + override val name: String + override val type: String +} + +sealed interface EntityUpdateData : FactorioEventUpdateData { + val chunkPosition: MapChunkPosition? + val graphicsVariation: UShort? + val health: Float? + val isActive: Boolean? + val isRotatable: Boolean? + val lastUser: UInt? + val localisedDescription: String? + val localisedName: String? + val prototype: PrototypeName? +} + @Serializable data class EntityUpdate( - /** A [unitNumber] is required for caching */ override val unitNumber: UnitNumber, override val name: String, override val type: String, - val chunkPosition: MapChunkPosition? = null, - val graphicsVariation: UShort? = null, - val health: Float? = null, - val isActive: Boolean? = null, - val isRotatable: Boolean? = null, - val lastUser: UInt? = null, - val localisedDescription: String? = null, - val localisedName: String? = null, - val prototype: PrototypeName? = null, -) : FactorioEventUpdate(), EntityIdentifiers { + override val chunkPosition: MapChunkPosition? = null, + override val graphicsVariation: UShort? = null, + override val health: Float? = null, + override val isActive: Boolean? = null, + override val isRotatable: Boolean? = null, + override val lastUser: UInt? = null, + override val localisedDescription: String? = null, + override val localisedName: String? = null, + override val prototype: PrototypeName? = null, +) : FactorioEventUpdate(), EntityIdentifiers, EntityUpdateKey, EntityUpdateData { @EncodeDefault override val updateType: FactorioEventUpdateType = FactorioEventUpdateType.ENTITY } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +sealed interface MapChunkUpdateKey : FactorioEventUpdateKey { + val chunkPosition: MapChunkPosition + val surfaceIndex: SurfaceIndex +} + + +sealed interface MapChunkUpdateData : FactorioEventUpdateData { + val player: PlayerIndex? + val robot: EntityIdentifiers? + val force: ForceIndex? + /** updated tiles - might be partial */ + val tiles: List? + val isDeleted: Boolean? +} + + @Serializable data class MapChunkUpdate( - val chunkPosition: MapChunkPosition, - val surfaceIndex: SurfaceIndex, + override val chunkPosition: MapChunkPosition, + override val surfaceIndex: SurfaceIndex, - val player: PlayerIndex? = null, - val robot: EntityIdentifiers? = null, - val force: ForceIndex? = null, - - /** Might be a partial list of updated tiles */ - val tiles: Map? = null, - val isDeleted: Boolean? = null, -) : FactorioEventUpdate() { + override val player: PlayerIndex? = null, + override val robot: EntityIdentifiers? = null, + override val force: ForceIndex? = null, + // note: this must be a List, not a Map + // because JSON can't have non-string keys. + override val tiles: List? = null, + override val isDeleted: Boolean? = null, +) : FactorioEventUpdate(), MapChunkUpdateKey, MapChunkUpdateData { @EncodeDefault override val updateType: FactorioEventUpdateType = FactorioEventUpdateType.MAP_CHUNK } + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt b/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt index a19221f..1d5a9cb 100644 --- a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt +++ b/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt @@ -14,12 +14,19 @@ fun main(args: Array) { TypeScriptGenerator( rootClasses = buildSet { addAll(KafkatorioPacket::class.sealedSubclasses) + addAll(FactorioObjectData::class.sealedSubclasses) + addAll(FactorioPrototype::class.sealedSubclasses) add(FactorioPrototypes::class) add(FactorioConfigurationUpdate::class) + + add(FactorioEventUpdatePacket::class) addAll(FactorioEventUpdate::class.sealedSubclasses) + addAll(FactorioEventUpdateKey::class.sealedSubclasses) + addAll(FactorioEventUpdateData::class.sealedSubclasses) + }, mappings = mapOf( // builtin Factorio numeric types > `typed-factorio/generated/builtin-types.d.ts` @@ -66,18 +73,38 @@ private fun splitDefinitions(definitions: String): Map { return definitions .split("\n\n") .groupBy { def -> + + when { - "extends FactorioObjectData " in def || - "interface FactorioObjectData " in def || - "type ObjectName " in def -> "object-data.d.ts" + + "interface FactorioObjectData " in def || + "type ObjectName " in def || + def.contains(Regex("interface.+extends.+(FactorioObjectData).*")) + -> "object-data.d.ts" + "extends FactorioPrototype " in def || "interface FactorioPrototypes " in def || "interface FactorioPrototype " in def || "type PrototypeObjectName " in def -> "prototype.d.ts" + "extends FactorioConfigurationUpdate " in def || "interface FactorioConfigurationUpdate " in def || "FactorioGameDataUpdate " in def || "FactorioModInfo " in def -> "config-update.d.ts" + + "interface FactorioEventUpdatePacket" in def || + "type FactorioEventUpdateType =" in def || + "interface FactorioEventUpdateKey {" in def || + "interface FactorioEventUpdateData {" in def || + def.contains( + Regex( + """ + interface.+extends.+(FactorioEventUpdate|PlayerUpdateKey|PlayerUpdateData).* + """.trimIndent() + ) + ) + -> "update.d.ts" + else -> "schema.d.ts" } }