Skip to content

Commit

Permalink
feat(world): added ItemShooterComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
Felipe-Devr committed Aug 28, 2024
1 parent c6bd76d commit e1836e4
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
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 @@ -15,3 +15,4 @@ export * from "./fluid-container";
export * from "./potion";
export * from "./smeltable";
export * from "./throwable";
export * from "./shooter";
100 changes: 100 additions & 0 deletions packages/world/src/components/item/shooter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { EntityIdentifier } from "@serenityjs/entity";
import { Vector3f, type ItemUseMethod } from "@serenityjs/protocol";

import { type ItemStack, ItemUseCause, type Player } from "../..";

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

import type { ItemIdentifier, Items } from "@serenityjs/item";

// TODO: Fix the projectile rotation
class ItemShooterComponent<T extends keyof Items> extends ItemComponent<T> {
public static readonly identifier: string = "minecraft:shooter";

// The item amounition of this shooter
public amounition?: ItemIdentifier;

// The projectile entity to spawn
public projectile: EntityIdentifier = EntityIdentifier.Arrow;

// Wetjher or not the power needs to be scaled based on the item use duration
public scalePowerByDuration: boolean = false;

// The power scale for the projectile, based on the item use duration
public powerScale: number = 1;

// The maximum launch power of the projectile, based on the item use duration
public maxLaunchPower: number = 1;

/**
* Retrieves the ammunition item stack from the player's inventory.
*
* @param player - The player whose inventory is being checked for ammunition.
* @returns The item stack of the ammunition if found, otherwise undefined.
*/
private getAmounition(player: Player): ItemStack | undefined {
const playerInventory = player.getComponent("minecraft:inventory");

return playerInventory.container.storage
.filter((item) => item !== null)
.find((item) => item.type.identifier == this.amounition);
}

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

/**
* Shoots a projectile from the player based on the item use duration and direction.
*
* @param player - The player who is using the item to shoot the projectile.
*/
private shoot(player: Player): void {
const duration = Number(player.getItemUseDuration()) / 20; // Get the item use duration

if (duration < 0.1) return; // You can't shoot a projectile if the duration is less than 0.1seconds
const direction = player.getViewDirection().normalize(); // Normalize the view direction
const projectile = player.dimension.spawnEntity(
this.projectile,
player.position.add(new Vector3f(0, 1, 0)).floor() // Spawn the projectile at the players view Y position
); // Spawn the projectile entity
const projectileComponent = projectile.getComponent("minecraft:projectile");

if (!projectileComponent)
throw new Error("Shooter projectile is not a projectile");

const power = Math.min(
this.maxLaunchPower,
this.scalePowerByDuration ? duration * this.powerScale : this.powerScale
); // Compute the projectile power (Speed)
projectile.rotation.yaw = player.rotation.yaw;
projectileComponent.owner = player; // Assign the projectile owner
projectileComponent.shoot(direction.multiply(power)); // Shoot the projectile
}

public onUse(): ItemUseMethod | undefined {
return;
}

public onStartUse(): void {}

public onStopUse(player: Player, cause: ItemUseCause): void {
if (cause !== ItemUseCause.Use) return;
const inventory = player.getComponent("minecraft:inventory");

if (!inventory) throw new Error("Player does not have an inventory");
const amounition = this.amounition ? this.getAmounition(player) : undefined;

if (!amounition && this.amounition) return;
else if (amounition) {
amounition.amount--; // Decrease the amounition amount
inventory.container.setItem(
inventory.container.storage.indexOf(amounition), // Get the amounition item slot
amounition
); // Update the amounition item
}
this.shoot(player);
}
}

export { ItemShooterComponent };
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 @@ -10,6 +10,7 @@ import type {
ItemLoreComponent,
ItemNametagComponent,
ItemPotionComponent,
ItemShooterComponent,
ItemSmeltableComponent,
ItemThrowableComponent
} from "../../components";
Expand All @@ -27,6 +28,7 @@ interface ItemComponents<T extends keyof Items> {
"minecraft:potion": ItemPotionComponent<T>;
"minecraft:smeltable": ItemSmeltableComponent<T>;
"minecraft:throwable": ItemThrowableComponent<T>;
"minecraft:shooter": ItemShooterComponent<T>;
}

export { ItemComponents };

0 comments on commit e1836e4

Please sign in to comment.