2020-06-15 15:15:20 +00:00
|
|
|
package com.thebrokenrail.twine.mixin;
|
|
|
|
|
2020-06-16 16:21:17 +00:00
|
|
|
import com.thebrokenrail.twine.util.BoatChestMode;
|
2020-06-15 15:15:20 +00:00
|
|
|
import com.thebrokenrail.twine.util.BoatInventory;
|
|
|
|
import com.thebrokenrail.twine.util.BoatUtil;
|
2020-06-16 16:21:17 +00:00
|
|
|
import net.minecraft.block.Block;
|
2020-06-15 15:15:20 +00:00
|
|
|
import net.minecraft.block.BlockState;
|
|
|
|
import net.minecraft.enchantment.EnchantmentHelper;
|
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
import net.minecraft.entity.damage.DamageSource;
|
2020-06-16 16:21:17 +00:00
|
|
|
import net.minecraft.entity.data.DataTracker;
|
|
|
|
import net.minecraft.entity.data.TrackedData;
|
|
|
|
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
2020-06-15 15:15:20 +00:00
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
|
|
import net.minecraft.entity.vehicle.BoatEntity;
|
|
|
|
import net.minecraft.inventory.Inventory;
|
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
import net.minecraft.nbt.CompoundTag;
|
|
|
|
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 {
|
2020-06-16 16:21:17 +00:00
|
|
|
private static final TrackedData<Integer> CHEST_MODE = DataTracker.registerData(BoatEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
|
|
|
|
2020-06-15 15:15:20 +00:00
|
|
|
@Inject(at = @At("RETURN"), method = "initDataTracker")
|
|
|
|
public void initDataTracker(CallbackInfo info) {
|
2020-06-16 16:21:17 +00:00
|
|
|
((BoatEntity) (Object) this).getDataTracker().startTracking(CHEST_MODE, BoatChestMode.NONE.getID());
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Inject(at = @At("HEAD"), method = "canAddPassenger", cancellable = true)
|
|
|
|
public void canAddPassenger(Entity passenger, CallbackInfoReturnable<Boolean> info) {
|
2020-06-16 16:21:17 +00:00
|
|
|
if (((BoatEntity) (Object) this).getPassengerList().size() > 0 && getChestMode() != BoatChestMode.NONE) {
|
2020-06-15 15:15:20 +00:00
|
|
|
info.setReturnValue(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:55:56 +00:00
|
|
|
@Redirect(at = @At(value = "INVOKE", target = "Ljava/util/List;size()I"), method = "updatePassengerPosition", allow = 2, require = 2)
|
2020-06-15 15:15:20 +00:00
|
|
|
public int updatePassengerPosition(List<Entity> list) {
|
2020-06-16 16:21:17 +00:00
|
|
|
if (getChestMode() != BoatChestMode.NONE) {
|
2020-06-15 15:15:20 +00:00
|
|
|
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) {
|
2020-06-16 16:21:17 +00:00
|
|
|
BoatChestMode mode = getChestMode();
|
|
|
|
ItemStack itemStack = player.getStackInHand(hand);
|
|
|
|
|
|
|
|
BoatChestMode newMode = BoatChestMode.valueOf(Block.getBlockFromItem(itemStack.getItem()));
|
|
|
|
|
|
|
|
if (newMode != BoatChestMode.NONE && mode == BoatChestMode.NONE) {
|
2020-06-15 15:15:20 +00:00
|
|
|
List<Entity> passengers = ((BoatEntity) (Object) this).getPassengerList();
|
|
|
|
for (int i = 1; i < passengers.size(); i++) {
|
|
|
|
passengers.get(i).stopRiding();
|
|
|
|
}
|
|
|
|
if (!player.getEntityWorld().isClient()) {
|
2020-06-16 16:21:17 +00:00
|
|
|
ItemStack newStack;
|
|
|
|
if (!player.isCreative()) {
|
|
|
|
newStack = itemStack.split(1);
|
|
|
|
} else {
|
|
|
|
newStack = itemStack.copy();
|
|
|
|
newStack.setCount(1);
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
2020-06-16 16:21:17 +00:00
|
|
|
|
|
|
|
setChestItem(newStack);
|
|
|
|
|
2020-06-16 16:50:42 +00:00
|
|
|
newMode.triggerAdvancement((ServerPlayerEntity) player);
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
info.setReturnValue(ActionResult.SUCCESS);
|
|
|
|
} else if (player.isSneaking()) {
|
|
|
|
if (!player.getEntityWorld().isClient()) {
|
|
|
|
openInventory(player);
|
|
|
|
}
|
|
|
|
info.setReturnValue(ActionResult.SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Unique
|
2020-06-16 16:21:17 +00:00
|
|
|
private void updateChestMode() {
|
|
|
|
BoatChestMode mode = BoatChestMode.valueOf(Block.getBlockFromItem(stack.getItem()));
|
|
|
|
|
|
|
|
((BoatEntity) (Object) this).getDataTracker().set(CHEST_MODE, mode.getID());
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Unique
|
2020-06-15 15:22:30 +00:00
|
|
|
private void dropItemsOnDestroy(boolean isCreative) {
|
2020-06-15 15:15:20 +00:00
|
|
|
if (((BoatEntity) (Object) this).getEntityWorld().getGameRules().getBoolean(GameRules.DO_ENTITY_DROPS)) {
|
2020-06-16 16:21:17 +00:00
|
|
|
BoatChestMode mode = getChestMode();
|
|
|
|
if (mode.containsItems()) {
|
|
|
|
((BoatEntity) (Object) this).dropStack(stack.copy());
|
|
|
|
} else {
|
|
|
|
if (!isCreative) {
|
|
|
|
((BoatEntity) (Object) this).dropStack(getStackWithoutItems());
|
|
|
|
}
|
|
|
|
dropItems();
|
2020-06-15 15:22:30 +00:00
|
|
|
}
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@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) {
|
2020-06-15 15:22:30 +00:00
|
|
|
dropItemsOnDestroy(source.getAttacker() instanceof PlayerEntity && ((PlayerEntity) source.getAttacker()).isCreative());
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@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) {
|
2020-06-15 15:22:30 +00:00
|
|
|
dropItemsOnDestroy(false);
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Unique
|
|
|
|
private BoatInventory items;
|
|
|
|
|
|
|
|
@Unique
|
|
|
|
private void updateInventory() {
|
2020-06-16 16:21:17 +00:00
|
|
|
BoatChestMode mode = getChestMode();
|
|
|
|
items = mode.hasItems() ? new BoatInventory((BoatEntity) (Object) this, mode.getSize(), stack, mode.getOpenSound(), mode.getCloseSound()) : null;
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Unique
|
|
|
|
private void dropItems() {
|
|
|
|
if (items != null) {
|
|
|
|
for (int i = 0; i < items.size(); ++i) {
|
2020-06-16 16:21:17 +00:00
|
|
|
ItemStack itemStack = items.getStack(i).copy();
|
2020-06-15 15:15:20 +00:00
|
|
|
if (!itemStack.isEmpty() && !EnchantmentHelper.hasVanishingCurse(itemStack)) {
|
|
|
|
((BoatEntity) (Object) this).dropStack(itemStack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 16:21:17 +00:00
|
|
|
private void setChestItem(ItemStack newStack) {
|
|
|
|
stack = newStack;
|
2020-06-15 15:15:20 +00:00
|
|
|
|
2020-06-16 16:21:17 +00:00
|
|
|
updateChestMode();
|
|
|
|
updateInventory();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Unique
|
|
|
|
private ItemStack stack;
|
|
|
|
|
|
|
|
@Unique
|
|
|
|
private ItemStack getStackWithoutItems() {
|
|
|
|
ItemStack newStack = stack.copy();
|
|
|
|
CompoundTag tag = newStack.getOrCreateTag();
|
|
|
|
|
|
|
|
CompoundTag entityTag = tag.getCompound("BlockEntityTag");
|
|
|
|
entityTag.remove("Items");
|
|
|
|
if (entityTag.getSize() < 1) {
|
|
|
|
tag.remove("BlockEntityTag");
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
2020-06-16 16:21:17 +00:00
|
|
|
|
|
|
|
return newStack;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Inject(at = @At("RETURN"), method = "writeCustomDataToTag")
|
|
|
|
public void writeCustomDataToTag(CompoundTag tag, CallbackInfo info) {
|
|
|
|
tag.put("ChestItem", stack.toTag(new CompoundTag()));
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Inject(at = @At("RETURN"), method = "readCustomDataFromTag")
|
|
|
|
public void readCustomDataFromTag(CompoundTag tag, CallbackInfo info) {
|
2020-06-16 16:21:17 +00:00
|
|
|
CompoundTag itemTag = tag.getCompound("ChestItem");
|
|
|
|
ItemStack newStack = ItemStack.fromTag(itemTag);
|
|
|
|
|
|
|
|
setChestItem(newStack);
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-06-16 16:21:17 +00:00
|
|
|
public BoatChestMode getChestMode() {
|
|
|
|
return BoatChestMode.valueOf(((BoatEntity) (Object) this).getDataTracker().get(CHEST_MODE));
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-06-16 00:25:12 +00:00
|
|
|
public Inventory getChestInventory() {
|
2020-06-15 15:15:20 +00:00
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void openInventory(PlayerEntity player) {
|
2020-06-16 16:21:17 +00:00
|
|
|
BoatChestMode mode = getChestMode();
|
|
|
|
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, playerInventory, playerEntity) -> mode.getScreenHandlerFactory().createMenu(i, playerInventory, playerEntity, MixinBoatEntity.this), mode.getScreenHandlerName(stack)));
|
2020-06-15 15:15:20 +00:00
|
|
|
}
|
|
|
|
}
|