Skip to content

Commit

Permalink
Merge pull request #91 from conmaster2112/develop
Browse files Browse the repository at this point in the history
Chunk Cache release test
  • Loading branch information
PMK744 authored Sep 26, 2024
2 parents b2379d1 + 811730f commit d97d36b
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 22 deletions.
125 changes: 110 additions & 15 deletions packages/serenity/src/providers/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class FileSystemProvider extends WorldProvider {
/**
* The chunks stored in the provider.
*/
public readonly chunks: Map<string, Map<bigint, Chunk>> = new Map();
public readonly chunks: Map<Dimension, Map<bigint, Chunk>> = new Map();

/**
* The path to the world.
Expand All @@ -55,6 +55,105 @@ class FileSystemProvider extends WorldProvider {
this.properties = properties;
}

/**
* The number of rented chunks by players in the provider.
*/
public readonly borrowers: WeakMap<Chunk, Set<object>> = new WeakMap();

public readChunkCache(
cx: number,
cz: number,
dimension: Dimension
): Chunk | null {
// Get the dimension index from the dimensions array.
// This will be used as the dimension key in the database.
const index = this.dimensionIndexOf(dimension);

// Check if the dimension index was found.
if (index === -1)
throw new Error(
`Dimension index "${dimension}" was not found for world.`
);

// Check if the chunks map has the index.
if (!this.chunks.has(dimension))
this.chunks.set(dimension, new Map<bigint, Chunk>());

// Get the chunks map for the dimension index.
const chunks = this.chunks.get(dimension);

// Check if no chunks were found.
if (!chunks)
throw new Error(
`Failed to get chunks for dimension "${dimension}" with index "${index}"`
);

// Hash the chunk coordinates.
const hash = ChunkCoords.hash({ x: cx, z: cz });

// Check if the chunk exists in the chunks map.
if (chunks.has(hash)) {
// Return the chunk from the chunks cache.
return chunks.get(hash) as Chunk;
}
return null;
}

public rentChunk<T extends object>(
borrower: T,
cx: number,
cz: number,
dimension: Dimension
): Chunk {
const chunk = this.readChunk(cx, cz, dimension);
const sets = this.borrowers.get(chunk) ?? new Set();
sets.add(borrower);
this.borrowers.set(chunk, sets);
return chunk;
}

public returnChunk<T extends object>(
borrower: T,
cx: number,
cz: number,
dimension: Dimension
): boolean {
const chunk = this.readChunkCache(cx, cz, dimension);
if (chunk) {
const sets = this.borrowers.get(chunk);
if (!sets) return false;

sets.delete(borrower);

// Get the dimension index from the dimensions array.
// This will be used as the dimension key in the database.
const index = this.dimensionIndexOf(dimension);

// Check if the dimension index was found.
if (index === -1)
throw new Error(
`Dimension index "${dimension}" was not found for world.`
);

// Check if the chunks map has the index.
if (!this.chunks.has(dimension)) return true; //Return true bc we know this chunk was borrowed

// Get the chunks map for the dimension index.
const chunks = this.chunks.get(dimension);

// Check if no chunks were found.
if (!chunks) return true; //Return true bc we know this chunk was borrowed

// Hash the chunk coordinates.
const hash = ChunkCoords.hash({ x: cx, z: cz });

// delete chunk from cache
chunks.delete(hash);
return true;
}
return false;
}

public static initialize(
config: WorldConfig,
path: string,
Expand Down Expand Up @@ -180,7 +279,7 @@ class FileSystemProvider extends WorldProvider {

// Log the amount of chunks to pregenerate.
this.logger.info(
`Preparing §c${amount}§r chunks for world §a${world.identifier}§r in dimension §a${dimension.identifier}§r.`
`Preparing §c${amount}§r chunks for world §a${world.identifier}§r in dimension §a${dimension}§r.`
);

// Iterate over the chunks to pregenerate.
Expand All @@ -195,7 +294,7 @@ class FileSystemProvider extends WorldProvider {

// Log the success message.
this.logger.success(
`Successfully pregenerated §c${amount}§r chunks for world §a${world.identifier}§r in dimension §a${dimension.identifier}§r.`
`Successfully pregenerated §c${amount}§r chunks for world §a${world.identifier}§r in dimension §a${dimension}§r.`
);
}

Expand Down Expand Up @@ -223,12 +322,12 @@ class FileSystemProvider extends WorldProvider {

public readChunk(cx: number, cz: number, dimension: Dimension): Chunk {
// Check if the chunks contain the dimension.
if (!this.chunks.has(dimension.identifier)) {
this.chunks.set(dimension.identifier, new Map());
if (!this.chunks.has(dimension)) {
this.chunks.set(dimension, new Map());
}

// Get the dimension chunks.
const chunks = this.chunks.get(dimension.identifier) as Map<bigint, Chunk>;
const chunks = this.chunks.get(dimension) as Map<bigint, Chunk>;

// Get the chunk hash.
const hash = ChunkCoords.hash({ x: cx, z: cz });
Expand Down Expand Up @@ -272,18 +371,14 @@ class FileSystemProvider extends WorldProvider {
}
}

public writeChunk(chunk: Chunk, dimension: Dimension | string): void {
// Get the dimension identifier.
const identifier =
typeof dimension === "string" ? dimension : dimension.identifier;

public writeChunk(chunk: Chunk, dimension: Dimension): void {
// Check if the chunks contain the dimension.
if (!this.chunks.has(identifier)) {
this.chunks.set(identifier, new Map());
if (!this.chunks.has(dimension)) {
this.chunks.set(dimension, new Map());
}

// Get the dimension chunks.
const chunks = this.chunks.get(identifier) as Map<bigint, Chunk>;
const chunks = this.chunks.get(dimension) as Map<bigint, Chunk>;

// Get the chunk hash.
const hash = ChunkCoords.hash({ x: chunk.x, z: chunk.z });
Expand All @@ -296,7 +391,7 @@ class FileSystemProvider extends WorldProvider {
join(
this.path,
"dims",
identifier,
dimension.identifier,
"chunks",
`${chunk.x}.${chunk.z}.bin`
),
Expand Down
99 changes: 99 additions & 0 deletions packages/serenity/src/providers/leveldb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ class LevelDBProvider extends WorldProvider {
*/
public readonly chunks: Map<Dimension, Map<bigint, Chunk>> = new Map();

/**
* The number of rented chunks by players in the provider.
*/
public readonly borrowers: WeakMap<Chunk, Set<object>> = new WeakMap();

public constructor(path: string) {
super();

Expand Down Expand Up @@ -113,6 +118,100 @@ class LevelDBProvider extends WorldProvider {
}
}

public readChunkCache(
cx: number,
cz: number,
dimension: Dimension
): Chunk | null {
// Get the dimension index from the dimensions array.
// This will be used as the dimension key in the database.
const index = this.dimensionIndexOf(dimension);

// Check if the dimension index was found.
if (index === -1)
throw new Error(
`Dimension index "${dimension.identifier}" was not found for world.`
);

// Check if the chunks map has the index.
if (!this.chunks.has(dimension))
this.chunks.set(dimension, new Map<bigint, Chunk>());

// Get the chunks map for the dimension index.
const chunks = this.chunks.get(dimension);

// Check if no chunks were found.
if (!chunks)
throw new Error(
`Failed to get chunks for dimension "${dimension.identifier}" with index "${index}"`
);

// Hash the chunk coordinates.
const hash = ChunkCoords.hash({ x: cx, z: cz });

// Check if the chunk exists in the chunks map.
if (chunks.has(hash)) {
// Return the chunk from the chunks cache.
return chunks.get(hash) as Chunk;
}
return null;
}

public rentChunk<T extends object>(
borrower: T,
cx: number,
cz: number,
dimension: Dimension
): Chunk {
const chunk = this.readChunk(cx, cz, dimension);
const sets = this.borrowers.get(chunk) ?? new Set();
sets.add(borrower);
this.borrowers.set(chunk, sets);
return chunk;
}

public returnChunk<T extends object>(
borrower: T,
cx: number,
cz: number,
dimension: Dimension
): boolean {
const chunk = this.readChunkCache(cx, cz, dimension);
if (chunk) {
const sets = this.borrowers.get(chunk);
if (!sets) return false;

sets.delete(borrower);

// Get the dimension index from the dimensions array.
// This will be used as the dimension key in the database.
const index = this.dimensionIndexOf(dimension);

// Check if the dimension index was found.
if (index === -1)
throw new Error(
`Dimension index "${dimension.identifier}" was not found for world.`
);

// Check if the chunks map has the index.
if (!this.chunks.has(dimension)) return true; //Return true bc we know this chunk was borrowed

// Get the chunks map for the dimension index.
const chunks = this.chunks.get(dimension);

// Check if no chunks were found.
if (!chunks) return true; //Return true bc we know this chunk was borrowed

// Hash the chunk coordinates.
const hash = ChunkCoords.hash({ x: cx, z: cz });

// delete chunk from cache
chunks.delete(hash);
return true;
}
return false;
}

/**
* Read a subchunk from the database.
* @param cx The chunk X coordinate.
Expand Down
22 changes: 22 additions & 0 deletions packages/world/src/components/player/chunk-rendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,20 @@ class PlayerChunkRenderingComponent extends PlayerComponent {

// Remove the chunk from the player's view
this.chunks.delete(ChunkCoords.hash(coord));

//Return chunk handler to the provider, chunk will be released from the memory later
// !!! 1, Be sure that borrowed chunk is returned with right dimension
// !!! 2, As i am not author of this PlayerChunkRenderingComponent, i relay on current behavior of this class
// !!! so keep in mind this once you are about to change core behavior of PlayerChunkRenderingComponent.
// !!! 3, Not sure if teleportation is handled well, and same when player leaves just hopeing it works

// !!! If you don't return the chunk then provider will hold you as a borrower so this class will not be deallocated
this.player.dimension.world.provider.returnChunk(
this,
coord.x,
coord.z,
this.player.dimension
);
}
}

Expand Down Expand Up @@ -193,6 +207,14 @@ class PlayerChunkRenderingComponent extends PlayerComponent {
// Check if the chunk is ready
if (!chunk.ready) return null;

// Rent a handle to this chunk
this.player.dimension.world.provider.rentChunk(
this,
coord.x,
coord.z,
this.player.dimension
);

// Return the chunk
return chunk;
})
Expand Down
Loading

0 comments on commit d97d36b

Please sign in to comment.