hack together some sort of queue to help stop the chunk updates overloading the server. It doesn't work too well I think...

This commit is contained in:
Adam 2022-01-23 13:50:21 +01:00
parent f2ccbbd456
commit 678cf5504e
11 changed files with 228 additions and 30 deletions

View file

@ -1,6 +1,13 @@
import {handleConfigurationUpdate} from "./main/config-update/handleConfigurationUpdate"; import {handleConfigurationUpdate} from "./main/config-update/handleConfigurationUpdate";
import {emitPrototypes} from "./main/config-update/prototypes";
import {Queue} from "./main/queue/queue";
require("./main/events/registerHandlers") require("./main/events/registerHandlers")
require("./main/commands/kafkatorioCommands") require("./main/commands/kafkatorioCommands")
script.on_configuration_changed(handleConfigurationUpdate) script.on_configuration_changed(handleConfigurationUpdate)
script.on_init(() => {
Queue.reset()
emitPrototypes()
})

View file

@ -1,7 +1,9 @@
import {emitPrototypes} from "../config-update/prototypes"; import {emitPrototypes} from "../config-update/prototypes";
import {handleChunkUpdate} from "../events/handlers"; import {handleChunkUpdate} from "../events/handlers";
import {Queue} from "../queue/queue";
import floor = math.floor; import floor = math.floor;
commands.add_command( commands.add_command(
"kafkatorio", "kafkatorio",
"kafkatorio innit bruv", "kafkatorio innit bruv",
@ -36,7 +38,7 @@ commands.add_command(
handleChunkUpdate( handleChunkUpdate(
e.tick, e.tick,
"player-command", "player-command-" + e.parameter,
player.surface.index, player.surface.index,
chunkPosition, chunkPosition,
chunkArea, chunkArea,
@ -44,23 +46,50 @@ commands.add_command(
} }
} else if ("CHUNKS" == e.parameter.toUpperCase()) { } else if ("CHUNKS" == e.parameter.toUpperCase()) {
for (let [, surface] of game.surfaces) { if (e.player_index != undefined) {
for (let chunk of surface.get_chunks()) { let player = game.players[e.player_index]
if (
(chunk.x >= -16 || chunk.x <= 16) let chunkPosition: ChunkPosition = {
&& x: floor(player.position.x / 32),
(chunk.y >= -16 || chunk.y <= 16) y: floor(player.position.y / 32),
) { }
handleChunkUpdate(
e.tick, let delta = 1
"player-command",
surface.index, let chunkXMin = chunkPosition.x - delta
chunk, let chunkXMax = chunkPosition.x + delta
chunk.area, let chunkYMin = chunkPosition.y - delta
) let chunkYMax = chunkPosition.y + delta
for (let [, surface] of game.surfaces) {
for (let chunk of surface.get_chunks()) {
if (
(chunk.x >= chunkXMin || chunk.x <= chunkXMax)
&&
(chunk.y >= chunkYMin || chunk.y <= chunkYMax)
) {
let data: OnChunkGeneratedEvent = {
name: defines.events.on_chunk_generated,
position: {x: chunk.x, y: chunk.y},
area: chunk.area,
surface: surface,
tick: e.tick
}
Queue.enqueue(
`${surface.index}${chunk.x}${chunk.y}`,
data,
50
)
}
} }
} }
} }
} else if ("QUEUE_RESET" == e.parameter.toUpperCase()) {
Queue.reset()
} else if ("QUEUE_INIT" == e.parameter.toUpperCase()) {
Queue.init()
} }
} }
) )

View file

@ -1,6 +1,7 @@
import {emitPacket} from "../emitKafkatorioPacket"; import {emitPacket} from "../emitKafkatorioPacket";
import {updateGlobal} from "./updateGlobal"; import {updateGlobal} from "./updateGlobal";
import {emitPrototypes} from "./prototypes"; import {emitPrototypes} from "./prototypes";
import {Queue} from "../queue/queue";
export function handleConfigurationUpdate(changeData: ConfigurationChangedData) { export function handleConfigurationUpdate(changeData: ConfigurationChangedData) {
updateGlobal() updateGlobal()
@ -12,6 +13,7 @@ export function handleConfigurationUpdate(changeData: ConfigurationChangedData)
factorioData: factorioData(changeData) factorioData: factorioData(changeData)
}) })
Queue.reset()
emitPrototypes() emitPrototypes()
} }

View file

@ -1,6 +1,7 @@
/** Emit a serialised KafkatorioPacket */ /** Emit a serialised KafkatorioPacket */
export function emitPacket<T extends KafkatorioPacket>(packet: T) { export function emitPacket<T extends KafkatorioPacket>(packet: T) {
let data = game.table_to_json(packet) let data = game.table_to_json(packet)
// localised_print(`KafkatorioPacket: ${packet.packetType}`)
localised_print(`KafkatorioPacket: ${data}`) localised_print(`KafkatorioPacket: ${data}`)
// rcon.print(`KafkatorioPacket: ${data}`) // rcon.print(`KafkatorioPacket: ${data}`)
} }

View file

@ -1,6 +1,3 @@
// const SERVER_ID: uint = 0
// const EVENT_FILE_DIR: string = "events"
import {emitPacket} from "../emitKafkatorioPacket"; import {emitPacket} from "../emitKafkatorioPacket";
/** Emit a serialised event */ /** Emit a serialised event */

View file

@ -1,12 +1,10 @@
import {Converters} from "./converters" import {Converters} from "./converters"
import {emitEvent} from "./emitEvent"; import {emitEvent} from "./emitEvent";
export function handlePlayerUpdate(tick: uint, eventType: string, playerIndex: uint) { export function handlePlayerUpdate(tick: uint, eventType: string, playerIndex: uint) {
let player: LuaPlayer = game.players[playerIndex] let player: LuaPlayer = game.players[playerIndex]
let table = Converters.playerToTable(player) let table = Converters.playerToTable(player)
emitEvent(table, tick, eventType) emitEvent(table, tick, eventType)
handleCharactersEvent(tick, eventType, playerIndex) handleCharactersEvent(tick, eventType, playerIndex)
@ -50,8 +48,6 @@ export function handleConsoleChat(
emitEvent(table, tick, eventType) emitEvent(table, tick, eventType)
} }
// const CHUNK_SIZE = 32
export function handleChunkUpdate( export function handleChunkUpdate(
tick: uint, tick: uint,
eventType: string, eventType: string,
@ -64,8 +60,6 @@ export function handleChunkUpdate(
let tiles: LuaTile[] = surface?.find_tiles_filtered({ let tiles: LuaTile[] = surface?.find_tiles_filtered({
area: area, area: area,
// position: {x: x, y: y},
// radius: CHUNK_SIZE,
collision_mask: ["ground-tile", "water-tile"] collision_mask: ["ground-tile", "water-tile"]
} }
) ?? [] ) ?? []

View file

@ -6,13 +6,20 @@ import {
handleSurfaceUpdate, handleSurfaceUpdate,
handleTilesUpdate handleTilesUpdate
} from "./handlers"; } from "./handlers";
import {Queue} from "../queue/queue";
import on_player_built_tile = defines.events.on_player_built_tile; import on_player_built_tile = defines.events.on_player_built_tile;
import on_robot_built_tile = defines.events.on_robot_built_tile; import on_robot_built_tile = defines.events.on_robot_built_tile;
const mapEventIdToName = new LuaTable<defines.Events, keyof typeof defines.events>() const mapEventIdToName = new LuaTable<defines.Events, keyof typeof defines.events>()
for (const [k, v] of pairs(defines.events)) { for (const [eventName, eventId] of pairs(defines.events)) {
mapEventIdToName.set(v, k) mapEventIdToName.set(eventId, eventName)
}
const mapEventIdToDefinedType = new LuaTable<EventId<EventData>, EventId<EventData>>()
for (const [eventName, eventId] of pairs(defines.events)) {
let definedType = defines.events[eventName]
mapEventIdToDefinedType.set(eventId, definedType)
} }
// script.on_event( // script.on_event(
@ -34,6 +41,9 @@ script.on_event(
script.on_event( script.on_event(
defines.events.on_player_joined_game, defines.events.on_player_joined_game,
(e: OnPlayerJoinedGameEvent) => { (e: OnPlayerJoinedGameEvent) => {
Queue.init() // TODO make Queue initialisation more stable, not dependent on events
handlePlayerUpdate(e.tick, mapEventIdToName.get(e.name), e.player_index) handlePlayerUpdate(e.tick, mapEventIdToName.get(e.name), e.player_index)
} }
) )
@ -52,6 +62,29 @@ script.on_event(
for (const [, surface] of pairs(game.surfaces)) { for (const [, surface] of pairs(game.surfaces)) {
handleSurfaceUpdate(e.tick, mapEventIdToName.get(e.name), surface) handleSurfaceUpdate(e.tick, mapEventIdToName.get(e.name), surface)
} }
// let packets = new KafkatorioPacketQueue().dequeueValues(1)
// for (const packet of packets) {
// emitPacket(packet)
// }
}
if (e.tick % 30 == 0) {
let events: EventData[] = Queue.dequeueValues(1)
if (events.length > 0) {
log(`[${e.tick}] dequed ${events.length} events, current size: ${Queue.size()}`)
for (const event of events) {
if (isEventType<OnChunkGeneratedEvent>(event)) {
let eName = mapEventIdToName.get(event.name)
log(`[${e.tick}] dequed event ${eName}`)
handleChunkUpdate(e.tick, eName, event.surface.index, event.position, event.area)
}
}
}
} }
} }
) )
@ -82,3 +115,14 @@ script.on_event(
) )
} }
) )
function isEventType<E extends EventData>(e: EventData): e is E {
let id: EventId<EventData> | string = e.name
if (typeof id === "string") {
return false
} else {
let name = mapEventIdToDefinedType.get(id)
return e.name == name
}
}

View file

@ -0,0 +1,124 @@
export namespace Queue {
declare const global: {
store: EventQueueStore
head: Node | null
tail: Node | null
size: uint
}
export function init() {
if (global.store == undefined) {
log("initialising EventQueue")
reset()
}
}
export function reset() {
log("Resetting EventQueue")
global.store = {}
global.head = null
global.tail = null
global.size = 0
}
export function size(): uint {
return global.size
}
export function enqueue(key: string, event: EventData, weight: int = 1) {
if (key ! in global.store) {
let node = new Node(key, weight)
if (global.head == null) {
global.head = node
}
if (global.tail != null) {
global.tail.next = node
}
global.tail = node
}
global.store[key] = event
global.size++
}
export function dequeue(): WeightedPacket | null {
if (global.head == null) {
return null
} else {
let weight = global.head.weight
let storeKey = global.head.storeKey
global.head = global.head.next
let storedPacket = global.store[storeKey]
global.store[storeKey] = null
if (storedPacket == null) {
return null
} else {
global.size--
return {
value: storedPacket,
weight: weight,
}
}
}
}
export function dequeueValues(targetWeight: uint = 50): EventData[] {
let values: EventData[] = []
let weight: uint = 0
do {
let packet = dequeue()
if (packet == null) {
break;
} else {
weight += packet.weight
values[values.length] = packet.value
}
} while (weight <= targetWeight)
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 PacketQueue<T> {
// enqueue(key: string, packet: T, weight: int): void
//
// dequeue(): WeightedPacket<T> | null
//
// dequeueValues(targetWeight: int): T[]
// }
//
interface WeightedPacket {
value: EventData,
weight: int,
}
}

View file

@ -1,6 +1,6 @@
{ {
"name": "kafkatorio-events-mod", "name": "kafkatorio-events-mod",
"version": "0.2.6", "version": "0.2.7",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View file

@ -1,6 +1,6 @@
{ {
"name": "kafkatorio-events-mod", "name": "kafkatorio-events-mod",
"version": "0.2.6", "version": "0.2.7",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "tstl", "build": "tstl",

View file

@ -1,9 +1,9 @@
{ {
"$schema": "https://raw.githubusercontent.com/TypeScriptToLua/vscode-typescript-to-lua/master/tsconfig-schema.json", "$schema": "https://raw.githubusercontent.com/TypeScriptToLua/vscode-typescript-to-lua/master/tsconfig-schema.json",
"compilerOptions": { "compilerOptions": {
"target": "es2019", "target": "esnext",
"lib": [ "lib": [
"es2019" "esnext"
], ],
"module": "commonjs", "module": "commonjs",
"moduleResolution": "node", "moduleResolution": "node",