Skip to content

Commit

Permalink
Optimise CatchupChunk and related uses (#77)
Browse files Browse the repository at this point in the history
* Optimise CatchupChunk and related uses

There's no need to have each chunk contain a copy of the world string when it can be stored once on the packet itself.

Also updated the CatchupRequestPacket so that there's no array expansion happening.

* No longer select world in getChunkTimestamps
  • Loading branch information
Protonull authored Aug 15, 2023
1 parent 6d32783 commit ddeb6ee
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 34 deletions.
7 changes: 3 additions & 4 deletions server/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export async function getChunkTimestamps(dimension: string, regions: Pos2D[]) {
db
.selectFrom('player_chunk')
.select([
'world',
(eb) =>
kysely.sql<string>`(cast(floor(${eb.ref(
'chunk_x',
Expand All @@ -107,11 +106,11 @@ export async function getChunkTimestamps(dimension: string, regions: Pos2D[]) {
'chunk_z as z',
(eb) => eb.fn.max('ts').as('timestamp'),
])
.groupBy(['world', 'x', 'z']),
.where('world', '=', dimension)
.groupBy(['x', 'z']),
)
.selectFrom('regions')
.select(['world', 'x as chunk_x', 'z as chunk_z', 'timestamp as ts'])
.where('world', '=', dimension)
.select(['x as chunkX', 'z as chunkZ', 'timestamp'])
.where(
'region',
'in',
Expand Down
24 changes: 13 additions & 11 deletions server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,23 +107,24 @@ export class Main {
if (!client.uuid) throw new Error(`${client.name} is not authenticated`)

for (const req of pkt.chunks) {
const { world, chunk_x, chunk_z } = req

let chunk = await database.getChunkData(world, chunk_x, chunk_z)
let chunk = await database.getChunkData(pkt.world, req.chunkX, req.chunkZ)
if (!chunk) {
console.error(`${client.name} requested unavailable chunk`, req)
console.error(`${client.name} requested unavailable chunk`, {
world: pkt.world,
...req,
})
continue
}

if (chunk.ts > req.ts) continue // someone sent a new chunk, which presumably got relayed to the client
if (chunk.ts < req.ts) continue // the client already has a chunk newer than this
if (chunk.ts > req.timestamp) continue // someone sent a new chunk, which presumably got relayed to the client
if (chunk.ts < req.timestamp) continue // the client already has a chunk newer than this

client.send({
type: 'ChunkTile',
world,
chunk_x,
chunk_z,
ts: req.ts,
world: pkt.world,
chunk_x: req.chunkX,
chunk_z: req.chunkX,
ts: req.timestamp,
data: {
hash: chunk.hash,
data: chunk.data,
Expand All @@ -140,6 +141,7 @@ export class Main {
if (!client.uuid) throw new Error(`${client.name} is not authenticated`)

const chunks = await database.getChunkTimestamps(pkt.world, pkt.regions)
if (chunks.length) client.send({ type: 'Catchup', chunks })
if (chunks.length)
client.send({ type: 'Catchup', world: pkt.world, chunks })
}
}
7 changes: 3 additions & 4 deletions server/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ export interface CatchupRegion {
}

export interface CatchupChunk {
world: string
chunk_x: number
chunk_z: number
ts: number
readonly chunkX: number
readonly chunkZ: number
readonly timestamp: number
}

export interface Pos2D {
Expand Down
12 changes: 7 additions & 5 deletions server/src/protocol/CatchupPacket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import { BufWriter } from './BufWriter'

export interface CatchupPacket {
type: 'Catchup'
world: string
chunks: CatchupChunk[]
}

export namespace CatchupPacket {
export function encode(pkt: CatchupPacket, writer: BufWriter) {
if (!pkt.chunks[0]) throw new Error(`Catchup chunks must not be empty`)
writer.writeString(pkt.chunks[0].world)
if (pkt.chunks.length < 1)
throw new Error(`Catchup chunks must not be empty`)
writer.writeString(pkt.world)
writer.writeUInt32(pkt.chunks.length)
for (const row of pkt.chunks) {
writer.writeInt32(row.chunk_x)
writer.writeInt32(row.chunk_z)
writer.writeUInt64(row.ts)
writer.writeInt32(row.chunkX)
writer.writeInt32(row.chunkZ)
writer.writeUInt64(row.timestamp)
}
}
}
19 changes: 9 additions & 10 deletions server/src/protocol/CatchupRequestPacket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@ import { BufReader } from './BufReader'

export interface CatchupRequestPacket {
type: 'CatchupRequest'
world: string
chunks: CatchupChunk[]
}

export namespace CatchupRequestPacket {
export function decode(reader: BufReader): CatchupRequestPacket {
const world = reader.readString()
const numChunks = reader.readUInt32()
const chunks: CatchupChunk[] = []
for (let i = 0; i < numChunks; i++) {
chunks.push({
world,
chunk_x: reader.readInt32(),
chunk_z: reader.readInt32(),
ts: reader.readUInt64(),
})
const chunks: CatchupChunk[] = new Array(reader.readUInt32())
for (let i = 0; i < chunks.length; i++) {
chunks[i] = {
chunkX: reader.readInt32(),
chunkZ: reader.readInt32(),
timestamp: reader.readUInt64(),
}
}
return { type: 'CatchupRequest', chunks }
return { type: 'CatchupRequest', world, chunks }
}
}

0 comments on commit ddeb6ee

Please sign in to comment.