package playasmob;
import net.minecraft.world.level.gameevent.GameEventListener;
import net.minecraft.world.item.component.Consumable;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.ai.attributes.DefaultAttributes;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.InteractionHand;
import net.minecraft.util.RandomSource;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.network.chat.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.Holder;
import java.util.List;
import java.util.ArrayList;
public abstract class BaseInfo implements InfoBundle {
public final ArrayList<GameEventListener> listeners = new ArrayList();
public final EntityType type;
public final Class typeClass;
public RandomSource random;
public Player player;
public BaseInfo(EntityType type, Class typeClass, Player player, CompoundTag compound) {
this.type = type;
this.typeClass = typeClass;
this.setHolder(player);
if (compound != null)
this.loadData(compound);
}
public BaseInfo(Player player) {
this(null, null, player, null);
}
public BaseInfo() {
this(null);
}
public CompoundTag saveData() {
CompoundTag compound = new CompoundTag();
if(this instanceof MaturableInfo maturable)
compound.putBoolean("IsBaby", maturable.isBaby());
if(this instanceof SmelterInfo smelter)
compound.put("SmeltData", smelter.saveSmelt());
return compound;
}
public void loadData(CompoundTag compound) {
if(this instanceof MaturableInfo maturable)
maturable.setBaby(compound.getBoolean("IsBaby"));
if(compound.contains("SmeltData") && this instanceof SmelterInfo smelter)
smelter.loadSmelt(compound.getCompound("SmeltData"));
}
@Override
public final boolean skipRender() {
return !this.<Boolean>get(shouldRender);
}
public final void updateDimensions() {
final Pose previousPose = this.getPose();
this.setPose(previousPose == Pose.SLIDING ? Pose.USING_TONGUE : Pose.SLIDING);
Utils.delay(1, () -> {
this.setPose(previousPose);
});
}
public final void setHolder(Player player) {
this.player = player;
this.random = player == null ? null : player.getRandom();
}
public final int getIndex() {
return this.getInfoType().getIndex();
}
public final ArrayList<GameEventListener> getListeners() {
return this.listeners;
}
public final Entity getEntity() {
return this.player;
}
public final void changeInfo(EntityType type, boolean convertData) {
this.changeInfo(type, convertData ? this.saveData() : null);
}
public final void changeInfo(InfoType type, boolean convertData) {
this.changeInfo(type, convertData ? this.saveData() : null);
}
public final void changeInfo(EntityType type, CompoundTag loadData) {
this.changeInfo(InfoType.byEntity(type, null), loadData);
}
public final void changeInfo(InfoType type, CompoundTag loadData) {
if (type != null && this.getPlayer() instanceof InfoHolder holder) {
logger.debug("Changing Info from " + this.getClass().getSimpleName() + " to " + type.info.getClass().getSimpleName());
holder.setInfo(type, loadData, Activatable.Type.Change);
}
}
@Override
public EntityType getType(EntityType original) {
return type;
}
public final Class getTypeClass() {
return this.typeClass;
}
public final InfoType getInfoType() {
return InfoType.byEntity(this.getType(EntityType.PLAYER), InfoType.Player);
}
public LivingEntity getTarget() {
return null;
}
public void ate(ItemStack stack, Consumable consumer, FoodProperties foodInfo) {
}
public boolean handUseageBlocked() {
return false;
}
public HandUse getHandUseage(boolean includeBlocked) {
if (this.isDeadOrDying())
return HandUse.Missing;
if (includeBlocked && this.handUseageBlocked())
return HandUse.Blocked;
if (this.isUsingItem())
return HandUse.UsingItem;
return HandUse.None;
}
public boolean canUseHands(HandUse type) {
HandUse currentUseage = this.getHandUseage(true);
return currentUseage == HandUse.None || currentUseage == type;
}
public boolean canUseItem(ItemStack stack) {
return this.canUseHands(HandUse.UsingItem);
}
@Override
public double blockInteractionRange(double original) {
return this.modifyInteractionRange(original);
}
@Override
public double entityInteractionRange(double original) {
return this.modifyInteractionRange(original);
}
public double modifyInteractionRange(double range) {
if(!this.canUseHands(HandUse.None))
return 0;
EntityDimensions modifedHitbox = this.type.getDimensions();
EntityDimensions defaultHitbox = EntityType.PLAYER.getDimensions();
float widthDiff = modifedHitbox.width() - defaultHitbox.width();
range += widthDiff;
return range;
}
public boolean canTradeWith(Entity entity) {
return false;
}
public void press(int key, boolean pressed, int time) {
logger.debug("BaseInfo.press(); key: " + key + ", pressed: " + pressed + ", time: " + time + ", isClientSide: " + this.level().isClientSide);
}
@Override
public void init() {
this.updateDimensions();
Utils.delay(1, () -> {
this.setupAttributes();
});
}
public void setupAttributes() {
logger.debug("setupAttributes::start");
if (!this.isBound())
return;
AttributeSupplier supplier = DefaultAttributes.getSupplier(this.type);
for (Holder<Attribute> attribute : BuiltInRegistries.ATTRIBUTE.asHolderIdMap()) {
if (!supplier.hasAttribute(attribute))
continue;
double base = supplier.getBaseValue(attribute);
AttributeInstance instance = this.getLivingEntity().getAttribute(attribute);
instance.setBaseValue(base);
}
logger.debug("setupAttributes::end");
}
public void replaceItemInSlot(ItemStack stack, EquipmentSlot slot, boolean drop) {
if (!this.isBound() || this.level().isClientSide || stack == null || stack.isEmpty() || stack.getCount() == 0)
return;
ItemStack precursor = this.getItemBySlot(slot).copy();
if (precursor == null || precursor.isEmpty() || precursor.getCount() == 0) {
this.setItemSlot(slot, stack);
} else if (ItemStack.isSameItemSameComponents(precursor, stack) && precursor.getCount() < precursor.getMaxStackSize()) {
int total = precursor.getCount() + stack.getCount();
int remaining = total - stack.getMaxStackSize();
stack.setCount(Math.min(total, stack.getMaxStackSize()));
this.setItemSlot(slot, stack);
if (remaining > 0) {
precursor.setCount(remaining);
boolean added = false;
if (!drop)
added = this.addItem(precursor);
if (!added)
this.drop(precursor, true);
}
} else {
this.setItemSlot(slot, stack);
boolean added = false;
if (!drop)
added = this.addItem(precursor);
if (!added)
this.drop(precursor, true);
}
}
public EntityDimensions getDimensions(Pose pose) {
return this.dynamicHitbox(this.getType().getDimensions(), pose);
}
public EntityDimensions dynamicHitbox(EntityDimensions hitbox, Pose pose) {
float smallerSide = Math.min(hitbox.width(), hitbox.height());
EntityDimensions smallHitbox = EntityDimensions.scalable(smallerSide, smallerSide);
EntityDimensions tinyHitbox = EntityDimensions.scalable(smallerSide * 0.666f, smallerSide * 0.666f);
hitbox = switch (pose) {
default -> hitbox;
case FALL_FLYING -> smallHitbox;
case SLEEPING -> tinyHitbox;
case SWIMMING -> smallHitbox;
case SPIN_ATTACK -> smallHitbox;
case CROUCHING -> EntityDimensions.scalable(hitbox.width(), hitbox.height() * 0.833f);
case DYING -> tinyHitbox;
};
if (!this.isBound())
return hitbox;
return hitbox.scale(this.getAgeScale());
}
public void preTick() {
}
public void postTick() {
if(this instanceof SmelterInfo smelter)
smelter.tick();
}
public void shotProjectile(ServerLevel server, InteractionHand hand, ItemStack weapon, List<ItemStack> projectiles, boolean isCrit, LivingEntity target) {
}
public ItemStack getDefaultProjectile(ItemStack weapon) {
return null;
}
@Override
public ItemStack getProjectile(ItemStack original, ItemStack weapon) {
if (!this.isBound())
return original;
ItemStack defaultProjectile = this.getDefaultProjectile(weapon);
if (defaultProjectile != null) {
defaultProjectile.set(DataComponents.ITEM_NAME, Component.literal("defaulted_projectile"));
if (original == null || original.isEmpty())
return defaultProjectile;
}
return original;
}
public void modifyArrow(AbstractArrow arrow, ItemStack projectileStack, ItemStack weaponStack) {
if (!this.isBound())
return;
if (projectileStack.get(DataComponents.ITEM_NAME).getString().equals("defaulted_projectile"))
arrow.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
}
@Override
public float getSpeed(float original) {
return original * (this.isSprinting() ? 0.33f : 0.25f);
}
}