From 328ddca458869166a4a5791fe59937d84a005753 Mon Sep 17 00:00:00 2001 From: Holly Date: Sun, 24 Dec 2023 17:47:20 +0000 Subject: [PATCH] Implement EntityLiving -> EntityLiving damage & block break sfx / effects --- server/MPClient.ts | 33 +++++++++++++++++++--- server/blocks/Block.ts | 9 +++++- server/blocks/BlockBehaviour.ts | 1 + server/blocks/BlockBehaviourClay.ts | 12 ++++++++ server/blocks/IBlockBehaviour.ts | 1 + server/entities/Entity.ts | 21 ++++++++------ server/entities/EntityItem.ts | 7 +++-- server/entities/EntityLiving.ts | 7 ----- server/enums/Packet.ts | 2 ++ server/enums/SoundEffects.ts | 10 +++++++ server/items/Item.ts | 2 ++ server/packets/SoundEffect.ts | 43 +++++++++++++++++++++++++++++ server/packets/UseEntity.ts | 8 +++--- 13 files changed, 129 insertions(+), 27 deletions(-) create mode 100644 server/blocks/BlockBehaviourClay.ts create mode 100644 server/enums/SoundEffects.ts create mode 100644 server/packets/SoundEffect.ts diff --git a/server/MPClient.ts b/server/MPClient.ts index 4c7537b..8dc5160 100644 --- a/server/MPClient.ts +++ b/server/MPClient.ts @@ -23,6 +23,11 @@ import { ItemStack } from "./inventories/ItemStack"; import { PacketWindowItems } from "./packets/WindowItems"; import { Block } from "./blocks/Block"; import { EntityItem } from "./entities/EntityItem"; +import AABB from "./AABB"; +import { PacketSoundEffect } from "./packets/SoundEffect"; +import { SoundEffects } from "./enums/SoundEffects"; +import { PacketUseEntity } from "./packets/UseEntity"; +import { EntityLiving } from "./entities/EntityLiving"; export class MPClient { private readonly mcServer:MinecraftServer; @@ -72,6 +77,7 @@ export class MPClient { switch (packetId) { case Packet.Chat: this.handleChat(new PacketChat().readData(reader)); break; + case Packet.UseEntity: this.handleUseEntity(new PacketUseEntity().readData(reader)); break; case Packet.Respawn: this.handlePacketRespawn(new PacketRespawn().readData(reader)); break; case Packet.Player: this.handlePacketPlayer(new PacketPlayer().readData(reader)); break; case Packet.PlayerPosition: this.handlePacketPlayerPosition(new PacketPlayerPosition().readData(reader)); break; @@ -92,6 +98,16 @@ export class MPClient { } } + private handleUseEntity(packet:PacketUseEntity) { + const attacker = this.entity.world.entites.get(packet.userId); + const target = this.entity.world.entites.get(packet.targetId); + if (attacker && target && target instanceof EntityLiving) { + if (packet.leftClick) { + target.damageFrom(2, attacker); + } + } + } + private handleChat(packet:PacketChat) { const message = packet.message.split(" "); if (message[0].startsWith("/")) { @@ -180,11 +196,16 @@ export class MPClient { this.entity.world.setBlockWithNotify(this.diggingAt.x, this.diggingAt.y, this.diggingAt.z, 0); //this.inventory.addItemStack(new ItemStack(Block.blockBehaviours[brokenBlockId].droppedItem(brokenBlockId), 1, metadata)); //this.send(new PacketWindowItems(0, this.inventory.getInventorySize(), this.inventory.constructInventoryPayload()).writeData()); - const itemId = Block.blockBehaviours[brokenBlockId].droppedItem(brokenBlockId); + const blockBehaviour = Block.blockBehaviours[brokenBlockId]; + const itemId = blockBehaviour.droppedItem(brokenBlockId); if (itemId !== -1) { - const itemEntity = new EntityItem(this.entity.world, new ItemStack(itemId, 1, metadata)); - itemEntity.position.set(x + 0.5, y + 0.5, z + 0.5); - this.entity.world.addEntity(itemEntity); + const itemCount = blockBehaviour.droppedCount(brokenBlockId); + for (let i = 0; i < ((itemCount - 1) >> 6) + 1; i++) { + const itemEntity = new EntityItem(this.entity.world, new ItemStack(itemId, Math.min(itemCount - 64 * i, 64), metadata)); + itemEntity.position.set(x + 0.5, y + 0.5, z + 0.5); + this.entity.world.addEntity(itemEntity); + this.entity.sendToNearby(new PacketSoundEffect(SoundEffects.BLOCK_BREAK, x, y, z, brokenBlockId).writeData()); + } } } @@ -220,6 +241,10 @@ export class MPClient { this.diggingAt.set(packet.x, packet.y, packet.z); this.mapCoordsFromFace(this.diggingAt, packet.face); + if (this.entity.entityAABB.intersects(AABB.getAABB(this.diggingAt.x, this.diggingAt.y, this.diggingAt.z, this.diggingAt.x + 1, this.diggingAt.y + 1, this.diggingAt.z + 1))) { + return; + } + const itemStack = this.getHeldItemStack(); if (itemStack == null || itemStack.size == 0) { return; diff --git a/server/blocks/Block.ts b/server/blocks/Block.ts index 656a2e4..cb6aa72 100644 --- a/server/blocks/Block.ts +++ b/server/blocks/Block.ts @@ -1,6 +1,7 @@ import AABB from "../AABB"; import { World } from "../World"; import { BlockBehaviour } from "./BlockBehaviour"; +import { BlockBehaviourClay } from "./BlockBehaviourClay"; import { BlockBehaviourFlower } from "./BlockBehaviourFlower"; import { BlockBehaviourGrass } from "./BlockBehaviourGrass"; import { BlockBehaviourStone } from "./BlockBehaviourStone"; @@ -15,6 +16,8 @@ abstract class Behaviour { public static tallGrass = new BlockBehaviourTallGrass(); public static flower = new BlockBehaviourFlower(); + + public static clay = new BlockBehaviourClay(); } export class Block { @@ -98,6 +101,10 @@ export class Block { this.behaviour.droppedItem(blockId); } + public droppedCount(blockId:number) { + this.behaviour.droppedCount(blockId); + } + public getHardness() { return this.hardness; } @@ -149,7 +156,7 @@ export class Block { static readonly flowerDandelion = new Block(37).setHardness(0).setLightPassage(255).setBehaviour(Behaviour.flower).setBlockName("Dandelion"); static readonly flowerRose = new Block(38).setHardness(0).setLightPassage(255).setBehaviour(Behaviour.flower).setBlockName("Rose"); - static readonly clay = new Block(82).setHardness(0.6).setBlockName("Clay"); + static readonly clay = new Block(82).setHardness(0.6).setBehaviour(Behaviour.clay).setBlockName("Clay"); static readonly netherrack = new Block(87).setHardness(0.4).setBlockName("Netherrack"); } \ No newline at end of file diff --git a/server/blocks/BlockBehaviour.ts b/server/blocks/BlockBehaviour.ts index c492e4e..d30f59b 100644 --- a/server/blocks/BlockBehaviour.ts +++ b/server/blocks/BlockBehaviour.ts @@ -5,5 +5,6 @@ import { IBlockBehaviour } from "./IBlockBehaviour"; export class BlockBehaviour implements IBlockBehaviour { public neighborBlockChange(world:World, x:number, y:number, z:number, blockId:number) {} public droppedItem(blockId:number) { return blockId; } + public droppedCount(blockId:number) { return 1; } public getBoundingBox(x:number, y:number, z:number) { return AABB.getAABB(0 + x, 0 + y, 0 + z, 1 + x, 1 + y, 1 + z); } } \ No newline at end of file diff --git a/server/blocks/BlockBehaviourClay.ts b/server/blocks/BlockBehaviourClay.ts new file mode 100644 index 0000000..5466552 --- /dev/null +++ b/server/blocks/BlockBehaviourClay.ts @@ -0,0 +1,12 @@ +import { Item } from "../items/Item"; +import { BlockBehaviour } from "./BlockBehaviour"; + +export class BlockBehaviourClay extends BlockBehaviour { + public droppedItem(blockId:number) { + return Item.clay.shiftedItemID; + } + + public droppedCount(blockId:number) { + return 4; + } +} \ No newline at end of file diff --git a/server/blocks/IBlockBehaviour.ts b/server/blocks/IBlockBehaviour.ts index 81915ff..9f15b23 100644 --- a/server/blocks/IBlockBehaviour.ts +++ b/server/blocks/IBlockBehaviour.ts @@ -4,5 +4,6 @@ import { World } from "../World"; export interface IBlockBehaviour { neighborBlockChange(world:World, x:number, y:number, z:number, blockId:number): void, droppedItem: (blockId:number) => number, + droppedCount: (blockId:number) => number, getBoundingBox: (x:number, y:number, z:number) => AABB, } \ No newline at end of file diff --git a/server/entities/Entity.ts b/server/entities/Entity.ts index 7e1f2cd..367439d 100644 --- a/server/entities/Entity.ts +++ b/server/entities/Entity.ts @@ -114,10 +114,10 @@ export class Entity implements IEntity { .writeByte(this.health); } - collidesWithPlayer(aabb:AABB) { + async collidesWithPlayer(aabb:AABB) { let collidedWith:Player | undefined; - this.world.players.forEach(player => { - if (this.entityAABB.intersects(player.entityAABB)) { + await this.world.players.forEach(player => { + if (this.entityAABB.intersects(player.entityAABB) && collidedWith == undefined) { collidedWith = player; } }); @@ -166,6 +166,8 @@ export class Entity implements IEntity { if (entity === undefined) { this.health -= damage; + } else { + this.health -= damage; } this.wasHurt = true; @@ -249,18 +251,21 @@ export class Entity implements IEntity { moveEntity(motionX:number, motionY:number, motionZ:number) { this.positionBeforeMove.set(this.position); - const blockId = this.chunk.getBlockId(Math.floor(this.positionBeforeMove.x) & 0xf, Math.floor(this.positionBeforeMove.y), Math.floor(this.positionBeforeMove.z) & 0xf); - const blockUnderEntity = blockId > 0 ? Block.blocks[blockId] : null; this.position.add(motionX, motionY, motionZ); this.entityAABB.move(this.position); + + const blockId = this.chunk.getBlockId(Math.floor(this.position.x) & 0xf, Math.floor(this.position.y), Math.floor(this.position.z) & 0xf); + const blockUnderEntity = blockId > 0 ? Block.blocks[blockId] : null; + if (blockUnderEntity !== null) { - const blockBoundingBox = blockUnderEntity.getBoundingBox(Math.floor(this.positionBeforeMove.x), Math.floor(this.positionBeforeMove.y), Math.floor(this.positionBeforeMove.z)); + const blockBoundingBox = blockUnderEntity.getBoundingBox(Math.floor(this.position.x), Math.floor(this.position.y), Math.floor(this.position.z)); // TODO: Handle X and Z collisions. if (this.entityAABB.intersects(blockBoundingBox)) { - const inersectionY = this.entityAABB.intersectionY(blockBoundingBox); - this.position.add(0, inersectionY, 0); + const intersectionY = this.entityAABB.intersectionY(blockBoundingBox); + console.log(intersectionY); + this.position.add(0, intersectionY, 0); this.motion.y = 0; this.onGround = true; } diff --git a/server/entities/EntityItem.ts b/server/entities/EntityItem.ts index a9954b7..71ea02c 100644 --- a/server/entities/EntityItem.ts +++ b/server/entities/EntityItem.ts @@ -24,13 +24,14 @@ export class EntityItem extends Entity { this.health = 5; } - onTick() { + async onTick() { super.onTick(); if (this.pickupDelay > 0) { this.pickupDelay--; } else { - let playerCollided; - if (playerCollided = this.collidesWithPlayer(this.entityAABB)) { + let playerCollided = await this.collidesWithPlayer(this.entityAABB); + if (playerCollided !== undefined) { + console.log(playerCollided.username); playerCollided.inventory.addItemStack(this.itemStack); playerCollided.itemPickup(this, this.itemStack.size); if (this.itemStack.size <= 0) { diff --git a/server/entities/EntityLiving.ts b/server/entities/EntityLiving.ts index df9cc56..c01a39f 100644 --- a/server/entities/EntityLiving.ts +++ b/server/entities/EntityLiving.ts @@ -1,15 +1,8 @@ import { IReader, IWriter } from "bufferstuff"; -import { Rotation } from "../Rotation"; -import Vec3 from "../Vec3"; import { World } from "../World"; import { Block } from "../blocks/Block"; import { EntityStatus } from "../enums/EntityStatus"; -import { PacketAnimation } from "../packets/Animation"; -import { PacketEntityLook } from "../packets/EntityLook"; -import { PacketEntityLookRelativeMove } from "../packets/EntityLookRelativeMove"; -import { PacketEntityRelativeMove } from "../packets/EntityRelativeMove"; import { PacketEntityStatus } from "../packets/EntityStatus"; -import { PacketEntityTeleport } from "../packets/EntityTeleport"; import { Entity } from "./Entity"; import { IEntity } from "./IEntity"; diff --git a/server/enums/Packet.ts b/server/enums/Packet.ts index 53a90ef..01acab0 100644 --- a/server/enums/Packet.ts +++ b/server/enums/Packet.ts @@ -35,6 +35,8 @@ export enum Packet { MultiBlockChange = 0x34, BlockChange = 0x035, + SoundEffect = 0x3D, + Entity = 0x1E, EntityRelativeMove = 0x1F, EntityLook = 0x20, diff --git a/server/enums/SoundEffects.ts b/server/enums/SoundEffects.ts new file mode 100644 index 0000000..88379c9 --- /dev/null +++ b/server/enums/SoundEffects.ts @@ -0,0 +1,10 @@ +export enum SoundEffects { + CLICK2 = 1000, + CLICK1 = 1001, + BOW_FIRE = 1002, + DOOR_TOGGLE = 1003, + EXTINGUISH = 1004, + RECORD_PLAY = 1005, + SMOKE = 2000, + BLOCK_BREAK = 2001 +} \ No newline at end of file diff --git a/server/items/Item.ts b/server/items/Item.ts index 241ea24..80a0d46 100644 --- a/server/items/Item.ts +++ b/server/items/Item.ts @@ -51,4 +51,6 @@ export class Item { static ironPickaxe = new Item(1).setMaxDamage(MaxUses.IRON).setName("Iron Pickaxe"); static ironAxe = new Item(2).setMaxDamage(MaxUses.IRON).setName("Iron Axe"); static ironSword = new Item(11).setMaxDamage(MaxUses.IRON).setName("Iron Sword"); + + static clay = new Item(81).setName("Clay"); } \ No newline at end of file diff --git a/server/packets/SoundEffect.ts b/server/packets/SoundEffect.ts new file mode 100644 index 0000000..60b5494 --- /dev/null +++ b/server/packets/SoundEffect.ts @@ -0,0 +1,43 @@ +import { createWriter, IReader, Endian } from "bufferstuff"; +import { IPacket } from "./IPacket"; +import { Packet } from "../enums/Packet"; +import { SoundEffects } from "../enums/SoundEffects"; + +export class PacketSoundEffect implements IPacket { + public packetId = Packet.SoundEffect; + public effectId:SoundEffects; + public x:number; + public y:number; + public z:number; + public soundData:number; + + public constructor(effectId:number, x:number, y:number, z:number, soundData:number) { + if (typeof(effectId) === "number" && typeof(x) === "number" && typeof(y) === "number" && typeof(z) === "number" && typeof(soundData) === "number") { + this.effectId = effectId; + this.x = x; + this.y = y; + this.z = z; + this.soundData = soundData; + } else { + this.effectId = Number.MIN_VALUE; + this.x = Number.MIN_VALUE; + this.y = Number.MIN_VALUE; + this.z = Number.MIN_VALUE; + this.soundData = Number.MIN_VALUE; + } + } + + public readData(reader:IReader) { + this.effectId = reader.readInt(); + this.x = reader.readInt(); + this.y = reader.readByte(); + this.z = reader.readInt(); + this.soundData = reader.readInt(); + + return this; + } + + public writeData() { + return createWriter(Endian.BE, 18).writeUByte(this.packetId).writeInt(this.effectId).writeInt(this.x).writeByte(this.y).writeInt(this.z).writeInt(this.soundData).toBuffer(); + } +} \ No newline at end of file diff --git a/server/packets/UseEntity.ts b/server/packets/UseEntity.ts index e56419c..34d1d7b 100644 --- a/server/packets/UseEntity.ts +++ b/server/packets/UseEntity.ts @@ -8,10 +8,10 @@ export class PacketUseEntity implements IPacket { public targetId:number; public leftClick:boolean; - public constructor(userId:number, targetId:number, leftClick:boolean) { - this.userId = userId; - this.targetId = targetId; - this.leftClick = leftClick; + public constructor(userId?:number, targetId?:number, leftClick?:boolean) { + this.userId = userId ?? Number.MIN_VALUE; + this.targetId = targetId ?? Number.MIN_VALUE; + this.leftClick = leftClick ?? false; } public readData(reader:IReader) {