diff --git a/modules/events-mod/src/generated/lua/main/cache/EventDataCache.lua b/modules/events-mod/src/generated/lua/main/cache/EventDataCache.lua deleted file mode 100644 index 610cf57..0000000 --- a/modules/events-mod/src/generated/lua/main/cache/EventDataCache.lua +++ /dev/null @@ -1,144 +0,0 @@ -local ____lualib = require("lualib_bundle") -local __TS__Class = ____lualib.__TS__Class -local __TS__New = ____lualib.__TS__New -local ____exports = {} -local ____KafkatorioSettings = require("main.settings.KafkatorioSettings") -local KafkatorioSettings = ____KafkatorioSettings.default -local ____PacketEmitter = require("main.PacketEmitter") -local packetEmitter = ____PacketEmitter.default -____exports.EventUpdates = {} -local EventUpdates = ____exports.EventUpdates -do - local CacheEntry - EventUpdates.Manager = __TS__Class() - local Manager = EventUpdates.Manager - Manager.name = "Manager" - function Manager.prototype.____constructor(self) - end - function Manager.prototype.init(self, force) - local isAnythingUndefined = global.cache == nil - log(((("Initialising EventDataCache (force=" .. tostring(force)) .. ", isAnythingUndefined=") .. tostring(isAnythingUndefined)) .. ")...") - if force == true or isAnythingUndefined then - log("Initialising global.cache") - global.cache = {} - end - log("Finished initialising EventDataCache") - end - function Manager.prototype.throttle(self, key, ____type, mutate, expirationDurationTicks) - self:update( - key, - ____type, - mutate, - false, - expirationDurationTicks - ) - end - function Manager.prototype.debounce(self, key, ____type, mutate, expirationDurationTicks) - self:update( - key, - ____type, - mutate, - true, - expirationDurationTicks - ) - end - function Manager.prototype.update(self, key, ____type, mutate, resetLastUpdated, expirationDurationTicks) - local entry = self:getCacheEntry(key, ____type) or EventUpdates.Manager:createCacheEntry(key, ____type) - mutate(entry.packet) - if resetLastUpdated then - entry.lastUpdatedTick = game.tick - end - if expirationDurationTicks ~= nil then - entry.expirationDurationTicks = expirationDurationTicks - end - if entry.expirationDurationTicks ~= nil and entry.expirationDurationTicks <= 0 then - self:extractAndEmitExpiredPackets() - end - end - function Manager.prototype.setExpiration(self, key, ____type, expirationDurationTicks) - local entry = self:getCacheEntry(key, ____type) - if entry ~= nil then - entry.expirationDurationTicks = expirationDurationTicks - end - end - function Manager.prototype.extractExpired(self) - local countExpired = 0 - local countTotal = 0 - local expiredData = {} - for key, entry in pairs(global.cache) do - countTotal = countTotal + 1 - if self:isExpired(entry) then - countExpired = countExpired + 1 - expiredData[#expiredData + 1] = entry.packet - global.cache[key] = nil - end - end - local hasExpiredItems = countExpired > 0 - local hasAnyItem = countTotal > 0 - if hasExpiredItems or game.tick % 30 == 0 and hasAnyItem then - log((("[extractExpired] expired items: " .. tostring(countExpired)) .. ", total: ") .. tostring(countTotal)) - end - return expiredData - end - function Manager.prototype.extractAndEmitExpiredPackets(self) - local cachedEvents = self:extractExpired() - if #cachedEvents > 0 then - log((("[EventDataCache] emitting " .. tostring(#cachedEvents)) .. " events on tick ") .. tostring(game.tick)) - for ____, event in ipairs(cachedEvents) do - packetEmitter:emitKeyedPacket(event) - end - end - return #cachedEvents - end - function Manager.prototype.getCacheEntry(self, key, ____type) - local hash = EventUpdates.Manager:hashKey(key) - if not (global.cache[hash] ~= nil) then - return nil - end - local value = global.cache[hash] - if self:isEntryInstanceOf(value, ____type) then - return value - else - return nil - end - end - function Manager.createCacheEntry(self, key, ____type) - local data = {type = ____type, key = key} - local entry = __TS__New(CacheEntry, data) - local hash = EventUpdates.Manager:hashKey(key) - global.cache[hash] = entry - return entry - end - function Manager.prototype.isExpired(self, entry) - local expiryDuration = entry.expirationDurationTicks or KafkatorioSettings:getEventCacheExpirationTicks(entry.packet) - if expiryDuration == nil then - return true - else - return game.tick - entry.lastUpdatedTick > expiryDuration - end - end - function Manager.prototype.isEntryInstanceOf(self, entry, ____type) - local ____self_isDataInstanceOf_2 = self.isDataInstanceOf - local ____entry_packet_0 = entry - if ____entry_packet_0 ~= nil then - ____entry_packet_0 = ____entry_packet_0.packet - end - return ____self_isDataInstanceOf_2(self, ____entry_packet_0, ____type) - end - function Manager.prototype.isDataInstanceOf(self, packet, ____type) - return packet ~= nil and packet.type == ____type - end - function Manager.hashKey(self, key) - return game.encode_string(game.table_to_json(key)) - end - CacheEntry = __TS__Class() - CacheEntry.name = "CacheEntry" - function CacheEntry.prototype.____constructor(self, packet, expirationDurationTicks) - self.lastUpdatedTick = game.tick - self.packet = packet - self.expirationDurationTicks = expirationDurationTicks - end -end -local EventUpdatesManager = __TS__New(____exports.EventUpdates.Manager) -____exports.default = EventUpdatesManager -return ____exports diff --git a/modules/events-mod/src/generated/lua/main/commands/kafkatorioCommands.lua b/modules/events-mod/src/generated/lua/main/commands/kafkatorioCommands.lua index e9939d2..48f6c25 100644 --- a/modules/events-mod/src/generated/lua/main/commands/kafkatorioCommands.lua +++ b/modules/events-mod/src/generated/lua/main/commands/kafkatorioCommands.lua @@ -5,10 +5,10 @@ local __TS__ParseInt = ____lualib.__TS__ParseInt local ____exports = {} local ____global_2Dinit = require("main.global-init") local initGlobal = ____global_2Dinit.initGlobal -local ____queue = require("main.queue.queue") -local Queue = ____queue.Queue local ____prototypeUpdates = require("main.events.prototypeUpdates") local emitPrototypes = ____prototypeUpdates.emitPrototypes +local ____queue = require("main.queue.queue") +local EventDataQueue = ____queue.default commands.add_command( "kafkatorio", "kafkatorio innit bruv", @@ -56,7 +56,7 @@ commands.add_command( surface = surface, tick = e.tick } - Queue.enqueue( + EventDataQueue:enqueue( (tostring(surface.index) .. tostring(chunk.x)) .. tostring(chunk.y), data, 50 diff --git a/modules/events-mod/src/generated/lua/main/emitting/EventDataCache.lua b/modules/events-mod/src/generated/lua/main/emitting/EventDataCache.lua new file mode 100644 index 0000000..7d4b9be --- /dev/null +++ b/modules/events-mod/src/generated/lua/main/emitting/EventDataCache.lua @@ -0,0 +1,141 @@ +local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__New = ____lualib.__TS__New +local ____exports = {} +local CacheEntry +local ____KafkatorioSettings = require("main.settings.KafkatorioSettings") +local KafkatorioSettings = ____KafkatorioSettings.default +local ____PacketEmitter = require("main.emitting.PacketEmitter") +local PacketEmitter = ____PacketEmitter.default +____exports.EventUpdatesManager = __TS__Class() +local EventUpdatesManager = ____exports.EventUpdatesManager +EventUpdatesManager.name = "EventUpdatesManager" +function EventUpdatesManager.prototype.____constructor(self) + self:init() +end +function EventUpdatesManager.prototype.init(self, force) + local isAnythingUndefined = global.eventUpdatesManagerCache == nil + log(((("Initialising EventDataCache (force=" .. tostring(force)) .. ", isAnythingUndefined=") .. tostring(isAnythingUndefined)) .. ")...") + if force == true or isAnythingUndefined then + log("Initialising global.cache") + global.eventUpdatesManagerCache = {} + end + log("Finished initialising EventDataCache") +end +function EventUpdatesManager.prototype.throttle(self, key, ____type, mutate, expirationDurationTicks) + self:update( + key, + ____type, + mutate, + false, + expirationDurationTicks + ) +end +function EventUpdatesManager.prototype.debounce(self, key, ____type, mutate, expirationDurationTicks) + self:update( + key, + ____type, + mutate, + true, + expirationDurationTicks + ) +end +function EventUpdatesManager.prototype.update(self, key, ____type, mutate, resetLastUpdated, expirationDurationTicks) + local entry = self:getCacheEntry(key, ____type) or ____exports.EventUpdatesManager:createCacheEntry(key, ____type) + mutate(entry.packet) + if resetLastUpdated then + entry.lastUpdatedTick = game.tick + end + if expirationDurationTicks ~= nil then + entry.expirationDurationTicks = expirationDurationTicks + end + if entry.expirationDurationTicks ~= nil and entry.expirationDurationTicks <= 0 then + self:extractAndEmitExpiredPackets() + end +end +function EventUpdatesManager.prototype.setExpiration(self, key, ____type, expirationDurationTicks) + local entry = self:getCacheEntry(key, ____type) + if entry ~= nil then + entry.expirationDurationTicks = expirationDurationTicks + end +end +function EventUpdatesManager.prototype.extractExpired(self) + local countExpired = 0 + local countTotal = 0 + local expiredData = {} + for key, entry in pairs(global.eventUpdatesManagerCache) do + countTotal = countTotal + 1 + if self:isExpired(entry) then + countExpired = countExpired + 1 + expiredData[#expiredData + 1] = entry.packet + global.eventUpdatesManagerCache[key] = nil + end + end + local hasExpiredItems = countExpired > 0 + local hasAnyItem = countTotal > 0 + if hasExpiredItems or game.tick % 30 == 0 and hasAnyItem then + log((("[extractExpired] expired items: " .. tostring(countExpired)) .. ", total: ") .. tostring(countTotal)) + end + return expiredData +end +function EventUpdatesManager.prototype.extractAndEmitExpiredPackets(self) + local cachedEvents = self:extractExpired() + if #cachedEvents > 0 then + log((("[EventDataCache] emitting " .. tostring(#cachedEvents)) .. " events on tick ") .. tostring(game.tick)) + for ____, event in ipairs(cachedEvents) do + PacketEmitter:emitKeyedPacket(event) + end + end + return #cachedEvents +end +function EventUpdatesManager.prototype.getCacheEntry(self, key, ____type) + local hash = ____exports.EventUpdatesManager:hashKey(key) + if not (global.eventUpdatesManagerCache[hash] ~= nil) then + return nil + end + local value = global.eventUpdatesManagerCache[hash] + if self:isEntryInstanceOf(value, ____type) then + return value + else + return nil + end +end +function EventUpdatesManager.createCacheEntry(self, key, ____type) + local data = {type = ____type, key = key} + local entry = __TS__New(CacheEntry, data) + local hash = ____exports.EventUpdatesManager:hashKey(key) + global.eventUpdatesManagerCache[hash] = entry + return entry +end +function EventUpdatesManager.prototype.isExpired(self, entry) + local expiryDuration = entry.expirationDurationTicks or KafkatorioSettings:getEventCacheExpirationTicks(entry.packet) + if expiryDuration == nil then + return true + else + return game.tick - entry.lastUpdatedTick > expiryDuration + end +end +function EventUpdatesManager.prototype.isEntryInstanceOf(self, entry, ____type) + local ____self_isDataInstanceOf_2 = self.isDataInstanceOf + local ____entry_packet_0 = entry + if ____entry_packet_0 ~= nil then + ____entry_packet_0 = ____entry_packet_0.packet + end + return ____self_isDataInstanceOf_2(self, ____entry_packet_0, ____type) +end +function EventUpdatesManager.prototype.isDataInstanceOf(self, packet, ____type) + return packet ~= nil and packet.type == ____type +end +function EventUpdatesManager.hashKey(self, key) + return game.encode_string(game.table_to_json(key)) +end +local EventUpdates = __TS__New(____exports.EventUpdatesManager) +____exports.default = EventUpdates +CacheEntry = __TS__Class() +CacheEntry.name = "CacheEntry" +function CacheEntry.prototype.____constructor(self, packet, expirationDurationTicks) + self.lastUpdatedTick = game.tick + self.packet = packet + self.expirationDurationTicks = expirationDurationTicks +end +return ____exports diff --git a/modules/events-mod/src/generated/lua/main/emitting/KafkatorioPacketQueue.lua b/modules/events-mod/src/generated/lua/main/emitting/KafkatorioPacketQueue.lua new file mode 100644 index 0000000..a64395e --- /dev/null +++ b/modules/events-mod/src/generated/lua/main/emitting/KafkatorioPacketQueue.lua @@ -0,0 +1,44 @@ +local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__SetDescriptor = ____lualib.__TS__SetDescriptor +local __TS__New = ____lualib.__TS__New +local ____exports = {} +____exports.KafkatorioPacketQueueManager = __TS__Class() +local KafkatorioPacketQueueManager = ____exports.KafkatorioPacketQueueManager +KafkatorioPacketQueueManager.name = "KafkatorioPacketQueueManager" +function KafkatorioPacketQueueManager.prototype.____constructor(self) + self.size = 0 + self.first = nil + self.last = nil +end +__TS__SetDescriptor( + KafkatorioPacketQueueManager.prototype, + "length", + {get = function(self) + return self.size + end}, + true +) +function KafkatorioPacketQueueManager.prototype.enqueue(self, packet) + local last = self.last + self.last = {value = packet} + if last ~= nil then + last.next = self.last + end + if self.first == nil then + self.first = self.last + end + self.size = self.size + 1 +end +function KafkatorioPacketQueueManager.prototype.dequeue(self) + local first = self.first + if first == nil then + return nil + end + self.first = first.next or nil + self.size = self.size - 1 + return first.value +end +local KafkatorioPacketQueue = __TS__New(____exports.KafkatorioPacketQueueManager) +____exports.default = KafkatorioPacketQueue +return ____exports diff --git a/modules/events-mod/src/generated/lua/main/PacketEmitter.lua b/modules/events-mod/src/generated/lua/main/emitting/PacketEmitter.lua similarity index 100% rename from modules/events-mod/src/generated/lua/main/PacketEmitter.lua rename to modules/events-mod/src/generated/lua/main/emitting/PacketEmitter.lua diff --git a/modules/events-mod/src/generated/lua/main/events/consoleUpdates.lua b/modules/events-mod/src/generated/lua/main/events/consoleUpdates.lua index daf3956..b764aa4 100644 --- a/modules/events-mod/src/generated/lua/main/events/consoleUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/consoleUpdates.lua @@ -1,21 +1,20 @@ local ____exports = {} -local ____PacketEmitter = require("main.PacketEmitter") -local PacketEmitter = ____PacketEmitter.default local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData -local Type = KafkatorioPacketData.Type +local ____KafkatorioPacketQueue = require("main.emitting.KafkatorioPacketQueue") +local KafkatorioPacketQueue = ____KafkatorioPacketQueue.default script.on_event( defines.events.on_console_chat, function(event) - local update = {type = Type.ConsoleChatUpdate, authorPlayerIndex = event.player_index or nil, content = event.message} - PacketEmitter:emitInstantPacket(update) + local update = {type = KafkatorioPacketData.Type.ConsoleChatUpdate, authorPlayerIndex = event.player_index or nil, content = event.message} + KafkatorioPacketQueue:enqueue(update) end ) script.on_event( defines.events.on_console_command, function(event) - local update = {type = Type.ConsoleCommandUpdate, authorPlayerIndex = event.player_index or nil, command = event.command, parameters = event.parameters} - PacketEmitter:emitInstantPacket(update) + local update = {type = KafkatorioPacketData.Type.ConsoleCommandUpdate, authorPlayerIndex = event.player_index or nil, command = event.command, parameters = event.parameters} + KafkatorioPacketQueue:enqueue(update) end ) return ____exports diff --git a/modules/events-mod/src/generated/lua/main/events/handlers/ConfigurationUpdateHandler.lua b/modules/events-mod/src/generated/lua/main/events/handlers/ConfigurationUpdateHandler.lua index b81701c..7463e91 100644 --- a/modules/events-mod/src/generated/lua/main/events/handlers/ConfigurationUpdateHandler.lua +++ b/modules/events-mod/src/generated/lua/main/events/handlers/ConfigurationUpdateHandler.lua @@ -9,8 +9,8 @@ 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 +local ____KafkatorioPacketQueue = require("main.emitting.KafkatorioPacketQueue") +local KafkatorioPacketQueue = ____KafkatorioPacketQueue.default ____exports.ConfigurationUpdateHandler = __TS__Class() local ConfigurationUpdateHandler = ____exports.ConfigurationUpdateHandler ConfigurationUpdateHandler.name = "ConfigurationUpdateHandler" @@ -24,7 +24,7 @@ function ConfigurationUpdateHandler.prototype.emitConfigurationUpdate(self, chan allMods = ____exports.ConfigurationUpdateHandler:allMods(changeData), factorioData = ____exports.ConfigurationUpdateHandler:factorioData(changeData) } - PacketEmitter:emitInstantPacket(configUpdateData) + KafkatorioPacketQueue:enqueue(configUpdateData) end function ConfigurationUpdateHandler.factorioData(self, changeData) return {oldVersion = changeData.old_version or nil, newVersion = changeData.new_version or nil} diff --git a/modules/events-mod/src/generated/lua/main/events/handlers/EntityUpdateHandler.lua b/modules/events-mod/src/generated/lua/main/events/handlers/EntityUpdateHandler.lua index 99afb01..16222f5 100644 --- a/modules/events-mod/src/generated/lua/main/events/handlers/EntityUpdateHandler.lua +++ b/modules/events-mod/src/generated/lua/main/events/handlers/EntityUpdateHandler.lua @@ -7,7 +7,7 @@ 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 = require("main.emitting.EventDataCache") local EventDataCache = ____EventDataCache.default ____exports.EntityUpdatesHandler = __TS__Class() local EntityUpdatesHandler = ____exports.EntityUpdatesHandler diff --git a/modules/events-mod/src/generated/lua/main/events/handlers/MapChunkUpdateHandler.lua b/modules/events-mod/src/generated/lua/main/events/handlers/MapChunkUpdateHandler.lua index f047ad7..b4efcbb 100644 --- a/modules/events-mod/src/generated/lua/main/events/handlers/MapChunkUpdateHandler.lua +++ b/modules/events-mod/src/generated/lua/main/events/handlers/MapChunkUpdateHandler.lua @@ -10,8 +10,8 @@ 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 ____EventDataCache = require("main.emitting.EventDataCache") +local EventUpdates = ____EventDataCache.default local MapChunkUpdateHandler = __TS__Class() MapChunkUpdateHandler.name = "MapChunkUpdateHandler" function MapChunkUpdateHandler.prototype.____constructor(self) @@ -124,7 +124,7 @@ function MapChunkUpdateHandler.prototype.handlePreChunkDeleted(self, event) end for ____, position in ipairs(event.positions) do local key = {surfaceIndex = surface.index, chunkPosition = {position.x, position.y}} - EventUpdatesManager:debounce( + EventUpdates:debounce( key, KafkatorioPacketData.Type.MapChunkTileUpdate, function(data) @@ -141,7 +141,7 @@ function MapChunkUpdateHandler.mapTilesUpdateDebounce(self, surface, chunkPositi end local eventName = Converters.eventNameString(event.name) local key = {surfaceIndex = surface.index, chunkPosition = chunkPosition} - EventUpdatesManager:debounce( + EventUpdates:debounce( key, KafkatorioPacketData.Type.MapChunkTileUpdate, function(data) diff --git a/modules/events-mod/src/generated/lua/main/events/handlers/PlayerUpdateHandler.lua b/modules/events-mod/src/generated/lua/main/events/handlers/PlayerUpdateHandler.lua index 0591e9b..f56b95d 100644 --- a/modules/events-mod/src/generated/lua/main/events/handlers/PlayerUpdateHandler.lua +++ b/modules/events-mod/src/generated/lua/main/events/handlers/PlayerUpdateHandler.lua @@ -6,8 +6,8 @@ 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 +local ____EventDataCache = require("main.emitting.EventDataCache") +local EventUpdates = ____EventDataCache.default ____exports.PlayerUpdateHandler = __TS__Class() local PlayerUpdateHandler = ____exports.PlayerUpdateHandler PlayerUpdateHandler.name = "PlayerUpdateHandler" @@ -31,7 +31,7 @@ function PlayerUpdateHandler.prototype.playerUpdateThrottle(self, event, mutate, return end local eventName = Converters.eventNameString(event.name) - EventUpdatesManager:throttle( + EventUpdates:throttle( {index = playerIndex}, KafkatorioPacketData.Type.PlayerUpdate, function(data) diff --git a/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua b/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua index 885348b..09e39b7 100644 --- a/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua @@ -4,7 +4,7 @@ local ____converters = require("main.events.converters") local Converters = ____converters.Converters local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData -local ____PacketEmitter = require("main.PacketEmitter") +local ____PacketEmitter = require("main.emitting.PacketEmitter") local packetEmitter = ____PacketEmitter.default local ____PlayerUpdateHandler = require("main.events.handlers.PlayerUpdateHandler") local PlayerUpdates = ____PlayerUpdateHandler.default diff --git a/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua b/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua index 551e592..145c154 100644 --- a/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua @@ -1,25 +1,21 @@ local ____exports = {} local emit, getMapTilePrototypes, getEntityPrototypes, convertItemGroup, convertItemSubgroup -local ____PacketEmitter = require("main.PacketEmitter") -local PacketEmitter = ____PacketEmitter.default local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local FactorioPrototype = ____kafkatorio_2Dschema.FactorioPrototype local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData local ____converters = require("main.events.converters") local Converters = ____converters.Converters +local ____KafkatorioPacketQueue = require("main.emitting.KafkatorioPacketQueue") +local KafkatorioPacketQueue = ____KafkatorioPacketQueue.default function emit(protosByType) for ____, protos in pairs(protosByType) do - PacketEmitter:emitInstantPacket({type = KafkatorioPacketData.Type.PrototypesUpdate, prototypes = protos}) + KafkatorioPacketQueue:enqueue({type = KafkatorioPacketData.Type.PrototypesUpdate, prototypes = protos}) end end function getMapTilePrototypes() local tiles = {} - if not (tiles.tile ~= nil) then - tiles.tile = {} - end for ____, tile in pairs(game.tile_prototypes) do - local ____tiles_tile_0 = tiles.tile - ____tiles_tile_0[#____tiles_tile_0 + 1] = { + tiles[#tiles + 1] = { type = FactorioPrototype.Type.MapTile, protoId = Converters.prototypeId("tile", tile.name), order = tile.order, @@ -29,13 +25,13 @@ function getMapTilePrototypes() canBeMined = tile.mineable_properties.minable } end - return tiles + return {tiles = tiles} 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 + if protos[key] == nil then protos[key] = {} end local entityProto = { @@ -58,8 +54,8 @@ function getEntityPrototypes() 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 + local ____protos_key_0 = protos[key] + ____protos_key_0[#____protos_key_0 + 1] = entityProto end return protos end @@ -67,19 +63,17 @@ 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 + local ____itemGroup_name_3 = itemGroup.name + local ____itemGroup_type_4 = itemGroup.type + local ____itemGroup_group_name_1 = itemGroup.group + if ____itemGroup_group_name_1 ~= nil then + ____itemGroup_group_name_1 = ____itemGroup_group_name_1.name end - return {name = ____itemGroup_name_4, type = ____itemGroup_type_5, parentName = ____itemGroup_group_name_2} + return {name = ____itemGroup_name_3, type = ____itemGroup_type_4, parentName = ____itemGroup_group_name_1} end function ____exports.emitPrototypes() local mapTileProtos = getMapTilePrototypes() emit(mapTileProtos) - local ____ = game.item_group_prototypes - local ____ = game.item_subgroup_prototypes local entityProtos = getEntityPrototypes() emit(entityProtos) end diff --git a/modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua b/modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua index 421c0b0..4d6e911 100644 --- a/modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua +++ b/modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua @@ -1,16 +1,20 @@ local ____exports = {} -local ____queue = require("main.queue.queue") -local Queue = ____queue.Queue local ____eventTypeCheck = require("main.events.eventTypeCheck") local isEventType = ____eventTypeCheck.isEventType local ____converters = require("main.events.converters") local Converters = ____converters.Converters local ____surfaceUpdates = require("main.events.surfaceUpdates") local handleSurfaceUpdate = ____surfaceUpdates.handleSurfaceUpdate -local ____EventDataCache = require("main.cache.EventDataCache") +local ____EventDataCache = require("main.emitting.EventDataCache") local EventCacheService = ____EventDataCache.default local ____MapChunkUpdateHandler = require("main.events.handlers.MapChunkUpdateHandler") local MapChunkUpdate = ____MapChunkUpdateHandler.default +local ____queue = require("main.queue.queue") +local EventDataQueue = ____queue.default +local ____KafkatorioPacketQueue = require("main.emitting.KafkatorioPacketQueue") +local KafkatorioPacketQueue = ____KafkatorioPacketQueue.default +local ____PacketEmitter = require("main.emitting.PacketEmitter") +local PacketEmitter = ____PacketEmitter.default script.on_event( defines.events.on_tick, function(event) @@ -23,6 +27,10 @@ script.on_event( ) end end + local kPacket = KafkatorioPacketQueue:dequeue() + if kPacket ~= nil then + PacketEmitter:emitInstantPacket(kPacket) + end if event.tick % 6 == 0 then local emittedCount = EventCacheService:extractAndEmitExpiredPackets() if emittedCount > 0 then @@ -30,9 +38,9 @@ script.on_event( end end if event.tick % 7 == 0 then - local events = Queue.dequeueValues(1) + local events = EventDataQueue:dequeueValues(1) if #events > 0 then - log((((("[on_tick:" .. tostring(event.tick)) .. "] dequeued ") .. tostring(#events)) .. " events, current size: ") .. tostring(Queue.size())) + log((((("[on_tick:" .. tostring(event.tick)) .. "] dequeued ") .. tostring(#events)) .. " events, current size: ") .. tostring(EventDataQueue:size())) local i = 1 for ____, event in ipairs(events) do if isEventType(event, defines.events.on_chunk_generated) then diff --git a/modules/events-mod/src/generated/lua/main/events/surfaceUpdates.lua b/modules/events-mod/src/generated/lua/main/events/surfaceUpdates.lua index 3e2f804..a1ff33a 100644 --- a/modules/events-mod/src/generated/lua/main/events/surfaceUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/surfaceUpdates.lua @@ -1,5 +1,5 @@ local ____exports = {} -local ____PacketEmitter = require("main.PacketEmitter") +local ____PacketEmitter = require("main.emitting.PacketEmitter") local PacketEmitter = ____PacketEmitter.default local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData diff --git a/modules/events-mod/src/generated/lua/main/global-init.lua b/modules/events-mod/src/generated/lua/main/global-init.lua index 5f21c61..28b970b 100644 --- a/modules/events-mod/src/generated/lua/main/global-init.lua +++ b/modules/events-mod/src/generated/lua/main/global-init.lua @@ -1,8 +1,8 @@ local ____exports = {} +local ____EventDataCache = require("main.emitting.EventDataCache") +local EventUpdates = ____EventDataCache.default local ____queue = require("main.queue.queue") -local Queue = ____queue.Queue -local ____EventDataCache = require("main.cache.EventDataCache") -local EventUpdatesManager = ____EventDataCache.default +local EventDataQueueManager = ____queue.EventDataQueueManager function ____exports.initGlobal(force) if force == nil then force = false @@ -10,8 +10,8 @@ function ____exports.initGlobal(force) log(("Initialising Kafkatorio Global variables (force=" .. tostring(force)) .. ")...") global.MOD_VERSION = script.active_mods[script.mod_name] global.FACTORIO_VERSION = script.active_mods.base - Queue.init(true) - EventUpdatesManager:init(true) + EventDataQueueManager:init(true) + EventUpdates:init(true) log("Finished initialising Kafkatorio Global variables") end return ____exports diff --git a/modules/events-mod/src/generated/lua/main/queue/queue.lua b/modules/events-mod/src/generated/lua/main/queue/queue.lua index 2dcf0ca..a8da3b8 100644 --- a/modules/events-mod/src/generated/lua/main/queue/queue.lua +++ b/modules/events-mod/src/generated/lua/main/queue/queue.lua @@ -1,84 +1,87 @@ local ____lualib = require("lualib_bundle") -local __TS__New = ____lualib.__TS__New local __TS__Class = ____lualib.__TS__Class +local __TS__New = ____lualib.__TS__New local ____exports = {} -____exports.Queue = {} -local Queue = ____exports.Queue -do - local Node - function Queue.init(force) - local isAnythingUndefined = global.store == nil or global.size == nil or global.head == nil or global.tail == nil - log(((("Initialising EventQueue globals (force=" .. tostring(force)) .. ", isAnythingUndefined=") .. tostring(isAnythingUndefined)) .. ")") - if force == true or isAnythingUndefined then - global.store = {} - global.head = nil - global.tail = nil - global.size = 0 - end - log("Finished initialising EventQueue") +local Node +____exports.EventDataQueueManager = __TS__Class() +local EventDataQueueManager = ____exports.EventDataQueueManager +EventDataQueueManager.name = "EventDataQueueManager" +function EventDataQueueManager.prototype.____constructor(self) +end +function EventDataQueueManager.init(self, force) + local isAnythingUndefined = global.store == nil or global.size == nil or global.head == nil or global.tail == nil + log(((("Initialising EventDataQueueManager globals (force=" .. tostring(force)) .. ", isAnythingUndefined=") .. tostring(isAnythingUndefined)) .. ")") + if force == true or isAnythingUndefined then + global.store = {} + global.head = nil + global.tail = nil + global.size = 0 end - function Queue.size() - return global.size + log("Finished initialising EventDataQueueManager") +end +function EventDataQueueManager.prototype.size(self) + return global.size +end +function EventDataQueueManager.prototype.enqueue(self, key, event, weight) + if weight == nil then + weight = 1 end - function Queue.enqueue(key, event, weight) - if weight == nil then - weight = 1 - end - if global.store[key] ~= nil then - local node = __TS__New(Node, key, weight) - if global.head == nil then - global.head = node - end - if global.tail ~= nil then - global.tail.next = node - end - global.tail = node - global.size = global.size + 1 - end - global.store[key] = event - end - function Queue.dequeue() + if global.store[key] ~= nil then + local node = __TS__New(Node, key, weight) if global.head == nil then + global.head = node + end + if global.tail ~= nil then + global.tail.next = node + end + global.tail = node + global.size = global.size + 1 + end + global.store[key] = event +end +function EventDataQueueManager.prototype.dequeue(self) + if global.head == nil then + return nil + else + local weight = global.head.weight + local storeKey = global.head.storeKey + global.head = global.head.next + global.size = global.size - 1 + local storedPacket = global.store[storeKey] + global.store[storeKey] = nil + if storedPacket == nil then return nil else - local weight = global.head.weight - local storeKey = global.head.storeKey - global.head = global.head.next - global.size = global.size - 1 - local storedPacket = global.store[storeKey] - global.store[storeKey] = nil - if storedPacket == nil then - return nil - else - return {value = storedPacket, weight = weight} - end + return {value = storedPacket, weight = weight} end end - function Queue.dequeueValues(targetWeight) - if targetWeight == nil then - targetWeight = 50 - end - local values = {} - local weight = 0 - repeat - do - local packet = Queue.dequeue() - if packet == nil then - break - else - weight = weight + packet.weight - values[#values + 1] = packet.value - end - end - until not (weight <= targetWeight) - return values - end - Node = __TS__Class() - Node.name = "Node" - function Node.prototype.____constructor(self, storeKey, weight) - self.next = nil - self.storeKey = storeKey - self.weight = weight - end +end +function EventDataQueueManager.prototype.dequeueValues(self, targetWeight) + if targetWeight == nil then + targetWeight = 50 + end + local values = {} + local weight = 0 + repeat + do + local packet = self:dequeue() + if packet == nil then + break + else + weight = weight + packet.weight + values[#values + 1] = packet.value + end + end + until not (weight <= targetWeight) + return values +end +local EventDataQueue = __TS__New(____exports.EventDataQueueManager) +____exports.default = EventDataQueue +Node = __TS__Class() +Node.name = "Node" +function Node.prototype.____constructor(self, storeKey, weight) + self.next = nil + self.storeKey = storeKey + self.weight = weight end return ____exports diff --git a/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts b/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts deleted file mode 100644 index 4c9b572..0000000 --- a/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts +++ /dev/null @@ -1,235 +0,0 @@ -import KafkatorioSettings from "../settings/KafkatorioSettings"; -import {KafkatorioKeyedPacketData} from "../types"; -import packetEmitter from "../PacketEmitter"; - -export namespace EventUpdates { - - - declare const global: { - /** Map the hash of the key, as a string, a cache entry */ - cache: LuaTable>, - } - - - export class Manager { - - - init(force?: boolean) { - - const isAnythingUndefined = global.cache == undefined - - log(`Initialising EventDataCache (force=${force}, isAnythingUndefined=${isAnythingUndefined})...`) - - if (force == true || isAnythingUndefined) { - log("Initialising global.cache") - global.cache = new LuaTable>() - } - log(`Finished initialising EventDataCache`) - } - - - /** - * Update the cache data without restarting the 'time-to-emit' countdown, so that the data won't - * be emitted more than once per {@link CacheEntry.expirationDurationTicks}. - */ - public throttle( - key: PacketKey, - type: PacketType, - mutate: CacheDataMutator, - expirationDurationTicks?: uint, - ) { - this.update(key, type, mutate, false, expirationDurationTicks) - } - - - /** - * Update the cache data and reset the 'time-to-emit' countdown, so the data won't be emitted - * until there's an inactivity gap of {@link CacheEntry.expirationDurationTicks}. - */ - public debounce( - key: PacketKey, - type: PacketType, - mutate: CacheDataMutator, - expirationDurationTicks?: uint, - ) { - this.update(key, type, mutate, true, expirationDurationTicks) - } - - - private update( - key: PacketKey, - type: PacketType, - mutate: CacheDataMutator, - resetLastUpdated: boolean, - expirationDurationTicks?: uint, - ) { - const entry: CacheEntry = this.getCacheEntry(key, type) ?? - Manager.createCacheEntry(key, type) - mutate(entry.packet) - if (resetLastUpdated) { - entry.lastUpdatedTick = game.tick - } - if (expirationDurationTicks != undefined) { - entry.expirationDurationTicks = expirationDurationTicks - } - - if (entry.expirationDurationTicks != undefined && entry.expirationDurationTicks <= 0) { - this.extractAndEmitExpiredPackets() - } - } - - - /** - * Usage example: If an urgent update comes in, then the expiration can be reduced so that - * it's transmitted sooner. - */ - public setExpiration( - key: PacketKey, - type: PacketType, - expirationDurationTicks: uint, - ) { - const entry = this.getCacheEntry(key, type) - if (entry != undefined) { - entry.expirationDurationTicks = expirationDurationTicks - } - } - - - /** Removes all expired entries from the cache, and return them. */ - // use in/out v4.7.0 https://github.com/microsoft/TypeScript/pull/48240 - private extractExpired(): Array { - let countExpired = 0 - let countTotal = 0 - const expiredData: Array = [] - for (const [key, entry] of global.cache) { - countTotal++ - if (this.isExpired(entry)) { - countExpired++ - expiredData.push(entry.packet) - global.cache.delete(key) - } - } - - const hasExpiredItems = countExpired > 0 - const hasAnyItem = countTotal > 0 - - if (hasExpiredItems || (game.tick % 30 == 0 && hasAnyItem)) { - log(`[extractExpired] expired items: ${countExpired}, total: ${countTotal}`) - } - return expiredData - } - - - /** - * Removes and emits all expired packets. - * - * @return the number of emitted packets - */ - public extractAndEmitExpiredPackets() { - const cachedEvents: Array = this.extractExpired() - - if (cachedEvents.length > 0) { - log(`[EventDataCache] emitting ${cachedEvents.length} events on tick ${game.tick}`) - for (const event of cachedEvents) { - packetEmitter.emitKeyedPacket(event) - } - } - - return cachedEvents.length - } - - - private getCacheEntry( - key: EventUpdates.PacketKey, - type: EventUpdates.PacketType, - ): CacheEntry | undefined { - const hash = Manager.hashKey(key) - if (!global.cache.has(hash)) { - return undefined - } - const value: CacheEntry = global.cache.get(hash) - if (this.isEntryInstanceOf(value, type)) { - return value - } else { - // Type mismatch. This shouldn't happen... - return undefined - } - } - - - private static createCacheEntry( - key: PacketKey, - type: PacketType, - ): CacheEntry { - const data: PACKET = { - type: type, - key: key, - } - const entry: CacheEntry = new CacheEntry(data) - const hash = Manager.hashKey(key) - global.cache.set(hash, entry) - return entry - } - - - isExpired(entry: CacheEntry): boolean { - const expiryDuration = - entry.expirationDurationTicks - ?? KafkatorioSettings.getEventCacheExpirationTicks(entry.packet) - - if (expiryDuration == undefined) { - return true - } else { - return game.tick - entry.lastUpdatedTick > expiryDuration - } - } - - - isEntryInstanceOf( - entry: CacheEntry | undefined, - type: EventUpdates.PacketType, - ): entry is CacheEntry { - return this.isDataInstanceOf(entry?.packet, type) - } - - - isDataInstanceOf( - packet: PACKET | undefined, - type: EventUpdates.PacketType, - ): packet is PACKET { - return packet != undefined && packet.type == type - } - - private static hashKey( - key: PacketKey, - ): string { - return game.encode_string(game.table_to_json(key))!! - } - - } - - export type PacketKey = PACKET["key"] - export type PacketType = PACKET["type"] - - export type CacheDataMutator = (packet: PACKET) => void - - class CacheEntry { - lastUpdatedTick: uint = game.tick - expirationDurationTicks?: uint - - packet: PACKET - - constructor( - packet: PACKET, - expirationDurationTicks?: uint, - ) { - - this.packet = packet - this.expirationDurationTicks = expirationDurationTicks - } - } -} - -const EventUpdatesManager = new EventUpdates.Manager() - -export default EventUpdatesManager diff --git a/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts b/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts index c9bdcc0..a1e4c67 100644 --- a/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts +++ b/modules/events-mod/src/main/typescript/main/commands/kafkatorioCommands.ts @@ -1,6 +1,6 @@ import {initGlobal} from "../global-init"; -import {Queue} from "../queue/queue"; import {emitPrototypes} from "../events/prototypeUpdates"; +import EventDataQueue from "../queue/queue"; commands.add_command( @@ -58,7 +58,7 @@ commands.add_command( tick: e.tick, } - Queue.enqueue( + EventDataQueue.enqueue( `${surface.index}${chunk.x}${chunk.y}`, data, 50 diff --git a/modules/events-mod/src/main/typescript/main/emitting/EventDataCache.ts b/modules/events-mod/src/main/typescript/main/emitting/EventDataCache.ts new file mode 100644 index 0000000..2547dab --- /dev/null +++ b/modules/events-mod/src/main/typescript/main/emitting/EventDataCache.ts @@ -0,0 +1,240 @@ +import KafkatorioSettings from "../settings/KafkatorioSettings"; +import {KafkatorioKeyedPacketData} from "../types"; +import PacketEmitter from "./PacketEmitter"; + + +declare const global: { + /** Map the hash of the key, as a string, a cache entry */ + eventUpdatesManagerCache: LuaTable>, +} + + +export class EventUpdatesManager { + + constructor() { + this.init() + } + + + init(force?: boolean) { + + const isAnythingUndefined = global.eventUpdatesManagerCache == undefined + + log(`Initialising EventDataCache (force=${force}, isAnythingUndefined=${isAnythingUndefined})...`) + + if (force == true || isAnythingUndefined) { + log("Initialising global.cache") + global.eventUpdatesManagerCache = new LuaTable>() + } + log(`Finished initialising EventDataCache`) + } + + + /** + * Update the cache data without restarting the 'time-to-emit' countdown, so that the data won't + * be emitted more than once per {@link CacheEntry.expirationDurationTicks}. + */ + public throttle( + key: PacketKey, + type: PacketType, + mutate: CacheDataMutator, + expirationDurationTicks?: uint, + ) { + this.update(key, type, mutate, false, expirationDurationTicks) + } + + + /** + * Update the cache data and reset the 'time-to-emit' countdown, so the data won't be emitted + * until there's an inactivity gap of {@link CacheEntry.expirationDurationTicks}. + */ + public debounce( + key: PacketKey, + type: PacketType, + mutate: CacheDataMutator, + expirationDurationTicks?: uint, + ) { + this.update(key, type, mutate, true, expirationDurationTicks) + } + + + private update( + key: PacketKey, + type: PacketType, + mutate: CacheDataMutator, + resetLastUpdated: boolean, + expirationDurationTicks?: uint, + ) { + const entry: CacheEntry = this.getCacheEntry(key, type) ?? + EventUpdatesManager.createCacheEntry(key, type) + mutate(entry.packet) + if (resetLastUpdated) { + entry.lastUpdatedTick = game.tick + } + if (expirationDurationTicks != undefined) { + entry.expirationDurationTicks = expirationDurationTicks + } + + if (entry.expirationDurationTicks != undefined && entry.expirationDurationTicks <= 0) { + this.extractAndEmitExpiredPackets() + } + } + + + /** + * Usage example: If an urgent update comes in, then the expiration can be reduced so that + * it's transmitted sooner. + */ + public setExpiration( + key: PacketKey, + type: PacketType, + expirationDurationTicks: uint, + ) { + const entry = this.getCacheEntry(key, type) + if (entry != undefined) { + entry.expirationDurationTicks = expirationDurationTicks + } + } + + + /** Removes all expired entries from the cache, and return them. */ + // use in/out v4.7.0 https://github.com/microsoft/TypeScript/pull/48240 + private extractExpired(): Array { + let countExpired = 0 + let countTotal = 0 + const expiredData: Array = [] + for (const [key, entry] of global.eventUpdatesManagerCache) { + countTotal++ + if (this.isExpired(entry)) { + countExpired++ + expiredData.push(entry.packet) + global.eventUpdatesManagerCache.delete(key) + } + } + + const hasExpiredItems = countExpired > 0 + const hasAnyItem = countTotal > 0 + + if (hasExpiredItems || (game.tick % 30 == 0 && hasAnyItem)) { + log(`[extractExpired] expired items: ${countExpired}, total: ${countTotal}`) + } + return expiredData + } + + + /** + * Removes and emits all expired packets. + * + * @return the number of emitted packets + */ + public extractAndEmitExpiredPackets() { + const cachedEvents: Array = this.extractExpired() + + if (cachedEvents.length > 0) { + log(`[EventDataCache] emitting ${cachedEvents.length} events on tick ${game.tick}`) + for (const event of cachedEvents) { + PacketEmitter.emitKeyedPacket(event) + } + } + + return cachedEvents.length + } + + + private getCacheEntry( + key: PacketKey, + type: PacketType, + ): CacheEntry | undefined { + const hash = EventUpdatesManager.hashKey(key) + if (!global.eventUpdatesManagerCache.has(hash)) { + return undefined + } + const value: CacheEntry = global.eventUpdatesManagerCache.get(hash) + if (this.isEntryInstanceOf(value, type)) { + return value + } else { + // Type mismatch. This shouldn't happen... + return undefined + } + } + + + private static createCacheEntry( + key: PacketKey, + type: PacketType, + ): CacheEntry { + const data: PACKET = { + type: type, + key: key, + } + const entry: CacheEntry = new CacheEntry(data) + const hash = EventUpdatesManager.hashKey(key) + global.eventUpdatesManagerCache.set(hash, entry) + return entry + } + + + isExpired(entry: CacheEntry): boolean { + const expiryDuration = + entry.expirationDurationTicks + ?? KafkatorioSettings.getEventCacheExpirationTicks(entry.packet) + + if (expiryDuration == undefined) { + return true + } else { + return game.tick - entry.lastUpdatedTick > expiryDuration + } + } + + + isEntryInstanceOf( + entry: CacheEntry | undefined, + type: PacketType, + ): entry is CacheEntry { + return this.isDataInstanceOf(entry?.packet, type) + } + + + isDataInstanceOf( + packet: PACKET | undefined, + type: PacketType, + ): packet is PACKET { + return packet != undefined && packet.type == type + } + + + private static hashKey( + key: PacketKey, + ): string { + return game.encode_string(game.table_to_json(key))!! + } + +} + + +const EventUpdates = new EventUpdatesManager() + +export default EventUpdates + + +export type PacketKey = PACKET["key"] +export type PacketType = PACKET["type"] + +export type CacheDataMutator = (packet: PACKET) => void + + +class CacheEntry { + lastUpdatedTick: uint = game.tick + expirationDurationTicks?: uint + + packet: PACKET + + constructor( + packet: PACKET, + expirationDurationTicks?: uint, + ) { + + this.packet = packet + this.expirationDurationTicks = expirationDurationTicks + } +} diff --git a/modules/events-mod/src/main/typescript/main/emitting/KafkatorioPacketQueue.ts b/modules/events-mod/src/main/typescript/main/emitting/KafkatorioPacketQueue.ts new file mode 100644 index 0000000..406ec86 --- /dev/null +++ b/modules/events-mod/src/main/typescript/main/emitting/KafkatorioPacketQueue.ts @@ -0,0 +1,48 @@ +import {KafkatorioPacketData} from "../../generated/kafkatorio-schema"; + +export class KafkatorioPacketQueueManager { + + private size: int = 0 + private first: Node | null = null + private last: Node | null = null + + public get length() { + return this.size + } + + public enqueue(packet: T) { + const last = this.last + this.last = { + value: packet + } + if (last != null) { + last.next = this.last + } + if (this.first == null) { + this.first = this.last + } + this.size++ + } + + public dequeue(): T | null { + const first = this.first + + if (first == null) { + return null + } + + this.first = first.next ?? null + this.size-- + return first.value + } + +} + +const KafkatorioPacketQueue = new KafkatorioPacketQueueManager() + +export default KafkatorioPacketQueue + +interface Node { + value: T + next?: Node +} diff --git a/modules/events-mod/src/main/typescript/main/PacketEmitter.ts b/modules/events-mod/src/main/typescript/main/emitting/PacketEmitter.ts similarity index 85% rename from modules/events-mod/src/main/typescript/main/PacketEmitter.ts rename to modules/events-mod/src/main/typescript/main/emitting/PacketEmitter.ts index a566499..5c3b943 100644 --- a/modules/events-mod/src/main/typescript/main/PacketEmitter.ts +++ b/modules/events-mod/src/main/typescript/main/emitting/PacketEmitter.ts @@ -1,8 +1,5 @@ -import { - KafkatorioPacket, - KafkatorioPacketData -} from "../generated/kafkatorio-schema"; -import {KafkatorioKeyedPacketData} from "./types"; +import {KafkatorioPacket, KafkatorioPacketData} from "../../generated/kafkatorio-schema"; +import {KafkatorioKeyedPacketData} from "../types"; export class KafkatorioPacketEmitter { diff --git a/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts b/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts index 2dcd812..ddfd728 100644 --- a/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts @@ -1,33 +1,26 @@ -import PacketEmitter from "../PacketEmitter"; import {KafkatorioPacketData} from "../../generated/kafkatorio-schema"; -import Type = KafkatorioPacketData.Type; +import KafkatorioPacketQueue from "../emitting/KafkatorioPacketQueue"; -script.on_event( - defines.events.on_console_chat, - (event: OnConsoleChatEvent) => { - const update: KafkatorioPacketData.ConsoleChatUpdate = { - type: Type.ConsoleChatUpdate, +script.on_event(defines.events.on_console_chat, (event: OnConsoleChatEvent) => { + const update: KafkatorioPacketData.ConsoleChatUpdate = { + type: KafkatorioPacketData.Type.ConsoleChatUpdate, - authorPlayerIndex: event.player_index ?? null, - content: event.message - } - PacketEmitter.emitInstantPacket(update) - } -) + authorPlayerIndex: event.player_index ?? null, + content: event.message + } + KafkatorioPacketQueue.enqueue(update) +}) -script.on_event( - defines.events.on_console_command, - (event: OnConsoleCommandEvent) => { - const update: KafkatorioPacketData.ConsoleCommandUpdate = { - type: Type.ConsoleCommandUpdate, +script.on_event(defines.events.on_console_command, (event: OnConsoleCommandEvent) => { + const update: KafkatorioPacketData.ConsoleCommandUpdate = { + type: KafkatorioPacketData.Type.ConsoleCommandUpdate, - authorPlayerIndex: event.player_index ?? null, - command: event.command, - parameters: event.parameters, - } + authorPlayerIndex: event.player_index ?? null, + command: event.command, + parameters: event.parameters, + } - PacketEmitter.emitInstantPacket(update) - } -) + KafkatorioPacketQueue.enqueue(update) +}) diff --git a/modules/events-mod/src/main/typescript/main/events/handlers/ConfigurationUpdateHandler.ts b/modules/events-mod/src/main/typescript/main/events/handlers/ConfigurationUpdateHandler.ts index b90fec1..72f63a3 100644 --- a/modules/events-mod/src/main/typescript/main/events/handlers/ConfigurationUpdateHandler.ts +++ b/modules/events-mod/src/main/typescript/main/events/handlers/ConfigurationUpdateHandler.ts @@ -3,8 +3,9 @@ import { ConfigurationUpdateModData, KafkatorioPacketData } from "../../../generated/kafkatorio-schema"; -import PacketEmitter from "../../PacketEmitter"; +import PacketEmitter from "../../emitting/PacketEmitter"; import ConfigurationUpdate = KafkatorioPacketData.ConfigurationUpdate; +import KafkatorioPacketQueue from "../../emitting/KafkatorioPacketQueue"; export class ConfigurationUpdateHandler { @@ -20,7 +21,7 @@ export class ConfigurationUpdateHandler { factorioData: ConfigurationUpdateHandler.factorioData(changeData) } - PacketEmitter.emitInstantPacket(configUpdateData) + KafkatorioPacketQueue.enqueue(configUpdateData) } diff --git a/modules/events-mod/src/main/typescript/main/events/handlers/EntityUpdateHandler.ts b/modules/events-mod/src/main/typescript/main/events/handlers/EntityUpdateHandler.ts index 7ac7d13..19c7afc 100644 --- a/modules/events-mod/src/main/typescript/main/events/handlers/EntityUpdateHandler.ts +++ b/modules/events-mod/src/main/typescript/main/events/handlers/EntityUpdateHandler.ts @@ -6,7 +6,7 @@ import { Tick } from "../../../generated/kafkatorio-schema"; import {Converters} from "../converters"; -import EventDataCache from "../../cache/EventDataCache"; +import EventDataCache from "../../emitting/EventDataCache"; export class EntityUpdatesHandler { diff --git a/modules/events-mod/src/main/typescript/main/events/handlers/MapChunkUpdateHandler.ts b/modules/events-mod/src/main/typescript/main/events/handlers/MapChunkUpdateHandler.ts index fabbe7c..5fcb365 100644 --- a/modules/events-mod/src/main/typescript/main/events/handlers/MapChunkUpdateHandler.ts +++ b/modules/events-mod/src/main/typescript/main/events/handlers/MapChunkUpdateHandler.ts @@ -3,13 +3,11 @@ import {isEventType} from "../eventTypeCheck"; import { KafkatorioPacketData, MapChunkPosition, - MinedProduct, PrototypeKey } from "../../../generated/kafkatorio-schema"; -import EventUpdatesManager, {EventUpdates} from "../../cache/EventDataCache"; +import EventUpdates, {PacketKey} from "../../emitting/EventDataCache"; import {MapChunkUpdateEvent, MapTileChangeEvent} from "../mapChunkUpdates"; -import PacketKey = EventUpdates.PacketKey; -import Type = MinedProduct.Type; + type MapChunkTileUpdater = (data: KafkatorioPacketData.MapChunkTileUpdate) => void @@ -141,7 +139,7 @@ class MapChunkUpdateHandler { chunkPosition: [position.x, position.y], } - EventUpdatesManager.debounce( + EventUpdates.debounce( key, KafkatorioPacketData.Type.MapChunkTileUpdate, data => data.isDeleted = true, @@ -171,7 +169,7 @@ class MapChunkUpdateHandler { chunkPosition: chunkPosition, } - EventUpdatesManager.debounce( + EventUpdates.debounce( key, KafkatorioPacketData.Type.MapChunkTileUpdate, data => { diff --git a/modules/events-mod/src/main/typescript/main/events/handlers/PlayerUpdateHandler.ts b/modules/events-mod/src/main/typescript/main/events/handlers/PlayerUpdateHandler.ts index d9a9a14..59e243b 100644 --- a/modules/events-mod/src/main/typescript/main/events/handlers/PlayerUpdateHandler.ts +++ b/modules/events-mod/src/main/typescript/main/events/handlers/PlayerUpdateHandler.ts @@ -1,6 +1,6 @@ import {KafkatorioPacketData} from "../../../generated/kafkatorio-schema"; import {Converters} from "../converters"; -import EventUpdatesManager from "../../cache/EventDataCache"; +import EventUpdates from "../../emitting/EventDataCache"; export type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void @@ -43,7 +43,7 @@ export class PlayerUpdateHandler { const eventName = Converters.eventNameString(event.name) - EventUpdatesManager.throttle( + EventUpdates.throttle( {index: playerIndex}, KafkatorioPacketData.Type.PlayerUpdate, data => { diff --git a/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts b/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts index d20afb4..da34131 100644 --- a/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts @@ -1,6 +1,6 @@ import {Converters} from "./converters"; import {ForceIndex, KafkatorioPacketData, PlayerUpdateKey} from "../../generated/kafkatorio-schema"; -import packetEmitter from "../PacketEmitter"; +import packetEmitter from "../emitting/PacketEmitter"; import PlayerUpdates from "./handlers/PlayerUpdateHandler"; diff --git a/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts b/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts index 6d17469..73dd991 100644 --- a/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts @@ -1,13 +1,14 @@ -import PacketEmitter from "../PacketEmitter"; +import PacketEmitter from "../emitting/PacketEmitter"; import { EntityItemGroup, FactorioPrototype, KafkatorioPacketData } from "../../generated/kafkatorio-schema"; import {Converters} from "./converters"; +import KafkatorioPacketQueue from "../emitting/KafkatorioPacketQueue"; -type PrototypesByType = LuaTable +type PrototypesByType = Record export function emitPrototypes() { @@ -16,10 +17,6 @@ export function emitPrototypes() { emit(mapTileProtos) - game.item_group_prototypes - game.item_subgroup_prototypes - - const entityProtos: PrototypesByType = getEntityPrototypes() emit(entityProtos) } @@ -27,7 +24,7 @@ export function emitPrototypes() { function emit(protosByType: PrototypesByType) { for (const [, protos] of pairs(protosByType)) { - PacketEmitter.emitInstantPacket({ + KafkatorioPacketQueue.enqueue({ type: KafkatorioPacketData.Type.PrototypesUpdate, prototypes: protos, }) @@ -36,13 +33,10 @@ function emit(protosByType: PrototypesByType) { function getMapTilePrototypes(): PrototypesByType { - const tiles = new LuaTable() - if (!tiles.has("tile")) { - tiles.set("tile", []) - } + const tiles: FactorioPrototype.MapTile[] = [] for (const [, tile] of game.tile_prototypes) { - tiles.get("tile").push({ + tiles[tiles.length] = { type: FactorioPrototype.Type.MapTile, protoId: Converters.prototypeId("tile", tile.name), @@ -51,21 +45,22 @@ function getMapTilePrototypes(): PrototypesByType { collisionMasks: Converters.convertCollisionMaskToNames(tile.collision_mask), mapColour: Converters.mapColour(tile.map_color), canBeMined: tile.mineable_properties.minable, - }) + } + } + + return { + "tiles": tiles } - return tiles } function getEntityPrototypes(): PrototypesByType { - const protos = new LuaTable() + const protos: PrototypesByType = {} for (const [, entity] of game.entity_prototypes) { const key: string = `${entity.group.name}/${entity.subgroup.name}` - if (!protos.has(key)) { - protos.set(key, []) - } + protos[key] ??= [] const entityProto: FactorioPrototype.Entity = { type: FactorioPrototype.Type.Entity, @@ -91,7 +86,7 @@ function getEntityPrototypes(): PrototypesByType { } entityProto.miningProperties = Converters.miningProperties(entity.mineable_properties) - protos.get(key).push(entityProto) + protos[key].push(entityProto) } return protos } diff --git a/modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts b/modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts index 54ee97e..cd0ee06 100644 --- a/modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts +++ b/modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts @@ -1,45 +1,50 @@ -import {Queue} from "../queue/queue"; import {isEventType} from "./eventTypeCheck"; import {Converters} from "./converters"; import {handleSurfaceUpdate} from "./surfaceUpdates"; -import EventCacheService from "../cache/EventDataCache"; +import EventCacheService from "../emitting/EventDataCache"; import MapChunkUpdate from "./handlers/MapChunkUpdateHandler"; +import EventDataQueue from "../queue/queue"; +import KafkatorioPacketQueue from "../emitting/KafkatorioPacketQueue"; +import PacketEmitter from "../emitting/PacketEmitter"; +import {KafkatorioPacketData} from "../../generated/kafkatorio-schema"; -script.on_event( - defines.events.on_tick, - (event: OnTickEvent) => { - if (event.tick % 1000 == 0) { - for (const [, surface] of game.surfaces) { - handleSurfaceUpdate(event, Converters.eventNameString(event.name), surface) - } - } +script.on_event(defines.events.on_tick, (event: OnTickEvent) => { + if (event.tick % 1000 == 0) { + for (const [, surface] of game.surfaces) { + handleSurfaceUpdate(event, Converters.eventNameString(event.name), surface) + } + } - if (event.tick % 6 == 0) { - // Every 0.1 seconds - const emittedCount = EventCacheService.extractAndEmitExpiredPackets() - if (emittedCount > 0) { - log(`[on_tick:${event.tick}] emitted ${emittedCount} events`) - } - } + const kPacket: KafkatorioPacketData | null = KafkatorioPacketQueue.dequeue() + if (kPacket != null) { + PacketEmitter.emitInstantPacket(kPacket) + } - if (event.tick % 7 == 0) { - const events: EventData[] = Queue.dequeueValues(1) + if (event.tick % 6 == 0) { + // Every 0.1 seconds + const emittedCount = EventCacheService.extractAndEmitExpiredPackets() + if (emittedCount > 0) { + log(`[on_tick:${event.tick}] emitted ${emittedCount} events`) + } + } - if (events.length > 0) { - log(`[on_tick:${event.tick}] dequeued ${events.length} events, current size: ${Queue.size()}`) + if (event.tick % 7 == 0) { + const events: EventData[] = EventDataQueue.dequeueValues(1) - let i = 1 - for (const event of events) { - if (isEventType(event, defines.events.on_chunk_generated)) { - let eName = Converters.eventNameString(event.name) + if (events.length > 0) { + log(`[on_tick:${event.tick}] dequeued ${events.length} events, current size: ${EventDataQueue.size()}`) - log(`[on_tick:${event.tick}] dequed event ${eName}, delay ${i}`) - MapChunkUpdate.handleChunkGeneratedEvent(event, i) - i += 1 - } - } + let i = 1 + for (const event of events) { + if (isEventType(event, defines.events.on_chunk_generated)) { + let eName = Converters.eventNameString(event.name) + + log(`[on_tick:${event.tick}] dequed event ${eName}, delay ${i}`) + MapChunkUpdate.handleChunkGeneratedEvent(event, i) + i += 1 } } } -) + } +}) diff --git a/modules/events-mod/src/main/typescript/main/events/settingsUpdate.ts b/modules/events-mod/src/main/typescript/main/events/settingsUpdate.ts index 93e3593..e22b244 100644 --- a/modules/events-mod/src/main/typescript/main/events/settingsUpdate.ts +++ b/modules/events-mod/src/main/typescript/main/events/settingsUpdate.ts @@ -1,7 +1,4 @@ -script.on_event( - defines.events.on_runtime_mod_setting_changed, - (e: OnRuntimeModSettingChangedEvent) => { - print(`Settings changed ${e.setting_type}, ${e.player_index}, ${e.setting}, ${e.mod_name}`) - // KafkatorioSettings.loadSettings() - } -) +script.on_event(defines.events.on_runtime_mod_setting_changed, (e: OnRuntimeModSettingChangedEvent) => { + print(`Settings changed ${e.setting_type}, ${e.player_index}, ${e.setting}, ${e.mod_name}`) + // KafkatorioSettings.loadSettings() +}) diff --git a/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts b/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts index a2bde69..005ca34 100644 --- a/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts @@ -1,4 +1,4 @@ -import PacketEmitter from "../PacketEmitter"; +import PacketEmitter from "../emitting/PacketEmitter"; import {KafkatorioPacketData} from "../../generated/kafkatorio-schema"; import Type = KafkatorioPacketData.Type; diff --git a/modules/events-mod/src/main/typescript/main/global-init.ts b/modules/events-mod/src/main/typescript/main/global-init.ts index 9670afb..21b366b 100644 --- a/modules/events-mod/src/main/typescript/main/global-init.ts +++ b/modules/events-mod/src/main/typescript/main/global-init.ts @@ -1,5 +1,5 @@ -import {Queue} from "./queue/queue"; -import EventUpdatesManager from "./cache/EventDataCache"; +import EventUpdates from "./emitting/EventDataCache"; +import {EventDataQueueManager} from "./queue/queue"; export function initGlobal(force: boolean = false) { @@ -8,8 +8,8 @@ export function initGlobal(force: boolean = false) { global.MOD_VERSION = script.active_mods[script.mod_name] global.FACTORIO_VERSION = script.active_mods["base"] - Queue.init(true) - EventUpdatesManager.init(true) + EventDataQueueManager.init(true) + EventUpdates.init(true) log("Finished initialising Kafkatorio Global variables") } diff --git a/modules/events-mod/src/main/typescript/main/queue/queue.ts b/modules/events-mod/src/main/typescript/main/queue/queue.ts index 95fd0cd..725ae75 100644 --- a/modules/events-mod/src/main/typescript/main/queue/queue.ts +++ b/modules/events-mod/src/main/typescript/main/queue/queue.ts @@ -1,23 +1,13 @@ -export namespace Queue { +export class EventDataQueueManager { - declare const global: { - store: EventQueueStore - - head: Node | null - tail: Node | null - - size: uint - } - - - export function init(force?: boolean) { + static init(force?: boolean) { const isAnythingUndefined = global.store == undefined || global.size == undefined || global.head == undefined || global.tail == undefined - log(`Initialising EventQueue globals (force=${force}, isAnythingUndefined=${isAnythingUndefined})`) + log(`Initialising EventDataQueueManager globals (force=${force}, isAnythingUndefined=${isAnythingUndefined})`) if (force == true || isAnythingUndefined) { global.store = {} @@ -26,16 +16,16 @@ export namespace Queue { global.size = 0 } - log(`Finished initialising EventQueue`) + log(`Finished initialising EventDataQueueManager`) } - export function size(): uint | undefined { + size(): uint | undefined { return global.size } - export function enqueue(key: string, event: EventData, weight: int = 1) { + enqueue(key: string, event: EventData, weight: int = 1) { if (key ! in global.store) { let node = new Node(key, weight) if (global.head == null) { @@ -52,7 +42,7 @@ export namespace Queue { } - export function dequeue(): WeightedPacket | null { + dequeue(): WeightedPacket | null { if (global.head == null) { return null } else { @@ -76,12 +66,12 @@ export namespace Queue { } - export function dequeueValues(targetWeight: uint = 50): EventData[] { + dequeueValues(targetWeight: uint = 50): EventData[] { let values: EventData[] = [] let weight: uint = 0 do { - let packet = dequeue() + let packet = this.dequeue() if (packet == null) { break; @@ -94,27 +84,43 @@ export namespace Queue { return values } - - class Node { - storeKey: string; - next: Node | null = null; - weight: uint - - constructor(storeKey: string, weight: uint) { - this.storeKey = storeKey; - this.weight = weight - } - } - - - interface EventQueueStore { - [key: string]: EventData | null; - } - - - interface WeightedPacket { - value: EventData, - weight: int, - } - +} + + +const EventDataQueue = new EventDataQueueManager() + + +export default EventDataQueue + + +declare const global: { + store: EventQueueStore + + head: Node | null + tail: Node | null + + size: uint +} + + +class Node { + storeKey: string; + next: Node | null = null; + weight: uint + + constructor(storeKey: string, weight: uint) { + this.storeKey = storeKey; + this.weight = weight + } +} + + +interface EventQueueStore { + [key: string]: EventData | null; +} + + +interface WeightedPacket { + value: EventData, + weight: int, }