diff --git a/packages/data/data/entity_types.json b/packages/data/data/entity_types.json index bacd973f..36c96a38 100644 --- a/packages/data/data/entity_types.json +++ b/packages/data/data/entity_types.json @@ -3,6 +3,10 @@ "identifier": "minecraft:balloon", "components": [] }, + { + "identifier": "minecraft:falling_block", + "components": [] + }, { "identifier": "minecraft:vindicator", "components": [ @@ -175,10 +179,7 @@ }, { "identifier": "minecraft:wind_charge_projectile", - "components": [ - "minecraft:type_family", - "minecraft:projectile" - ] + "components": ["minecraft:type_family", "minecraft:projectile"] }, { "identifier": "minecraft:sheep", @@ -558,9 +559,7 @@ }, { "identifier": "minecraft:arrow", - "components": [ - "minecraft:projectile" - ] + "components": ["minecraft:projectile"] }, { "identifier": "minecraft:llama", @@ -867,9 +866,7 @@ }, { "identifier": "minecraft:ender_crystal", - "components": [ - "minecraft:fire_immune" - ] + "components": ["minecraft:fire_immune"] }, { "identifier": "minecraft:silverfish", @@ -1448,9 +1445,7 @@ }, { "identifier": "minecraft:xp_orb", - "components": [ - "minecraft:type_family" - ] + "components": ["minecraft:type_family"] }, { "identifier": "minecraft:zombie_villager_v2", @@ -1535,21 +1530,15 @@ }, { "identifier": "minecraft:xp_bottle", - "components": [ - "minecraft:projectile" - ] + "components": ["minecraft:projectile"] }, { "identifier": "minecraft:tnt", - "components": [ - "minecraft:type_family" - ] + "components": ["minecraft:type_family"] }, { "identifier": "minecraft:splash_potion", - "components": [ - "minecraft:projectile" - ] + "components": ["minecraft:projectile"] }, { "identifier": "minecraft:lingering_potion", @@ -1569,9 +1558,7 @@ }, { "identifier": "minecraft:snowball", - "components": [ - "minecraft:projectile" - ] + "components": ["minecraft:projectile"] }, { "identifier": "minecraft:fishing_hook", @@ -1583,9 +1570,7 @@ }, { "identifier": "minecraft:egg", - "components": [ - "minecraft:projectile" - ] + "components": ["minecraft:projectile"] }, { "identifier": "minecraft:dragon_fireball", @@ -1603,9 +1588,7 @@ }, { "identifier": "minecraft:lightning_bolt", - "components": [ - "minecraft:type_family" - ] + "components": ["minecraft:type_family"] }, { "identifier": "minecraft:tripod_camera", @@ -1613,10 +1596,7 @@ }, { "identifier": "minecraft:tnt_minecart", - "components": [ - "minecraft:type_family", - "minecraft:is_stackable" - ] + "components": ["minecraft:type_family", "minecraft:is_stackable"] }, { "identifier": "minecraft:minecart", @@ -1644,10 +1624,7 @@ }, { "identifier": "minecraft:command_block_minecart", - "components": [ - "minecraft:inventory", - "minecraft:type_family" - ] + "components": ["minecraft:inventory", "minecraft:type_family"] }, { "identifier": "minecraft:chest_minecart", @@ -1669,4 +1646,4 @@ "minecraft:is_stackable" ] } -] \ No newline at end of file +] diff --git a/packages/entity/src/enums/identifier.ts b/packages/entity/src/enums/identifier.ts index 5b60c0f9..e4b653d3 100644 --- a/packages/entity/src/enums/identifier.ts +++ b/packages/entity/src/enums/identifier.ts @@ -3,6 +3,7 @@ export enum EntityIdentifier { Balloon = "minecraft:balloon", + FallingBlock = "minecraft:falling_block", Vindicator = "minecraft:vindicator", VillagerV2 = "minecraft:villager_v2", IceBomb = "minecraft:ice_bomb", diff --git a/packages/world/src/components/block/gravity.ts b/packages/world/src/components/block/gravity.ts new file mode 100644 index 00000000..2ba6b34b --- /dev/null +++ b/packages/world/src/components/block/gravity.ts @@ -0,0 +1,54 @@ +import { BlockIdentifier } from "@serenityjs/block"; +import { EntityIdentifier } from "@serenityjs/entity"; + +import { Entity } from "../../entity"; +import { EntityFallingBlockComponent } from "../entity"; + +import { BlockComponent } from "./block-component"; + +import type { Block } from "../../block"; + +class BlockGravityComponent extends BlockComponent { + public static readonly identifier = "minecraft:gravity"; + + public static readonly types = [ + BlockIdentifier.Sand, + BlockIdentifier.Gravel, + BlockIdentifier.Glowingobsidian + ]; + + public constructor(block: Block) { + super(block, BlockGravityComponent.identifier); + } + + public onUpdate(): void { + // Check if the block below is air + const below = this.block.below(); + if (!below.isAir()) return; + + // Create a new FallingBlock entity + const entity = new Entity( + EntityIdentifier.FallingBlock, + this.block.dimension + ); + + // Set the entity's position + entity.position.x = this.block.position.x + 0.5; + entity.position.y = this.block.position.y; + entity.position.z = this.block.position.z + 0.5; + + // Create a new EntityFallingBlockComponent + const component = new EntityFallingBlockComponent(entity); + + // Set the permutation of the falling block + component.setPermutation(this.block.permutation); + + // Spawn the entity + entity.spawn(); + + // Destroy the block + this.block.destroy(); + } +} + +export { BlockGravityComponent }; diff --git a/packages/world/src/components/block/index.ts b/packages/world/src/components/block/index.ts index 6401d42a..bbc14f75 100644 --- a/packages/world/src/components/block/index.ts +++ b/packages/world/src/components/block/index.ts @@ -13,3 +13,4 @@ export * from "./sign"; export * from "./loot"; export * from "./supported"; export * from "./tillable"; +export * from "./gravity"; diff --git a/packages/world/src/components/block/supported.ts b/packages/world/src/components/block/supported.ts index 9a179b52..152441a2 100644 --- a/packages/world/src/components/block/supported.ts +++ b/packages/world/src/components/block/supported.ts @@ -48,9 +48,7 @@ class BlockSupportedComponent extends BlockComponent { const itemStack = this.block.getItemStack(); // Get the position of the block - const position = this.block.position.add( - new BlockPosition(0.5, 0, 0.5) - ); + const position = this.block.position.add(new BlockPosition(0.5, 0, 0.5)); // Spawn the item stack entity this.block.dimension.spawnItem(itemStack, position); diff --git a/packages/world/src/components/entity/falling-block.ts b/packages/world/src/components/entity/falling-block.ts new file mode 100644 index 00000000..54cb5f73 --- /dev/null +++ b/packages/world/src/components/entity/falling-block.ts @@ -0,0 +1,85 @@ +import { EntityIdentifier } from "@serenityjs/entity"; +import { BlockIdentifier, type BlockPermutation } from "@serenityjs/block"; + +import { EntityComponent } from "./entity-component"; +import { EntityPhysicsComponent } from "./physics"; +import { EntityHasGravityComponent } from "./flag"; +import { EntityVariantComponent } from "./data"; + +import type { Block } from "../../block"; +import type { Entity } from "../../entity"; + +class EntityFallingBlockComponent extends EntityComponent { + public static readonly identifier = "minecraft:falling_block"; + + public static readonly types = [EntityIdentifier.FallingBlock]; + + /** + * The block permutation of the falling block. + */ + public permutation: BlockPermutation = this.entity + .getWorld() + .blocks.resolvePermutation(BlockIdentifier.Air); + + public constructor(entity: Entity) { + super(entity, EntityFallingBlockComponent.identifier); + + // Add the physics component to the entity + new EntityPhysicsComponent(entity); + + // Add the has gravity component to the entity + new EntityHasGravityComponent(entity); + + // Add the variant component to the entity + new EntityVariantComponent(entity); + } + + public onTick(): void { + // Check if the entity is on the ground + if (!this.entity.onGround) return; + + // Get the block position + const position = this.entity.position.floor(); + + // Get the block at the position + const block = this.entity.dimension.getBlock(position); + + // Try to place the falling block + this.tryPlace(block); + } + + /** + * Sets the permutation of the falling block. + * @param permutation The permutation to set. + */ + public setPermutation(permutation: BlockPermutation): void { + // Update the entity's permutation + this.permutation = permutation; + + // Update the entity's variant + const variant = this.entity.getComponent("minecraft:variant"); + + // Set the current value of the variant to the permutation's network value + variant.setCurrentValue(this.permutation.network); + } + + /** + * Tries to place the falling block at the given block. + * @param block The block to place the falling block at. + */ + protected tryPlace(block: Block): void { + // Check if the block is air + if (block.isAir()) { + // Set the block at the position to the falling block + block.setPermutation(this.permutation); + + // Destroy the falling block entity + return this.entity.despawn(); + } else { + // Check if the block is a falling block + return this.tryPlace(block.above()); + } + } +} + +export { EntityFallingBlockComponent }; diff --git a/packages/world/src/components/entity/index.ts b/packages/world/src/components/entity/index.ts index 921e25bf..86a9bec3 100644 --- a/packages/world/src/components/entity/index.ts +++ b/packages/world/src/components/entity/index.ts @@ -15,3 +15,4 @@ export * from "./damage"; export * from "./projectile"; export * from "./collision-box"; export * from "./loot"; +export * from "./falling-block"; diff --git a/packages/world/src/components/player/entity-rendering.ts b/packages/world/src/components/player/entity-rendering.ts index b13a2307..77d46936 100644 --- a/packages/world/src/components/player/entity-rendering.ts +++ b/packages/world/src/components/player/entity-rendering.ts @@ -44,6 +44,8 @@ class PlayerEntityRenderingComponent extends PlayerComponent { // Check if the entity is a player and if the player is spawned if (entity.isPlayer() && entity.status !== PlayerStatus.Spawned) continue; + if (!entity.isAlive) continue; + // Add the entity to the rendered entities this.entities.add(unique);