219 lines
8.7 KiB
Java
219 lines
8.7 KiB
Java
package com.thebrokenrail.twine.mixin;
|
|
|
|
import com.thebrokenrail.twine.Twine;
|
|
import com.thebrokenrail.twine.advancement.ChestBoatCriterion;
|
|
import com.thebrokenrail.twine.util.BoatInventory;
|
|
import com.thebrokenrail.twine.util.BoatUtil;
|
|
import com.thebrokenrail.twine.util.EnderChestInventoryWrapper;
|
|
import net.minecraft.block.BlockState;
|
|
import net.minecraft.block.EnderChestBlock;
|
|
import net.minecraft.enchantment.EnchantmentHelper;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.damage.DamageSource;
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
import net.minecraft.entity.vehicle.BoatEntity;
|
|
import net.minecraft.inventory.Inventory;
|
|
import net.minecraft.item.Item;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.item.Items;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.ListTag;
|
|
import net.minecraft.screen.GenericContainerScreenHandler;
|
|
import net.minecraft.screen.SimpleNamedScreenHandlerFactory;
|
|
import net.minecraft.server.network.ServerPlayerEntity;
|
|
import net.minecraft.util.ActionResult;
|
|
import net.minecraft.util.Hand;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.world.GameRules;
|
|
import org.spongepowered.asm.mixin.Mixin;
|
|
import org.spongepowered.asm.mixin.Unique;
|
|
import org.spongepowered.asm.mixin.injection.At;
|
|
import org.spongepowered.asm.mixin.injection.Inject;
|
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
|
|
import java.util.List;
|
|
|
|
@Mixin(BoatEntity.class)
|
|
public class MixinBoatEntity implements BoatUtil {
|
|
@Inject(at = @At("RETURN"), method = "initDataTracker")
|
|
public void initDataTracker(CallbackInfo info) {
|
|
((BoatEntity) (Object) this).getDataTracker().startTracking(BoatUtil.HAS_CHEST, BoatChestMode.NONE.name());
|
|
}
|
|
|
|
@Inject(at = @At("HEAD"), method = "canAddPassenger", cancellable = true)
|
|
public void canAddPassenger(Entity passenger, CallbackInfoReturnable<Boolean> info) {
|
|
if (((BoatEntity) (Object) this).getPassengerList().size() > 0 && hasChest() != BoatChestMode.NONE) {
|
|
info.setReturnValue(false);
|
|
}
|
|
}
|
|
|
|
@Redirect(at = @At(value = "INVOKE", target = "Ljava/util/List;size()I"), method = "updatePassengerPosition", allow = 2, require = 2)
|
|
public int updatePassengerPosition(List<Entity> list) {
|
|
if (hasChest() != BoatChestMode.NONE) {
|
|
return list.size() + 1;
|
|
} else {
|
|
return list.size();
|
|
}
|
|
}
|
|
|
|
@Inject(at = @At("HEAD"), method = "interact", cancellable = true)
|
|
public void interact(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> info) {
|
|
BoatChestMode hasChest = hasChest();
|
|
ItemStack stack = player.getStackInHand(hand);
|
|
if ((stack.getItem() == Items.CHEST || stack.getItem() == Items.ENDER_CHEST) && hasChest == BoatChestMode.NONE) {
|
|
List<Entity> passengers = ((BoatEntity) (Object) this).getPassengerList();
|
|
for (int i = 1; i < passengers.size(); i++) {
|
|
passengers.get(i).stopRiding();
|
|
}
|
|
if (!player.getEntityWorld().isClient()) {
|
|
if (stack.getItem() == Items.CHEST) {
|
|
Twine.CHEST_BOAT_CRITERION.trigger((ServerPlayerEntity) player);
|
|
setHasChest(BoatChestMode.CHEST);
|
|
} else {
|
|
Twine.ENDER_CHEST_BOAT_CRITERION.trigger((ServerPlayerEntity) player);
|
|
setHasChest(BoatChestMode.ENDER_CHEST);
|
|
}
|
|
updateInventory();
|
|
}
|
|
if (!player.isCreative()) {
|
|
stack.decrement(1);
|
|
}
|
|
info.setReturnValue(ActionResult.SUCCESS);
|
|
} else if (player.isSneaking()) {
|
|
if (!player.getEntityWorld().isClient()) {
|
|
openInventory(player);
|
|
}
|
|
info.setReturnValue(ActionResult.SUCCESS);
|
|
}
|
|
}
|
|
|
|
@Unique
|
|
private void setHasChest(BoatChestMode mode) {
|
|
((BoatEntity) (Object) this).getDataTracker().set(BoatUtil.HAS_CHEST, mode.name());
|
|
}
|
|
|
|
@Override
|
|
public Item getChestItem() {
|
|
switch (hasChest()) {
|
|
case CHEST: {
|
|
return Items.CHEST;
|
|
}
|
|
case ENDER_CHEST: {
|
|
return Items.ENDER_CHEST;
|
|
}
|
|
default: {
|
|
return Items.AIR;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Unique
|
|
private void dropItemsOnDestroy(boolean isCreative) {
|
|
if (((BoatEntity) (Object) this).getEntityWorld().getGameRules().getBoolean(GameRules.DO_ENTITY_DROPS)) {
|
|
if (!isCreative) {
|
|
((BoatEntity) (Object) this).dropStack(new ItemStack(getChestItem()));
|
|
}
|
|
dropItems();
|
|
}
|
|
}
|
|
|
|
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/vehicle/BoatEntity;remove()V"), method = "damage")
|
|
public void damage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) {
|
|
dropItemsOnDestroy(source.getAttacker() instanceof PlayerEntity && ((PlayerEntity) source.getAttacker()).isCreative());
|
|
}
|
|
|
|
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/vehicle/BoatEntity;remove()V"), method = "fall")
|
|
public void fall(double heightDifference, boolean onGround, BlockState landedState, BlockPos landedPosition, CallbackInfo info) {
|
|
dropItemsOnDestroy(false);
|
|
}
|
|
|
|
@Unique
|
|
private BoatInventory items;
|
|
|
|
@Unique
|
|
private void updateInventory() {
|
|
items = hasChest() == BoatChestMode.CHEST ? new BoatInventory((BoatEntity) (Object) this, 27) : null;
|
|
}
|
|
|
|
@Unique
|
|
private void dropItems() {
|
|
if (items != null) {
|
|
for (int i = 0; i < items.size(); ++i) {
|
|
ItemStack itemStack = items.getStack(i);
|
|
if (!itemStack.isEmpty() && !EnchantmentHelper.hasVanishingCurse(itemStack)) {
|
|
((BoatEntity) (Object) this).dropStack(itemStack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Inject(at = @At("RETURN"), method = "writeCustomDataToTag")
|
|
public void writeCustomDataToTag(CompoundTag tag, CallbackInfo info) {
|
|
BoatChestMode hasChest = hasChest();
|
|
tag.putString("HasChest", hasChest.name());
|
|
if (hasChest == BoatChestMode.CHEST) {
|
|
ListTag listTag = new ListTag();
|
|
|
|
for (int i = 2; i < this.items.size(); ++i) {
|
|
ItemStack itemStack = this.items.getStack(i);
|
|
if (!itemStack.isEmpty()) {
|
|
CompoundTag compoundTag = new CompoundTag();
|
|
compoundTag.putByte("Slot", (byte)i);
|
|
itemStack.toTag(compoundTag);
|
|
listTag.add(compoundTag);
|
|
}
|
|
}
|
|
|
|
tag.put("Items", listTag);
|
|
}
|
|
}
|
|
|
|
@Inject(at = @At("RETURN"), method = "readCustomDataFromTag")
|
|
public void readCustomDataFromTag(CompoundTag tag, CallbackInfo info) {
|
|
BoatChestMode hasChest;
|
|
try {
|
|
hasChest = BoatChestMode.valueOf(tag.getString("HasChest"));
|
|
} catch (IllegalArgumentException e) {
|
|
hasChest = BoatChestMode.NONE;
|
|
}
|
|
setHasChest(hasChest);
|
|
updateInventory();
|
|
if (hasChest == BoatChestMode.CHEST) {
|
|
ListTag listTag = tag.getList("Items", 10);
|
|
|
|
for (int i = 0; i < listTag.size(); ++i) {
|
|
CompoundTag compoundTag = listTag.getCompound(i);
|
|
int j = compoundTag.getByte("Slot") & 255;
|
|
if (j >= 2 && j < items.size()) {
|
|
items.setStack(j, ItemStack.fromTag(compoundTag));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public BoatChestMode hasChest() {
|
|
try {
|
|
return BoatChestMode.valueOf(((BoatEntity) (Object) this).getDataTracker().get(BoatUtil.HAS_CHEST));
|
|
} catch (IllegalArgumentException e) {
|
|
return BoatChestMode.NONE;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Inventory getInventory() {
|
|
return items;
|
|
}
|
|
|
|
@Override
|
|
public void openInventory(PlayerEntity player) {
|
|
if (hasChest() == BoatUtil.BoatChestMode.CHEST) {
|
|
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, playerInventory, playerEntity) -> GenericContainerScreenHandler.createGeneric9x3(i, playerInventory, getInventory()), ((BoatEntity) (Object) this).getDisplayName()));
|
|
} else {
|
|
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, playerInventory, playerEntity) -> GenericContainerScreenHandler.createGeneric9x3(i, playerInventory, new EnderChestInventoryWrapper((BoatEntity) (Object) this, player.getEnderChestInventory())), EnderChestBlock.CONTAINER_NAME));
|
|
}
|
|
}
|
|
}
|