@@ -18,9 +18,9 @@ export interface Database {
1818 world : string ;
1919 chunk_x : number ;
2020 chunk_z : number ;
21- region_x : kysely . Generated < number > ;
22- region_z : kysely . Generated < number > ;
23- region_coord : kysely . Generated < string > ;
21+ gen_region_x : kysely . Generated < number > ;
22+ gen_region_z : kysely . Generated < number > ;
23+ gen_region_coord : kysely . Generated < string > ;
2424 uuid : string ;
2525 ts : number ;
2626 hash : Buffer ;
@@ -43,62 +43,71 @@ export function get() {
4343
4444export async function setup ( ) {
4545 await get ( )
46- . schema . createTable ( "chunk_data" )
47- . ifNotExists ( )
48- . addColumn ( "hash" , "blob" , ( col ) => col . notNull ( ) . primaryKey ( ) )
49- . addColumn ( "version" , "integer" , ( col ) => col . notNull ( ) )
50- . addColumn ( "data" , "blob" , ( col ) => col . notNull ( ) )
51- . execute ( ) ;
52- await get ( )
53- . schema . createTable ( "player_chunk" )
54- . ifNotExists ( )
55- . addColumn ( "world" , "text" , ( col ) => col . notNull ( ) )
56- . addColumn ( "chunk_x" , "integer" , ( col ) => col . notNull ( ) )
57- . addColumn ( "chunk_z" , "integer" , ( col ) => col . notNull ( ) )
58- . addColumn ( "region_x" , "integer" , ( col ) =>
59- col
60- . generatedAlwaysAs ( kysely . sql < number > `floor(chunk_x / 32.0)` )
61- . notNull ( ) ,
62- )
63- . addColumn ( "region_z" , "integer" , ( col ) =>
64- col
65- . generatedAlwaysAs ( kysely . sql < number > `floor(chunk_z / 32.0)` )
66- . notNull ( ) ,
67- )
68- . addColumn ( "region_coord" , "text" , ( col ) => {
69- return col
70- . generatedAlwaysAs ( kysely . sql < string > `cast(floor(chunk_x / 32.0) as int) || '_' || cast(floor(chunk_z / 32.0) as int)` )
71- . notNull ( ) ;
72- } )
73- . addColumn ( "uuid" , "text" , ( col ) => col . notNull ( ) )
74- . addColumn ( "ts" , "bigint" , ( col ) => col . notNull ( ) )
75- . addColumn ( "hash" , "blob" , ( col ) => col . notNull ( ) )
76- . addPrimaryKeyConstraint ( "PK_coords_and_player" , [
77- "world" ,
78- "chunk_x" ,
79- "chunk_z" ,
80- "uuid" ,
81- ] )
82- . addForeignKeyConstraint (
83- "FK_chunk_ref" ,
84- [ "hash" ] ,
85- "chunk_data" ,
86- [ "hash" ] ,
87- ( fk ) => fk . onUpdate ( "no action" ) . onDelete ( "no action" ) ,
88- )
89- . execute ( ) ;
46+ . transaction ( )
47+ . execute ( async ( db ) => {
48+ await db . schema
49+ . createTable ( "chunk_data" )
50+ . ifNotExists ( )
51+ . addColumn ( "hash" , "blob" , ( col ) => col . notNull ( ) . primaryKey ( ) )
52+ . addColumn ( "version" , "integer" , ( col ) => col . notNull ( ) )
53+ . addColumn ( "data" , "blob" , ( col ) => col . notNull ( ) )
54+ . execute ( ) ;
55+ await db . schema
56+ . createTable ( "player_chunk" )
57+ . ifNotExists ( )
58+ . addColumn ( "world" , "text" , ( col ) => col . notNull ( ) )
59+ . addColumn ( "chunk_x" , "integer" , ( col ) => col . notNull ( ) )
60+ . addColumn ( "chunk_z" , "integer" , ( col ) => col . notNull ( ) )
61+ . addColumn ( "gen_region_x" , "integer" , ( col ) =>
62+ col
63+ . generatedAlwaysAs (
64+ kysely . sql < number > `floor(chunk_x / 32.0)` ,
65+ )
66+ . notNull ( ) ,
67+ )
68+ . addColumn ( "gen_region_z" , "integer" , ( col ) =>
69+ col
70+ . generatedAlwaysAs (
71+ kysely . sql < number > `floor(chunk_z / 32.0)` ,
72+ )
73+ . notNull ( ) ,
74+ )
75+ . addColumn ( "gen_region_coord" , "text" , ( col ) => {
76+ return col
77+ . generatedAlwaysAs (
78+ kysely . sql < string > `gen_region_x || '_' || gen_region_z` ,
79+ )
80+ . notNull ( ) ;
81+ } )
82+ . addColumn ( "uuid" , "text" , ( col ) => col . notNull ( ) )
83+ . addColumn ( "ts" , "bigint" , ( col ) => col . notNull ( ) )
84+ . addColumn ( "hash" , "blob" , ( col ) => col . notNull ( ) )
85+ . addPrimaryKeyConstraint ( "PK_coords_and_player" , [
86+ "world" ,
87+ "chunk_x" ,
88+ "chunk_z" ,
89+ "uuid" ,
90+ ] )
91+ . addForeignKeyConstraint (
92+ "FK_chunk_ref" ,
93+ [ "hash" ] ,
94+ "chunk_data" ,
95+ [ "hash" ] ,
96+ ( fk ) => fk . onUpdate ( "no action" ) . onDelete ( "no action" ) ,
97+ )
98+ . execute ( ) ;
99+ } ) ;
90100}
91101
92102/**
93- * Converts the entire database of player chunks into regions, with each region
94- * having the highest (aka newest) timestamp.
103+ * Gets the timestamps for ALL regions stored.
95104 */
96105export async function getRegionTimestamps ( dimension : string ) {
97106 return await get ( )
98107 . selectFrom ( "player_chunk" )
99108 . select ( [
100- "region_x as regionX" ,
101- "region_z as regionZ" ,
109+ "gen_region_x as regionX" ,
110+ "gen_region_z as regionZ" ,
102111 ( eb ) => eb . fn . max ( "ts" ) . as ( "timestamp" ) ,
103112 ] )
104113 . where ( "world" , "=" , dimension )
@@ -107,9 +116,6 @@ export async function getRegionTimestamps(dimension: string) {
107116 . execute ( ) ;
108117}
109118
110- /**
111- * Converts an array of region coords into an array of timestamped chunk coords.
112- */
113119export async function getChunkTimestamps ( dimension : string , regions : Pos2D [ ] ) {
114120 return await get ( )
115121 . selectFrom ( "player_chunk" )
@@ -119,7 +125,7 @@ export async function getChunkTimestamps(dimension: string, regions: Pos2D[]) {
119125 ( eb ) => eb . fn . max ( "ts" ) . as ( "timestamp" ) ,
120126 ] )
121127 . where (
122- "region_coord " ,
128+ "gen_region_coord " ,
123129 "in" ,
124130 regions . map ( ( region ) => region . x + "_" + region . z ) ,
125131 )
@@ -171,21 +177,25 @@ export async function storeChunkData(
171177 data : Buffer ,
172178) {
173179 await get ( )
174- . insertInto ( "chunk_data" )
175- . values ( { hash, version, data } )
176- . onConflict ( ( oc ) => oc . column ( "hash" ) . doNothing ( ) )
177- . execute ( ) ;
178- await get ( )
179- . replaceInto ( "player_chunk" )
180- . values ( {
181- world : dimension ,
182- chunk_x : chunkX ,
183- chunk_z : chunkZ ,
184- uuid,
185- ts : timestamp ,
186- hash,
187- } )
188- . execute ( ) ;
180+ . transaction ( )
181+ . execute ( async ( db ) => {
182+ await db
183+ . insertInto ( "chunk_data" )
184+ . values ( { hash, version, data } )
185+ . onConflict ( ( oc ) => oc . column ( "hash" ) . doNothing ( ) )
186+ . execute ( ) ;
187+ await db
188+ . replaceInto ( "player_chunk" )
189+ . values ( {
190+ world : dimension ,
191+ chunk_x : chunkX ,
192+ chunk_z : chunkZ ,
193+ uuid,
194+ ts : timestamp ,
195+ hash,
196+ } )
197+ . execute ( ) ;
198+ } ) ;
189199}
190200
191201/**
@@ -196,10 +206,6 @@ export async function getRegionChunks(
196206 regionX : number ,
197207 regionZ : number ,
198208) {
199- const minChunkX = regionX << 4 ,
200- maxChunkX = minChunkX + 16 ;
201- const minChunkZ = regionZ << 4 ,
202- maxChunkZ = minChunkZ + 16 ;
203209 return await get ( )
204210 . selectFrom ( "player_chunk" )
205211 . innerJoin ( "chunk_data" , "chunk_data.hash" , "player_chunk.hash" )
@@ -211,10 +217,8 @@ export async function getRegionChunks(
211217 "chunk_data.data as data" ,
212218 ] )
213219 . where ( "player_chunk.world" , "=" , dimension )
214- . where ( "player_chunk.chunk_x" , ">=" , minChunkX )
215- . where ( "player_chunk.chunk_x" , "<" , maxChunkX )
216- . where ( "player_chunk.chunk_z" , ">=" , minChunkZ )
217- . where ( "player_chunk.chunk_z" , "<" , maxChunkZ )
220+ . where ( "player_chunk.gen_region_x" , "=" , regionX )
221+ . where ( "player_chunk.gen_region_z" , "=" , regionZ )
218222 . groupBy ( [ "chunk_x" , "chunk_z" , "version" , "data" ] )
219223 . orderBy ( "player_chunk.ts" , "desc" )
220224 . execute ( ) ;
0 commit comments