Skip to content

Commit

Permalink
Merge pull request #64 from Felipe-Devr/develop
Browse files Browse the repository at this point in the history
feat: added ItemFoodComponent, exhausting player on attacking, sprinting and breaking blocks
  • Loading branch information
PMK744 committed Jul 18, 2024
2 parents e8229ac + c4fd9eb commit 05f5efc
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 6 deletions.
3 changes: 3 additions & 0 deletions packages/serenity/src/handlers/player-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ class PlayerAction extends SerenityHandler {
// If so, we will return.
if (player.gamemode === Gamemode.Creative) return;

// Exhaust the player
player.exhaust(0.005);

// Create a new ItemStack.
const itemType = ItemType.resolve(permutation.type) as ItemType;
const itemStack = ItemStack.create(itemType, 1, permutation.index);
Expand Down
20 changes: 20 additions & 0 deletions packages/world/src/components/entity/attribute/absorption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AttributeName } from "@serenityjs/protocol";

import { EntityAttributeComponent } from "./attribute";

import type { Player } from "../../../player";

class PlayerAbsorptionComponent extends EntityAttributeComponent {
public static readonly identifier = AttributeName.Absorption;

public readonly effectiveMin: number = 0;
public readonly effectiveMax: number = 512;
public readonly defaultValue: number = 0;

public constructor(player: Player) {
super(player, PlayerAbsorptionComponent.identifier);
this.setCurrentValue(this.defaultValue, false);
}
}

export { PlayerAbsorptionComponent };
23 changes: 19 additions & 4 deletions packages/world/src/components/entity/attribute/health.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ActorEventIds,
ActorEventPacket,
AttributeName,
EffectType,
Gamemode,
ItemUseOnEntityInventoryTransactionType,
Vector3f
Expand Down Expand Up @@ -52,12 +53,25 @@ class EntityHealthComponent extends EntityAttributeComponent {
* @param damage The amount of damage to apply to the entity.
*/
public applyDamage(damage: number, cause?: ActorDamageCause): void {
// Decrease the health of the entity
this.decreaseValue(damage);

// Create a new actor event packet
const packet = new ActorEventPacket();

if (
this.entity.hasEffect(EffectType.Absorption) &&
this.entity.hasComponent("minecraft:absorption")
) {
// ? Get the current absorption value
const absorption = this.entity.getComponent("minecraft:absorption");
// ? Get the new damage, to decrease the health if there is more damage than absorption points
const remainingDamage = damage - absorption.getCurrentValue();

// ? Decrease absorption points and health if remaining
absorption.decreaseValue(damage);
this.decreaseValue(Math.max(0, remainingDamage));
} else {
// Decrease the health of the entity
this.decreaseValue(damage);
}
// Assign the values to the packet
packet.actorRuntimeId = this.entity.runtime;
packet.eventId = ActorEventIds.HURT_ANIMATION;
Expand Down Expand Up @@ -100,7 +114,6 @@ class EntityHealthComponent extends EntityAttributeComponent {

// Decrease the health of the entity
this.decreaseValue(damage);

// Return the current health of the entity
return this.getCurrentValue();
}
Expand All @@ -114,6 +127,8 @@ class EntityHealthComponent extends EntityAttributeComponent {
*/
// Check if the player is attacking the entity
if (type !== ItemUseOnEntityInventoryTransactionType.Attack) return;
// Exhaust the player after attacking
player.exhaust(0.1);

// Check if the entity is a player and the player is in creative mode
if (this.entity.isPlayer() && this.entity.gamemode === Gamemode.Creative)
Expand Down
1 change: 1 addition & 0 deletions packages/world/src/components/entity/attribute/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from "./attribute";
// Concrete components
export * from "./health";
export * from "./movement";
export * from "./absorption";
78 changes: 78 additions & 0 deletions packages/world/src/components/item/food.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { ItemIdentifier, type Items } from "@serenityjs/item";

import { ItemUseCause } from "../../enums";
import { ItemStack } from "../../item";

import { ItemComponent } from "./item-component";

import type { Player } from "../../player";

class ItemFoodComponent<T extends keyof Items> extends ItemComponent<T> {
public static readonly identifier = "minecraft:food";

/**
* The nutrition value that will be given to the player when eated
*/
public nutrition: number = 0;

/**
* The saturation modifier to apply the saturation buff
*/
public saturationModifier: number = 0;

/**
* Means if the food can be eaten whether the player is hungry or not
*/
public canAlwaysEat: boolean = false;

/**
* It's the item that will be converted to when eaten
*/
public convertsTo: ItemIdentifier = ItemIdentifier.Air;

public constructor(item: ItemStack<T>) {
super(item, ItemFoodComponent.identifier);
}

public onUse(player: Player, cause: ItemUseCause): boolean {
if (cause != ItemUseCause.Use || !player.usingItem) return false;
if (!this.canAlwaysEat && !player.isHungry()) return false;
// ? Get the player hunger, saturation and inventory
const hungerComponent = player.getComponent("minecraft:player.hunger");
const saturationComponent = player.getComponent(
"minecraft:player.saturation"
);
const { container, selectedSlot } = player.getComponent(
"minecraft:inventory"
);
// ? Increase the food based on nutrition
hungerComponent.increaseValue(this.nutrition);
// ? Add a saturation buff using the formula nutrition * saturationModifier * 2
saturationComponent.increaseValue(
this.nutrition * this.saturationModifier * 2
);
// ? Decrement the food item amount
player.usingItem.decrement(1);

// ? If the item will be converted to a item different than air, convert it
if (this.convertsTo != ItemIdentifier.Air) {
const convertedItemStack = new ItemStack(this.convertsTo, 1);

if (player.usingItem.amount > 0) {
container.addItem(convertedItemStack);
return true;
}
container.setItem(selectedSlot, convertedItemStack);
}
return true;
}

/**
* ? Necessary methods to make it work lol
*/
public onStartUse(player: Player, cause: ItemUseCause): void {}

public onStopUse(player: Player, cause: ItemUseCause): void {}
}

export { ItemFoodComponent };
1 change: 1 addition & 0 deletions packages/world/src/components/item/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from "./enchantable";
export * from "./lore";
export * from "./durability";
export * from "./armor";
export * from "./food";
3 changes: 3 additions & 0 deletions packages/world/src/components/player/attribute/hunger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class PlayerHungerComponent extends EntityAttributeComponent {
this.tickTimer++;
// difficulty modifier

// Exhaust player if its running (Temporary)
if (this.entity.isSprinting) this.exhaust(0.05);

// Reset tick timer after 4 seconds
if (this.tickTimer >= 80) this.tickTimer = 0;
if (this.tickTimer == 0) {
Expand Down
29 changes: 29 additions & 0 deletions packages/world/src/effect/absorption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Color, EffectType } from "@serenityjs/protocol";

import { Effect } from "./effect";

import type { Entity } from "../entity";

class AbsorptionEffect<T extends Entity> extends Effect {
public effectType: EffectType = EffectType.Absorption;
public color: Color = new Color(255, 37, 82, 165);

public onTick?(entity: T): void;

public onAdd?(entity: T): void {
if (!entity.isPlayer()) return;
const playerAbsorption = entity.getComponent("minecraft:absorption");

if (this.amplifier * 4 == playerAbsorption.getCurrentValue()) return;
playerAbsorption.setCurrentValue(this.amplifier * 4, true);
}

public onRemove?(entity: T): void {
if (!entity.isPlayer()) return;
const playerAbsorption = entity.getComponent("minecraft:absorption");

playerAbsorption.resetToDefaultValue();
}
}

export { AbsorptionEffect };
26 changes: 25 additions & 1 deletion packages/world/src/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ import {
EntityHasGravityComponent,
EntityBreathingComponent,
PlayerExperienceLevelComponent,
PlayerExperienceComponent
PlayerExperienceComponent,
PlayerAbsorptionComponent
} from "../components";
import { ItemStack } from "../item";

Expand Down Expand Up @@ -377,6 +378,28 @@ class Player extends Entity {
super.kill();
}

/**
* Querys if the player is hungry
* @returns The player is hungry
*/

public isHungry(): boolean {
if (!this.hasComponent("minecraft:player.hunger")) return false;
const hungerComponent = this.getComponent("minecraft:player.hunger");
return hungerComponent.isHungry;
}

/**
* Exhausts the player decreasing food over time
* @param amount The exhaustion amount
*/
public exhaust(amount: number): void {
if (!this.hasComponent("minecraft:player.hunger")) return;
const hungerComponent = this.getComponent("minecraft:player.hunger");

hungerComponent.exhaust(amount);
}

/**
* Despawns the player from the world.
* @param player The player to despawn the player from.
Expand Down Expand Up @@ -769,3 +792,4 @@ PlayerChunkRenderingComponent.register(type);
PlayerEntityRenderingComponent.register(type);
PlayerExperienceLevelComponent.register(type);
PlayerExperienceComponent.register(type);
PlayerAbsorptionComponent.register(type);
3 changes: 2 additions & 1 deletion packages/world/src/types/components/entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
PlayerAbsorptionComponent,
EntityAlwaysShowNametagComponent,
EntityArmorComponent,
EntityBoundingHeightComponent,
Expand All @@ -23,8 +24,8 @@ import type {
*/
interface EntityAttributeComponents {
"minecraft:health": EntityHealthComponent;
"minecraft:absorption": PlayerAbsorptionComponent;
}

/**
* The metadata components of an entity.
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/world/src/types/components/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
ItemArmorComponent,
ItemDurabilityComponent,
ItemEnchantableComponent,
ItemFoodComponent,
ItemLoreComponent,
ItemNametagComponent
} from "../../components";
Expand All @@ -13,6 +14,7 @@ interface ItemComponents<T extends keyof Items> {
"minecraft:lore": ItemLoreComponent<T>;
"minecraft:durability": ItemDurabilityComponent<T>;
"minecraft:armor": ItemArmorComponent<T>;
"minecraft:food": ItemFoodComponent<T>;
}

export { ItemComponents };

0 comments on commit 05f5efc

Please sign in to comment.