emit entity prototypes

- mod: refactor event handlers to separate files
- lib: update models for prototypes
This commit is contained in:
Adam 2022-07-08 21:06:09 +02:00
parent 4510ec4a6e
commit 80eb001bbf
27 changed files with 1570 additions and 1437 deletions

View file

@ -8,15 +8,16 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("kafkatorio.prototype.FactorioPrototype") @SerialName("kafkatorio.prototype.FactorioPrototype")
sealed interface FactorioPrototype { sealed interface FactorioPrototype {
val protoId: PrototypeId val protoId: PrototypeId
val mapColour: Colour
@SerialName("kafkatorio.prototype.MapTile") @SerialName("kafkatorio.prototype.MapTile")
@Serializable @Serializable
data class MapTile( data class MapTile(
override val protoId: PrototypeId, override val protoId: PrototypeId,
override val mapColour: Colour,
val mapColour: Colour,
val layer: UInt, val layer: UInt,
@Contextual @Contextual
@ -27,27 +28,47 @@ sealed interface FactorioPrototype {
) : FactorioPrototype ) : FactorioPrototype
/**
* @param[colour] The colour of the prototype, or `null` if the prototype doesn't have colour.
* @param[mapColour] The map colour used when charting this entity if a
* [friendly][mapColourFriend] or [enemy][mapColourEnemy] colour isn't defined or `null`.
* @param[mapColourFriend] The friendly map colour used when charting this entity.
* @param[mapColourEnemy] The enemy map colour used when charting this entity.
*/
@SerialName("kafkatorio.prototype.Entity") @SerialName("kafkatorio.prototype.Entity")
@Serializable @Serializable
data class Entity( data class Entity(
override val protoId: PrototypeId, override val protoId: PrototypeId,
override val mapColour: Colour,
val protoType: String, val group: ItemGroup,
val objectName: String, val subgroup: ItemGroup,
val colour: Colour,
val colour: Colour? = null,
val mapColour: Colour? = null,
val mapColourFriend: Colour? = null,
val mapColourEnemy: Colour? = null,
val maxHealth: Float, val maxHealth: Float,
val isBuilding: Boolean, val isBuilding: Boolean,
val isEntityWithOwner: Boolean, val isEntityWithOwner: Boolean,
val isMilitaryTarget: Boolean, val isMilitaryTarget: Boolean,
val miningProperties: MiningProperties val miningProperties: MiningProperties? = null,
) : FactorioPrototype { ) : FactorioPrototype {
@Serializable @Serializable
@SerialName("kafkatorio.prototype.EntityMiningProperties")
data class MiningProperties( data class MiningProperties(
val canBeMined: Boolean, val canBeMined: Boolean,
val products: List<MinedProduct>?, val products: List<MinedProduct>?,
) )
@Serializable
@SerialName("kafkatorio.prototype.EntityItemGroup")
data class ItemGroup(
val name: String,
val type: String,
val parentName: String? = null,
)
} }
} }

View file

@ -1,65 +1,13 @@
local ____lualib = require("lualib_bundle")
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
local __TS__ArrayConcat = ____lualib.__TS__ArrayConcat
local Set = ____lualib.Set
local __TS__New = ____lualib.__TS__New
local __TS__Spread = ____lualib.__TS__Spread
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local ____exports = {} local ____exports = {}
local emitConfigurationUpdate, factorioData, allMods, Type
local ____PacketEmitter = require("main.PacketEmitter")
local PacketEmitter = ____PacketEmitter.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____global_2Dinit = require("main.global-init") local ____global_2Dinit = require("main.global-init")
local initGlobal = ____global_2Dinit.initGlobal local initGlobal = ____global_2Dinit.initGlobal
local ____prototypeUpdates = require("main.events.prototypeUpdates") local ____prototypeUpdates = require("main.events.prototypeUpdates")
local emitPrototypes = ____prototypeUpdates.emitPrototypes local emitPrototypes = ____prototypeUpdates.emitPrototypes
function emitConfigurationUpdate(changeData) local ____ConfigurationUpdateHandler = require("main.events.handlers.ConfigurationUpdateHandler")
local configUpdateData = { local ConfigurationUpdates = ____ConfigurationUpdateHandler.default
type = Type.ConfigurationUpdate,
migrationApplied = changeData.migration_applied,
modStartupSettingsChange = changeData.mod_startup_settings_changed,
allMods = allMods(changeData),
factorioData = factorioData(changeData)
}
PacketEmitter:emitInstantPacket(configUpdateData)
end
function factorioData(changeData)
return {oldVersion = changeData.old_version or nil, newVersion = changeData.new_version or nil}
end
function allMods(e)
local namesOfChangedMods = __TS__ObjectKeys(e.mod_changes)
local namesOfCurrentMods = __TS__ObjectKeys(script.active_mods)
local modNames = {__TS__Spread(__TS__New(
Set,
__TS__ArrayConcat(namesOfChangedMods, namesOfCurrentMods)
))}
return __TS__ArrayMap(
modNames,
function(____, modName)
local ____script_active_mods_modName_2 = script.active_mods[modName]
if ____script_active_mods_modName_2 == nil then
local ____e_mod_changes_modName_new_version_0 = e.mod_changes[modName]
if ____e_mod_changes_modName_new_version_0 ~= nil then
____e_mod_changes_modName_new_version_0 = ____e_mod_changes_modName_new_version_0.new_version
end
____script_active_mods_modName_2 = ____e_mod_changes_modName_new_version_0
end
local currentVer = ____script_active_mods_modName_2 or nil
local ____e_mod_changes_modName_old_version_3 = e.mod_changes[modName]
if ____e_mod_changes_modName_old_version_3 ~= nil then
____e_mod_changes_modName_old_version_3 = ____e_mod_changes_modName_old_version_3.old_version
end
local previousVer = ____e_mod_changes_modName_old_version_3 or nil
return {modName = modName, currentVersion = currentVer, previousVersion = previousVer}
end
)
end
Type = KafkatorioPacketData.Type
script.on_configuration_changed(function(data) script.on_configuration_changed(function(data)
initGlobal(true) initGlobal(true)
emitConfigurationUpdate(data) ConfigurationUpdates:emitConfigurationUpdate(data)
emitPrototypes() emitPrototypes()
end) end)
return ____exports return ____exports

View file

@ -2,6 +2,7 @@ local ____exports = {}
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local EntityStatus = ____kafkatorio_2Dschema.EntityStatus local EntityStatus = ____kafkatorio_2Dschema.EntityStatus
local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData
local MinedProduct = ____kafkatorio_2Dschema.MinedProduct
____exports.Converters = {} ____exports.Converters = {}
local Converters = ____exports.Converters local Converters = ____exports.Converters
do do
@ -87,6 +88,34 @@ do
return EntityStatusRecord[status] return EntityStatusRecord[status]
end end
end end
function Converters.miningProperties(properties)
local products = {}
if properties.products ~= nil then
for ____, product in ipairs(properties.products) do
if product.type == "fluid" then
products[#products + 1] = {
type = MinedProduct.Type.MinedProductFluid,
amount = product.amount,
resultProtoId = ____exports.Converters.prototypeId(product.type, product.name)
}
end
if product.type == "item" then
products[#products + 1] = {
type = MinedProduct.Type.MinedProductItem,
amount = product.amount,
resultProtoId = ____exports.Converters.prototypeId(product.type, product.name)
}
end
end
end
return {canBeMined = properties.minable, products = products}
end
function Converters.playerOnlineInfo(player, data)
data.lastOnline = player.last_online
data.onlineTime = player.online_time
data.afkTime = player.afk_time
data.isConnected = player.connected
end
EntityStatusRecord = { EntityStatusRecord = {
[defines.entity_status.cant_divide_segments] = EntityStatus.CANT_DIVIDE_SEGMENTS, [defines.entity_status.cant_divide_segments] = EntityStatus.CANT_DIVIDE_SEGMENTS,
[defines.entity_status.charging] = EntityStatus.CHARGING, [defines.entity_status.charging] = EntityStatus.CHARGING,

View file

@ -1,177 +1,6 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__New = ____lualib.__TS__New
local ____exports = {} local ____exports = {}
local ____converters = require("main.events.converters") local ____EntityUpdateHandler = require("main.events.handlers.EntityUpdateHandler")
local Converters = ____converters.Converters local EntityUpdates = ____EntityUpdateHandler.default
local ____EventDataCache = require("main.cache.EventDataCache")
local EventDataCache = ____EventDataCache.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
____exports.EntityUpdatesHandler = __TS__Class()
local EntityUpdatesHandler = ____exports.EntityUpdatesHandler
EntityUpdatesHandler.name = "EntityUpdatesHandler"
function EntityUpdatesHandler.prototype.____constructor(self)
end
function EntityUpdatesHandler.prototype.handleMinedTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
local tilesByChunk = {}
for ____, tile in ipairs(event.tiles) do
local chunkPosition = Converters.tilePositionToChunkPosition(tile.position)
tilesByChunk[chunkPosition] = tile
end
for chunkPos, tiles in pairs(tilesByChunk) do
local entities = {}
for tile in pairs(tiles) do
local resources = ____exports.EntityUpdatesHandler:getTileResourceEntities(surface, chunkPos)
for ____, resource in ipairs(resources) do
entities[#entities + 1] = resource
end
end
____exports.EntityUpdatesHandler:throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick,
event.surface_index,
{chunkPos[1], chunkPos[2]},
entities
)
end
end
function EntityUpdatesHandler.prototype.handleMinedEntityEvent(self, event)
____exports.EntityUpdatesHandler:throttleEntityUpdate(event, event.entity)
end
function EntityUpdatesHandler.prototype.handleBuiltEntityEvent(self, event)
____exports.EntityUpdatesHandler:throttleEntityUpdate(event, event.created_entity)
end
function EntityUpdatesHandler.prototype.handleChunkGeneratedEvent(self, event)
local entities = ____exports.EntityUpdatesHandler:getAreaResourceEntities(event.surface, event.area)
____exports.EntityUpdatesHandler:throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick,
event.surface.index,
{event.position.x, event.position.y},
entities
)
end
function EntityUpdatesHandler.throttleEntityUpdate(self, event, entity)
if entity.unit_number == nil then
return
end
local eventName = Converters.eventNameString(event.name)
local entityUpdateKey = {
protoId = Converters.prototypeIdEntity(entity),
surfaceIndex = entity.surface.index,
chunkPosition = Converters.mapPositionToChunkPosition(entity.position)
}
local ____FactorioEntityData_Type_Standard_2 = FactorioEntityData.Type.Standard
local ____Converters_prototypeIdEntity_result_3 = Converters.prototypeIdEntity(entity)
local ____entity_graphics_variation_4 = entity.graphics_variation
local ____entity_health_5 = entity.health
local ____entity_active_6 = entity.active
local ____entity_rotatable_7 = entity.rotatable
local ____entity_last_user_index_0 = entity.last_user
if ____entity_last_user_index_0 ~= nil then
____entity_last_user_index_0 = ____entity_last_user_index_0.index
end
local entityUpdate = {
type = ____FactorioEntityData_Type_Standard_2,
protoId = ____Converters_prototypeIdEntity_result_3,
graphicsVariation = ____entity_graphics_variation_4,
health = ____entity_health_5,
isActive = ____entity_active_6,
isRotatable = ____entity_rotatable_7,
lastUser = ____entity_last_user_index_0,
localisedDescription = nil,
localisedName = nil,
position = {entity.position.x, entity.position.y},
status = Converters.entityStatus(entity.status)
}
local entityKey = tostring(entity.unit_number)
EventDataCache:throttle(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
function(data)
if data.events == nil then
data.events = {}
end
local ____data_events_8, ____eventName_9 = data.events, eventName
if ____data_events_8[____eventName_9] == nil then
____data_events_8[____eventName_9] = {}
end
local ____data_events_eventName_10 = data.events[eventName]
____data_events_eventName_10[#____data_events_eventName_10 + 1] = event.tick
if data.distinctEntities == nil then
data.distinctEntities = {}
end
data.distinctEntities[entityKey] = entityUpdate
end
)
end
function EntityUpdatesHandler.throttleResourceEntitiesUpdate(self, eventName, eventTick, surfaceIndex, chunkPosition, entities)
local entitiesByProtoId = {}
for ____, entity in ipairs(entities) do
local ____entitiesByProtoId_11, ____entity_protoId_12 = entitiesByProtoId, entity.protoId
if ____entitiesByProtoId_11[____entity_protoId_12] == nil then
____entitiesByProtoId_11[____entity_protoId_12] = {}
end
local ____entitiesByProtoId_entity_protoId_13 = entitiesByProtoId[entity.protoId]
____entitiesByProtoId_entity_protoId_13[#____entitiesByProtoId_entity_protoId_13 + 1] = entity
end
for protoId, resourceEntities in pairs(entitiesByProtoId) do
local entityUpdateKey = {protoId = protoId, surfaceIndex = surfaceIndex, chunkPosition = {chunkPosition[1], chunkPosition[2]}}
EventDataCache:throttle(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
function(data)
if data.events == nil then
data.events = {}
end
local ____data_events_14, ____eventName_15 = data.events, eventName
if ____data_events_14[____eventName_15] == nil then
____data_events_14[____eventName_15] = {}
end
local ____data_events_eventName_16 = data.events[eventName]
____data_events_eventName_16[#____data_events_eventName_16 + 1] = eventTick
for ____, entity in ipairs(resourceEntities) do
local x, y = table.unpack(entity.position)
local entityKey = (tostring(x) .. ",") .. tostring(y)
if data.distinctEntities == nil then
data.distinctEntities = {}
end
data.distinctEntities[entityKey] = entity
end
end
)
end
end
function EntityUpdatesHandler.getTileResourceEntities(self, surface, mapPosition)
local rawEntities = surface.find_entities_filtered({position = mapPosition, collision_mask = "resource-layer"})
local resources = {}
for ____, rawEntity in ipairs(rawEntities) do
local entity = Converters.convertResourceEntity(rawEntity)
if entity ~= nil then
resources[#resources + 1] = entity
end
end
return resources
end
function EntityUpdatesHandler.getAreaResourceEntities(self, surface, area)
local rawEntities = surface.find_entities_filtered({area = area, collision_mask = "resource-layer"})
local resources = {}
for ____, rawEntity in ipairs(rawEntities) do
local entity = Converters.convertResourceEntity(rawEntity)
if entity ~= nil then
resources[#resources + 1] = entity
end
end
return resources
end
local EntityUpdates = __TS__New(____exports.EntityUpdatesHandler)
____exports.default = EntityUpdates
script.on_event( script.on_event(
defines.events.on_built_entity, defines.events.on_built_entity,
function(e) function(e)

View file

@ -0,0 +1,62 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
local __TS__ArrayConcat = ____lualib.__TS__ArrayConcat
local Set = ____lualib.Set
local __TS__New = ____lualib.__TS__New
local __TS__Spread = ____lualib.__TS__Spread
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local ____exports = {}
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____PacketEmitter = require("main.PacketEmitter")
local PacketEmitter = ____PacketEmitter.default
____exports.ConfigurationUpdateHandler = __TS__Class()
local ConfigurationUpdateHandler = ____exports.ConfigurationUpdateHandler
ConfigurationUpdateHandler.name = "ConfigurationUpdateHandler"
function ConfigurationUpdateHandler.prototype.____constructor(self)
end
function ConfigurationUpdateHandler.prototype.emitConfigurationUpdate(self, changeData)
local configUpdateData = {
type = KafkatorioPacketData.Type.ConfigurationUpdate,
migrationApplied = changeData.migration_applied,
modStartupSettingsChange = changeData.mod_startup_settings_changed,
allMods = ____exports.ConfigurationUpdateHandler:allMods(changeData),
factorioData = ____exports.ConfigurationUpdateHandler:factorioData(changeData)
}
PacketEmitter:emitInstantPacket(configUpdateData)
end
function ConfigurationUpdateHandler.factorioData(self, changeData)
return {oldVersion = changeData.old_version or nil, newVersion = changeData.new_version or nil}
end
function ConfigurationUpdateHandler.allMods(self, e)
local namesOfChangedMods = __TS__ObjectKeys(e.mod_changes)
local namesOfCurrentMods = __TS__ObjectKeys(script.active_mods)
local modNames = {__TS__Spread(__TS__New(
Set,
__TS__ArrayConcat(namesOfChangedMods, namesOfCurrentMods)
))}
return __TS__ArrayMap(
modNames,
function(____, modName)
local ____script_active_mods_modName_2 = script.active_mods[modName]
if ____script_active_mods_modName_2 == nil then
local ____e_mod_changes_modName_new_version_0 = e.mod_changes[modName]
if ____e_mod_changes_modName_new_version_0 ~= nil then
____e_mod_changes_modName_new_version_0 = ____e_mod_changes_modName_new_version_0.new_version
end
____script_active_mods_modName_2 = ____e_mod_changes_modName_new_version_0
end
local currentVer = ____script_active_mods_modName_2 or nil
local ____e_mod_changes_modName_old_version_3 = e.mod_changes[modName]
if ____e_mod_changes_modName_old_version_3 ~= nil then
____e_mod_changes_modName_old_version_3 = ____e_mod_changes_modName_old_version_3.old_version
end
local previousVer = ____e_mod_changes_modName_old_version_3 or nil
return {modName = modName, currentVersion = currentVer, previousVersion = previousVer}
end
)
end
local ConfigurationUpdates = __TS__New(____exports.ConfigurationUpdateHandler)
____exports.default = ConfigurationUpdates
return ____exports

View file

@ -0,0 +1,175 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__New = ____lualib.__TS__New
local ____exports = {}
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____converters = require("main.events.converters")
local Converters = ____converters.Converters
local ____EventDataCache = require("main.cache.EventDataCache")
local EventDataCache = ____EventDataCache.default
____exports.EntityUpdatesHandler = __TS__Class()
local EntityUpdatesHandler = ____exports.EntityUpdatesHandler
EntityUpdatesHandler.name = "EntityUpdatesHandler"
function EntityUpdatesHandler.prototype.____constructor(self)
end
function EntityUpdatesHandler.prototype.handleMinedTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
local tilesByChunk = {}
for ____, tile in ipairs(event.tiles) do
local chunkPosition = Converters.tilePositionToChunkPosition(tile.position)
tilesByChunk[chunkPosition] = tile
end
for chunkPos, tiles in pairs(tilesByChunk) do
local entities = {}
for tile in pairs(tiles) do
local resources = ____exports.EntityUpdatesHandler:getTileResourceEntities(surface, chunkPos)
for ____, resource in ipairs(resources) do
entities[#entities + 1] = resource
end
end
____exports.EntityUpdatesHandler:throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick,
event.surface_index,
{chunkPos[1], chunkPos[2]},
entities
)
end
end
function EntityUpdatesHandler.prototype.handleMinedEntityEvent(self, event)
____exports.EntityUpdatesHandler:throttleEntityUpdate(event, event.entity)
end
function EntityUpdatesHandler.prototype.handleBuiltEntityEvent(self, event)
____exports.EntityUpdatesHandler:throttleEntityUpdate(event, event.created_entity)
end
function EntityUpdatesHandler.prototype.handleChunkGeneratedEvent(self, event)
local entities = ____exports.EntityUpdatesHandler:getAreaResourceEntities(event.surface, event.area)
____exports.EntityUpdatesHandler:throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick,
event.surface.index,
{event.position.x, event.position.y},
entities
)
end
function EntityUpdatesHandler.throttleEntityUpdate(self, event, entity)
if entity.unit_number == nil then
return
end
local eventName = Converters.eventNameString(event.name)
local entityUpdateKey = {
protoId = Converters.prototypeIdEntity(entity),
surfaceIndex = entity.surface.index,
chunkPosition = Converters.mapPositionToChunkPosition(entity.position)
}
local ____FactorioEntityData_Type_Standard_2 = FactorioEntityData.Type.Standard
local ____Converters_prototypeIdEntity_result_3 = Converters.prototypeIdEntity(entity)
local ____entity_graphics_variation_4 = entity.graphics_variation
local ____entity_health_5 = entity.health
local ____entity_active_6 = entity.active
local ____entity_rotatable_7 = entity.rotatable
local ____entity_last_user_index_0 = entity.last_user
if ____entity_last_user_index_0 ~= nil then
____entity_last_user_index_0 = ____entity_last_user_index_0.index
end
local entityUpdate = {
type = ____FactorioEntityData_Type_Standard_2,
protoId = ____Converters_prototypeIdEntity_result_3,
graphicsVariation = ____entity_graphics_variation_4,
health = ____entity_health_5,
isActive = ____entity_active_6,
isRotatable = ____entity_rotatable_7,
lastUser = ____entity_last_user_index_0,
localisedDescription = nil,
localisedName = nil,
position = {entity.position.x, entity.position.y},
status = Converters.entityStatus(entity.status)
}
local entityKey = tostring(entity.unit_number)
EventDataCache:throttle(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
function(data)
if data.events == nil then
data.events = {}
end
local ____data_events_8, ____eventName_9 = data.events, eventName
if ____data_events_8[____eventName_9] == nil then
____data_events_8[____eventName_9] = {}
end
local ____data_events_eventName_10 = data.events[eventName]
____data_events_eventName_10[#____data_events_eventName_10 + 1] = event.tick
if data.distinctEntities == nil then
data.distinctEntities = {}
end
data.distinctEntities[entityKey] = entityUpdate
end
)
end
function EntityUpdatesHandler.throttleResourceEntitiesUpdate(self, eventName, eventTick, surfaceIndex, chunkPosition, entities)
local entitiesByProtoId = {}
for ____, entity in ipairs(entities) do
local ____entitiesByProtoId_11, ____entity_protoId_12 = entitiesByProtoId, entity.protoId
if ____entitiesByProtoId_11[____entity_protoId_12] == nil then
____entitiesByProtoId_11[____entity_protoId_12] = {}
end
local ____entitiesByProtoId_entity_protoId_13 = entitiesByProtoId[entity.protoId]
____entitiesByProtoId_entity_protoId_13[#____entitiesByProtoId_entity_protoId_13 + 1] = entity
end
for protoId, resourceEntities in pairs(entitiesByProtoId) do
local entityUpdateKey = {protoId = protoId, surfaceIndex = surfaceIndex, chunkPosition = {chunkPosition[1], chunkPosition[2]}}
EventDataCache:throttle(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
function(data)
if data.events == nil then
data.events = {}
end
local ____data_events_14, ____eventName_15 = data.events, eventName
if ____data_events_14[____eventName_15] == nil then
____data_events_14[____eventName_15] = {}
end
local ____data_events_eventName_16 = data.events[eventName]
____data_events_eventName_16[#____data_events_eventName_16 + 1] = eventTick
for ____, entity in ipairs(resourceEntities) do
local x, y = table.unpack(entity.position)
local entityKey = (tostring(x) .. ",") .. tostring(y)
if data.distinctEntities == nil then
data.distinctEntities = {}
end
data.distinctEntities[entityKey] = entity
end
end
)
end
end
function EntityUpdatesHandler.getTileResourceEntities(self, surface, mapPosition)
local rawEntities = surface.find_entities_filtered({position = mapPosition, collision_mask = "resource-layer"})
local resources = {}
for ____, rawEntity in ipairs(rawEntities) do
local entity = Converters.convertResourceEntity(rawEntity)
if entity ~= nil then
resources[#resources + 1] = entity
end
end
return resources
end
function EntityUpdatesHandler.getAreaResourceEntities(self, surface, area)
local rawEntities = surface.find_entities_filtered({area = area, collision_mask = "resource-layer"})
local resources = {}
for ____, rawEntity in ipairs(rawEntities) do
local entity = Converters.convertResourceEntity(rawEntity)
if entity ~= nil then
resources[#resources + 1] = entity
end
end
return resources
end
local EntityUpdates = __TS__New(____exports.EntityUpdatesHandler)
____exports.default = EntityUpdates
return ____exports

View file

@ -0,0 +1,208 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local Map = ____lualib.Map
local __TS__Iterator = ____lualib.__TS__Iterator
local __TS__New = ____lualib.__TS__New
local ____exports = {}
local ____converters = require("main.events.converters")
local Converters = ____converters.Converters
local ____eventTypeCheck = require("main.events.eventTypeCheck")
local isEventType = ____eventTypeCheck.isEventType
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____EventDataCache = require("main.cache.EventDataCache")
local EventUpdatesManager = ____EventDataCache.default
local MapChunkUpdateHandler = __TS__Class()
MapChunkUpdateHandler.name = "MapChunkUpdateHandler"
function MapChunkUpdateHandler.prototype.____constructor(self)
end
function MapChunkUpdateHandler.prototype.handleChunkGeneratedEvent(self, event, expirationDurationTicks)
local tiles = event.surface.find_tiles_filtered({area = event.area})
MapChunkUpdateHandler:mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
nil,
expirationDurationTicks
)
end
function MapChunkUpdateHandler.prototype.handleBuiltTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
local eventName = Converters.eventNameString(event.name)
log("[handleBuiltTileEvent] undefined surface " .. eventName)
return
end
local tiles = Converters.convertPlacedTiles(event.tile, event.tiles)
local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
function(data)
if isEventType(event, defines.events.on_player_built_tile) then
data.player = event.player_index
return
end
if isEventType(event, defines.events.on_robot_built_tile) then
local ____data_2 = data
local ____event_robot_unit_number_0 = event.robot
if ____event_robot_unit_number_0 ~= nil then
____event_robot_unit_number_0 = ____event_robot_unit_number_0.unit_number
end
____data_2.robot = {
unitNumber = ____event_robot_unit_number_0 or nil,
protoId = Converters.prototypeId(event.robot.type, event.robot.name)
}
return
end
local exhaustiveCheck = event
end
)
end
end
function MapChunkUpdateHandler.prototype.handleMinedTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
local eventName = Converters.eventNameString(event.name)
log("[handleMinedTileEvent] undefined surface " .. eventName)
return
end
local tiles = Converters.convertRemovedTiles(surface, event.tiles)
local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
function(data)
if isEventType(event, defines.events.on_player_mined_tile) then
data.player = event.player_index
return
end
if isEventType(event, defines.events.on_robot_mined_tile) then
local ____data_5 = data
local ____event_robot_unit_number_3 = event.robot
if ____event_robot_unit_number_3 ~= nil then
____event_robot_unit_number_3 = ____event_robot_unit_number_3.unit_number
end
____data_5.robot = {
unitNumber = ____event_robot_unit_number_3 or nil,
protoId = Converters.prototypeId(event.robot.type, event.robot.name)
}
return
end
local exhaustiveCheck = event
end
)
end
end
function MapChunkUpdateHandler.prototype.handleScriptSetTilesEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
local groupedTiles = MapChunkUpdateHandler:groupTiles(event.tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
end
end
function MapChunkUpdateHandler.prototype.handlePreChunkDeleted(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
for ____, position in ipairs(event.positions) do
local key = {surfaceIndex = surface.index, chunkPosition = {position.x, position.y}}
EventUpdatesManager:debounce(
key,
KafkatorioPacketData.Type.MapChunkTileUpdate,
function(data)
data.isDeleted = true
return true
end,
0
)
end
end
function MapChunkUpdateHandler.mapTilesUpdateDebounce(self, surface, chunkPosition, tiles, event, updater, expirationDurationTicks)
if surface == nil then
return
end
local eventName = Converters.eventNameString(event.name)
local key = {surfaceIndex = surface.index, chunkPosition = chunkPosition}
EventUpdatesManager:debounce(
key,
KafkatorioPacketData.Type.MapChunkTileUpdate,
function(data)
if data.tileDictionary == nil then
data.tileDictionary = {tilesXY = {}, protos = {}}
end
local protosCount = table_size(data.tileDictionary.protos)
for ____, tile in ipairs(tiles) do
local protoId = Converters.prototypeId("tile", tile.name)
if data.tileDictionary.protos[protoId] == nil then
end
local ____data_tileDictionary_protos_7, ____protoId_8 = data.tileDictionary.protos, protoId
if ____data_tileDictionary_protos_7[____protoId_8] == nil then
local ____protosCount_6 = protosCount
protosCount = ____protosCount_6 + 1
____data_tileDictionary_protos_7[____protoId_8] = ____protosCount_6
end
local protoKey = data.tileDictionary.protos[protoId]
local xString = tostring(tile.position.x)
local yString = tostring(tile.position.y)
local ____data_tileDictionary_tilesXY_9, ____xString_10 = data.tileDictionary.tilesXY, xString
if ____data_tileDictionary_tilesXY_9[____xString_10] == nil then
____data_tileDictionary_tilesXY_9[____xString_10] = {}
end
data.tileDictionary.tilesXY[xString][yString] = protoKey
end
if data.events == nil then
data.events = {}
end
local ____data_events_11, ____eventName_12 = data.events, eventName
if ____data_events_11[____eventName_12] == nil then
____data_events_11[____eventName_12] = {}
end
local ____data_events_eventName_13 = data.events[eventName]
____data_events_eventName_13[#____data_events_eventName_13 + 1] = event.tick
if updater ~= nil then
updater(data)
end
end,
expirationDurationTicks
)
end
function MapChunkUpdateHandler.groupTiles(self, tiles)
local mapChunkPositionToTiles = __TS__New(Map)
for ____, tile in ipairs(tiles) do
local chunkPosition = {
math.floor(tile.position.x / 32),
math.floor(tile.position.y / 32)
}
if not mapChunkPositionToTiles:has(chunkPosition) then
mapChunkPositionToTiles:set(chunkPosition, {})
end
local ____mapChunkPositionToTiles_get_result_push_result_14 = mapChunkPositionToTiles:get(chunkPosition)
if ____mapChunkPositionToTiles_get_result_push_result_14 ~= nil then
local ____temp_15 = mapChunkPositionToTiles:get(chunkPosition)
____temp_15[#____temp_15 + 1] = tile
____mapChunkPositionToTiles_get_result_push_result_14 = nil
end
end
return mapChunkPositionToTiles
end
local MapChunkUpdate = __TS__New(MapChunkUpdateHandler)
____exports.default = MapChunkUpdate
return ____exports

View file

@ -0,0 +1,60 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__New = ____lualib.__TS__New
local ____exports = {}
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____converters = require("main.events.converters")
local Converters = ____converters.Converters
local ____EventDataCache = require("main.cache.EventDataCache")
local EventUpdatesManager = ____EventDataCache.default
____exports.PlayerUpdateHandler = __TS__Class()
local PlayerUpdateHandler = ____exports.PlayerUpdateHandler
PlayerUpdateHandler.name = "PlayerUpdateHandler"
function PlayerUpdateHandler.prototype.____constructor(self)
end
function PlayerUpdateHandler.prototype.handleBannedEvent(self, event)
self:playerUpdateThrottle(
event,
function(player, data)
data.bannedReason = event.reason or nil
Converters.playerOnlineInfo(player, data)
end
)
end
function PlayerUpdateHandler.prototype.playerUpdateThrottle(self, event, mutate, expirationDurationTicks)
if expirationDurationTicks == nil then
expirationDurationTicks = nil
end
local playerIndex = event.player_index
if playerIndex == nil then
return
end
local eventName = Converters.eventNameString(event.name)
EventUpdatesManager:throttle(
{index = playerIndex},
KafkatorioPacketData.Type.PlayerUpdate,
function(data)
local player = game.players[playerIndex]
if player ~= nil then
mutate(player, data)
end
if data.events == nil then
data.events = {}
end
local ____data_events_0, ____eventName_1 = data.events, eventName
if ____data_events_0[____eventName_1] == nil then
____data_events_0[____eventName_1] = {}
end
local ____data_events_eventName_2 = data.events[eventName]
____data_events_eventName_2[#____data_events_eventName_2 + 1] = event.tick
end,
expirationDurationTicks
)
end
function PlayerUpdateHandler.prototype.playerUpdateImmediate(self, event, mutate)
self:playerUpdateThrottle(event, mutate, 0)
end
local PlayerUpdates = __TS__New(____exports.PlayerUpdateHandler)
____exports.default = PlayerUpdates
return ____exports

View file

@ -1,213 +1,8 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local Map = ____lualib.Map
local __TS__Iterator = ____lualib.__TS__Iterator
local __TS__New = ____lualib.__TS__New
local ____exports = {} local ____exports = {}
local ____eventTypeCheck = require("main.events.eventTypeCheck") local ____EntityUpdateHandler = require("main.events.handlers.EntityUpdateHandler")
local isEventType = ____eventTypeCheck.isEventType local EntityUpdates = ____EntityUpdateHandler.default
local ____converters = require("main.events.converters") local ____MapChunkUpdateHandler = require("main.events.handlers.MapChunkUpdateHandler")
local Converters = ____converters.Converters local MapChunkUpdate = ____MapChunkUpdateHandler.default
local ____EventDataCache = require("main.cache.EventDataCache")
local EventUpdatesManager = ____EventDataCache.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____entityUpdates = require("main.events.entityUpdates")
local EntityUpdates = ____entityUpdates.default
local Type = KafkatorioPacketData.Type
local MapChunkUpdateHandler = __TS__Class()
MapChunkUpdateHandler.name = "MapChunkUpdateHandler"
function MapChunkUpdateHandler.prototype.____constructor(self)
end
function MapChunkUpdateHandler.prototype.handleChunkGeneratedEvent(self, event, expirationDurationTicks)
local tiles = event.surface.find_tiles_filtered({area = event.area})
MapChunkUpdateHandler:mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
nil,
expirationDurationTicks
)
end
function MapChunkUpdateHandler.prototype.handleBuiltTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
local eventName = Converters.eventNameString(event.name)
log("[handleBuiltTileEvent] undefined surface " .. eventName)
return
end
local tiles = Converters.convertPlacedTiles(event.tile, event.tiles)
local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
function(data)
if isEventType(event, defines.events.on_player_built_tile) then
data.player = event.player_index
return
end
if isEventType(event, defines.events.on_robot_built_tile) then
local ____data_2 = data
local ____event_robot_unit_number_0 = event.robot
if ____event_robot_unit_number_0 ~= nil then
____event_robot_unit_number_0 = ____event_robot_unit_number_0.unit_number
end
____data_2.robot = {
unitNumber = ____event_robot_unit_number_0 or nil,
protoId = Converters.prototypeId(event.robot.type, event.robot.name)
}
return
end
local exhaustiveCheck = event
end
)
end
end
function MapChunkUpdateHandler.prototype.handleMinedTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
local eventName = Converters.eventNameString(event.name)
log("[handleMinedTileEvent] undefined surface " .. eventName)
return
end
local tiles = Converters.convertRemovedTiles(surface, event.tiles)
local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
function(data)
if isEventType(event, defines.events.on_player_mined_tile) then
data.player = event.player_index
return
end
if isEventType(event, defines.events.on_robot_mined_tile) then
local ____data_5 = data
local ____event_robot_unit_number_3 = event.robot
if ____event_robot_unit_number_3 ~= nil then
____event_robot_unit_number_3 = ____event_robot_unit_number_3.unit_number
end
____data_5.robot = {
unitNumber = ____event_robot_unit_number_3 or nil,
protoId = Converters.prototypeId(event.robot.type, event.robot.name)
}
return
end
local exhaustiveCheck = event
end
)
end
end
function MapChunkUpdateHandler.prototype.handleScriptSetTilesEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
local groupedTiles = MapChunkUpdateHandler:groupTiles(event.tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
end
end
function MapChunkUpdateHandler.prototype.handlePreChunkDeleted(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
for ____, position in ipairs(event.positions) do
local key = {surfaceIndex = surface.index, chunkPosition = {position.x, position.y}}
EventUpdatesManager:debounce(
key,
Type.MapChunkTileUpdate,
function(data)
data.isDeleted = true
return true
end,
0
)
end
end
function MapChunkUpdateHandler.mapTilesUpdateDebounce(self, surface, chunkPosition, tiles, event, updater, expirationDurationTicks)
if surface == nil then
return
end
local eventName = Converters.eventNameString(event.name)
local key = {surfaceIndex = surface.index, chunkPosition = chunkPosition}
EventUpdatesManager:debounce(
key,
Type.MapChunkTileUpdate,
function(data)
if data.tileDictionary == nil then
data.tileDictionary = {tilesXY = {}, protos = {}}
end
local protosCount = table_size(data.tileDictionary.protos)
for ____, tile in ipairs(tiles) do
local protoId = Converters.prototypeId("tile", tile.name)
if data.tileDictionary.protos[protoId] == nil then
end
local ____data_tileDictionary_protos_7, ____protoId_8 = data.tileDictionary.protos, protoId
if ____data_tileDictionary_protos_7[____protoId_8] == nil then
local ____protosCount_6 = protosCount
protosCount = ____protosCount_6 + 1
____data_tileDictionary_protos_7[____protoId_8] = ____protosCount_6
end
local protoKey = data.tileDictionary.protos[protoId]
local xString = tostring(tile.position.x)
local yString = tostring(tile.position.y)
local ____data_tileDictionary_tilesXY_9, ____xString_10 = data.tileDictionary.tilesXY, xString
if ____data_tileDictionary_tilesXY_9[____xString_10] == nil then
____data_tileDictionary_tilesXY_9[____xString_10] = {}
end
data.tileDictionary.tilesXY[xString][yString] = protoKey
end
if data.events == nil then
data.events = {}
end
local ____data_events_11, ____eventName_12 = data.events, eventName
if ____data_events_11[____eventName_12] == nil then
____data_events_11[____eventName_12] = {}
end
local ____data_events_eventName_13 = data.events[eventName]
____data_events_eventName_13[#____data_events_eventName_13 + 1] = event.tick
if updater ~= nil then
updater(data)
end
end,
expirationDurationTicks
)
end
function MapChunkUpdateHandler.groupTiles(self, tiles)
local mapChunkPositionToTiles = __TS__New(Map)
for ____, tile in ipairs(tiles) do
local chunkPosition = {
math.floor(tile.position.x / 32),
math.floor(tile.position.y / 32)
}
if not mapChunkPositionToTiles:has(chunkPosition) then
mapChunkPositionToTiles:set(chunkPosition, {})
end
local ____mapChunkPositionToTiles_get_result_push_result_14 = mapChunkPositionToTiles:get(chunkPosition)
if ____mapChunkPositionToTiles_get_result_push_result_14 ~= nil then
local ____temp_15 = mapChunkPositionToTiles:get(chunkPosition)
____temp_15[#____temp_15 + 1] = tile
____mapChunkPositionToTiles_get_result_push_result_14 = nil
end
end
return mapChunkPositionToTiles
end
local MapChunkUpdate = __TS__New(MapChunkUpdateHandler)
____exports.default = MapChunkUpdate
script.on_event( script.on_event(
defines.events.on_chunk_generated, defines.events.on_chunk_generated,
function(e) function(e)

View file

@ -1,75 +1,26 @@
local ____exports = {} local ____exports = {}
local playerUpdateThrottle, playerOnlineInfo, handleBannedEvent, Type local disconnectReasons
local ____converters = require("main.events.converters") local ____converters = require("main.events.converters")
local Converters = ____converters.Converters local Converters = ____converters.Converters
local ____EventDataCache = require("main.cache.EventDataCache")
local EventUpdatesManager = ____EventDataCache.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____PacketEmitter = require("main.PacketEmitter") local ____PacketEmitter = require("main.PacketEmitter")
local packetEmitter = ____PacketEmitter.default local packetEmitter = ____PacketEmitter.default
function playerUpdateThrottle(event, mutate, expirationDurationTicks) local ____PlayerUpdateHandler = require("main.events.handlers.PlayerUpdateHandler")
if expirationDurationTicks == nil then local PlayerUpdates = ____PlayerUpdateHandler.default
expirationDurationTicks = nil
end
local playerIndex = event.player_index
if playerIndex == nil then
return
end
local eventName = Converters.eventNameString(event.name)
EventUpdatesManager:throttle(
{index = playerIndex},
Type.PlayerUpdate,
function(data)
local player = game.players[playerIndex]
if player ~= nil then
mutate(player, data)
end
if data.events == nil then
data.events = {}
end
local ____data_events_0, ____eventName_1 = data.events, eventName
if ____data_events_0[____eventName_1] == nil then
____data_events_0[____eventName_1] = {}
end
local ____data_events_eventName_2 = data.events[eventName]
____data_events_eventName_2[#____data_events_eventName_2 + 1] = event.tick
end,
expirationDurationTicks
)
end
function playerOnlineInfo(player, data)
data.lastOnline = player.last_online
data.onlineTime = player.online_time
data.afkTime = player.afk_time
data.isConnected = player.connected
end
function handleBannedEvent(event)
playerUpdateThrottle(
event,
function(player, data)
data.bannedReason = event.reason or nil
playerOnlineInfo(player, data)
end
)
end
Type = KafkatorioPacketData.Type
local function playerUpdateImmediate(event, mutate)
playerUpdateThrottle(event, mutate, 0)
end
script.on_event( script.on_event(
defines.events.on_player_joined_game, defines.events.on_player_joined_game,
function(e) function(e)
playerUpdateThrottle( PlayerUpdates:playerUpdateThrottle(
e, e,
function(player, data) function(player, data)
data.isAdmin = player.admin data.isAdmin = player.admin
local ____data_5 = data local ____data_2 = data
local ____player_character_unit_number_3 = player.character local ____player_character_unit_number_0 = player.character
if ____player_character_unit_number_3 ~= nil then if ____player_character_unit_number_0 ~= nil then
____player_character_unit_number_3 = ____player_character_unit_number_3.unit_number ____player_character_unit_number_0 = ____player_character_unit_number_0.unit_number
end end
____data_5.characterUnitNumber = ____player_character_unit_number_3 or nil ____data_2.characterUnitNumber = ____player_character_unit_number_0 or nil
data.chatColour = Converters.mapColour(player.chat_color) data.chatColour = Converters.mapColour(player.chat_color)
data.colour = Converters.mapColour(player.color) data.colour = Converters.mapColour(player.color)
data.forceIndex = player.force.index data.forceIndex = player.force.index
@ -78,7 +29,7 @@ script.on_event(
data.isSpectator = player.spectator data.isSpectator = player.spectator
data.surfaceIndex = player.surface.index data.surfaceIndex = player.surface.index
data.tag = player.tag data.tag = player.tag
playerOnlineInfo(player, data) Converters.playerOnlineInfo(player, data)
end end
) )
end end
@ -86,7 +37,7 @@ script.on_event(
script.on_event( script.on_event(
defines.events.on_player_changed_position, defines.events.on_player_changed_position,
function(e) function(e)
playerUpdateThrottle( PlayerUpdates:playerUpdateThrottle(
e, e,
function(player, data) function(player, data)
data.position = {player.position.x, player.position.y} data.position = {player.position.x, player.position.y}
@ -97,7 +48,7 @@ script.on_event(
script.on_event( script.on_event(
defines.events.on_player_changed_surface, defines.events.on_player_changed_surface,
function(e) function(e)
playerUpdateThrottle( PlayerUpdates:playerUpdateThrottle(
e, e,
function(player, data) function(player, data)
data.position = {player.position.x, player.position.y} data.position = {player.position.x, player.position.y}
@ -109,11 +60,11 @@ script.on_event(
script.on_event( script.on_event(
defines.events.on_player_died, defines.events.on_player_died,
function(e) function(e)
playerUpdateThrottle( PlayerUpdates:playerUpdateThrottle(
e, e,
function(player, data) function(player, data)
data.ticksToRespawn = player.ticks_to_respawn or nil data.ticksToRespawn = player.ticks_to_respawn or nil
playerOnlineInfo(player, data) Converters.playerOnlineInfo(player, data)
if e.cause ~= nil then if e.cause ~= nil then
data.diedCause = { data.diedCause = {
unitNumber = e.cause.unit_number or nil, unitNumber = e.cause.unit_number or nil,
@ -124,25 +75,31 @@ script.on_event(
) )
end end
) )
script.on_event(defines.events.on_player_banned, handleBannedEvent) script.on_event(
script.on_event(defines.events.on_player_unbanned, handleBannedEvent) defines.events.on_player_banned,
function(event)
PlayerUpdates:handleBannedEvent(event)
end
)
script.on_event(
defines.events.on_player_unbanned,
function(event)
PlayerUpdates:handleBannedEvent(event)
end
)
script.on_event( script.on_event(
defines.events.on_player_kicked, defines.events.on_player_kicked,
function(event) function(event)
log((("on_player_kicked " .. tostring(event.tick)) .. " ") .. tostring(event.name)) log((("on_player_kicked " .. tostring(event.tick)) .. " ") .. tostring(event.name))
playerUpdateImmediate( PlayerUpdates:playerUpdateImmediate(
event, event,
function(player, data) function(player, data)
data.kickedReason = event.reason or nil data.kickedReason = event.reason or nil
playerOnlineInfo(player, data) Converters.playerOnlineInfo(player, data)
end end
) )
end end
) )
local disconnectReasons = {}
for name, disconnectId in pairs(defines.disconnect_reason) do
disconnectReasons[disconnectId] = name
end
script.on_event( script.on_event(
defines.events.on_pre_player_left_game, defines.events.on_pre_player_left_game,
function(event) function(event)
@ -156,13 +113,17 @@ script.on_event(
defines.events.on_player_removed, defines.events.on_player_removed,
function(event) function(event)
log((("on_player_removed " .. tostring(event.tick)) .. " ") .. tostring(event.name)) log((("on_player_removed " .. tostring(event.tick)) .. " ") .. tostring(event.name))
playerUpdateImmediate( PlayerUpdates:playerUpdateImmediate(
event, event,
function(player, data) function(player, data)
data.isRemoved = true data.isRemoved = true
playerOnlineInfo(player, data) Converters.playerOnlineInfo(player, data)
end end
) )
end end
) )
disconnectReasons = {}
for name, disconnectId in pairs(defines.disconnect_reason) do
disconnectReasons[disconnectId] = name
end
return ____exports return ____exports

View file

@ -1,7 +1,5 @@
local ____lualib = require("lualib_bundle")
local __TS__ArrayPushArray = ____lualib.__TS__ArrayPushArray
local ____exports = {} local ____exports = {}
local prototypeUpdates, getMapTilePrototypes local emit, getMapTilePrototypes, getEntityPrototypes, convertItemGroup, convertItemSubgroup
local ____PacketEmitter = require("main.PacketEmitter") local ____PacketEmitter = require("main.PacketEmitter")
local PacketEmitter = ____PacketEmitter.default local PacketEmitter = ____PacketEmitter.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
@ -9,18 +7,19 @@ local FactorioPrototype = ____kafkatorio_2Dschema.FactorioPrototype
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
local ____converters = require("main.events.converters") local ____converters = require("main.events.converters")
local Converters = ____converters.Converters local Converters = ____converters.Converters
function prototypeUpdates() function emit(protosByType)
local prototypes = {} for ____, protos in pairs(protosByType) do
__TS__ArrayPushArray( PacketEmitter:emitInstantPacket({type = KafkatorioPacketData.Type.PrototypesUpdate, prototypes = protos})
prototypes, end
getMapTilePrototypes()
)
return prototypes
end end
function getMapTilePrototypes() function getMapTilePrototypes()
local tiles = {} local tiles = {}
if not (tiles.tile ~= nil) then
tiles.tile = {}
end
for ____, tile in pairs(game.tile_prototypes) do for ____, tile in pairs(game.tile_prototypes) do
tiles[#tiles + 1] = { local ____tiles_tile_0 = tiles.tile
____tiles_tile_0[#____tiles_tile_0 + 1] = {
type = FactorioPrototype.Type.MapTile, type = FactorioPrototype.Type.MapTile,
protoId = Converters.prototypeId("tile", tile.name), protoId = Converters.prototypeId("tile", tile.name),
order = tile.order, order = tile.order,
@ -32,11 +31,56 @@ function getMapTilePrototypes()
end end
return tiles return tiles
end end
function getEntityPrototypes()
local protos = {}
for ____, entity in pairs(game.entity_prototypes) do
local key = (entity.group.name .. "/") .. entity.subgroup.name
if not (protos[key] ~= nil) then
protos[key] = {}
end
local entityProto = {
type = FactorioPrototype.Type.Entity,
protoId = Converters.prototypeId(entity.type, entity.name),
group = convertItemGroup(entity.group),
subgroup = convertItemSubgroup(entity.subgroup),
isBuilding = entity.is_building,
isEntityWithOwner = entity.is_entity_with_owner,
isMilitaryTarget = entity.is_military_target,
maxHealth = entity.max_health
}
if entity.map_color ~= nil then
entityProto.mapColour = Converters.mapColour(entity.map_color)
end
if entity.friendly_map_color ~= nil then
entityProto.mapColourFriend = Converters.mapColour(entity.friendly_map_color)
end
if entity.enemy_map_color ~= nil then
entityProto.mapColourEnemy = Converters.mapColour(entity.enemy_map_color)
end
entityProto.miningProperties = Converters.miningProperties(entity.mineable_properties)
local ____protos_key_1 = protos[key]
____protos_key_1[#____protos_key_1 + 1] = entityProto
end
return protos
end
function convertItemGroup(itemGroup)
return {name = itemGroup.name, type = itemGroup.type, parentName = nil}
end
function convertItemSubgroup(itemGroup)
local ____itemGroup_name_4 = itemGroup.name
local ____itemGroup_type_5 = itemGroup.type
local ____itemGroup_group_name_2 = itemGroup.group
if ____itemGroup_group_name_2 ~= nil then
____itemGroup_group_name_2 = ____itemGroup_group_name_2.name
end
return {name = ____itemGroup_name_4, type = ____itemGroup_type_5, parentName = ____itemGroup_group_name_2}
end
function ____exports.emitPrototypes() function ____exports.emitPrototypes()
local data = { local mapTileProtos = getMapTilePrototypes()
prototypes = prototypeUpdates(), emit(mapTileProtos)
type = KafkatorioPacketData.Type.PrototypesUpdate local ____ = game.item_group_prototypes
} local ____ = game.item_subgroup_prototypes
PacketEmitter:emitInstantPacket(data) local entityProtos = getEntityPrototypes()
emit(entityProtos)
end end
return ____exports return ____exports

View file

@ -9,8 +9,8 @@ local ____surfaceUpdates = require("main.events.surfaceUpdates")
local handleSurfaceUpdate = ____surfaceUpdates.handleSurfaceUpdate local handleSurfaceUpdate = ____surfaceUpdates.handleSurfaceUpdate
local ____EventDataCache = require("main.cache.EventDataCache") local ____EventDataCache = require("main.cache.EventDataCache")
local EventCacheService = ____EventDataCache.default local EventCacheService = ____EventDataCache.default
local ____mapChunkUpdates = require("main.events.mapChunkUpdates") local ____MapChunkUpdateHandler = require("main.events.handlers.MapChunkUpdateHandler")
local MapChunkUpdate = ____mapChunkUpdates.default local MapChunkUpdate = ____MapChunkUpdateHandler.default
script.on_event( script.on_event(
defines.events.on_tick, defines.events.on_tick,
function(event) function(event)

View file

@ -211,15 +211,17 @@ export namespace FactorioPrototype {
export interface Entity { export interface Entity {
type: FactorioPrototype.Type.Entity; type: FactorioPrototype.Type.Entity;
protoId: PrototypeId; protoId: PrototypeId;
mapColour: Colour; group: EntityItemGroup;
protoType: string; subgroup: EntityItemGroup;
objectName: string; colour?: Colour | null;
colour: Colour; mapColour?: Colour | null;
mapColourFriend?: Colour | null;
mapColourEnemy?: Colour | null;
maxHealth: Float; maxHealth: Float;
isBuilding: boolean; isBuilding: boolean;
isEntityWithOwner: boolean; isEntityWithOwner: boolean;
isMilitaryTarget: boolean; isMilitaryTarget: boolean;
miningProperties: MiningProperties; miningProperties?: EntityMiningProperties | null;
} }
export interface MapTile { export interface MapTile {
@ -278,7 +280,13 @@ export namespace FactorioEntityData {
} }
} }
export interface MiningProperties { export interface EntityItemGroup {
name: string;
type: string;
parentName?: string | null;
}
export interface EntityMiningProperties {
canBeMined: boolean; canBeMined: boolean;
products: MinedProduct[] | null; products: MinedProduct[] | null;
} }

View file

@ -1,65 +1,12 @@
import PacketEmitter from "../PacketEmitter";
import {
ConfigurationUpdateGameData,
ConfigurationUpdateModData,
KafkatorioPacketData
} from "../../generated/kafkatorio-schema";
import {initGlobal} from "../global-init"; import {initGlobal} from "../global-init";
import {emitPrototypes} from "./prototypeUpdates"; import {emitPrototypes} from "./prototypeUpdates";
import Type = KafkatorioPacketData.Type; import ConfigurationUpdates from "./handlers/ConfigurationUpdateHandler";
import ConfigurationUpdate = KafkatorioPacketData.ConfigurationUpdate;
script.on_configuration_changed((data: ConfigurationChangedData) => { script.on_configuration_changed((data: ConfigurationChangedData) => {
// runs whenever the version of the base game, or a mod, changes // runs whenever the version of the base game, or a mod, changes
initGlobal(true) initGlobal(true)
// KafkatorioSettings.loadSettings() // KafkatorioSettings.loadSettings()
emitConfigurationUpdate(data) ConfigurationUpdates.emitConfigurationUpdate(data)
emitPrototypes() emitPrototypes()
}) })
function emitConfigurationUpdate(changeData: ConfigurationChangedData) {
const configUpdateData: ConfigurationUpdate = {
type: Type.ConfigurationUpdate,
migrationApplied: changeData.migration_applied,
modStartupSettingsChange: changeData.mod_startup_settings_changed,
allMods: allMods(changeData),
factorioData: factorioData(changeData)
}
PacketEmitter.emitInstantPacket(configUpdateData)
}
function factorioData(changeData: ConfigurationChangedData): ConfigurationUpdateGameData {
return {
oldVersion: changeData.old_version ?? null,
newVersion: changeData.new_version ?? null,
}
}
function allMods(e: ConfigurationChangedData): ConfigurationUpdateModData[] {
let namesOfChangedMods: string[] = Object.keys(e.mod_changes)
let namesOfCurrentMods: string[] = Object.keys(script.active_mods)
let modNames = [...new Set<string>(
namesOfChangedMods.concat(namesOfCurrentMods)
)]
return modNames.map((modName) => {
let currentVer = script.active_mods[modName] ?? e.mod_changes[modName]?.new_version ?? null
let previousVer = e.mod_changes[modName]?.old_version ?? null
return {
modName: modName,
currentVersion: currentVer,
previousVersion: previousVer,
}
})
}

View file

@ -1,10 +1,13 @@
import {DefinedEventName} from "../types"; import {DefinedEventName} from "../types";
import { import {
Colour, Colour,
EntityMiningProperties,
EntityStatus, EntityStatus,
EventName, EventName,
FactorioEntityData, FactorioEntityData,
KafkatorioPacketData,
MapChunkPosition, MapChunkPosition,
MinedProduct,
PrototypeId, PrototypeId,
} from "../../generated/kafkatorio-schema"; } from "../../generated/kafkatorio-schema";
@ -133,6 +136,46 @@ export namespace Converters {
} }
export function miningProperties(
properties: LuaEntityPrototype["mineable_properties"]
): EntityMiningProperties {
const products: MinedProduct[] = []
if (properties.products != null) {
for (const product of properties.products) {
if (product.type == "fluid") {
products[products.length] = {
type: MinedProduct.Type.MinedProductFluid,
amount: product.amount,
resultProtoId: Converters.prototypeId(product.type, product.name),
}
}
if (product.type == "item") {
products[products.length] = {
type: MinedProduct.Type.MinedProductItem,
amount: product.amount,
resultProtoId: Converters.prototypeId(product.type, product.name),
}
}
}
}
return {
canBeMined: properties.minable,
products: products,
}
}
export function playerOnlineInfo(player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) {
data.lastOnline = player.last_online
data.onlineTime = player.online_time
data.afkTime = player.afk_time
data.isConnected = player.connected
}
const EntityStatusRecord: Record<defines.entity_status, EntityStatus> = { const EntityStatusRecord: Record<defines.entity_status, EntityStatus> = {
//@formatter:off //@formatter:off
[ defines.entity_status.cant_divide_segments ]: EntityStatus.CANT_DIVIDE_SEGMENTS, [ defines.entity_status.cant_divide_segments ]: EntityStatus.CANT_DIVIDE_SEGMENTS,

View file

@ -1,230 +1,4 @@
import {Converters} from "./converters"; import EntityUpdates from "./handlers/EntityUpdateHandler";
import EventDataCache from "../cache/EventDataCache";
import {
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) => { script.on_event(defines.events.on_built_entity, (e: OnBuiltEntityEvent) => {
log(`on_built_entity ${e.tick}`) log(`on_built_entity ${e.tick}`)
@ -248,29 +22,3 @@ script.on_event(defines.events.on_robot_mined_entity, (e: OnRobotMinedEntityEven
log(`on_robot_mined_entity ${e.tick}`) log(`on_robot_mined_entity ${e.tick}`)
EntityUpdates.handleMinedEntityEvent(e) EntityUpdates.handleMinedEntityEvent(e)
}) })
type EntityUpdateEvent =
| OnBuiltEntityEvent
| OnEntityClonedEvent
| OnEntityDamagedEvent
| OnEntityDestroyedEvent
| OnEntityDiedEvent
| OnEntityLogisticSlotChangedEvent
| OnEntityRenamedEvent
| OnEntitySettingsPastedEvent
| OnEntitySpawnedEvent
| OnPlayerMinedEntityEvent
| OnPlayerRepairedEntityEvent
| OnPlayerRotatedEntityEvent
| OnRobotMinedEntityEvent
| OnRobotBuiltEntityEvent
| OnPostEntityDiedEvent
| OnPreEntitySettingsPastedEvent
| OnSelectedEntityChangedEvent
| OnTriggerCreatedEntityEvent

View file

@ -0,0 +1,62 @@
import {
ConfigurationUpdateGameData,
ConfigurationUpdateModData,
KafkatorioPacketData
} from "../../../generated/kafkatorio-schema";
import PacketEmitter from "../../PacketEmitter";
import ConfigurationUpdate = KafkatorioPacketData.ConfigurationUpdate;
export class ConfigurationUpdateHandler {
emitConfigurationUpdate(changeData: ConfigurationChangedData) {
const configUpdateData: ConfigurationUpdate = {
type: KafkatorioPacketData.Type.ConfigurationUpdate,
migrationApplied: changeData.migration_applied,
modStartupSettingsChange: changeData.mod_startup_settings_changed,
allMods: ConfigurationUpdateHandler.allMods(changeData),
factorioData: ConfigurationUpdateHandler.factorioData(changeData)
}
PacketEmitter.emitInstantPacket(configUpdateData)
}
private static factorioData(changeData: ConfigurationChangedData): ConfigurationUpdateGameData {
return {
oldVersion: changeData.old_version ?? null,
newVersion: changeData.new_version ?? null,
}
}
private static allMods(e: ConfigurationChangedData): ConfigurationUpdateModData[] {
let namesOfChangedMods: string[] = Object.keys(e.mod_changes)
let namesOfCurrentMods: string[] = Object.keys(script.active_mods)
let modNames = [...new Set<string>(
namesOfChangedMods.concat(namesOfCurrentMods)
)]
return modNames.map((modName) => {
let currentVer = script.active_mods[modName] ?? e.mod_changes[modName]?.new_version ?? null
let previousVer = e.mod_changes[modName]?.old_version ?? null
return {
modName: modName,
currentVersion: currentVer,
previousVersion: previousVer,
}
})
}
}
const ConfigurationUpdates = new ConfigurationUpdateHandler()
export default ConfigurationUpdates

View file

@ -0,0 +1,250 @@
import {
EventName,
FactorioEntityData,
KafkatorioPacketData,
MapChunkPosition, PrototypeId,
Tick
} from "../../../generated/kafkatorio-schema";
import {Converters} from "../converters";
import EventDataCache from "../../cache/EventDataCache";
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
type EntityUpdateEvent =
| OnBuiltEntityEvent
| OnEntityClonedEvent
| OnEntityDamagedEvent
| OnEntityDestroyedEvent
| OnEntityDiedEvent
| OnEntityLogisticSlotChangedEvent
| OnEntityRenamedEvent
| OnEntitySettingsPastedEvent
| OnEntitySpawnedEvent
| OnPlayerMinedEntityEvent
| OnPlayerRepairedEntityEvent
| OnPlayerRotatedEntityEvent
| OnRobotMinedEntityEvent
| OnRobotBuiltEntityEvent
| OnPostEntityDiedEvent
| OnPreEntitySettingsPastedEvent
| OnSelectedEntityChangedEvent
| OnTriggerCreatedEntityEvent

View file

@ -0,0 +1,242 @@
import {Converters} from "../converters";
import {isEventType} from "../eventTypeCheck";
import {
KafkatorioPacketData,
MapChunkPosition,
MinedProduct,
PrototypeKey
} from "../../../generated/kafkatorio-schema";
import EventUpdatesManager, {EventUpdates} from "../../cache/EventDataCache";
import {MapChunkUpdateEvent, MapTileChangeEvent} from "../mapChunkUpdates";
import PacketKey = EventUpdates.PacketKey;
import Type = MinedProduct.Type;
type MapChunkTileUpdater = (data: KafkatorioPacketData.MapChunkTileUpdate) => void
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,
)
}
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
}
)
)
}
}
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
}
const tiles: TileRead[] = Converters.convertRemovedTiles(surface, 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_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
}
)
)
}
}
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: PacketKey<KafkatorioPacketData.MapChunkTileUpdate> = {
surfaceIndex: surface.index,
chunkPosition: [position.x, position.y],
}
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkTileUpdate>(
key,
KafkatorioPacketData.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,
KafkatorioPacketData.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
}
}
const MapChunkUpdate = new MapChunkUpdateHandler()
export default MapChunkUpdate

View file

@ -0,0 +1,75 @@
import {KafkatorioPacketData} from "../../../generated/kafkatorio-schema";
import {Converters} from "../converters";
import EventUpdatesManager from "../../cache/EventDataCache";
export type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void
export type PlayerUpdateEvent =
| OnPlayerJoinedGameEvent
| OnPlayerChangedPositionEvent
| OnPlayerChangedSurfaceEvent
| OnPlayerDiedEvent
| OnPlayerBannedEvent
| OnPlayerUnbannedEvent
| OnPlayerKickedEvent
| OnPrePlayerLeftGameEvent
| OnPlayerRemovedEvent
export class PlayerUpdateHandler {
handleBannedEvent(event: OnPlayerBannedEvent | OnPlayerUnbannedEvent) {
this.playerUpdateThrottle(
event,
(player, data) => {
data.bannedReason = event.reason ?? null
Converters.playerOnlineInfo(player, data)
}
)
}
playerUpdateThrottle(
event: PlayerUpdateEvent,
mutate: PlayerUpdater,
expirationDurationTicks: uint | undefined = undefined,
) {
const playerIndex = event.player_index
if (playerIndex == undefined) {
return
}
const eventName = Converters.eventNameString(event.name)
EventUpdatesManager.throttle<KafkatorioPacketData.PlayerUpdate>(
{index: playerIndex},
KafkatorioPacketData.Type.PlayerUpdate,
data => {
const player = game.players[playerIndex]
if (player != undefined) {
mutate(player, data)
}
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
},
expirationDurationTicks,
)
}
playerUpdateImmediate(
event: PlayerUpdateEvent,
mutate: PlayerUpdater,
) {
this.playerUpdateThrottle(event, mutate, 0)
}
}
const PlayerUpdates = new PlayerUpdateHandler()
export default PlayerUpdates

View file

@ -1,17 +1,5 @@
import {isEventType} from "./eventTypeCheck"; import EntityUpdates from "./handlers/EntityUpdateHandler";
import {Converters} from "./converters"; import MapChunkUpdate from "./handlers/MapChunkUpdateHandler";
import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
import {
KafkatorioPacketData,
MapChunkPosition, PrototypeId,
PrototypeKey,
} from "../../generated/kafkatorio-schema";
import EntityUpdates from "./entityUpdates";
import CacheKey = EventUpdates.PacketKey;
import Type = KafkatorioPacketData.Type;
type MapChunkTileUpdater = (data: KafkatorioPacketData.MapChunkTileUpdate) => void
export type MapTileChangeEvent = export type MapTileChangeEvent =
@ -29,242 +17,11 @@ export type MapChunkUpdateEvent =
| OnPreChunkDeletedEvent | OnPreChunkDeletedEvent
class MapChunkUpdateHandler { script.on_event(defines.events.on_chunk_generated, (e: OnChunkGeneratedEvent) => {
log(`on_chunk_generated ${e.tick}`)
handleChunkGeneratedEvent( MapChunkUpdate.handleChunkGeneratedEvent(e)
event: OnChunkGeneratedEvent, EntityUpdates.handleChunkGeneratedEvent(e)
expirationDurationTicks?: uint, })
) {
const tiles = event.surface.find_tiles_filtered({area: event.area})
MapChunkUpdateHandler.mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
undefined,
expirationDurationTicks,
)
}
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
}
)
)
}
}
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
}
const tiles: TileRead[] = Converters.convertRemovedTiles(surface, 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_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
}
)
)
}
}
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
}
}
const MapChunkUpdate = new MapChunkUpdateHandler()
export default MapChunkUpdate
script.on_event(
defines.events.on_chunk_generated,
(e: OnChunkGeneratedEvent) => {
log(`on_chunk_generated ${e.tick}`)
MapChunkUpdate.handleChunkGeneratedEvent(e)
EntityUpdates.handleChunkGeneratedEvent(e)
}
)
// script.on_event( // script.on_event(

View file

@ -1,61 +1,7 @@
import {Converters} from "./converters"; import {Converters} from "./converters";
import EventUpdatesManager from "../cache/EventDataCache";
import {ForceIndex, KafkatorioPacketData, PlayerUpdateKey} from "../../generated/kafkatorio-schema"; import {ForceIndex, KafkatorioPacketData, PlayerUpdateKey} from "../../generated/kafkatorio-schema";
import packetEmitter from "../PacketEmitter"; import packetEmitter from "../PacketEmitter";
import Type = KafkatorioPacketData.Type; import PlayerUpdates from "./handlers/PlayerUpdateHandler";
type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void
type PlayerUpdateEvent =
| OnPlayerJoinedGameEvent
| OnPlayerChangedPositionEvent
| OnPlayerChangedSurfaceEvent
| OnPlayerDiedEvent
| OnPlayerBannedEvent
| OnPlayerUnbannedEvent
| OnPlayerKickedEvent
| OnPrePlayerLeftGameEvent
| OnPlayerRemovedEvent
function playerUpdateThrottle(
event: PlayerUpdateEvent,
mutate: PlayerUpdater,
expirationDurationTicks: uint | undefined = undefined,
) {
const playerIndex = event.player_index
if (playerIndex == undefined) {
return
}
const eventName = Converters.eventNameString(event.name)
EventUpdatesManager.throttle<KafkatorioPacketData.PlayerUpdate>(
{index: playerIndex },
Type.PlayerUpdate,
data => {
const player = game.players[playerIndex]
if (player != undefined) {
mutate(player, data)
}
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
},
expirationDurationTicks,
)
}
function playerUpdateImmediate(
event: PlayerUpdateEvent,
mutate: PlayerUpdater,
) {
playerUpdateThrottle(event, mutate, 0)
}
// function playerUpdateDebounce(playerIndex: uint, mutate: PlayerUpdater) { // function playerUpdateDebounce(playerIndex: uint, mutate: PlayerUpdater) {
@ -68,154 +14,122 @@ function playerUpdateImmediate(
// ) // )
// } // }
function playerOnlineInfo(player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) {
data.lastOnline = player.last_online
data.onlineTime = player.online_time
data.afkTime = player.afk_time
data.isConnected = player.connected
}
script.on_event( script.on_event(defines.events.on_player_joined_game, (e: OnPlayerJoinedGameEvent) => {
defines.events.on_player_joined_game, PlayerUpdates.playerUpdateThrottle(
(e: OnPlayerJoinedGameEvent) => { e,
playerUpdateThrottle(
e,
(player, data) => {
data.isAdmin = player.admin
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 as ForceIndex
data.name = player.name
data.isShowOnMap = player.show_on_map
data.isSpectator = player.spectator
data.surfaceIndex = player.surface.index
data.tag = player.tag
playerOnlineInfo(player, data)
}
)
}
)
script.on_event(
defines.events.on_player_changed_position,
(e: OnPlayerChangedPositionEvent) => {
playerUpdateThrottle(
e,
(player, data) => {
data.position = [player.position.x, player.position.y]
}
)
}
)
script.on_event(
defines.events.on_player_changed_surface,
(e: OnPlayerChangedSurfaceEvent) => {
playerUpdateThrottle(
e,
(player, data) => {
data.position = [player.position.x, player.position.y]
data.surfaceIndex = player.surface.index
}
)
}
)
script.on_event(
defines.events.on_player_died,
(e: OnPlayerDiedEvent) => {
playerUpdateThrottle(
e,
(player, data) => {
data.ticksToRespawn = player.ticks_to_respawn ?? null
playerOnlineInfo(player, data)
if (e.cause != undefined) {
data.diedCause = {
unitNumber: e.cause.unit_number ?? null,
protoId: Converters.prototypeId(e.cause.type, e.cause.name),
}
}
}
)
}
)
script.on_event(defines.events.on_player_banned, handleBannedEvent)
script.on_event(defines.events.on_player_unbanned, handleBannedEvent)
function handleBannedEvent(event: OnPlayerBannedEvent | OnPlayerUnbannedEvent) {
playerUpdateThrottle(
event,
(player, data) => { (player, data) => {
data.bannedReason = event.reason ?? null data.isAdmin = player.admin
playerOnlineInfo(player, data) 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 as ForceIndex
data.name = player.name
data.isShowOnMap = player.show_on_map
data.isSpectator = player.spectator
data.surfaceIndex = player.surface.index
data.tag = player.tag
Converters.playerOnlineInfo(player, data)
} }
) )
} })
script.on_event( script.on_event(defines.events.on_player_changed_position, (e: OnPlayerChangedPositionEvent) => {
defines.events.on_player_kicked, PlayerUpdates.playerUpdateThrottle(
(event: OnPlayerKickedEvent) => { e,
log(`on_player_kicked ${event.tick} ${event.name}`) (player, data) => {
playerUpdateImmediate( data.position = [player.position.x, player.position.y]
event, }
(player, data) => { )
data.kickedReason = event.reason ?? null })
playerOnlineInfo(player, data)
script.on_event(defines.events.on_player_changed_surface, (e: OnPlayerChangedSurfaceEvent) => {
PlayerUpdates.playerUpdateThrottle(
e,
(player, data) => {
data.position = [player.position.x, player.position.y]
data.surfaceIndex = player.surface.index
}
)
})
script.on_event(defines.events.on_player_died, (e: OnPlayerDiedEvent) => {
PlayerUpdates.playerUpdateThrottle(
e,
(player, data) => {
data.ticksToRespawn = player.ticks_to_respawn ?? null
Converters.playerOnlineInfo(player, data)
if (e.cause != undefined) {
data.diedCause = {
unitNumber: e.cause.unit_number ?? null,
protoId: Converters.prototypeId(e.cause.type, e.cause.name),
} }
) }
} }
) )
})
script.on_event(defines.events.on_player_banned, (event: OnPlayerBannedEvent) => {
PlayerUpdates.handleBannedEvent(event)
})
script.on_event(defines.events.on_player_unbanned, (event: OnPlayerBannedEvent) => {
PlayerUpdates.handleBannedEvent(event)
})
script.on_event(defines.events.on_player_kicked, (event: OnPlayerKickedEvent) => {
log(`on_player_kicked ${event.tick} ${event.name}`)
PlayerUpdates.playerUpdateImmediate(
event,
(player, data) => {
data.kickedReason = event.reason ?? null
Converters.playerOnlineInfo(player, data)
}
)
})
script.on_event(defines.events.on_pre_player_left_game, (event: OnPrePlayerLeftGameEvent) => {
log(`on_pre_player_left_game ${event.tick} ${event.name}`)
const playerUpdateKey: PlayerUpdateKey = {
index: event.player_index,
}
const playerUpdate: KafkatorioPacketData.PlayerUpdate = {
type: KafkatorioPacketData.Type.PlayerUpdate,
key: playerUpdateKey,
disconnectReason: disconnectReasons.get(event.reason)
}
packetEmitter.emitKeyedPacket(playerUpdate)
// playerUpdateImmediate(
// event,
// (player, data) => {
// data.disconnectReason = disconnectReasons.get(event.reason)
// playerOnlineInfo(player, data)
// }
// )
})
script.on_event(defines.events.on_player_removed, (event: OnPlayerRemovedEvent) => {
log(`on_player_removed ${event.tick} ${event.name}`)
PlayerUpdates.playerUpdateImmediate(
event,
(player, data) => {
data.isRemoved = true
Converters.playerOnlineInfo(player, data)
}
)
})
const disconnectReasons = new LuaTable<defines.disconnect_reason, keyof typeof defines.disconnect_reason>() const disconnectReasons = new LuaTable<defines.disconnect_reason, keyof typeof defines.disconnect_reason>()
for (const [name, disconnectId] of pairs(defines.disconnect_reason)) { for (const [name, disconnectId] of pairs(defines.disconnect_reason)) {
disconnectReasons.set(disconnectId, name) disconnectReasons.set(disconnectId, name)
} }
script.on_event(
defines.events.on_pre_player_left_game,
(event: OnPrePlayerLeftGameEvent) => {
log(`on_pre_player_left_game ${event.tick} ${event.name}`)
const playerUpdateKey: PlayerUpdateKey = {
index: event.player_index ,
}
const playerUpdate: KafkatorioPacketData.PlayerUpdate = {
type: KafkatorioPacketData.Type.PlayerUpdate,
key: playerUpdateKey,
disconnectReason: disconnectReasons.get(event.reason)
}
packetEmitter.emitKeyedPacket(playerUpdate)
// playerUpdateImmediate(
// event,
// (player, data) => {
// data.disconnectReason = disconnectReasons.get(event.reason)
// playerOnlineInfo(player, data)
// }
// )
}
)
script.on_event(
defines.events.on_player_removed,
(event: OnPlayerRemovedEvent) => {
log(`on_player_removed ${event.tick} ${event.name}`)
playerUpdateImmediate(
event,
(player, data) => {
data.isRemoved = true
playerOnlineInfo(player, data)
}
)
}
)

View file

@ -1,33 +1,48 @@
import PacketEmitter from "../PacketEmitter"; import PacketEmitter from "../PacketEmitter";
import {FactorioPrototype, KafkatorioPacketData} from "../../generated/kafkatorio-schema"; import {
EntityItemGroup,
FactorioPrototype,
KafkatorioPacketData
} from "../../generated/kafkatorio-schema";
import {Converters} from "./converters"; import {Converters} from "./converters";
import PrototypesUpdate = KafkatorioPacketData.PrototypesUpdate;
type PrototypesByType<T extends FactorioPrototype> = LuaTable<string, T[]>
export function emitPrototypes() { export function emitPrototypes() {
const data: PrototypesUpdate = { const mapTileProtos: PrototypesByType<FactorioPrototype.MapTile> = getMapTilePrototypes()
prototypes: prototypeUpdates(), emit(mapTileProtos)
type: KafkatorioPacketData.Type.PrototypesUpdate,
game.item_group_prototypes
game.item_subgroup_prototypes
const entityProtos: PrototypesByType<FactorioPrototype.Entity> = getEntityPrototypes()
emit(entityProtos)
}
function emit<T extends FactorioPrototype>(protosByType: PrototypesByType<T>) {
for (const [, protos] of pairs(protosByType)) {
PacketEmitter.emitInstantPacket({
type: KafkatorioPacketData.Type.PrototypesUpdate,
prototypes: protos,
})
}
}
function getMapTilePrototypes(): PrototypesByType<FactorioPrototype.MapTile> {
const tiles = new LuaTable<string, FactorioPrototype.MapTile[]>()
if (!tiles.has("tile")) {
tiles.set("tile", [])
} }
PacketEmitter.emitInstantPacket(data)
}
function prototypeUpdates(): FactorioPrototype[] {
let prototypes: FactorioPrototype[] = []
prototypes.push(...getMapTilePrototypes())
return prototypes
}
function getMapTilePrototypes(): FactorioPrototype.MapTile[] {
let tiles: FactorioPrototype.MapTile[] = []
for (const [, tile] of game.tile_prototypes) { for (const [, tile] of game.tile_prototypes) {
tiles.push({ tiles.get("tile").push({
type: FactorioPrototype.Type.MapTile, type: FactorioPrototype.Type.MapTile,
protoId: Converters.prototypeId("tile", tile.name), protoId: Converters.prototypeId("tile", tile.name),
@ -42,19 +57,59 @@ function getMapTilePrototypes(): FactorioPrototype.MapTile[] {
} }
// function getEntityPrototypes(): FactorioPrototype.MapTile[] { function getEntityPrototypes(): PrototypesByType<FactorioPrototype.Entity> {
// let tiles: FactorioPrototype.MapTile[] = [] const protos = new LuaTable<string, FactorioPrototype.Entity[]>()
// for (const [, tile] of game.tile_prototypes) {
// tiles.push({ for (const [, entity] of game.entity_prototypes) {
// type: FactorioPrototype.Type.MapTile, const key: string = `${entity.group.name}/${entity.subgroup.name}`
//
// name: tile.name, if (!protos.has(key)) {
// order: tile.order, protos.set(key, [])
// layer: tile.layer, }
// collisionMasks: convertCollisionMaskToNames(tile.collision_mask),
// mapColour: Converters.mapColour(tile.map_color), const entityProto: FactorioPrototype.Entity = {
// canBeMined: tile.mineable_properties.minable, type: FactorioPrototype.Type.Entity,
// }) protoId: Converters.prototypeId(entity.type, entity.name),
// }
// return tiles group: convertItemGroup(entity.group),
// } subgroup: convertItemSubgroup(entity.subgroup),
isBuilding: entity.is_building,
isEntityWithOwner: entity.is_entity_with_owner,
isMilitaryTarget: entity.is_military_target,
maxHealth: entity.max_health,
}
if (entity.map_color != undefined) {
entityProto.mapColour = Converters.mapColour(entity.map_color)
}
if (entity.friendly_map_color != undefined) {
entityProto.mapColourFriend = Converters.mapColour(entity.friendly_map_color)
}
if (entity.enemy_map_color != undefined) {
entityProto.mapColourEnemy = Converters.mapColour(entity.enemy_map_color)
}
entityProto.miningProperties = Converters.miningProperties(entity.mineable_properties)
protos.get(key).push(entityProto)
}
return protos
}
function convertItemGroup(itemGroup: LuaGroup): EntityItemGroup {
return {
name: itemGroup.name,
type: itemGroup.type,
parentName: null,
}
}
function convertItemSubgroup(itemGroup: LuaGroup): EntityItemGroup {
return {
name: itemGroup.name,
type: itemGroup.type,
parentName: itemGroup.group?.name,
}
}

View file

@ -3,7 +3,7 @@ import {isEventType} from "./eventTypeCheck";
import {Converters} from "./converters"; import {Converters} from "./converters";
import {handleSurfaceUpdate} from "./surfaceUpdates"; import {handleSurfaceUpdate} from "./surfaceUpdates";
import EventCacheService from "../cache/EventDataCache"; import EventCacheService from "../cache/EventDataCache";
import MapChunkUpdate from "./mapChunkUpdates"; import MapChunkUpdate from "./handlers/MapChunkUpdateHandler";
script.on_event( script.on_event(

View file

@ -1,99 +0,0 @@
// 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

@ -211,16 +211,15 @@ fun KTable<ServerMapChunkId, ServerMapChunkTiles<ColourHex>>.streamMapChunkColou
val pid = "$pid.output-chunk.${chunkSize.name}" val pid = "$pid.output-chunk.${chunkSize.name}"
toStream("$pid.stream") toStream("$pid.stream")
.filter("$pid.filter-tiles-not-empty") { _, v -> .filter("$pid.filter-tiles-not-empty") { _, chunkTiles ->
!v?.map.isNullOrEmpty() !chunkTiles?.map.isNullOrEmpty()
} }
.mapValues("$pid.map-not-null") { _, v -> .mapValues("$pid.map-not-null") { _, chunkTiles ->
requireNotNull(v) requireNotNull(chunkTiles)
} }
.peek("$pid.print-group-result") { _, v -> .peek("$pid.print-group-result") { _, chunkTiles ->
println("Grouping map tiles result: ${v.chunkId} / ${v.map.size}") println("Grouping map tiles result: ${chunkTiles.chunkId} / size:${chunkTiles.map.size}")
} }.to(
.to(
outputTopic, outputTopic,
producedAs( producedAs(
"$pid.grouped-map-chunks", "$pid.grouped-map-chunks",