Skip to content

Commit

Permalink
feat(world): added BlockPalette and ItemPalette
Browse files Browse the repository at this point in the history
  • Loading branch information
PMK744 committed Sep 20, 2024
1 parent 5a83a4e commit 2467d31
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 66 deletions.
3 changes: 3 additions & 0 deletions packages/block/src/permutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ class BlockPermutation<T extends keyof BlockState = keyof BlockState> {
// Register the block permutation.
BlockPermutation.permutations.set(permutation.network, permutation);

// Register the permutation in the block type.
type.permutations.push(permutation);

// Return the block permutation.
return permutation;
}
Expand Down
8 changes: 4 additions & 4 deletions packages/item/src/creative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ class CreativeItem {
* @param metadata The metadata of the creative item.
*/
public static register(type: ItemType, metadata: number): void {
// Get the index for the item.
const index = CreativeItem.items.size;

// Set the item in the registry.
CreativeItem.items.set(
CreativeItem.items.size + 1,
new CreativeItem(type, metadata)
);
CreativeItem.items.set(index, new CreativeItem(type, metadata));
}
}

Expand Down
20 changes: 11 additions & 9 deletions packages/serenity/src/handlers/resource-pack-client-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
} from "@serenityjs/protocol";
import { BIOME_DEFINITION_LIST, CRAFTING_DATA } from "@serenityjs/data";
import { CreativeItem, CustomItemType, ItemType } from "@serenityjs/item";
import { CustomBlockType } from "@serenityjs/block";
import { PlayerStatus } from "@serenityjs/world";

import { ResourcePack } from "../resource-packs/resource-pack-manager";
Expand Down Expand Up @@ -123,10 +122,14 @@ class ResourcePackClientResponse extends SerenityHandler {
// Set the player as connected
player.status = PlayerStatus.Connected;

const blocks: Array<BlockProperties> = CustomBlockType.getAll().map(
(type) => {
// Get the player's world
const world = player.dimension.world;

const blocks: Array<BlockProperties> = world.blocks
.getAllCustomTypes()
.map((type) => {
// Get the item type from the block type
const item = ItemType.resolve(type) as CustomItemType;
const item = world.items.resolveType(type) as CustomItemType;

// Get the block nbt and item nbt
const blockNbt = type.nbt;
Expand Down Expand Up @@ -158,8 +161,7 @@ class ResourcePackClientResponse extends SerenityHandler {
name: item.identifier,
nbt: blockNbt
};
}
);
});

const packet = new StartGamePacket();
packet.entityId = player.unique;
Expand Down Expand Up @@ -434,9 +436,9 @@ class ResourcePackClientResponse extends SerenityHandler {
packet.blockProperties = blocks;

// Map the custom items to the packet
packet.items = ItemType.getAll().map((item) =>
ItemType.toItemData(item)
);
packet.items = world.items
.getAllTypes()
.map((item) => ItemType.toItemData(item));

packet.multiplayerCorrelationId = "<raknet>a555-7ece-2f1c-8f69";
packet.serverAuthoritativeInventory = true;
Expand Down
5 changes: 4 additions & 1 deletion packages/serenity/src/providers/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ class FileSystemProvider extends WorldProvider {
const name = basename(directory.name);

// Create the generator instance.
const instance = new generator(properties.getValue("world-seed"));
const instance = new generator(
world.blocks,
properties.getValue("world-seed")
);

// Create a new dimension for the world.
const dimension = world.createDimension(
Expand Down
2 changes: 1 addition & 1 deletion packages/serenity/src/providers/leveldb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ class LevelDBProvider extends WorldProvider {
: DimensionType.End;

// Create a new instance of the generator & dimension.
const instance = new dgenerator(config.seed);
const instance = new dgenerator(world.blocks, config.seed);
const dimension = world.createDimension(identifier, dim, instance);

// Set the view distance for the dimension.
Expand Down
2 changes: 1 addition & 1 deletion packages/world/src/block/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from "./block";
// export * from "./custom";
export * from "./palette";
151 changes: 151 additions & 0 deletions packages/world/src/block/palette.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import {
BlockIdentifier,
BlockType,
BlockPermutation,
CustomBlockType,
type BlockState
} from "@serenityjs/block";

import { BlockEnum } from "../commands";

class BlockPalette {
/**
* The registered block types for the palette.
*/
public readonly types = BlockType.types;

/**
* The registered block permutations for the palette.
*/
public readonly permutations = BlockPermutation.permutations;

/**
* Gets all block types from the palette.
* @returns All block types from the palette.
*/
public getAllTypes(): Array<BlockType> {
return [...this.types.values()];
}

/**
* Gets all custom block types from the palette.
*/
public getAllCustomTypes(): Array<CustomBlockType> {
return [...this.types.values()].filter(
(type) => type instanceof CustomBlockType
) as Array<CustomBlockType>;
}

/**
* Gets all block permutations from the palette.
* @returns All block permutations from the palette.
*/
public getAllPermutations(): Array<BlockPermutation> {
return [...this.permutations.values()];
}

/**
* Gets a block type from the palette.
* @param identifier The block identifier to get.
* @returns The block type from the palette.
*/
public resolveType(identifier: BlockIdentifier): BlockType {
return this.types.get(identifier) as BlockType;
}

/**
* Resolves a block permutation from the block identifier and state.
* @param identifier The block identifier to resolve.
* @param state The block state to resolve.
* @returns The block permutation from the palette.
*/
public resolvePermutation<T extends keyof BlockState>(
identifier: T,
state?: BlockState[T]
): BlockPermutation<T> {
// Get the block type from the registry.
const type = this.resolveType(identifier as BlockIdentifier);

// Check if the block type exists.
if (!type)
return this.resolvePermutation(
BlockIdentifier.Air
) as BlockPermutation<T>;

// Check if the state is not provided.
const permutation = type.permutations.find((permutation) => {
for (const key in state) {
// Get the value of the block state.
const value = (permutation.state as never)[key];

// Check if the value is a boolean
const bool = value === true || value === false ? true : false;

// Convert the state to a boolean if it is a boolean.
const query =
bool && (state[key] === 0 || state[key] === 1)
? state[key] === 1
: state[key];

// Check if the block state matches
if (value !== query) {
return false;
}
}

// Return true if the block permutation matches.
return true;
});

// Check if the block permutation does not exist.
if (!permutation) {
// Return the default permutation if the state is not found.
return type.permutations[0] as BlockPermutation<T>;
}

// Return the block permutation.
return permutation as BlockPermutation<T>;
}

/**
* Register a block type to the palette.
* @param type The block type to register.
* @returns Whether the block type was registered.
*/
public registerType(type: BlockType): boolean {
// Check if the block type already exists.
if (this.types.has(type.identifier)) return false;

// Register the block type.
this.types.set(type.identifier, type);

// Register the permutations of the block type.
for (const permutation of type.permutations) {
this.registerPermutation(permutation);
}

// Register the block type to the BlockEnum.
BlockEnum.options.push(type.identifier);

// Return true if the block type was registered.
return true;
}

/**
* Register a block permutation to the palette.
* @param permutation The block permutation to register.
* @returns Whether the block permutation was registered.
*/
public registerPermutation(permutation: BlockPermutation): boolean {
// Check if the block permutation already exists.
if (this.permutations.has(permutation.network)) return false;

// Register the block permutation.
this.permutations.set(permutation.network, permutation);

// Return true if the block permutation was registered.
return true;
}
}

export { BlockPalette };
13 changes: 11 additions & 2 deletions packages/world/src/generator/generator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { BlockPalette } from "../block";
import type { Worker } from "node:worker_threads";
import type { TerrainWorker } from "./worker";
import type { DimensionType } from "@serenityjs/protocol";
Expand All @@ -22,6 +23,11 @@ export class TerrainGenerator {
*/
public readonly identifier: string;

/**
* The block palette for the generator.
*/
public readonly palette: BlockPalette;

/**
* The chunks that are queued for threaded generation.
*/
Expand All @@ -39,10 +45,13 @@ export class TerrainGenerator {

/**
* Creates a new generator instance.
*
* @param palette The block palette for the generator.
* @param seed The seed of the generator.
*/
public constructor(seed: number) {
public constructor(palette: BlockPalette, seed: number) {
// Set the palette of the generator.
this.palette = palette;

// Set the seed of the generator.
this.seed = seed;

Expand Down
57 changes: 30 additions & 27 deletions packages/world/src/generator/overworld.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { createNoise2D, type NoiseFunction2D } from "simplex-noise";
import { BlockPermutation, BlockIdentifier } from "@serenityjs/block";
import { BlockIdentifier, type BlockPermutation } from "@serenityjs/block";
//@ts-expect-error No Types but we are propably going to creaate ones one day
import fastnoise from "fastnoise-lite";

import { Chunk } from "../chunk";

import { TerrainGenerator } from "./generator";

import type { BlockPalette } from "../block";
import type { DimensionType } from "@serenityjs/protocol";

class Overworld extends TerrainGenerator {
Expand Down Expand Up @@ -35,43 +36,45 @@ class Overworld extends TerrainGenerator {
return kinds[Math.floor(Math.random() * kinds.length)]!;
}

public constructor() {
super(0);
public constructor(palette: BlockPalette, seed: number) {
super(palette, seed);

this.worldNoise = createNoise2D(() => this.seed);
this.foilageNoise = createNoise2D(() => this.seed * 0.1337);
this.treeNoise = createNoise2D(() => this.seed * 0.925);

this.base = BlockPermutation.resolve(BlockIdentifier.Bedrock);
this.base = this.palette.resolvePermutation(BlockIdentifier.Bedrock);
this.fill = [
BlockPermutation.resolve(BlockIdentifier.Cobblestone),
BlockPermutation.resolve(BlockIdentifier.Cobblestone),
BlockPermutation.resolve(BlockIdentifier.Stone),
BlockPermutation.resolve(BlockIdentifier.Stone),
BlockPermutation.resolve(BlockIdentifier.MossyCobblestone),
BlockPermutation.resolve(BlockIdentifier.MossyCobblestone)
this.palette.resolvePermutation(BlockIdentifier.Cobblestone),
this.palette.resolvePermutation(BlockIdentifier.Cobblestone),
this.palette.resolvePermutation(BlockIdentifier.Stone),
this.palette.resolvePermutation(BlockIdentifier.Stone),
this.palette.resolvePermutation(BlockIdentifier.MossyCobblestone),
this.palette.resolvePermutation(BlockIdentifier.MossyCobblestone)
];
this.top_layer = [
BlockPermutation.resolve(BlockIdentifier.GrassBlock),
BlockPermutation.resolve(BlockIdentifier.GrassBlock),
BlockPermutation.resolve(BlockIdentifier.GrassBlock),
BlockPermutation.resolve(BlockIdentifier.MossBlock)
this.palette.resolvePermutation(BlockIdentifier.GrassBlock),
this.palette.resolvePermutation(BlockIdentifier.GrassBlock),
this.palette.resolvePermutation(BlockIdentifier.GrassBlock),
this.palette.resolvePermutation(BlockIdentifier.MossBlock)
];
this.vegetation = [
BlockPermutation.resolve(BlockIdentifier.Cornflower),
BlockPermutation.resolve(BlockIdentifier.Poppy),
BlockPermutation.resolve(BlockIdentifier.RedTulip),
BlockPermutation.resolve(BlockIdentifier.WhiteTulip),
BlockPermutation.resolve(BlockIdentifier.RedTulip),
BlockPermutation.resolve(BlockIdentifier.TallGrass),
BlockPermutation.resolve(BlockIdentifier.TallGrass),
BlockPermutation.resolve(BlockIdentifier.TallGrass),
BlockPermutation.resolve(BlockIdentifier.TallGrass)
this.palette.resolvePermutation(BlockIdentifier.Cornflower),
this.palette.resolvePermutation(BlockIdentifier.Poppy),
this.palette.resolvePermutation(BlockIdentifier.RedTulip),
this.palette.resolvePermutation(BlockIdentifier.WhiteTulip),
this.palette.resolvePermutation(BlockIdentifier.RedTulip),
this.palette.resolvePermutation(BlockIdentifier.TallGrass),
this.palette.resolvePermutation(BlockIdentifier.TallGrass),
this.palette.resolvePermutation(BlockIdentifier.TallGrass),
this.palette.resolvePermutation(BlockIdentifier.TallGrass)
];
this.dirt = BlockPermutation.resolve(BlockIdentifier.Dirt);
this.water = BlockPermutation.resolve(BlockIdentifier.Water);
this.oak_log = BlockPermutation.resolve(BlockIdentifier.OakLog);
this.oak_leaves = BlockPermutation.resolve(BlockIdentifier.OakLeaves);
this.dirt = this.palette.resolvePermutation(BlockIdentifier.Dirt);
this.water = this.palette.resolvePermutation(BlockIdentifier.Water);
this.oak_log = this.palette.resolvePermutation(BlockIdentifier.OakLog);
this.oak_leaves = this.palette.resolvePermutation(
BlockIdentifier.OakLeaves
);
this.fast = new fastnoise(this.seed);
this.fast.SetNoiseType(fastnoise.NoiseType.Perlin);
this.fast.SetFractalOctaves(3);
Expand Down
Loading

0 comments on commit 2467d31

Please sign in to comment.