ChatRoomMapManager
Index
Namespaces
Interfaces
Variables
Functions
Namespaces
MapEffectsCodecs_v0
ConstSettings
arrayLenInBytesBits
bitLenBits
rleBitsEmpty
rleBitsFilled
rleMaxEmpty
rleMaxFilled
DynamicSettings
baseIdBits
effectIdMin
effectIdShiftedToRemapId
effectIdsShifted
effectsLength
remapIdToEffectIdShifted
remappedIdBits
shiftedIdBits
Interfaces
EffectsCodec
read
Parameters
reader: BitStringReader
requiredTilesCount: number
Returns ChatRoomMapEffectStaticLighting[][]
write
Parameters
effectsFlat: ChatRoomMapEffectStaticLighting[][]
writer: BitStringWriter
Returns boolean
MapCodec
Type parameters
- T
read
Parameters
reader: BitStringReader
requiredTilesCount: number
Returns T
write
Parameters
map: T
writer: BitStringWriter
Returns boolean
Variables
Map
Functions
OnMapDataUpdated
This function should be called each time the external code updates ChatRoomData.MapData.
This function decodes the updated map data and replaces the data stored in $ChatRoomMapManager.Map with the decoded map.
Returns void
OnViewActivate
Initializes the map with the current global data if needed. Must be called in ChatRoomMapViewActivate.
Returns void
Binary-encoded map data
This module implements the new way of encoding the map data.
At its core lies the concept of a BitString: a stream of tightly-packed numbers with arbitrary bit width. This allows us to store data way more efficiently than using plain JSONs, even if they are packed with LZString.
Compatibility
Binary encoding, while efficient, requires a very careful architectural approach to ensure maximum compatibility. Notable, we must ensure that:
Binary encoding makes achieving those requirements non-trivial, because to decode a given BitString the game must know exactly what were the bit widths of the integers encoded into it, and also their meaning. If we just change the code that encodes the map data, then we would no longer able to decode the old data.
To solve this issue, we introduce the concept of codec versions. A version is a number that we write into the bit stream before the actual data, which would allow the game to understand which codec was used to encode the data, and call it to decode the data.
Whenever we need to sufficiently change the encoding scheme, we copy the latest codec, increase its version and make the required changes. Copying and pasting the code, while usually not advised, would be a better approach in this specific case. This way, we ensure that the old codecs remain "frozen" in time, so no matter how old the map data is, we always have an appropriate codec for it.
One issue which may arise in the future is the change in the schemas of the objects we encode. In this case, we would need an additional "migrations" layer which would take the old decoded data and convert it to the one we currently require.
Solving the issue of letting the old clients to use the data from beta versions is not that straightforward, and on the most occasions we would require ad-hoc solutions. For example, during the beta period we may use two fields,
DataandDataOld, with the former containing the data encoded with the most recent codec, and the latter having the data encoded with the previous codec. Of course, depending on the nature of the required changes, it may be possible to make a more space-efficient solution.Future work
Currently, we only binary-encode the map effects, to remain in the scope of the original MR. We do this by storing the encoded map effects in the ChatRoomData.MapData.Effects global value, while ChatRoomData.MapData.Tiles and ChatRoomData.MapData.Objects remain unchanged. Thus, we don't need to change much of the existing code, which continues to use those latter fields.
In future MRs we hope to unify the encoding of tiles, objects and effects, writing them all into a single BitString. This would allow us to have much greater compression and save a lot of traffic.
Later, all map data would be stored in ChatRoomMapManager.Map global value instead of ChatRoomData.MapData. This is because we're no longer storing the map data as simple strings which we can trivially serialize and send to the server. Ideally, the outside code would use ChatRoomMapManager methods to obtain the encoded map data when needed (e.g. sending it to the server, or saving the map data for room recreation, or exporting the room via a room code). Failing that, we can continue the approach used in the initial version of this system: having the decoded map data in ChatRoomMapManager.Map and maintain the encoded representation of this map in ChatRoomData.MapData.
After that we would have an avenue for encoding additional arbitrary data within each tile while retaining the compact encoding. This, then, would allow us to have any sorts of "tile settings", which would be a great addition to the map rooms in the Club.
Mod compatibility
This module is a work in progress and would change significantly in the future. As such, only the minimum amount of public APIs is exposed as of now. Mod authors are advised to not rely on its current behavior if at all possible. We expect to expose more public APIs in the future as the module matures.
General design choices
While being public, ChatRoomMapManager.Map preferably should be only accessed inside this file as it is an implementation detail of this module. If the outside code requires to access something in this module, it's best to provide a separate function in the ChatRoomMapManager namespace, or a global one.
Codecs general overview
Version 0
The initial codecs version. Only encoding map effects. Only allows for a single map effect per tile (the groundwork for having multiple effects per tile is laid, but the rest of the code is not ready for it).
Effects are encoded by their IDs, similar to the original Tiles and Objects encoding. A simple RLE compression is applied to the "flat" effects array, with a small twist: we use larger bit width for storing run-lengths of the blank effect sequences. This allows us to more efficiently encode the typical maps where the most of the tiles would have blank effects.
Additionally, we modify the effect IDs in the following way:
This allows us to write the least possible amount of data per effect ID: for example, if only one effect - besides the blank - is used in a map, then each mention of that ID would only require a single bit of data, no matter what the actual value of this effect is.
This scheme results in a sufficiently efficient compression rate in practice.