- add some proper Factorio settings to control EventDataCache
- bump Typescript version - make some classes a bit more typescript-ey - comment out some unused code
This commit is contained in:
parent
e630ce3702
commit
8eac84da50
15 changed files with 331 additions and 219 deletions
|
|
@ -0,0 +1,20 @@
|
||||||
|
[mod-setting-name]
|
||||||
|
|
||||||
|
kafkatorio_event-cache_default-expiration-duration-seconds_PLAYER=Kafkatorio: Player update rate (seconds)
|
||||||
|
kafkatorio_event-cache_default-expiration-duration-seconds_MAP_CHUNK=Kafkatorio: Map update rate (seconds)
|
||||||
|
kafkatorio_event-cache_default-expiration-duration-seconds_ENTITY=Kafkatorio: Entity update rate (seconds)
|
||||||
|
|
||||||
|
|
||||||
|
[mod-setting-description]
|
||||||
|
|
||||||
|
kafkatorio_event-cache_default-expiration-duration-seconds_PLAYER=How frequently Player updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (0.25 seconds) is probably fine!
|
||||||
|
kafkatorio_event-cache_default-expiration-duration-seconds_MAP_CHUNK=How frequently Map updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine!
|
||||||
|
kafkatorio_event-cache_default-expiration-duration-seconds_ENTITY=How frequently Entity updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (5 seconds) is probably fine!
|
||||||
|
|
||||||
|
|
||||||
|
[string-mod-setting]
|
||||||
|
#<setting-name>-<dropdown-item-name>=<translated dropdown item>
|
||||||
|
|
||||||
|
|
||||||
|
[string-mod-setting-description]
|
||||||
|
#<setting-name>-<dropdown-item-name>=<tooltip of dropdown item>
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import {emitConfigurationUpdate} from "./main/config-update/handleConfigurationUpdate";
|
import {emitConfigurationUpdate} from "./main/config-update/handleConfigurationUpdate";
|
||||||
import {emitPrototypes} from "./main/config-update/prototypes";
|
import {emitPrototypes} from "./main/config-update/prototypes";
|
||||||
import {initGlobal} from "./main/global-init";
|
import {initGlobal} from "./main/global-init";
|
||||||
|
import KafkatorioSettings from "./main/settings/KafkatorioSettings";
|
||||||
|
|
||||||
require("./main/events/registerHandlers")
|
require("./main/events/registerHandlers")
|
||||||
require("./main/events/onMapChunkEventListeners")
|
require("./main/events/onMapChunkEventListeners")
|
||||||
|
|
@ -12,6 +13,7 @@ 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()
|
||||||
emitConfigurationUpdate(data)
|
emitConfigurationUpdate(data)
|
||||||
emitPrototypes()
|
emitPrototypes()
|
||||||
})
|
})
|
||||||
|
|
@ -20,4 +22,5 @@ script.on_configuration_changed((data: ConfigurationChangedData) => {
|
||||||
script.on_init(() => {
|
script.on_init(() => {
|
||||||
// runs only once (when the mod is first added to the save)
|
// runs only once (when the mod is first added to the save)
|
||||||
initGlobal(true)
|
initGlobal(true)
|
||||||
|
KafkatorioSettings.loadSettings()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ interface FactorioPrototype {
|
||||||
prototypeObjectName: PrototypeObjectName;
|
prototypeObjectName: PrototypeObjectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FactorioPrototypes extends KafkatorioPacket {
|
||||||
|
modVersion: string;
|
||||||
|
packetType: PacketType;
|
||||||
|
prototypes: FactorioPrototype[];
|
||||||
|
}
|
||||||
|
|
||||||
interface MapTilePrototype extends FactorioPrototype {
|
interface MapTilePrototype extends FactorioPrototype {
|
||||||
canBeMined: boolean;
|
canBeMined: boolean;
|
||||||
collisionMasks: string[];
|
collisionMasks: string[];
|
||||||
|
|
@ -15,9 +21,3 @@ interface MapTilePrototype extends FactorioPrototype {
|
||||||
order: string;
|
order: string;
|
||||||
prototypeObjectName: PrototypeObjectName;
|
prototypeObjectName: PrototypeObjectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FactorioPrototypes extends KafkatorioPacket {
|
|
||||||
modVersion: string;
|
|
||||||
packetType: PacketType;
|
|
||||||
prototypes: FactorioPrototype[];
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,14 @@ interface KafkatorioPacket {
|
||||||
packetType: PacketType;
|
packetType: PacketType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FactorioEvent extends KafkatorioPacket {
|
||||||
|
data: FactorioObjectData;
|
||||||
|
eventType: string;
|
||||||
|
modVersion: string;
|
||||||
|
packetType: PacketType;
|
||||||
|
tick: uint;
|
||||||
|
}
|
||||||
|
|
||||||
interface MapEntityPosition {
|
interface MapEntityPosition {
|
||||||
x: double;
|
x: double;
|
||||||
y: double;
|
y: double;
|
||||||
|
|
@ -46,14 +54,6 @@ interface MapTile {
|
||||||
y: int;
|
y: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FactorioEvent extends KafkatorioPacket {
|
|
||||||
data: FactorioObjectData;
|
|
||||||
eventType: string;
|
|
||||||
modVersion: string;
|
|
||||||
packetType: PacketType;
|
|
||||||
tick: uint;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EntityIdentifiers {
|
interface EntityIdentifiers {
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
|
|
||||||
|
|
@ -1,133 +1,162 @@
|
||||||
export namespace EventDataCache {
|
import KafkatorioSettings from "../settings/KafkatorioSettings";
|
||||||
|
|
||||||
|
export namespace EventUpdates {
|
||||||
|
|
||||||
|
|
||||||
declare const global: {
|
declare const global: {
|
||||||
cache: LuaTable<string, CacheEntry<FactorioEventUpdateType>>,
|
cache: LuaTable<string, CacheEntry<FactorioEventUpdateType>>,
|
||||||
defaultCacheDurationTicks: Record<FactorioEventUpdateType | "default", uint>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function init(force?: boolean) {
|
export class Manager {
|
||||||
|
|
||||||
const isAnythingUndefined = global.cache == undefined ||
|
|
||||||
global.defaultCacheDurationTicks == undefined
|
|
||||||
|
|
||||||
log(`Initialising EventDataCache (force=${force}, isAnythingUndefined=${isAnythingUndefined})...`)
|
init(force?: boolean) {
|
||||||
|
|
||||||
if (force == true || isAnythingUndefined) {
|
const isAnythingUndefined = global.cache == undefined
|
||||||
log("Initialising global.cache")
|
|
||||||
global.cache = new LuaTable<string, CacheEntry<FactorioEventUpdateType>>()
|
|
||||||
|
|
||||||
log("Initialising global.DEFAULT_CACHE_DURATION_TICKS")
|
log(`Initialising EventDataCache (force=${force}, isAnythingUndefined=${isAnythingUndefined})...`)
|
||||||
global.defaultCacheDurationTicks = {
|
|
||||||
"PLAYER": 15, // 0.25 seconds
|
if (force == true || isAnythingUndefined) {
|
||||||
"MAP_CHUNK": 60 * 30, // 30 seconds
|
log("Initialising global.cache")
|
||||||
"ENTITY": 60 * 2, // 2 seconds
|
global.cache = new LuaTable<string, CacheEntry<FactorioEventUpdateType>>()
|
||||||
"default": 60 * 5, // 5 seconds
|
}
|
||||||
|
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<TYPE extends FactorioEventUpdateType>(
|
||||||
|
key: CacheKey<TYPE>,
|
||||||
|
mutate: CacheDataMutator<TYPE>,
|
||||||
|
) {
|
||||||
|
this.update(key, mutate, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<TYPE extends FactorioEventUpdateType>(
|
||||||
|
key: CacheKey<TYPE>,
|
||||||
|
mutate: CacheDataMutator<TYPE>,
|
||||||
|
) {
|
||||||
|
this.update(key, mutate, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private update<TYPE extends FactorioEventUpdateType>(
|
||||||
|
key: CacheKey<TYPE>,
|
||||||
|
mutate: CacheDataMutator<TYPE>,
|
||||||
|
resetLastUpdated: boolean,
|
||||||
|
) {
|
||||||
|
const entry = this.getCacheEntry(key) ?? this.createCacheEntry(key, mutate)
|
||||||
|
mutate(entry.data)
|
||||||
|
if (resetLastUpdated) {
|
||||||
|
entry.lastUpdatedTick = game.tick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log(`Finished initialising EventDataCache`)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the cache data without restarting the 'time-to-emit' countdown, so that the data won't
|
* Usage example: If an urgent update comes in, then the expiration can be reduced so that
|
||||||
* be emitted more than once per {@link CacheEntry.expirationDurationTicks}.
|
* it's transmitted sooner.
|
||||||
*/
|
*/
|
||||||
export function throttle<TYPE extends FactorioEventUpdateType>(
|
public setExpiration(
|
||||||
key: CacheKey<TYPE>,
|
key: CacheKey<FactorioEventUpdateType>,
|
||||||
mutate: CacheDataMutator<TYPE>,
|
expirationDurationTicks: uint,
|
||||||
) {
|
) {
|
||||||
update(key, mutate, false)
|
const entry = this.getCacheEntry(key)
|
||||||
}
|
if (entry != undefined) {
|
||||||
|
entry.expirationDurationTicks = 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}.
|
|
||||||
*/
|
|
||||||
export function debounce<TYPE extends FactorioEventUpdateType>(
|
|
||||||
key: CacheKey<TYPE>,
|
|
||||||
mutate: CacheDataMutator<TYPE>,
|
|
||||||
) {
|
|
||||||
update(key, mutate, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function update<TYPE extends FactorioEventUpdateType>(
|
|
||||||
key: CacheKey<TYPE>,
|
|
||||||
mutate: CacheDataMutator<TYPE>,
|
|
||||||
resetLastUpdated: boolean,
|
|
||||||
) {
|
|
||||||
const entry = getCacheEntry(key) ?? createCacheEntry(key, mutate)
|
|
||||||
mutate(entry.data)
|
|
||||||
if (resetLastUpdated) {
|
|
||||||
entry.lastUpdatedTick = game.tick
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Usage example: If an urgent update comes in, then the expiration can be reduced so that
|
|
||||||
* it's transmitted sooner.
|
|
||||||
*/
|
|
||||||
export function setExpiration(
|
|
||||||
key: CacheKey<FactorioEventUpdateType>,
|
|
||||||
expirationDurationTicks: uint,
|
|
||||||
) {
|
|
||||||
const entry = getCacheEntry(key)
|
|
||||||
if (entry != undefined) {
|
|
||||||
entry.expirationDurationTicks = expirationDurationTicks
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function extractExpired(): Array<FactorioEventUpdate> {
|
|
||||||
let countExpired = 0
|
|
||||||
let countTotal = 0
|
|
||||||
const expiredData: Array<FactorioEventUpdate> = []
|
|
||||||
for (let [key, entry] of global.cache) {
|
|
||||||
countTotal++
|
|
||||||
if (isExpired(entry)) {
|
|
||||||
countExpired++
|
|
||||||
expiredData.push(entry.data)
|
|
||||||
global.cache.delete(key)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (countExpired + countTotal > 0) {
|
|
||||||
log(`cache expired items count: ${countExpired}, total: ${countTotal}`)
|
|
||||||
|
public extractExpired(): Array<FactorioEventUpdate> {
|
||||||
|
let countExpired = 0
|
||||||
|
let countTotal = 0
|
||||||
|
const expiredData: Array<FactorioEventUpdate> = []
|
||||||
|
for (let [key, entry] of global.cache) {
|
||||||
|
countTotal++
|
||||||
|
if (this.isExpired(entry)) {
|
||||||
|
countExpired++
|
||||||
|
expiredData.push(entry.data)
|
||||||
|
global.cache.delete(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (countExpired + countTotal > 0) {
|
||||||
|
log(`cache expired items count: ${countExpired}, total: ${countTotal}`)
|
||||||
|
}
|
||||||
|
return expiredData
|
||||||
}
|
}
|
||||||
return expiredData
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getCacheEntry<TYPE extends FactorioEventUpdateType>(
|
private getCacheEntry<TYPE extends FactorioEventUpdateType>(
|
||||||
key: CacheKey<TYPE>
|
key: CacheKey<TYPE>
|
||||||
): CacheEntry<TYPE> | undefined {
|
): CacheEntry<TYPE> | undefined {
|
||||||
const hash = game.encode_string(game.table_to_json(key))!!
|
const hash = game.encode_string(game.table_to_json(key))!!
|
||||||
if (!global.cache.has(hash)) {
|
if (!global.cache.has(hash)) {
|
||||||
return undefined
|
return undefined
|
||||||
|
}
|
||||||
|
const value: CacheEntry<any> = global.cache.get(hash)
|
||||||
|
if (this.isEntryInstanceOf(value, key.updateType)) {
|
||||||
|
return value
|
||||||
|
} else {
|
||||||
|
// Type mismatch. This shouldn't happen...
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const value: CacheEntry<any> = global.cache.get(hash)
|
|
||||||
if (isEntryInstanceOf(value, key.updateType)) {
|
|
||||||
return value
|
private createCacheEntry<TYPE extends FactorioEventUpdateType>(
|
||||||
} else {
|
key: CacheKey<TYPE>,
|
||||||
// Type mismatch. This shouldn't happen...
|
mutate: CacheDataMutator<TYPE>,
|
||||||
return undefined
|
): CacheEntry<TYPE> {
|
||||||
|
const data: CacheData<TYPE> = <CacheData<TYPE>>{...key}
|
||||||
|
mutate(data)
|
||||||
|
let entry: CacheEntry<TYPE> = new CacheEntry<TYPE>(data)
|
||||||
|
const hash = game.encode_string(game.table_to_json(key))!!
|
||||||
|
global.cache.set(hash, entry)
|
||||||
|
return entry
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function createCacheEntry<TYPE extends FactorioEventUpdateType>(
|
isExpired<TYPE extends FactorioEventUpdateType>(entry: CacheEntry<TYPE>): boolean {
|
||||||
key: CacheKey<TYPE>,
|
const expiryDuration = entry.expirationDurationTicks
|
||||||
mutate: CacheDataMutator<TYPE>,
|
??
|
||||||
): CacheEntry<TYPE> {
|
KafkatorioSettings.getEventCacheExpirationTicks(entry.data.updateType)
|
||||||
const data: CacheData<TYPE> = <CacheData<TYPE>>{...key}
|
return game.tick - entry.lastUpdatedTick > expiryDuration
|
||||||
mutate(data)
|
}
|
||||||
let entry: CacheEntry<TYPE> = new CacheEntry<TYPE>(data)
|
|
||||||
const hash = game.encode_string(game.table_to_json(key))!!
|
|
||||||
global.cache.set(hash, entry)
|
isEntryInstanceOf<TYPE extends FactorioEventUpdateType>(
|
||||||
return entry
|
entry: CacheEntry<any> | undefined,
|
||||||
|
updateType: TYPE,
|
||||||
|
): entry is CacheEntry<TYPE> {
|
||||||
|
return this.isDataInstanceOf<TYPE>(entry?.data, updateType)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
isDataInstanceOf<TYPE extends FactorioEventUpdateType>(
|
||||||
|
data: CacheData<any> | undefined,
|
||||||
|
updateType: TYPE,
|
||||||
|
): data is CacheData<TYPE> {
|
||||||
|
return data != undefined && data.updateType == updateType
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// function isKeyInstanceOf<TYPE extends FactorioEventUpdateType>(
|
||||||
|
// key: CacheKey<any> | undefined,
|
||||||
|
// updateType: TYPE,
|
||||||
|
// ): key is CacheKey<TYPE> {
|
||||||
|
// return key != undefined && key.updateType == updateType
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -184,34 +213,7 @@ export namespace EventDataCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function isExpired<TYPE extends FactorioEventUpdateType>(entry: CacheEntry<TYPE>): boolean {
|
|
||||||
const expiryDuration =
|
|
||||||
entry.expirationDurationTicks ?? global.defaultCacheDurationTicks[entry.data.updateType]
|
|
||||||
return game.tick - entry.lastUpdatedTick > expiryDuration
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function isEntryInstanceOf<TYPE extends FactorioEventUpdateType>(
|
|
||||||
entry: CacheEntry<any> | undefined,
|
|
||||||
updateType: TYPE,
|
|
||||||
): entry is CacheEntry<TYPE> {
|
|
||||||
return isDataInstanceOf<TYPE>(entry?.data, updateType)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function isDataInstanceOf<TYPE extends FactorioEventUpdateType>(
|
|
||||||
data: CacheData<any> | undefined,
|
|
||||||
updateType: TYPE,
|
|
||||||
): data is CacheData<TYPE> {
|
|
||||||
return data != undefined && data.updateType == updateType
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// function isKeyInstanceOf<TYPE extends FactorioEventUpdateType>(
|
|
||||||
// key: CacheKey<any> | undefined,
|
|
||||||
// updateType: TYPE,
|
|
||||||
// ): key is CacheKey<TYPE> {
|
|
||||||
// return key != undefined && key.updateType == updateType
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EventUpdatesManager = new EventUpdates.Manager()
|
||||||
|
export default EventUpdatesManager
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import {EventDataCache} from "./EventDataCache";
|
|
||||||
import {emitPacket} from "../emitKafkatorioPacket";
|
import {emitPacket} from "../emitKafkatorioPacket";
|
||||||
|
import EventCacheService from "./EventDataCache";
|
||||||
|
|
||||||
/** Every 0.1 seconds */
|
/** Every 0.1 seconds */
|
||||||
script.on_nth_tick(6, (nthTick: NthTickEventData) => {
|
script.on_nth_tick(6, (nthTick: NthTickEventData) => {
|
||||||
const cachedEvents: Array<FactorioEventUpdate> = EventDataCache.extractExpired()
|
const cachedEvents: Array<FactorioEventUpdate> = EventCacheService.extractExpired()
|
||||||
|
|
||||||
if (cachedEvents.length > 0) {
|
if (cachedEvents.length > 0) {
|
||||||
log(`nth tick ${nthTick.tick} has ${cachedEvents.length} events`)
|
log(`nth tick ${nthTick.tick} has ${cachedEvents.length} events`)
|
||||||
|
|
|
||||||
|
|
@ -78,31 +78,31 @@ export function handleChunkUpdate(
|
||||||
emitEvent(mapChunk, tick, eventType)
|
emitEvent(mapChunk, tick, eventType)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleTilesUpdate(
|
// export function handleTilesUpdate(
|
||||||
tick: uint,
|
// tick: uint,
|
||||||
eventType: string,
|
// eventType: string,
|
||||||
surfaceIndex: uint,
|
// surfaceIndex: uint,
|
||||||
newTileType: LuaTilePrototype,
|
// newTileType: LuaTilePrototype,
|
||||||
updatedTiles: OldTileAndPosition[],
|
// updatedTiles: OldTileAndPosition[],
|
||||||
) {
|
// ) {
|
||||||
|
//
|
||||||
if (!newTileType.collision_mask["ground-tile"] && !newTileType.collision_mask["water-tile"]) {
|
// if (!newTileType.collision_mask["ground-tile"] && !newTileType.collision_mask["water-tile"]) {
|
||||||
return
|
// return
|
||||||
} else {
|
// } else {
|
||||||
|
//
|
||||||
let convertedTiles: MapTile[] = updatedTiles.map((it) => {
|
// let convertedTiles: MapTile[] = updatedTiles.map((it) => {
|
||||||
return {
|
// return {
|
||||||
x: it.position.x,
|
// x: it.position.x,
|
||||||
y: it.position.y,
|
// y: it.position.y,
|
||||||
proto: newTileType.name
|
// proto: newTileType.name
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
let mapTiles: MapTiles = createMapTiles(surfaceIndex, convertedTiles)
|
// let mapTiles: MapTiles = createMapTiles(surfaceIndex, convertedTiles)
|
||||||
|
//
|
||||||
emitEvent(mapTiles, tick, eventType)
|
// emitEvent(mapTiles, tick, eventType)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
function createMapTiles(
|
function createMapTiles(
|
||||||
surfaceIndex: uint,
|
surfaceIndex: uint,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import {EventDataCache} from "../cache/EventDataCache";
|
|
||||||
import {isEventType} from "./eventTypeCheck";
|
import {isEventType} from "./eventTypeCheck";
|
||||||
import {Converters} from "./converters";
|
import {Converters} from "./converters";
|
||||||
import CacheKey = EventDataCache.CacheKey;
|
import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
|
||||||
import CacheData = EventDataCache.CacheData;
|
import CacheKey = EventUpdates.CacheKey;
|
||||||
|
import CacheData = EventUpdates.CacheData;
|
||||||
|
|
||||||
|
|
||||||
type MapChunkUpdater = (data: CacheData<"MAP_CHUNK">) => void
|
type MapChunkUpdater = (data: CacheData<"MAP_CHUNK">) => void
|
||||||
|
|
@ -37,7 +37,7 @@ function mapTilesUpdateDebounce(
|
||||||
updateType: "MAP_CHUNK",
|
updateType: "MAP_CHUNK",
|
||||||
}
|
}
|
||||||
|
|
||||||
EventDataCache.debounce<"MAP_CHUNK">(
|
EventUpdatesManager.debounce<"MAP_CHUNK">(
|
||||||
key,
|
key,
|
||||||
data => {
|
data => {
|
||||||
data.tileDictionary ??= <MapTileDictionary>{
|
data.tileDictionary ??= <MapTileDictionary>{
|
||||||
|
|
@ -242,14 +242,14 @@ script.on_event(
|
||||||
updateType: "MAP_CHUNK",
|
updateType: "MAP_CHUNK",
|
||||||
}
|
}
|
||||||
|
|
||||||
EventDataCache.debounce<"MAP_CHUNK">(
|
EventUpdatesManager.debounce<"MAP_CHUNK">(
|
||||||
key,
|
key,
|
||||||
data => {
|
data => {
|
||||||
data.isDeleted = true
|
data.isDeleted = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// deletion is important - emit ASAP
|
// deletion is important - emit ASAP
|
||||||
EventDataCache.setExpiration(key, 0)
|
EventUpdatesManager.setExpiration(key, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import {EventDataCache} from "../cache/EventDataCache";
|
|
||||||
import {Converters} from "./converters";
|
import {Converters} from "./converters";
|
||||||
import CacheData = EventDataCache.CacheData;
|
import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
|
||||||
|
import CacheData = EventUpdates.CacheData;
|
||||||
|
|
||||||
|
|
||||||
type PlayerUpdater = (player: LuaPlayer, data: CacheData<"PLAYER">) => void
|
type PlayerUpdater = (player: LuaPlayer, data: CacheData<"PLAYER">) => void
|
||||||
|
|
||||||
|
|
@ -9,9 +10,9 @@ function playerUpdateThrottle(
|
||||||
eventName: string,
|
eventName: string,
|
||||||
mutate: PlayerUpdater,
|
mutate: PlayerUpdater,
|
||||||
) {
|
) {
|
||||||
EventDataCache.throttle<"PLAYER">(
|
EventUpdatesManager.throttle<"PLAYER">(
|
||||||
{index: playerIndex, updateType: "PLAYER"},
|
{index: playerIndex, updateType: "PLAYER"},
|
||||||
(data => {
|
data => {
|
||||||
const player = game.players[playerIndex]
|
const player = game.players[playerIndex]
|
||||||
if (player != undefined) {
|
if (player != undefined) {
|
||||||
mutate(player, data)
|
mutate(player, data)
|
||||||
|
|
@ -21,19 +22,19 @@ function playerUpdateThrottle(
|
||||||
data.eventCounts = {}
|
data.eventCounts = {}
|
||||||
}
|
}
|
||||||
data.eventCounts[eventName] = ((data.eventCounts ?? {}) [eventName] ?? 0) + 1
|
data.eventCounts[eventName] = ((data.eventCounts ?? {}) [eventName] ?? 0) + 1
|
||||||
})
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function playerUpdateDebounce(playerIndex: uint, mutate: PlayerUpdater) {
|
// function playerUpdateDebounce(playerIndex: uint, mutate: PlayerUpdater) {
|
||||||
EventDataCache.debounce<"PLAYER">(
|
// EventUpdatesManager.debounce<"PLAYER">(
|
||||||
{index: playerIndex, updateType: "PLAYER"},
|
// {index: playerIndex, updateType: "PLAYER"},
|
||||||
(data => {
|
// data => {
|
||||||
const player = game.players[playerIndex]
|
// const player = game.players[playerIndex]
|
||||||
mutate(player, data)
|
// mutate(player, data)
|
||||||
})
|
// }
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
function playerOnlineInfo(player: LuaPlayer, data: CacheData<"PLAYER">) {
|
function playerOnlineInfo(player: LuaPlayer, data: CacheData<"PLAYER">) {
|
||||||
data.lastOnline = player.last_online
|
data.lastOnline = player.last_online
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
import {Queue} from "../queue/queue";
|
import {Queue} from "../queue/queue";
|
||||||
import {isEventType} from "./eventTypeCheck";
|
import {isEventType} from "./eventTypeCheck";
|
||||||
import {Converters} from "./converters";
|
import {Converters} from "./converters";
|
||||||
|
import KafkatorioSettings from "../settings/KafkatorioSettings";
|
||||||
|
|
||||||
|
|
||||||
script.on_event(
|
script.on_event(
|
||||||
|
|
@ -46,22 +47,22 @@ script.on_event(
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.tick % 30 == 0) {
|
// if (e.tick % 30 == 0) {
|
||||||
let events: EventData[] = Queue.dequeueValues(1)
|
// let events: EventData[] = Queue.dequeueValues(1)
|
||||||
|
//
|
||||||
if (events.length > 0) {
|
// if (events.length > 0) {
|
||||||
log(`[${e.tick}] dequed ${events.length} events, current size: ${Queue.size()}`)
|
// log(`[${e.tick}] dequed ${events.length} events, current size: ${Queue.size()}`)
|
||||||
|
//
|
||||||
for (const event of events) {
|
// for (const event of events) {
|
||||||
if (isEventType(event, defines.events.on_chunk_generated)) {
|
// if (isEventType(event, defines.events.on_chunk_generated)) {
|
||||||
let eName = Converters.eventNameString(event.name)
|
// let eName = Converters.eventNameString(event.name)
|
||||||
|
//
|
||||||
log(`[${e.tick}] dequed event ${eName}`)
|
// log(`[${e.tick}] dequed event ${eName}`)
|
||||||
handleChunkUpdate(e.tick, eName, event.surface.index, event.position, event.area)
|
// handleChunkUpdate(e.tick, eName, event.surface.index, event.position, event.area)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -80,3 +81,11 @@ script.on_event(
|
||||||
// defines.events.on_robot_built_tile, ], (builtTilesEvent) => { handleTilesUpdate(
|
// defines.events.on_robot_built_tile, ], (builtTilesEvent) => { handleTilesUpdate(
|
||||||
// builtTilesEvent.tick, mapEventIdToName.get(builtTilesEvent.name), builtTilesEvent.surface_index,
|
// builtTilesEvent.tick, mapEventIdToName.get(builtTilesEvent.name), builtTilesEvent.surface_index,
|
||||||
// builtTilesEvent.tile, builtTilesEvent.tiles, ) } )
|
// builtTilesEvent.tile, builtTilesEvent.tiles, ) } )
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import {Queue} from "./queue/queue";
|
import {Queue} from "./queue/queue";
|
||||||
import {EventDataCache} from "./cache/EventDataCache";
|
import EventUpdatesManager from "./cache/EventDataCache";
|
||||||
|
|
||||||
|
|
||||||
export function initGlobal(force: boolean = false) {
|
export function initGlobal(force: boolean = false) {
|
||||||
|
|
@ -9,7 +9,7 @@ export function initGlobal(force: boolean = false) {
|
||||||
global.FACTORIO_VERSION = script.active_mods["base"]
|
global.FACTORIO_VERSION = script.active_mods["base"]
|
||||||
|
|
||||||
Queue.init(true)
|
Queue.init(true)
|
||||||
EventDataCache.init(true)
|
EventUpdatesManager.init(true)
|
||||||
|
|
||||||
log("Finished initialising Kafkatorio Global variables")
|
log("Finished initialising Kafkatorio Global variables")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
import {Data, DoubleSettingDefinition} from "typed-factorio/settings/types"
|
||||||
|
|
||||||
|
export class KafkatorioSettingsConfig {
|
||||||
|
|
||||||
|
|
||||||
|
private static eventCacheExpirationDefaultSeconds: Record<FactorioEventUpdateType, uint> = {
|
||||||
|
"PLAYER": 0.25,
|
||||||
|
"MAP_CHUNK": 30,
|
||||||
|
"ENTITY": 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private eventCacheExpirationTicks: Record<FactorioEventUpdateType, double> = {
|
||||||
|
"PLAYER": KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds["PLAYER"],
|
||||||
|
"MAP_CHUNK": KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds["MAP_CHUNK"],
|
||||||
|
"ENTITY": KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds["ENTITY"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getEventCacheExpirationTicks(type: FactorioEventUpdateType): uint {
|
||||||
|
return this.eventCacheExpirationTicks[type]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
loadSettings(): void {
|
||||||
|
const types: FactorioEventUpdateType[] = ["PLAYER", "MAP_CHUNK", "ENTITY"]
|
||||||
|
for (const type of types) {
|
||||||
|
const seconds: double = settings.global[KafkatorioSettingsConfig.cacheDurationSettingName(type)].value as double
|
||||||
|
this.eventCacheExpirationTicks[type] = seconds * 60 // convert ticks to seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initialiseSettings(data: Data): void {
|
||||||
|
data.extend(
|
||||||
|
[
|
||||||
|
this.createDefaultCacheDuration("PLAYER"),
|
||||||
|
this.createDefaultCacheDuration("MAP_CHUNK"),
|
||||||
|
this.createDefaultCacheDuration("ENTITY"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private createDefaultCacheDuration(
|
||||||
|
type: FactorioEventUpdateType,
|
||||||
|
defaultExpirationSeconds: uint = KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds[type],
|
||||||
|
): DoubleSettingDefinition {
|
||||||
|
return <DoubleSettingDefinition>{
|
||||||
|
type: "double-setting",
|
||||||
|
name: KafkatorioSettingsConfig.cacheDurationSettingName(type),
|
||||||
|
setting_type: "runtime-global",
|
||||||
|
default_value: defaultExpirationSeconds,
|
||||||
|
// min: 0.25 seconds, max: 2 minutes
|
||||||
|
minimum_value: 0.25,
|
||||||
|
maximum_value: 120,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static cacheDurationSettingName(type: FactorioEventUpdateType): string {
|
||||||
|
return `kafkatorio_event-cache_default-expiration-duration-seconds_${type}`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const KafkatorioSettings = new KafkatorioSettingsConfig()
|
||||||
|
export default KafkatorioSettings
|
||||||
|
|
@ -80,9 +80,9 @@
|
||||||
"integrity": "sha512-/iLa916Cw33vC6wgmCb4cPLjmvUA2zVviTx/vy80iEvpOHjoNkuHkGSsmvss1aItwUKUlHaLi3k0fK5OPiw1iA=="
|
"integrity": "sha512-/iLa916Cw33vC6wgmCb4cPLjmvUA2zVviTx/vy80iEvpOHjoNkuHkGSsmvss1aItwUKUlHaLi3k0fK5OPiw1iA=="
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.5.5",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
|
||||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA=="
|
"integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg=="
|
||||||
},
|
},
|
||||||
"typescript-to-lua": {
|
"typescript-to-lua": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.4",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
"lua-types": "^2.11.0",
|
"lua-types": "^2.11.0",
|
||||||
"typescript-to-lua": "1.3.4",
|
"typescript-to-lua": "1.3.4",
|
||||||
"typed-factorio": "0.19.1",
|
"typed-factorio": "0.19.1",
|
||||||
"typescript": "4.5.5"
|
"typescript": "4.6.2"
|
||||||
},
|
},
|
||||||
"// @types/node": "^12.0.8",
|
"// @types/node": "^12.0.8",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
|
|
|
||||||
7
modules/events-mod/src/main/typescript/settings.ts
Normal file
7
modules/events-mod/src/main/typescript/settings.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import {Data, Mods} from "typed-factorio/settings/types"
|
||||||
|
import KafkatorioSettings from "./main/settings/KafkatorioSettings";
|
||||||
|
|
||||||
|
declare const data: Data
|
||||||
|
declare const mods: Mods
|
||||||
|
|
||||||
|
KafkatorioSettings.initialiseSettings(data)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue