massive refactor to export entities (buildings and resources)

- minor version bumps
- new Factorio version
- use both prototype name and type to identify a prototype
- kxs-ts-gen: use BrandTyping, but exclude some identifiers
- kxs-ts-gen: manually create zip dist, so it can run after the project compiles
- mod: use typed-factorio strict types
- mod: refactor event handlers to be a little more consistent and object-oriented
This commit is contained in:
Adam 2022-07-05 23:44:23 +02:00
parent 88982d818a
commit 90dc520d22
62 changed files with 2629 additions and 713 deletions

View file

@ -1,14 +1,16 @@
[mod-setting-name]
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-PlayerUpdate=Player update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkUpdate=Map update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkTileUpdate=Map tile update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkEntityUpdate=Entity update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-EntityUpdate=Entity update rate (seconds)
[mod-setting-description]
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-PlayerUpdate=How frequently Player updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (0.25 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkUpdate=How frequently Map updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkTileUpdate=How frequently Map updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkEntityUpdate=How frequently entity updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-EntityUpdate=How frequently Entity updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (5 seconds) is probably fine!

View file

@ -1,7 +1,7 @@
import {initGlobal} from "./main/global-init";
import {emitPrototypes} from "./main/events/prototypeUpdates";
require("./main/events/registerHandlers")
require("./main/events/registerEventListeners")
require("./main/events/mapChunkUpdates")
require("./main/events/playerUpdates")
require("./main/events/entityUpdates")

View file

@ -14,7 +14,8 @@ export type KafkatorioPacketData =
| KafkatorioPacketData.ConsoleCommandUpdate
| KafkatorioPacketData.EntityUpdate
| KafkatorioPacketData.Error
| KafkatorioPacketData.MapChunkUpdate
| KafkatorioPacketData.MapChunkEntityUpdate
| KafkatorioPacketData.MapChunkTileUpdate
| KafkatorioPacketData.PlayerUpdate
| KafkatorioPacketData.PrototypesUpdate
| KafkatorioPacketData.SurfaceUpdate;
@ -27,7 +28,8 @@ export namespace KafkatorioPacketData {
PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate",
SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate",
EntityUpdate = "kafkatorio.packet.keyed.EntityUpdate",
MapChunkUpdate = "kafkatorio.packet.keyed.MapChunkUpdate",
MapChunkEntityUpdate = "kafkatorio.packet.keyed.MapChunkEntityUpdate",
MapChunkTileUpdate = "kafkatorio.packet.keyed.MapChunkTileUpdate",
PlayerUpdate = "kafkatorio.packet.keyed.PlayerUpdate",
Error = "kafkatorio.packet.KafkatorioPacketData.Error",
}
@ -77,12 +79,18 @@ export namespace KafkatorioPacketData {
lastUser?: UInt | null;
localisedDescription?: string | null;
localisedName?: string | null;
prototype?: PrototypeName | null;
}
export interface MapChunkUpdate {
type: KafkatorioPacketData.Type.MapChunkUpdate;
key: MapChunkUpdateKey;
export interface MapChunkEntityUpdate {
type: KafkatorioPacketData.Type.MapChunkEntityUpdate;
key: MapChunkEntityUpdateKey;
events?: { [key: EventName]: Tick[] } | null;
distinctEntities?: { [key: string]: FactorioEntityData } | null;
}
export interface MapChunkTileUpdate {
type: KafkatorioPacketData.Type.MapChunkTileUpdate;
key: MapChunkTileUpdateKey;
events?: { [key: EventName]: Tick[] } | null;
player?: PlayerIndex | null;
robot?: EntityIdentifiersData | null;
@ -132,16 +140,11 @@ export interface ConfigurationUpdateGameData {
newVersion?: string | null;
}
export type PlayerIndex = UInt;
export type SurfaceIndex = UInt;
export type Double = double;
export interface EntityUpdateKey {
unitNumber: UnitNumber;
name: string;
protoType: string;
protoId: PrototypeId;
}
export type MapEntityPosition = [
@ -153,32 +156,33 @@ export type UByte = uint8;
export type Float = float;
export type PrototypeName = string;
export interface MapChunkEntityUpdateKey {
protoId: PrototypeId;
surfaceIndex: SurfaceIndex;
chunkPosition: MapChunkPosition;
}
export interface MapChunkUpdateKey {
export interface MapChunkTileUpdateKey {
chunkPosition: MapChunkPosition;
surfaceIndex: SurfaceIndex;
}
export interface EntityIdentifiersData {
unitNumber?: UnitNumber | null;
name: string;
protoType: string;
protoId: PrototypeId;
}
export type ForceIndex = UInt;
export type ForceIndex = UInt & { __ForceIndex__: void };
export interface MapTileDictionary {
tilesXY: { [key: string]: { [key: string]: PrototypeKey } };
protos: { [key: PrototypeName]: PrototypeKey };
protos: { [key: PrototypeId]: PrototypeKey };
}
export interface PlayerUpdateKey {
index: PlayerIndex;
}
export type UnitNumber = UInt;
export type Colour = [
red: Float,
green: Float,
@ -206,7 +210,7 @@ export namespace FactorioPrototype {
export interface Entity {
type: FactorioPrototype.Type.Entity;
name: PrototypeName;
protoId: PrototypeId;
mapColour: Colour;
protoType: string;
objectName: string;
@ -220,7 +224,7 @@ export namespace FactorioPrototype {
export interface MapTile {
type: FactorioPrototype.Type.MapTile;
name: PrototypeName;
protoId: PrototypeId;
mapColour: Colour;
layer: UInt;
collisionMasks: List;
@ -229,7 +233,9 @@ export namespace FactorioPrototype {
}
}
export type EventName = string;
export type PrototypeId = string & { __PrototypeId__: void };
export type EventName = string & { __EventName__: void };
export type Byte = int8;
@ -238,22 +244,114 @@ export type MapChunkPosition = [
y: Int,
];
export type FactorioEntityData =
| FactorioEntityData.Resource
| FactorioEntityData.Standard;
export namespace FactorioEntityData {
export enum Type {
Resource = "kafkatorio.entity.FactorioEntityData.Resource",
Standard = "kafkatorio.entity.FactorioEntityData.Standard",
}
export interface Resource {
type: FactorioEntityData.Type.Resource;
protoId: PrototypeId;
status?: EntityStatus | null;
position: MapEntityPosition;
amount: UInt;
initialAmount?: UInt | null;
}
export interface Standard {
type: FactorioEntityData.Type.Standard;
protoId: PrototypeId;
status?: EntityStatus | null;
position: MapEntityPosition;
graphicsVariation?: UByte | null;
health?: Float | null;
isActive?: boolean | null;
isRotatable?: boolean | null;
lastUser?: UInt | null;
localisedDescription?: string | null;
localisedName?: string | null;
}
}
export interface MiningProperties {
canBeMined: boolean;
products: MinedProduct[] | null;
}
export type List = any;
export type List = any & { __List__: void };
export type PrototypeKey = Int;
export interface MinedProduct {
type: MinedProductType;
name: PrototypeName;
amount: Double | null;
export enum EntityStatus {
CANT_DIVIDE_SEGMENTS = "CANT_DIVIDE_SEGMENTS",
CHARGING = "CHARGING",
CLOSED_BY_CIRCUIT_NETWORK = "CLOSED_BY_CIRCUIT_NETWORK",
DISABLED = "DISABLED",
DISABLED_BY_CONTROL_BEHAVIOR = "DISABLED_BY_CONTROL_BEHAVIOR",
DISABLED_BY_SCRIPT = "DISABLED_BY_SCRIPT",
DISCHARGING = "DISCHARGING",
FLUID_INGREDIENT_SHORTAGE = "FLUID_INGREDIENT_SHORTAGE",
FULLY_CHARGED = "FULLY_CHARGED",
FULL_OUTPUT = "FULL_OUTPUT",
ITEM_INGREDIENT_SHORTAGE = "ITEM_INGREDIENT_SHORTAGE",
LAUNCHING_ROCKET = "LAUNCHING_ROCKET",
LOW_INPUT_FLUID = "LOW_INPUT_FLUID",
LOW_POWER = "LOW_POWER",
LOW_TEMPERATURE = "LOW_TEMPERATURE",
MARKED_FOR_DECONSTRUCTION = "MARKED_FOR_DECONSTRUCTION",
MISSING_REQUIRED_FLUID = "MISSING_REQUIRED_FLUID",
MISSING_SCIENCE_PACKS = "MISSING_SCIENCE_PACKS",
NETWORKS_CONNECTED = "NETWORKS_CONNECTED",
NETWORKS_DISCONNECTED = "NETWORKS_DISCONNECTED",
NORMAL = "NORMAL",
NOT_CONNECTED_TO_RAIL = "NOT_CONNECTED_TO_RAIL",
NOT_PLUGGED_IN_ELECTRIC_NETWORK = "NOT_PLUGGED_IN_ELECTRIC_NETWORK",
NO_AMMO = "NO_AMMO",
NO_FUEL = "NO_FUEL",
NO_INGREDIENTS = "NO_INGREDIENTS",
NO_INPUT_FLUID = "NO_INPUT_FLUID",
NO_MINABLE_RESOURCES = "NO_MINABLE_RESOURCES",
NO_MODULES_TO_TRANSMIT = "NO_MODULES_TO_TRANSMIT",
NO_POWER = "NO_POWER",
NO_RECIPE = "NO_RECIPE",
NO_RESEARCH_IN_PROGRESS = "NO_RESEARCH_IN_PROGRESS",
OPENED_BY_CIRCUIT_NETWORK = "OPENED_BY_CIRCUIT_NETWORK",
OUT_OF_LOGISTIC_NETWORK = "OUT_OF_LOGISTIC_NETWORK",
PREPARING_ROCKET_FOR_LAUNCH = "PREPARING_ROCKET_FOR_LAUNCH",
RECHARGING_AFTER_POWER_OUTAGE = "RECHARGING_AFTER_POWER_OUTAGE",
TURNED_OFF_DURING_DAYTIME = "TURNED_OFF_DURING_DAYTIME",
WAITING_FOR_SOURCE_ITEMS = "WAITING_FOR_SOURCE_ITEMS",
WAITING_FOR_SPACE_IN_DESTINATION = "WAITING_FOR_SPACE_IN_DESTINATION",
WAITING_FOR_TARGET_TO_BE_BUILT = "WAITING_FOR_TARGET_TO_BE_BUILT",
WAITING_FOR_TRAIN = "WAITING_FOR_TRAIN",
WAITING_TO_LAUNCH_ROCKET = "WAITING_TO_LAUNCH_ROCKET",
WORKING = "WORKING",
}
export enum MinedProductType {
item = "item",
fluid = "fluid",
export type PrototypeKey = Int & { __PrototypeKey__: void };
export type MinedProduct =
| MinedProduct.MinedProductFluid
| MinedProduct.MinedProductItem;
export namespace MinedProduct {
export enum Type {
MinedProductFluid = "kafkatorio.resource.MinedProduct.MinedProductFluid",
MinedProductItem = "kafkatorio.resource.MinedProduct.MinedProductItem",
}
export interface MinedProductFluid {
type: MinedProduct.Type.MinedProductFluid;
amount?: Double | null;
resultProtoId: PrototypeId;
}
export interface MinedProductItem {
type: MinedProduct.Type.MinedProductItem;
amount?: Double | null;
resultProtoId: PrototypeId;
}
}

View file

@ -101,7 +101,7 @@ export namespace EventUpdates {
let countExpired = 0
let countTotal = 0
const expiredData: Array<KafkatorioKeyedPacketData> = []
for (let [key, entry] of global.cache) {
for (const [key, entry] of global.cache) {
countTotal++
if (this.isExpired(entry)) {
countExpired++

View file

@ -23,7 +23,7 @@ script.on_event(
const update: KafkatorioPacketData.ConsoleCommandUpdate = {
type: Type.ConsoleCommandUpdate,
authorPlayerIndex: event.player_index ?? null,
authorPlayerIndex: event.player_index ?? null,
command: event.command,
parameters: event.parameters,
}

View file

@ -1,16 +1,25 @@
import {EventName} from "../types";
import {Colour, MapChunkPosition} from "../../generated/kafkatorio-schema";
import {DefinedEventName} from "../types";
import {
Colour,
EntityStatus,
EventName,
FactorioEntityData,
MapChunkPosition,
PrototypeId,
} from "../../generated/kafkatorio-schema";
export namespace Converters {
const mapEventIdToName = new LuaTable<defines.Events, EventName>()
import floor = math.floor;
const mapEventIdToName = new LuaTable<defines.Events, DefinedEventName>()
for (const [eventName, eventId] of pairs(defines.events)) {
mapEventIdToName.set(eventId, eventName)
}
export function eventNameString(event: defines.Events): EventName {
return mapEventIdToName.get(event)
return mapEventIdToName.get(event) as EventName
}
@ -60,10 +69,115 @@ export namespace Converters {
export function convertCollisionMaskToNames(cm: CollisionMask): string[] {
let masks: string[] = []
for (let [name] of pairs(cm)) {
for (const [name] of pairs(cm)) {
masks.push(name)
}
return masks
}
export function convertResourceEntity(
entity: LuaEntity
): FactorioEntityData.Resource | null {
if (entity.type != "resource") {
return null
} else {
return {
type: FactorioEntityData.Type.Resource,
protoId: prototypeId(entity.type, entity.name),
status: convertEntityStatus(entity.status),
amount: entity.amount,
initialAmount: entity.initial_amount,
position: convertMapTablePosition(entity.position),
}
}
}
function convertEntityStatus(
status: defines.entity_status | undefined
): EntityStatus | null {
if (status == undefined) {
return null
} else {
return EntityStatusRecord[status]
}
}
export function prototypeIdEntity(entity: LuaEntity): PrototypeId {
return prototypeId(entity.type, entity.name)
}
export function prototypeId(type: string, name: string): PrototypeId {
return `${type}/${name}` as PrototypeId
}
export function tilePositionToChunkPosition(mapPosition: TilePositionTable): MapChunkPosition {
return [floor(mapPosition.x / 32), floor(mapPosition.y)]
}
export function mapPositionToChunkPosition(mapPosition: MapPositionTable): MapChunkPosition {
return [floor(mapPosition.x / 32), floor(mapPosition.y)]
}
export function entityStatus(status: defines.entity_status | undefined): EntityStatus | undefined {
if (status == undefined) {
return undefined
} else {
return EntityStatusRecord[status]
}
}
const EntityStatusRecord: Record<defines.entity_status, EntityStatus> = {
//@formatter:off
[ defines.entity_status.cant_divide_segments ]: EntityStatus.CANT_DIVIDE_SEGMENTS,
[ defines.entity_status.charging ]: EntityStatus.CHARGING,
[ defines.entity_status.closed_by_circuit_network ]: EntityStatus.CLOSED_BY_CIRCUIT_NETWORK,
[ defines.entity_status.disabled ]: EntityStatus.DISABLED,
[ defines.entity_status.disabled_by_control_behavior ]: EntityStatus.DISABLED_BY_CONTROL_BEHAVIOR,
[ defines.entity_status.disabled_by_script ]: EntityStatus.DISABLED_BY_SCRIPT,
[ defines.entity_status.discharging ]: EntityStatus.DISCHARGING,
[ defines.entity_status.fluid_ingredient_shortage ]: EntityStatus.FLUID_INGREDIENT_SHORTAGE,
[ defines.entity_status.fully_charged ]: EntityStatus.FULLY_CHARGED,
[ defines.entity_status.full_output ]: EntityStatus.FULL_OUTPUT,
[ defines.entity_status.item_ingredient_shortage ]: EntityStatus.ITEM_INGREDIENT_SHORTAGE,
[ defines.entity_status.launching_rocket ]: EntityStatus.LAUNCHING_ROCKET,
[ defines.entity_status.low_input_fluid ]: EntityStatus.LOW_INPUT_FLUID,
[ defines.entity_status.low_power ]: EntityStatus.LOW_POWER,
[ defines.entity_status.low_temperature ]: EntityStatus.LOW_TEMPERATURE,
[ defines.entity_status.marked_for_deconstruction ]: EntityStatus.MARKED_FOR_DECONSTRUCTION,
[ defines.entity_status.missing_required_fluid ]: EntityStatus.MISSING_REQUIRED_FLUID,
[ defines.entity_status.missing_science_packs ]: EntityStatus.MISSING_SCIENCE_PACKS,
[ defines.entity_status.networks_connected ]: EntityStatus.NETWORKS_CONNECTED,
[ defines.entity_status.networks_disconnected ]: EntityStatus.NETWORKS_DISCONNECTED,
[ defines.entity_status.normal ]: EntityStatus.NORMAL,
[ defines.entity_status.not_connected_to_rail ]: EntityStatus.NOT_CONNECTED_TO_RAIL,
[ defines.entity_status.not_plugged_in_electric_network ]: EntityStatus.NOT_PLUGGED_IN_ELECTRIC_NETWORK,
[ defines.entity_status.no_ammo ]: EntityStatus.NO_AMMO,
[ defines.entity_status.no_fuel ]: EntityStatus.NO_FUEL,
[ defines.entity_status.no_ingredients ]: EntityStatus.NO_INGREDIENTS,
[ defines.entity_status.no_input_fluid ]: EntityStatus.NO_INPUT_FLUID,
[ defines.entity_status.no_minable_resources ]: EntityStatus.NO_MINABLE_RESOURCES,
[ defines.entity_status.no_modules_to_transmit ]: EntityStatus.NO_MODULES_TO_TRANSMIT,
[ defines.entity_status.no_power ]: EntityStatus.NO_POWER,
[ defines.entity_status.no_recipe ]: EntityStatus.NO_RECIPE,
[ defines.entity_status.no_research_in_progress ]: EntityStatus.NO_RESEARCH_IN_PROGRESS,
[ defines.entity_status.opened_by_circuit_network ]: EntityStatus.OPENED_BY_CIRCUIT_NETWORK,
[ defines.entity_status.out_of_logistic_network ]: EntityStatus.OUT_OF_LOGISTIC_NETWORK,
[ defines.entity_status.preparing_rocket_for_launch ]: EntityStatus.PREPARING_ROCKET_FOR_LAUNCH,
[ defines.entity_status.recharging_after_power_outage ]: EntityStatus.RECHARGING_AFTER_POWER_OUTAGE,
[ defines.entity_status.turned_off_during_daytime ]: EntityStatus.TURNED_OFF_DURING_DAYTIME,
[ defines.entity_status.waiting_for_source_items ]: EntityStatus.WAITING_FOR_SOURCE_ITEMS,
[ defines.entity_status.waiting_for_space_in_destination ]: EntityStatus.WAITING_FOR_SPACE_IN_DESTINATION,
[ defines.entity_status.waiting_for_target_to_be_built ]: EntityStatus.WAITING_FOR_TARGET_TO_BE_BUILT,
[ defines.entity_status.waiting_for_train ]: EntityStatus.WAITING_FOR_TRAIN,
[ defines.entity_status.waiting_to_launch_rocket ]: EntityStatus.WAITING_TO_LAUNCH_ROCKET,
[ defines.entity_status.working ]: EntityStatus.WORKING,
//@formatter:on
}
}

View file

@ -1,97 +1,276 @@
import {Converters} from "./converters";
import EventDataCache from "../cache/EventDataCache";
import {
EntityUpdateKey,
KafkatorioPacketData
EventName,
FactorioEntityData,
KafkatorioPacketData,
MapChunkPosition,
PrototypeId,
Tick,
} from "../../generated/kafkatorio-schema";
export class EntityUpdatesHandler {
handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == null) {
return
}
const tilesByChunk: LuaTable<MapChunkPosition, OldTileAndPosition> = new LuaTable<MapChunkPosition, OldTileAndPosition>()
for (const tile of event.tiles) {
const chunkPosition = Converters.tilePositionToChunkPosition(tile.position)
tilesByChunk.set(chunkPosition, tile)
}
for (const [chunkPos, tiles] of pairs(tilesByChunk)) {
const entities: FactorioEntityData.Resource[] = []
for (const tile in tiles) {
const resources: FactorioEntityData.Resource[] = EntityUpdatesHandler.getTileResourceEntities(surface, chunkPos)
for (const resource of resources) {
entities[entities.length] = resource
}
}
EntityUpdatesHandler.throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick as Tick,
event.surface_index,
[chunkPos[0], chunkPos[1]],
entities,
)
}
}
handleMinedEntityEvent(
event: OnPlayerMinedEntityEvent | OnRobotMinedEntityEvent,
) {
EntityUpdatesHandler.throttleEntityUpdate(event, event.entity)
}
handleBuiltEntityEvent(
event: OnBuiltEntityEvent | OnRobotBuiltEntityEvent,
) {
EntityUpdatesHandler.throttleEntityUpdate(event, event.created_entity)
}
handleChunkGeneratedEvent(event: OnChunkGeneratedEvent) {
const entities = EntityUpdatesHandler.getAreaResourceEntities(event.surface, event.area)
EntityUpdatesHandler.throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick as Tick,
event.surface.index,
[event.position.x, event.position.y],
entities,
)
}
private static throttleEntityUpdate(event: EntityUpdateEvent, entity: LuaEntity) {
if (entity.unit_number == undefined) {
// ignore for now - I'm not sure how to track entities without a unit_number
return
}
const eventName = Converters.eventNameString(event.name)
const entityUpdateKey: KafkatorioPacketData.MapChunkEntityUpdate["key"] = {
protoId: Converters.prototypeIdEntity(entity),
surfaceIndex: entity.surface.index,
chunkPosition: Converters.mapPositionToChunkPosition(entity.position)
}
const entityUpdate: FactorioEntityData.Standard = {
type: FactorioEntityData.Type.Standard,
protoId: Converters.prototypeIdEntity(entity),
graphicsVariation: entity.graphics_variation,
health: entity.health,
isActive: entity.active,
isRotatable: entity.rotatable,
lastUser: entity.last_user?.index,
localisedDescription: null,
localisedName: null,
position: [entity.position.x, entity.position.y],
status: Converters.entityStatus(entity.status),
}
const entityKey: string = `${entity.unit_number}`
EventDataCache.throttle<KafkatorioPacketData.MapChunkEntityUpdate>(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
data => {
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
data.distinctEntities ??= {}
data.distinctEntities[entityKey] = entityUpdate
}
)
}
private static throttleResourceEntitiesUpdate(
eventName: EventName,
eventTick: Tick,
surfaceIndex: SurfaceIndex,
chunkPosition: MapChunkPosition,
entities: FactorioEntityData.Resource[],
) {
// first group by prototype ID
const entitiesByProtoId: { [protoId: PrototypeId]: FactorioEntityData.Resource[] } = {}
for (const entity of entities) {
entitiesByProtoId[entity.protoId] ??= []
entitiesByProtoId[entity.protoId].push(entity)
}
for (const [protoId, resourceEntities] of pairs(entitiesByProtoId)) {
// create an update for each prototype
const entityUpdateKey: KafkatorioPacketData.MapChunkEntityUpdate["key"] = {
protoId: protoId,
surfaceIndex: surfaceIndex,
chunkPosition: [chunkPosition[0], chunkPosition[1]],
}
EventDataCache.throttle<KafkatorioPacketData.MapChunkEntityUpdate>(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
data => {
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(eventTick)
for (const entity of resourceEntities) {
const [x, y] = entity.position
const entityKey: string = `${x},${y}`
data.distinctEntities ??= {}
data.distinctEntities[entityKey] = entity
}
}
)
}
}
/** Get all resources on a tile-position */
private static getTileResourceEntities(
surface: LuaSurface,
mapPosition: MapPosition,
): FactorioEntityData.Resource[] {
const rawEntities = surface.find_entities_filtered({
position: mapPosition,
collision_mask: "resource-layer",
}
)
const resources: FactorioEntityData.Resource[] = []
for (const rawEntity of rawEntities) {
const entity = Converters.convertResourceEntity(rawEntity)
if (entity != null) {
resources[resources.length] = entity
}
}
return resources
}
/** Get all resources within a map-area */
private static getAreaResourceEntities(
surface: LuaSurface,
area: BoundingBoxTable,
): FactorioEntityData.Resource[] {
const rawEntities = surface.find_entities_filtered({
area: area,
collision_mask: "resource-layer",
}
)
const resources: FactorioEntityData.Resource[] = []
for (const rawEntity of rawEntities) {
const entity = Converters.convertResourceEntity(rawEntity)
if (entity != null) {
resources[resources.length] = entity
}
}
return resources
}
}
const EntityUpdates = new EntityUpdatesHandler()
export default EntityUpdates
script.on_event(defines.events.on_built_entity, (e: OnBuiltEntityEvent) => {
log(`on_built_entity ${e.tick}`)
handleBuiltEntityEvent(e)
EntityUpdates.handleBuiltEntityEvent(e)
})
script.on_event(defines.events.on_robot_built_entity, (e: OnRobotBuiltEntityEvent) => {
log(`on_robot_built_entity ${e.tick}`)
handleBuiltEntityEvent(e)
EntityUpdates.handleBuiltEntityEvent(e)
})
function handleBuiltEntityEvent(event: OnBuiltEntityEvent | OnRobotBuiltEntityEvent) {
const eventName = Converters.eventNameString(event.name)
if (event.created_entity.unit_number == undefined) {
return
}
const key: EntityUpdateKey = {
name: event.created_entity.name,
protoType: event.created_entity.prototype.name,
unitNumber: event.created_entity.unit_number
}
EventDataCache.debounce<KafkatorioPacketData.EntityUpdate>(
key,
KafkatorioPacketData.Type.EntityUpdate,
data => {
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
data.chunkPosition = Converters.convertMapTablePosition(event.created_entity.position)
data.graphicsVariation = event.created_entity.graphics_variation
data.health = event.created_entity.health
data.isActive = event.created_entity.active
data.isRotatable = event.created_entity.rotatable
data.lastUser = event.created_entity.last_user?.index
data.prototype = event.created_entity.prototype.name
}
)
}
script.on_event(defines.events.on_player_mined_entity, (e: OnPlayerMinedEntityEvent) => {
log(`on_player_mined_entity ${e.tick}`)
handleMinedEntityEvent(e)
EntityUpdates.handleMinedEntityEvent(e)
})
script.on_event(defines.events.on_robot_mined_entity, (e: OnRobotMinedEntityEvent) => {
log(`on_robot_mined_entity ${e.tick}`)
handleMinedEntityEvent(e)
EntityUpdates.handleMinedEntityEvent(e)
})
function handleMinedEntityEvent(event: OnPlayerMinedEntityEvent | OnRobotMinedEntityEvent) {
const eventName = Converters.eventNameString(event.name)
type EntityUpdateEvent =
| OnBuiltEntityEvent
if (event.entity.unit_number == undefined) {
return
}
| OnEntityClonedEvent
| OnEntityDamagedEvent
| OnEntityDestroyedEvent
| OnEntityDiedEvent
| OnEntityLogisticSlotChangedEvent
| OnEntityRenamedEvent
| OnEntitySettingsPastedEvent
| OnEntitySpawnedEvent
const key: EntityUpdateKey = {
name: event.entity.name,
protoType: event.entity.prototype.name,
unitNumber: event.entity.unit_number
}
| OnPlayerMinedEntityEvent
| OnPlayerRepairedEntityEvent
| OnPlayerRotatedEntityEvent
EventDataCache.debounce<KafkatorioPacketData.EntityUpdate>(
key,
KafkatorioPacketData.Type.EntityUpdate,
data => {
| OnRobotMinedEntityEvent
| OnRobotBuiltEntityEvent
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
| OnPostEntityDiedEvent
| OnPreEntitySettingsPastedEvent
data.chunkPosition = Converters.convertMapTablePosition(event.entity.position)
data.graphicsVariation = event.entity.graphics_variation
data.health = event.entity.health
data.isActive = event.entity.active
data.isRotatable = event.entity.rotatable
data.lastUser = event.entity.last_user?.index
data.prototype = event.entity.prototype.name
}
)
}
| OnSelectedEntityChangedEvent
| OnTriggerCreatedEntityEvent

View file

@ -3,129 +3,270 @@ import {Converters} from "./converters";
import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
import {
KafkatorioPacketData,
MapChunkPosition
MapChunkPosition, PrototypeId,
PrototypeKey,
} from "../../generated/kafkatorio-schema";
import EntityUpdates from "./entityUpdates";
import CacheKey = EventUpdates.PacketKey;
import Type = KafkatorioPacketData.Type;
type MapChunkUpdater = (data: KafkatorioPacketData.MapChunkUpdate) => void
type MapChunkTileUpdater = (data: KafkatorioPacketData.MapChunkTileUpdate) => void
type MapTileUpdateEvent =
| OnChunkGeneratedEvent
export type MapTileChangeEvent =
| OnPlayerBuiltTileEvent
| OnPlayerMinedEntityEvent
| OnPlayerMinedTileEvent
| OnRobotBuiltTileEvent
| OnRobotMinedEntityEvent
| OnRobotMinedTileEvent
| ScriptRaisedSetTilesEvent
function mapTilesUpdateDebounce(
surface: LuaSurface | undefined,
chunkPosition: MapChunkPosition,
tiles: TileRead[],
event: MapTileUpdateEvent,
updater?: MapChunkUpdater,
expirationDurationTicks?: uint,
) {
export type MapChunkUpdateEvent =
| OnChunkChartedEvent
| OnChunkDeletedEvent
| OnChunkGeneratedEvent
| OnPreChunkDeletedEvent
if (surface == undefined) {
return
class MapChunkUpdateHandler {
handleChunkGeneratedEvent(
event: OnChunkGeneratedEvent,
expirationDurationTicks?: uint,
) {
const tiles = event.surface.find_tiles_filtered({area: event.area})
MapChunkUpdateHandler.mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
undefined,
expirationDurationTicks,
)
}
const eventName = Converters.eventNameString(event.name)
const key: KafkatorioPacketData.MapChunkUpdate["key"] = {
surfaceIndex: surface.index,
chunkPosition: chunkPosition,
handleBuiltTileEvent(event: OnPlayerBuiltTileEvent | OnRobotBuiltTileEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleBuiltTileEvent] undefined surface ${eventName}`)
return
}
const tiles: TileRead[] = Converters.convertPlacedTiles(event.tile, event.tiles)
const groupedTiles = MapChunkUpdateHandler.groupTiles(tiles)
for (const [chunkPos, tiles] of groupedTiles) {
MapChunkUpdateHandler.mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_built_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_built_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
protoId: Converters.prototypeId(event.robot.type, event.robot.name),
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
}
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkUpdate>(
key,
Type.MapChunkUpdate,
data => {
// tile dictionary update
if (data.tileDictionary == undefined) {
data.tileDictionary = {
tilesXY: {},
protos: {},
}
}
handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleMinedTileEvent] undefined surface ${eventName}`)
return
}
let protosCount: uint = table_size(data.tileDictionary.protos)
for (const tile of tiles) {
data.tileDictionary.protos[tile.name] ??= protosCount++
const tiles: TileRead[] = Converters.convertRemovedTiles(surface, event.tiles)
const groupedTiles = MapChunkUpdateHandler.groupTiles(tiles)
const protoKey = data.tileDictionary.protos[tile.name]
for (const [chunkPos, tiles] of groupedTiles) {
const xString = `${tile.position.x}`
const yString = `${tile.position.y}`
data.tileDictionary.tilesXY[xString] ??= {}
data.tileDictionary.tilesXY[xString][yString] = protoKey
}
// events count update
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
// apply mutator
if (updater != undefined) {
updater(data)
}
},
expirationDurationTicks,
)
}
MapChunkUpdateHandler.mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_mined_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_mined_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
protoId: Converters.prototypeId(event.robot.type, event.robot.name),
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
}
function getTiles(
surface: LuaSurface | undefined,
area: BoundingBoxTable
): LuaTile[] {
return surface?.find_tiles_filtered({
area: area,
// collision_mask: ["ground-tile", "water-tile"]
handleScriptSetTilesEvent(event: ScriptRaisedSetTilesEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == undefined) {
return
}
const groupedTiles = MapChunkUpdateHandler.groupTiles(event.tiles)
for (const [chunkPos, tiles] of groupedTiles) {
MapChunkUpdateHandler.mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
}
}
handlePreChunkDeleted(event: OnPreChunkDeletedEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == undefined) {
return
}
for (const position of event.positions) {
const key: CacheKey<KafkatorioPacketData.MapChunkTileUpdate> = {
surfaceIndex: surface.index,
chunkPosition: [position.x, position.y],
}
) ?? []
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkTileUpdate>(
key,
Type.MapChunkTileUpdate,
data => data.isDeleted = true,
0, // deletion is important - emit ASAP
)
}
}
private static mapTilesUpdateDebounce(
surface: LuaSurface | undefined,
chunkPosition: MapChunkPosition,
tiles: TileRead[],
event: MapChunkUpdateEvent | MapTileChangeEvent,
updater?: MapChunkTileUpdater,
expirationDurationTicks?: uint,
) {
if (surface == undefined) {
return
}
const eventName = Converters.eventNameString(event.name)
const key: KafkatorioPacketData.MapChunkTileUpdate["key"] = {
surfaceIndex: surface.index,
chunkPosition: chunkPosition,
}
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkTileUpdate>(
key,
Type.MapChunkTileUpdate,
data => {
// tile dictionary update
if (data.tileDictionary == undefined) {
data.tileDictionary = {
tilesXY: {},
protos: {},
}
}
let protosCount: uint = table_size(data.tileDictionary.protos)
for (const tile of tiles) {
const protoId = Converters.prototypeId("tile", tile.name)
if (data.tileDictionary.protos[protoId] == null) {
}
data.tileDictionary.protos[protoId] ??= protosCount++ as PrototypeKey
const protoKey = data.tileDictionary.protos[protoId]
const xString = `${tile.position.x}`
const yString = `${tile.position.y}`
data.tileDictionary.tilesXY[xString] ??= {}
data.tileDictionary.tilesXY[xString][yString] = protoKey
}
// events count update
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
// apply mutator
if (updater != undefined) {
updater(data)
}
},
expirationDurationTicks,
)
}
private static groupTiles(tiles: TileRead[]): Map<MapChunkPosition, TileRead[]> {
const mapChunkPositionToTiles = new Map<MapChunkPosition, TileRead[]>()
for (const tile of tiles) {
const chunkPosition: MapChunkPosition = [
math.floor((tile.position.x / 32)),
math.floor((tile.position.y / 32)),
]
if (!mapChunkPositionToTiles.has(chunkPosition)) {
mapChunkPositionToTiles.set(chunkPosition, [])
}
mapChunkPositionToTiles.get(chunkPosition)?.push(tile)
}
return mapChunkPositionToTiles
}
}
function getSurface(surfaceIndex: uint): LuaSurface | undefined {
return game.surfaces[surfaceIndex]
}
const MapChunkUpdate = new MapChunkUpdateHandler()
export default MapChunkUpdate
script.on_event(
defines.events.on_chunk_generated,
(e: OnChunkGeneratedEvent) => {
log(`on_chunk_generated ${e.tick}`)
handleChunkGeneratedEvent(e)
MapChunkUpdate.handleChunkGeneratedEvent(e)
EntityUpdates.handleChunkGeneratedEvent(e)
}
)
export function handleChunkGeneratedEvent(
event: OnChunkGeneratedEvent,
expirationDurationTicks?: uint,
) {
let tiles = getTiles(event.surface, event.area)
mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
undefined,
expirationDurationTicks,
)
}
// script.on_event(
// defines.events.on_chunk_charted,
// (e: OnChunkChartedEvent) => {
@ -144,169 +285,38 @@ export function handleChunkGeneratedEvent(
// )
script.on_event(
defines.events.script_raised_set_tiles,
(event: ScriptRaisedSetTilesEvent) => {
log(`script_raised_set_tiles ${event.tick}`)
const surface = getSurface(event.surface_index)
if (surface == undefined) {
return
}
const groupedTiles = groupTiles(event.tiles)
for (const [chunkPos, tiles] of groupedTiles) {
mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
}
}
)
function groupTiles(tiles: TileRead[]): Map<MapChunkPosition, TileRead[]> {
const mapChunkPositionToTiles = new Map<MapChunkPosition, TileRead[]>()
for (const tile of tiles) {
const chunkPosition: MapChunkPosition = [
math.floor((tile.position.x / 32)),
math.floor((tile.position.y / 32)),
]
if (!mapChunkPositionToTiles.has(chunkPosition)) {
mapChunkPositionToTiles.set(chunkPosition, [])
}
// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1256
mapChunkPositionToTiles.get(chunkPosition)?.push(tile)
// const tiles = mapChunkPositionToTiles.get(chunkPosition)
// if (tiles != null) {
// tiles.push(tile)
// }
}
return mapChunkPositionToTiles
}
script.on_event(defines.events.script_raised_set_tiles, (event: ScriptRaisedSetTilesEvent) => {
log(`script_raised_set_tiles ${event.tick}`)
MapChunkUpdate.handleScriptSetTilesEvent(event)
})
script.on_event(defines.events.on_player_built_tile, (e: OnPlayerBuiltTileEvent) => {
log(`on_player_built_tile ${e.tick}`)
handleBuiltTileEvent(e)
MapChunkUpdate.handleBuiltTileEvent(e)
})
script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) => {
log(`on_robot_built_tile ${e.tick}`)
handleBuiltTileEvent(e)
MapChunkUpdate.handleBuiltTileEvent(e)
})
function handleBuiltTileEvent(event: OnPlayerBuiltTileEvent | OnRobotBuiltTileEvent) {
const surface = getSurface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleBuiltTileEvent] undefined surface ${eventName}`)
return
}
const tiles: TileRead[] = Converters.convertPlacedTiles(event.tile, event.tiles)
const groupedTiles = groupTiles(tiles)
for (const [chunkPos, tiles] of groupedTiles) {
mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_built_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_built_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
name: event.robot.name,
protoType: event.robot.type,
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
}
script.on_event(defines.events.on_player_mined_tile, (e: OnPlayerMinedTileEvent) => {
log(`on_player_mined_tile ${e.tick}`)
handleMinedTileEvent(e)
MapChunkUpdate.handleMinedTileEvent(e)
EntityUpdates.handleMinedTileEvent(e)
})
script.on_event(defines.events.on_robot_mined_tile, (e: OnRobotMinedTileEvent) => {
log(`on_robot_mined_tile ${e.tick}`)
handleMinedTileEvent(e)
MapChunkUpdate.handleMinedTileEvent(e)
})
function handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) {
const surface = getSurface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleMinedTileEvent] undefined surface ${eventName}`)
return
}
const tiles: TileRead[] = Converters.convertRemovedTiles(surface, event.tiles)
const groupedTiles = groupTiles(tiles)
for (const [chunkPos, tiles] of groupedTiles) {
mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_mined_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_mined_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
name: event.robot.name,
protoType: event.robot.type,
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
}
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) {
return
}
for (const position of e.positions) {
const key: CacheKey<KafkatorioPacketData.MapChunkUpdate> = {
surfaceIndex: surface.index,
chunkPosition: [position.x, position.y],
}
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkUpdate>(
key,
Type.MapChunkUpdate,
data => data.isDeleted = true,
0, // deletion is important - emit ASAP
)
}
}
)
script.on_event(defines.events.on_pre_chunk_deleted, (e: OnPreChunkDeletedEvent) => {
log(`on_pre_chunk_deleted ${e.tick}`)
MapChunkUpdate.handlePreChunkDeleted(e)
})

View file

@ -1,11 +1,8 @@
import {Converters} from "./converters";
import EventUpdatesManager from "../cache/EventDataCache";
import {
KafkatorioPacketData,
PlayerUpdateKey
} from "../../generated/kafkatorio-schema";
import Type = KafkatorioPacketData.Type;
import {ForceIndex, KafkatorioPacketData, PlayerUpdateKey} from "../../generated/kafkatorio-schema";
import packetEmitter from "../PacketEmitter";
import Type = KafkatorioPacketData.Type;
type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void
@ -36,7 +33,7 @@ function playerUpdateThrottle(
const eventName = Converters.eventNameString(event.name)
EventUpdatesManager.throttle<KafkatorioPacketData.PlayerUpdate>(
{index: playerIndex},
{index: playerIndex },
Type.PlayerUpdate,
data => {
const player = game.players[playerIndex]
@ -88,7 +85,7 @@ script.on_event(
data.characterUnitNumber = player.character?.unit_number ?? null
data.chatColour = Converters.mapColour(player.chat_color)
data.colour = Converters.mapColour(player.color)
data.forceIndex = player.force.index
data.forceIndex = player.force.index as ForceIndex
data.name = player.name
data.isShowOnMap = player.show_on_map
data.isSpectator = player.spectator
@ -139,8 +136,7 @@ script.on_event(
if (e.cause != undefined) {
data.diedCause = {
unitNumber: e.cause.unit_number ?? null,
name: e.cause.name,
protoType: e.cause.type
protoId: Converters.prototypeId(e.cause.type, e.cause.name),
}
}
}
@ -189,7 +185,7 @@ script.on_event(
log(`on_pre_player_left_game ${event.tick} ${event.name}`)
const playerUpdateKey: PlayerUpdateKey = {
index: event.player_index
index: event.player_index ,
}
const playerUpdate: KafkatorioPacketData.PlayerUpdate = {

View file

@ -26,11 +26,11 @@ function prototypeUpdates(): FactorioPrototype[] {
function getMapTilePrototypes(): FactorioPrototype.MapTile[] {
let tiles: FactorioPrototype.MapTile[] = []
for (let [, tile] of game.tile_prototypes) {
for (const [, tile] of game.tile_prototypes) {
tiles.push({
type: FactorioPrototype.Type.MapTile,
name: tile.name,
protoId: Converters.prototypeId("tile", tile.name),
order: tile.order,
layer: tile.layer,
collisionMasks: Converters.convertCollisionMaskToNames(tile.collision_mask),
@ -44,7 +44,7 @@ function getMapTilePrototypes(): FactorioPrototype.MapTile[] {
// function getEntityPrototypes(): FactorioPrototype.MapTile[] {
// let tiles: FactorioPrototype.MapTile[] = []
// for (let [, tile] of game.tile_prototypes) {
// for (const [, tile] of game.tile_prototypes) {
// tiles.push({
// type: FactorioPrototype.Type.MapTile,
//

View file

@ -1,9 +1,9 @@
import {Queue} from "../queue/queue";
import {isEventType} from "./eventTypeCheck";
import {Converters} from "./converters";
import {handleChunkGeneratedEvent} from "./mapChunkUpdates";
import {handleSurfaceUpdate} from "./surfaceUpdates";
import EventCacheService from "../cache/EventDataCache";
import MapChunkUpdate from "./mapChunkUpdates";
script.on_event(
@ -35,7 +35,7 @@ script.on_event(
let eName = Converters.eventNameString(event.name)
log(`[on_tick:${event.tick}] dequed event ${eName}, delay ${i}`)
handleChunkGeneratedEvent(event, i)
MapChunkUpdate.handleChunkGeneratedEvent(event, i)
i += 1
}
}

View file

@ -0,0 +1,99 @@
// import {isEventType} from "./eventTypeCheck";
// import {Converters} from "./converters";
// import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
// import {
// KafkatorioPacketData,
// MapChunkPosition,
// PrototypeKey,
// } from "../../generated/kafkatorio-schema";
// import CacheKey = EventUpdates.PacketKey;
// import Type = KafkatorioPacketData.Type;
//
//
// export class ResourceEntityUpdatesHandler {
//
//
// handleChunkGeneratedEvent(
// event: OnChunkGeneratedEvent,
// expirationDurationTicks?: uint,
// ) {
// const resourceEntities = this.getAreaResourceEntities(event.surface, event.area)
//
// mapTilesUpdateDebounce(
// event.surface,
// Converters.convertMapTablePosition(event.position),
// tiles,
// event,
// undefined,
// expirationDurationTicks,
// )
// }
//
//
// private resourceEntityUpdatesThrottle(
// surface: LuaSurface | undefined,
// chunkPosition: MapChunkPosition,
// tiles: TileRead[],
// event: MapTileUpdateEvent,
// updater?: MapChunkUpdater,
// expirationDurationTicks?: uint,
// ) {
//
// if (surface == undefined) {
// return
// }
//
// const eventName = Converters.eventNameString(event.name)
//
// const key: KafkatorioPacketData.ResourceEntitiesUpdate["key"] = {
// surfaceIndex: surface.index as SurfaceIndex,
// chunkPosition: chunkPosition,
// }
//
// EventUpdatesManager.throttle<KafkatorioPacketData.ResourceEntitiesUpdate>(
// key,
// Type.MapChunkUpdate,
// data => {
//
// // tile dictionary update
// if (data.tileDictionary == undefined) {
// data.tileDictionary = {
// tilesXY: {},
// protos: {},
// }
// }
//
// let protosCount: uint = table_size(data.tileDictionary.protos)
// for (const tile of tiles) {
// const tileName = tile.name as PrototypeIdMapTile
// const protoKey = protosCount++ as PrototypeKey
// data.tileDictionary.protos[tileName] ??= protoKey
//
// const xString = `${tile.position.x}`
// const yString = `${tile.position.y}`
//
// data.tileDictionary.tilesXY[xString] ??= {}
// data.tileDictionary.tilesXY[xString][yString] = protoKey
// }
//
// // events count update
// data.events ??= {}
// data.events[eventName] ??= []
// data.events[eventName].push(event.tick)
//
// // apply mutator
// if (updater != undefined) {
// updater(data)
// }
// },
// expirationDurationTicks,
// )
// }
//
// }
//
//
//
// const ResourceEntityUpdates = new ResourceEntityUpdatesHandler()
//
// export default ResourceEntityUpdates

View file

@ -13,7 +13,7 @@ export function handleSurfaceUpdate(
name: surface.name,
index: surface.index,
daytime: surface.daytime
daytime: surface.daytime,
}
PacketEmitter.emitInstantPacket(update)

View file

@ -6,7 +6,8 @@ export class KafkatorioSettingsConfig {
private static eventCacheExpirationDefaultSeconds: Record<KafkatorioKeyedPacketTypes, double> = {
"kafkatorio.packet.keyed.PlayerUpdate": 0.5,
"kafkatorio.packet.keyed.MapChunkUpdate": 30,
"kafkatorio.packet.keyed.MapChunkTileUpdate": 30,
"kafkatorio.packet.keyed.MapChunkEntityUpdate": 30,
"kafkatorio.packet.keyed.EntityUpdate": 5,
}
@ -21,7 +22,7 @@ export class KafkatorioSettingsConfig {
public initialiseSettings(data: Data): void {
for (const [type,] of pairs(KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds)) {
data.extend(
[ KafkatorioSettingsConfig.createDefaultCacheDuration(type)]
[KafkatorioSettingsConfig.createDefaultCacheDuration(type)]
)
}
}

View file

@ -1,6 +1,6 @@
import {KafkatorioPacketData} from "../generated/kafkatorio-schema";
export type EventName = keyof typeof defines.events
export type DefinedEventName = keyof typeof defines.events
/** Get all keys of `TYPE` that are not nullable. */