Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor brushable component #146

Merged
merged 12 commits into from
Jan 5, 2025
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.github.thedeathlycow.frostiful.client.mixin.entity_renderer;

import com.github.thedeathlycow.frostiful.client.BrushableTextures;
import com.github.thedeathlycow.frostiful.entity.FBrushable;
import com.github.thedeathlycow.frostiful.registry.FComponents;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.render.entity.PolarBearEntityRenderer;
Expand All @@ -15,18 +15,14 @@
@Mixin(PolarBearEntityRenderer.class)
@Environment(EnvType.CLIENT)
public class PolarBearShearedTextureMixin {


@Inject(
method = "getTexture(Lnet/minecraft/entity/passive/PolarBearEntity;)Lnet/minecraft/util/Identifier;",
at = @At("HEAD"),
cancellable = true
)
public void getShearedTexture(PolarBearEntity polarBear, CallbackInfoReturnable<Identifier> cir) {
if (polarBear instanceof FBrushable brushable && brushable.frostiful$wasBrushed()) {
if (FComponents.BRUSHABLE_COMPONENT.get(polarBear).wasBrushed()) {
cir.setReturnValue(BrushableTextures.POLAR_BEAR);
}
}


}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,28 +1,69 @@
package com.github.thedeathlycow.frostiful.entity.component;

import com.github.thedeathlycow.frostiful.entity.FBrushable;
import com.github.thedeathlycow.frostiful.Frostiful;
import com.github.thedeathlycow.frostiful.registry.FComponents;
import com.github.thedeathlycow.frostiful.registry.FLootTables;
import com.github.thedeathlycow.frostiful.registry.tag.FEntityTypeTags;
import com.github.thedeathlycow.frostiful.util.FLootHelper;
import net.fabricmc.fabric.api.tag.convention.v2.ConventionalItemTags;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.Angerable;
import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.entity.passive.TameableEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.loot.LootTable;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
import net.minecraft.world.event.GameEvent;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.cca.api.v3.component.Component;
import org.ladysnake.cca.api.v3.component.sync.AutoSyncedComponent;

public class BrushableComponent implements Component, AutoSyncedComponent {

private static final String LAST_BRUSHED_TIME_KEY = "last_brushed_time";

private static final int BRUSH_COOLDOWN = 20 * 300;
private long lastBrushTime = -1;

private final AnimalEntity provider;
private final FBrushable brushable;

public BrushableComponent(AnimalEntity provider) {
this.provider = provider;
this.brushable = (FBrushable) provider;
}

/**
* @param animal The mob that was interacted with
* @param player The player who interacted with the mob
* @param hand The hand they used to interact
* @param base Original action result for the interaction
*/
public static ActionResult interactWithMob(AnimalEntity animal, PlayerEntity player, Hand hand, ActionResult base) {
if (player.isSpectator() || base != ActionResult.PASS) {
return base;
}

ItemStack heldItem = player.getStackInHand(hand);
BrushableComponent component = FComponents.BRUSHABLE_COMPONENT.getNullable(animal);
if (component != null && component.isBrushable() && heldItem.isIn(ConventionalItemTags.BRUSH_TOOLS)) {
component.brush(player);
if (!animal.getWorld().isClient) {
heldItem.damage(16, player, LivingEntity.getSlotForHand(hand));
}
return ActionResult.success(animal.getWorld().isClient);
}

return ActionResult.PASS;
}

@Override
Expand All @@ -44,8 +85,8 @@ public void readFromNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryL

@Override
public void writeToNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) {
if (brushable.frostiful$wasBrushed()) {
tag.putLong(LAST_BRUSHED_TIME_KEY, lastBrushTime);
if (this.wasBrushed()) {
tag.putLong(LAST_BRUSHED_TIME_KEY, this.getLastBrushTime());
}
}

Expand All @@ -63,11 +104,74 @@ public void setLastBrushTime(long lastBrushTime) {
public boolean isBrushable() {
return this.provider.isAlive()
&& !this.provider.isBaby()
&& !this.wasBrushed();
&& !this.wasBrushed()
&& this.provider.getType().isIn(FEntityTypeTags.IS_BRUSHABLE);
}

public boolean wasBrushed() {
return lastBrushTime >= 0L
&& this.provider.getWorld().getTimeOfDay() - lastBrushTime <= FBrushable.BRUSH_COOLDOWN;
&& this.provider.getWorld().getTimeOfDay() - lastBrushTime <= BRUSH_COOLDOWN;
}

private void brush(PlayerEntity brusher) {
World world = provider.getWorld();
world.playSoundFromEntity(
null,
provider,
SoundEvents.ITEM_BRUSH_BRUSHING_GENERIC,
SoundCategory.PLAYERS,
1.0f, 1.0f
);
provider.emitGameEvent(GameEvent.SHEAR, brusher);

if (!world.isClient) {
RegistryKey<LootTable> furLootTable = getLootTableForAnimal(provider);

if (furLootTable != null) {
FLootHelper.dropLootFromEntity(provider, furLootTable);
} else {
Frostiful.LOGGER.warn(
"Attempted to brush an animal type {} that does not drop fur!",
provider.getType().getRegistryEntry().toString()
);
}

this.setLastBrushTime(world.getTime());
this.setAngryAt(brusher);
}
}

@Nullable
private static RegistryKey<LootTable> getLootTableForAnimal(AnimalEntity animal) {
EntityType<?> type = animal.getType();
if (type.isIn(FEntityTypeTags.BRUSHING_DROPS_POLAR_BEAR_FUR)) {
return FLootTables.POLAR_BEAR_BRUSHING_GAMEPLAY;
} else if (type.isIn(FEntityTypeTags.BRUSHING_DROPS_WOLF_FUR)) {
return FLootTables.WOLF_BRUSHING_GAMEPLAY;
} else if (type.isIn(FEntityTypeTags.BRUSHING_DROPS_OCELOT_FUR)) {
return FLootTables.OCELOT_BRUSHING_GAMEPLAY;
} else {
return null;
}
}

/**
* Sets the provider to be angry at the brusher if the provider is not tamed
*
* @param brusher the player who brushed the provider
*/
private void setAngryAt(PlayerEntity brusher) {
if (brusher.isCreative()) {
return;
}

if (provider instanceof TameableEntity tameable && tameable.isTamed()) {
return;
}

if (provider instanceof Angerable angerable) {
angerable.chooseRandomAngerTime();
angerable.setAngryAt(brusher.getUuid());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package com.github.thedeathlycow.frostiful.mixins.entity.brushing;
package com.github.thedeathlycow.frostiful.mixins.entity;

import com.github.thedeathlycow.frostiful.entity.FBrushable;
import com.github.thedeathlycow.frostiful.entity.component.BrushableComponent;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(MobEntity.class)
public abstract class MobBrushingMixin extends LivingEntity {

protected MobBrushingMixin(EntityType<? extends LivingEntity> entityType, World world) {
@Mixin(AnimalEntity.class)
public abstract class AnimalEntityMixin extends MobEntity {
protected AnimalEntityMixin(EntityType<? extends MobEntity> entityType, World world) {
super(entityType, world);
}

Expand All @@ -26,8 +25,8 @@ protected MobBrushingMixin(EntityType<? extends LivingEntity> entityType, World
method = "interactMob",
at = @At("TAIL")
)
private ActionResult brushPolarBear(ActionResult original, PlayerEntity player, Hand hand) {
MobEntity animal = (MobEntity) (Object) this;
return FBrushable.interact(animal, player, hand, original);
private ActionResult postInteract(ActionResult original, PlayerEntity player, Hand hand) {
AnimalEntity animal = (AnimalEntity) (Object) this;
return BrushableComponent.interactWithMob(animal, player, hand, original);
}
}
}

This file was deleted.

Loading