Barrel Boats
Twine/pipeline/head This commit looks good Details

This commit is contained in:
TheBrokenRail 2020-06-16 18:33:45 -04:00
parent c41c42c5cc
commit 6d74e6b663
21 changed files with 274 additions and 218 deletions

View File

@ -30,7 +30,7 @@ Glowing Obsidian heals monsters and hurts everything else. It naturally generate
</table>
## Chest Boats
Right-Click a Boat with a Chest to place it in the Boat, you can also use an Ender Chest, Trapped Chest, or Shulker Box. Shift-Right-Click the Boat to open the Chest. You can also open the Chest inside the Boat by opening your inventory.
Right-Click a Boat with a Chest to place it in the Boat, you can also use an Ender Chest, Trapped Chest, Barrel, or Shulker Box. Shift-Right-Click the Boat to open the Chest. You can also open the Chest inside the Boat by opening your inventory.
## Difficulty Stages
Each player has a "personal" stage of an area, the highest online player's difficulty stage in an area will be the "effective" difficulty stage of that area.

View File

@ -1,5 +1,6 @@
package com.thebrokenrail.twine;
import com.thebrokenrail.twine.advancement.BarrelBoatCriterion;
import com.thebrokenrail.twine.advancement.ChestBoatCriterion;
import com.thebrokenrail.twine.advancement.EnderChestBoatCriterion;
import com.thebrokenrail.twine.advancement.ShulkerBoxBoatCriterion;
@ -8,7 +9,7 @@ import com.thebrokenrail.twine.block.GlowingObsidianBlock;
import com.thebrokenrail.twine.item.BackpackItem;
import com.thebrokenrail.twine.item.DivinerItem;
import com.thebrokenrail.twine.mixin.CriteriaHook;
import com.thebrokenrail.twine.util.BackpackScreenHandler;
import com.thebrokenrail.twine.util.backpack.BackpackScreenHandler;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
@ -49,6 +50,7 @@ public class Twine implements ModInitializer {
public static ChestBoatCriterion CHEST_BOAT_CRITERION = CriteriaHook.callRegister(new ChestBoatCriterion());
public static EnderChestBoatCriterion ENDER_CHEST_BOAT_CRITERION = CriteriaHook.callRegister(new EnderChestBoatCriterion());
public static ShulkerBoxBoatCriterion SHULKER_BOX_BOAT_CRITERION = CriteriaHook.callRegister(new ShulkerBoxBoatCriterion());
public static BarrelBoatCriterion BARREL_BOAT_CRITERION = CriteriaHook.callRegister(new BarrelBoatCriterion());
@Override
public void onInitialize() {

View File

@ -0,0 +1,29 @@
package com.thebrokenrail.twine.advancement;
import com.google.gson.JsonObject;
import com.thebrokenrail.twine.Twine;
import net.minecraft.advancement.criterion.AbstractCriterion;
import net.minecraft.advancement.criterion.AbstractCriterionConditions;
import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer;
import net.minecraft.predicate.entity.EntityPredicate;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
public class BarrelBoatCriterion extends AbstractCriterion<AbstractCriterionConditions> {
private static final Identifier ID = new Identifier(Twine.NAMESPACE, "barrel_boat");
public void trigger(ServerPlayerEntity player) {
this.test(player, conditions -> true);
}
@Override
protected AbstractCriterionConditions conditionsFromJson(JsonObject obj, EntityPredicate.Extended playerPredicate, AdvancementEntityPredicateDeserializer predicateDeserializer) {
return new AbstractCriterionConditions(ID, playerPredicate) {
};
}
@Override
public Identifier getId() {
return ID;
}
}

View File

@ -1,7 +1,7 @@
package com.thebrokenrail.twine.item;
import com.thebrokenrail.twine.Twine;
import com.thebrokenrail.twine.util.BackpackScreenHandler;
import com.thebrokenrail.twine.util.backpack.BackpackScreenHandler;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;

View File

@ -1,8 +1,10 @@
package com.thebrokenrail.twine.mixin;
import com.thebrokenrail.twine.util.BoatChestMode;
import com.thebrokenrail.twine.util.BoatInventory;
import com.thebrokenrail.twine.util.BoatUtil;
import com.thebrokenrail.twine.util.boat.BoatChestMode;
import com.thebrokenrail.twine.util.boat.BoatChestModes;
import com.thebrokenrail.twine.util.boat.BoatUtil;
import com.thebrokenrail.twine.util.boat.inventory.BoatInventory;
import com.thebrokenrail.twine.util.boat.inventory.BoatInventoryWrapper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
@ -38,19 +40,19 @@ public class MixinBoatEntity implements BoatUtil {
@Inject(at = @At("RETURN"), method = "initDataTracker")
public void initDataTracker(CallbackInfo info) {
((BoatEntity) (Object) this).getDataTracker().startTracking(CHEST_MODE, BoatChestMode.NONE.getID());
((BoatEntity) (Object) this).getDataTracker().startTracking(CHEST_MODE, BoatChestModes.NONE.getID());
}
@Inject(at = @At("HEAD"), method = "canAddPassenger", cancellable = true)
public void canAddPassenger(Entity passenger, CallbackInfoReturnable<Boolean> info) {
if (((BoatEntity) (Object) this).getPassengerList().size() > 0 && getChestMode() != BoatChestMode.NONE) {
if (((BoatEntity) (Object) this).getPassengerList().size() > 0 && getChestMode() != BoatChestModes.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 (getChestMode() != BoatChestMode.NONE) {
if (getChestMode() != BoatChestModes.NONE) {
return list.size() + 1;
} else {
return list.size();
@ -64,7 +66,7 @@ public class MixinBoatEntity implements BoatUtil {
BoatChestMode newMode = BoatChestMode.valueOf(Block.getBlockFromItem(itemStack.getItem()));
if (newMode != BoatChestMode.NONE && mode == BoatChestMode.NONE) {
if (newMode != BoatChestModes.NONE && mode == BoatChestModes.NONE) {
List<Entity> passengers = ((BoatEntity) (Object) this).getPassengerList();
for (int i = 1; i < passengers.size(); i++) {
passengers.get(i).stopRiding();
@ -129,7 +131,7 @@ public class MixinBoatEntity implements BoatUtil {
@Unique
private void updateInventory() {
BoatChestMode mode = getChestMode();
items = mode.hasItems() ? new BoatInventory((BoatEntity) (Object) this, mode.getSize(), stack, mode.getOpenSound(), mode.getCloseSound()) : null;
items = mode.hasItems() ? new BoatInventory((BoatEntity) (Object) this, mode.getSize(), stack, mode) : null;
}
@Unique
@ -194,6 +196,6 @@ public class MixinBoatEntity implements BoatUtil {
@Override
public void openInventory(PlayerEntity player) {
BoatChestMode mode = getChestMode();
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, playerInventory, playerEntity) -> mode.getScreenHandlerFactory().createMenu(i, playerInventory, playerEntity, MixinBoatEntity.this), mode.getScreenHandlerName(stack)));
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, playerInventory, playerEntity) -> mode.getScreenHandlerFactory().createMenu(i, playerInventory, playerEntity, MixinBoatEntity.this, inventory -> new BoatInventoryWrapper((Entity) (Object) this, inventory, mode)), mode.getScreenHandlerName(stack)));
}
}

View File

@ -1,6 +1,6 @@
package com.thebrokenrail.twine.mixin;
import com.thebrokenrail.twine.util.BoatUtil;
import com.thebrokenrail.twine.util.boat.BoatUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockRenderType;

View File

@ -1,7 +1,7 @@
package com.thebrokenrail.twine.mixin;
import com.thebrokenrail.twine.util.BoatChestMode;
import com.thebrokenrail.twine.util.BoatUtil;
import com.thebrokenrail.twine.util.boat.BoatChestModes;
import com.thebrokenrail.twine.util.boat.BoatUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
@ -24,7 +24,7 @@ public class MixinClientPlayerInteractionManager {
@Inject(at = @At("HEAD"), method = "hasRidingInventory", cancellable = true)
public void hasRidingInventory(CallbackInfoReturnable<Boolean> info) {
assert client.player != null;
if (client.player.hasVehicle() && client.player.getVehicle() instanceof BoatEntity && ((BoatUtil) client.player.getVehicle()).getChestMode() != BoatChestMode.NONE) {
if (client.player.hasVehicle() && client.player.getVehicle() instanceof BoatEntity && ((BoatUtil) client.player.getVehicle()).getChestMode() != BoatChestModes.NONE) {
info.setReturnValue(true);
}
}

View File

@ -1,7 +1,7 @@
package com.thebrokenrail.twine.mixin;
import com.thebrokenrail.twine.util.BoatChestMode;
import com.thebrokenrail.twine.util.BoatUtil;
import com.thebrokenrail.twine.util.boat.BoatChestModes;
import com.thebrokenrail.twine.util.boat.BoatUtil;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
import net.minecraft.server.network.ServerPlayNetworkHandler;
@ -19,7 +19,7 @@ public class MixinServerPlayNetworkHandler {
@Inject(at = @At("TAIL"), method = "onClientCommand")
public void onClientCommand(ClientCommandC2SPacket packet, CallbackInfo info) {
if (packet.getMode() == ClientCommandC2SPacket.Mode.OPEN_INVENTORY && player.hasVehicle() && player.getVehicle() instanceof BoatEntity && ((BoatUtil) player.getVehicle()).getChestMode() != BoatChestMode.NONE) {
if (packet.getMode() == ClientCommandC2SPacket.Mode.OPEN_INVENTORY && player.hasVehicle() && player.getVehicle() instanceof BoatEntity && ((BoatUtil) player.getVehicle()).getChestMode() != BoatChestModes.NONE) {
((BoatUtil) player.getVehicle()).openInventory(player);
}
}

View File

@ -1,7 +1,7 @@
package com.thebrokenrail.twine.mixin;
import com.thebrokenrail.twine.item.BackpackItem;
import com.thebrokenrail.twine.util.BackpackInventory;
import com.thebrokenrail.twine.util.backpack.inventory.BackpackInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;

View File

@ -1,143 +0,0 @@
package com.thebrokenrail.twine.util;
import com.google.common.collect.Lists;
import com.thebrokenrail.twine.Twine;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.EnderChestBlock;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ShulkerBoxScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.DyeColor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
public class BoatChestMode {
public interface BoatScreenHandlerFactory {
ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player, BoatUtil boat);
}
private static final ArrayList<BoatChestMode> values = new ArrayList<>();
public static final BoatChestMode NONE = new BoatChestMode(Blocks.AIR, null, null, null);
static {
BoatScreenHandlerFactory chestScreenHandler = (i, playerInventory, playerEntity, boat) -> GenericContainerScreenHandler.createGeneric9x3(i, playerInventory, boat.getChestInventory());
ChestBlockEntity chest = new ChestBlockEntity();
Function<ItemStack, Text> chestScreenHandlerName = stack -> stack.hasCustomName() ? stack.getName() : chest.getName();
new BoatChestMode(Blocks.ENDER_CHEST, (i, playerInventory, playerEntity, boat) -> GenericContainerScreenHandler.createGeneric9x3(i, playerInventory, new EnderChestInventoryWrapper((Entity) boat, playerEntity.getEnderChestInventory())), stack -> EnderChestBlock.CONTAINER_NAME, player -> Twine.ENDER_CHEST_BOAT_CRITERION.trigger(player));
new BoatChestMode(Blocks.CHEST, true, false, 27, chestScreenHandler, chestScreenHandlerName, player -> Twine.CHEST_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_CHEST_OPEN, SoundEvents.BLOCK_CHEST_CLOSE);
new BoatChestMode(Blocks.TRAPPED_CHEST, true, false, 27, chestScreenHandler, chestScreenHandlerName, player -> Twine.CHEST_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_CHEST_OPEN, SoundEvents.BLOCK_CHEST_CLOSE);
ShulkerBoxBlockEntity shulker = new ShulkerBoxBlockEntity();
List<DyeColor> colors = Lists.asList(null, DyeColor.values());
for (DyeColor value : colors) {
new BoatChestMode(ShulkerBoxBlock.get(value), true, true, 27, (i, playerInventory, playerEntity, boat) -> new ShulkerBoxScreenHandler(i, playerInventory, boat.getChestInventory()), stack -> stack.hasCustomName() ? stack.getName() : shulker.getName(), player -> Twine.SHULKER_BOX_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_SHULKER_BOX_OPEN, SoundEvents.BLOCK_SHULKER_BOX_CLOSE);
}
}
private final Block block;
private final boolean hasItems;
private final boolean containsItems;
private final int size;
private final BoatScreenHandlerFactory screenHandlerFactory;
private final Function<ItemStack, Text> screenHandlerNameFactory;
private final Consumer<ServerPlayerEntity> advancementTrigger;
private final int id;
private final SoundEvent openSound;
private final SoundEvent closeSound;
private BoatChestMode(Block block, boolean hasItems, boolean containsItems, int size, BoatScreenHandlerFactory screenHandlerFactory, Function<ItemStack, Text> screenHandlerNameFactory, Consumer<ServerPlayerEntity> advancementTrigger, SoundEvent openSound, SoundEvent closeSound) {
this.screenHandlerFactory = screenHandlerFactory;
this.size = size;
this.screenHandlerNameFactory = screenHandlerNameFactory;
this.advancementTrigger = advancementTrigger;
this.openSound = openSound;
this.closeSound = closeSound;
this.id = values.size();
this.block = block;
this.hasItems = hasItems;
this.containsItems = containsItems;
values.add(this);
}
private BoatChestMode(Block block, BoatScreenHandlerFactory screenHandlerFactory, Function<ItemStack, Text> screenHandlerNameFactory, Consumer<ServerPlayerEntity> advancementTrigger) {
this(block,false, false, 0, screenHandlerFactory, screenHandlerNameFactory, advancementTrigger, null, null);
}
public int getSize() {
return size;
}
public BoatScreenHandlerFactory getScreenHandlerFactory() {
return screenHandlerFactory;
}
public Text getScreenHandlerName(ItemStack stack) {
return screenHandlerNameFactory.apply(stack);
}
public void triggerAdvancement(ServerPlayerEntity player) {
if (advancementTrigger != null) {
advancementTrigger.accept(player);
}
}
public SoundEvent getOpenSound() {
return openSound;
}
public SoundEvent getCloseSound() {
return closeSound;
}
public Block getBlock() {
return block;
}
public boolean hasItems() {
return hasItems;
}
public boolean containsItems() {
return containsItems;
}
public int getID() {
return id;
}
public static BoatChestMode valueOf(Block block) {
for (BoatChestMode mode : values) {
if (mode.getBlock() == block) {
return mode;
}
}
return NONE;
}
public static BoatChestMode valueOf(int index) {
BoatChestMode mode = values.get(index);
return mode != null ? mode : NONE;
}
}

View File

@ -1,39 +0,0 @@
package com.thebrokenrail.twine.util;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundEvent;
public class BoatInventory extends ItemInventory {
private final Entity entity;
private final SoundEvent openSound;
private final SoundEvent closeSound;
public BoatInventory(Entity entity, int size, ItemStack stack, SoundEvent openSound, SoundEvent closeSound) {
super(size, stack);
this.entity = entity;
this.openSound = openSound;
this.closeSound = closeSound;
}
@Override
public boolean canPlayerUse(PlayerEntity player) {
return BoatUtil.canReachEntity(player, entity) && entity.isAlive() && ((BoatUtil) entity).getChestMode().hasItems();
}
@Override
public void onOpen(PlayerEntity player) {
if (openSound != null) {
BoatUtil.playSound(entity, openSound);
}
}
@Override
public void onClose(PlayerEntity player) {
if (closeSound != null) {
BoatUtil.playSound(entity, closeSound);
}
}
}

View File

@ -1,6 +1,7 @@
package com.thebrokenrail.twine.util;
package com.thebrokenrail.twine.util.backpack;
import com.thebrokenrail.twine.Twine;
import com.thebrokenrail.twine.util.backpack.inventory.BackpackInventory;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.network.PacketByteBuf;

View File

@ -1,5 +1,6 @@
package com.thebrokenrail.twine.util;
package com.thebrokenrail.twine.util.backpack.inventory;
import com.thebrokenrail.twine.util.inventory.ItemInventory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Hand;

View File

@ -0,0 +1,117 @@
package com.thebrokenrail.twine.util.boat;
import net.minecraft.block.Block;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.Function;
public class BoatChestMode {
public interface BoatScreenHandlerFactory {
ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player, BoatUtil boat, Function<Inventory, Inventory> inventoryWrapper);
}
private static final ArrayList<BoatChestMode> values = new ArrayList<>();
private final Block block;
private final boolean hasItems;
private final boolean containsItems;
private final int size;
private final BoatScreenHandlerFactory screenHandlerFactory;
private final Function<ItemStack, Text> screenHandlerNameFactory;
private final Consumer<ServerPlayerEntity> advancementTrigger;
private final int id;
private final SoundEvent openSound;
private final SoundEvent closeSound;
BoatChestMode(Block block, boolean hasItems, boolean containsItems, int size, BoatScreenHandlerFactory screenHandlerFactory, Function<ItemStack, Text> screenHandlerNameFactory, Consumer<ServerPlayerEntity> advancementTrigger, SoundEvent openSound, SoundEvent closeSound) {
this.screenHandlerFactory = screenHandlerFactory;
this.size = size;
this.screenHandlerNameFactory = screenHandlerNameFactory;
this.advancementTrigger = advancementTrigger;
this.openSound = openSound;
this.closeSound = closeSound;
this.id = values.size();
this.block = block;
this.hasItems = hasItems;
this.containsItems = containsItems;
values.add(this);
}
public BoatChestMode(Block block, BoatScreenHandlerFactory screenHandlerFactory, Function<ItemStack, Text> screenHandlerNameFactory, Consumer<ServerPlayerEntity> advancementTrigger, SoundEvent openSound, SoundEvent closeSound) {
this(block, false, false, 0, screenHandlerFactory, screenHandlerNameFactory, advancementTrigger, openSound, closeSound);
}
public int getSize() {
return size;
}
public BoatScreenHandlerFactory getScreenHandlerFactory() {
return screenHandlerFactory;
}
public Text getScreenHandlerName(ItemStack stack) {
return screenHandlerNameFactory.apply(stack);
}
public void triggerAdvancement(ServerPlayerEntity player) {
if (advancementTrigger != null) {
advancementTrigger.accept(player);
}
}
public SoundEvent getOpenSound() {
return openSound;
}
public SoundEvent getCloseSound() {
return closeSound;
}
public Block getBlock() {
return block;
}
public boolean hasItems() {
return hasItems;
}
public boolean containsItems() {
return containsItems;
}
public int getID() {
return id;
}
public static BoatChestMode valueOf(Block block) {
for (BoatChestMode mode : values) {
if (mode.getBlock() == block) {
return mode;
}
}
return BoatChestModes.NONE;
}
public static BoatChestMode valueOf(int index) {
BoatChestMode mode = values.get(index);
return mode != null ? mode : BoatChestModes.NONE;
}
static {
BoatChestModes.register();
}
}

View File

@ -0,0 +1,45 @@
package com.thebrokenrail.twine.util.boat;
import com.google.common.collect.Lists;
import com.thebrokenrail.twine.Twine;
import net.minecraft.block.Blocks;
import net.minecraft.block.EnderChestBlock;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.block.entity.BarrelBlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ShulkerBoxScreenHandler;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.DyeColor;
import java.util.List;
import java.util.function.Function;
public class BoatChestModes {
public static final BoatChestMode NONE = new BoatChestMode(Blocks.AIR, null, null, null, null, null);
static void register() {
new BoatChestMode(Blocks.ENDER_CHEST, (i, playerInventory, playerEntity, boat, inventoryWrapper) -> GenericContainerScreenHandler.createGeneric9x3(i, playerInventory, inventoryWrapper.apply(playerEntity.getEnderChestInventory())), stack -> EnderChestBlock.CONTAINER_NAME, player -> Twine.ENDER_CHEST_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_ENDER_CHEST_OPEN, SoundEvents.BLOCK_ENDER_CHEST_CLOSE);
BoatChestMode.BoatScreenHandlerFactory chestScreenHandler = (i, playerInventory, playerEntity, boat, inventoryWrapper) -> GenericContainerScreenHandler.createGeneric9x3(i, playerInventory, boat.getChestInventory());
ChestBlockEntity chest = new ChestBlockEntity();
Function<ItemStack, Text> chestScreenHandlerName = stack -> stack.hasCustomName() ? stack.getName() : chest.getName();
new BoatChestMode(Blocks.CHEST, true, false, 27, chestScreenHandler, chestScreenHandlerName, player -> Twine.CHEST_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_CHEST_OPEN, SoundEvents.BLOCK_CHEST_CLOSE);
new BoatChestMode(Blocks.TRAPPED_CHEST, true, false, 27, chestScreenHandler, chestScreenHandlerName, player -> Twine.CHEST_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_CHEST_OPEN, SoundEvents.BLOCK_CHEST_CLOSE);
BarrelBlockEntity barrel = new BarrelBlockEntity();
Function<ItemStack, Text> barrelScreenHandlerName = stack -> stack.hasCustomName() ? stack.getName() : barrel.getName();
new BoatChestMode(Blocks.BARREL, true, false, 27, chestScreenHandler, barrelScreenHandlerName, player -> Twine.BARREL_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_BARREL_OPEN, SoundEvents.BLOCK_BARREL_CLOSE);
ShulkerBoxBlockEntity shulker = new ShulkerBoxBlockEntity();
List<DyeColor> colors = Lists.asList(null, DyeColor.values());
for (DyeColor value : colors) {
new BoatChestMode(ShulkerBoxBlock.get(value), true, true, 27, (i, playerInventory, playerEntity, boat, inventoryWrapper) -> new ShulkerBoxScreenHandler(i, playerInventory, boat.getChestInventory()), stack -> stack.hasCustomName() ? stack.getName() : shulker.getName(), player -> Twine.SHULKER_BOX_BOAT_CRITERION.trigger(player), SoundEvents.BLOCK_SHULKER_BOX_OPEN, SoundEvents.BLOCK_SHULKER_BOX_CLOSE);
}
}
}

View File

@ -1,4 +1,4 @@
package com.thebrokenrail.twine.util;
package com.thebrokenrail.twine.util.boat;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;

View File

@ -0,0 +1,12 @@
package com.thebrokenrail.twine.util.boat.inventory;
import com.thebrokenrail.twine.util.boat.BoatChestMode;
import com.thebrokenrail.twine.util.inventory.ItemInventory;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
public class BoatInventory extends BoatInventoryWrapper {
public BoatInventory(Entity entity, int size, ItemStack stack, BoatChestMode mode) {
super(entity, new ItemInventory(size, stack), mode);
}
}

View File

@ -1,20 +1,21 @@
package com.thebrokenrail.twine.util;
package com.thebrokenrail.twine.util.boat.inventory;
import net.minecraft.block.Blocks;
import com.thebrokenrail.twine.util.boat.BoatChestMode;
import com.thebrokenrail.twine.util.boat.BoatUtil;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EnderChestInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundEvents;
public class EnderChestInventoryWrapper implements Inventory {
private final EnderChestInventory inventory;
public class BoatInventoryWrapper implements Inventory {
private final Inventory inventory;
private final Entity entity;
private final BoatChestMode mode;
public EnderChestInventoryWrapper(Entity entity, EnderChestInventory inventory) {
public BoatInventoryWrapper(Entity entity, Inventory inventory, BoatChestMode mode) {
this.entity = entity;
this.inventory = inventory;
this.mode = mode;
}
@Override
@ -54,17 +55,21 @@ public class EnderChestInventoryWrapper implements Inventory {
@Override
public boolean canPlayerUse(PlayerEntity player) {
return BoatUtil.canReachEntity(player, entity) && entity.isAlive() && ((BoatUtil) entity).getChestMode().getBlock() == Blocks.ENDER_CHEST;
return BoatUtil.canReachEntity(player, entity) && entity.isAlive() && ((BoatUtil) entity).getChestMode() == mode;
}
@Override
public void onOpen(PlayerEntity player) {
BoatUtil.playSound(entity, SoundEvents.BLOCK_ENDER_CHEST_OPEN);
if (mode.getOpenSound() != null) {
BoatUtil.playSound(entity, mode.getOpenSound());
}
}
@Override
public void onClose(PlayerEntity player) {
BoatUtil.playSound(entity, SoundEvents.BLOCK_ENDER_CHEST_CLOSE);
if (mode.getCloseSound() != null) {
BoatUtil.playSound(entity, mode.getCloseSound());
}
}
@Override

View File

@ -1,4 +1,4 @@
package com.thebrokenrail.twine.util;
package com.thebrokenrail.twine.util.inventory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventories;
@ -6,7 +6,7 @@ import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.collection.DefaultedList;
public abstract class ItemInventory implements Inventory {
public class ItemInventory implements Inventory {
private final int size;
private final ItemStack stack;
private final DefaultedList<ItemStack> inv;
@ -73,7 +73,9 @@ public abstract class ItemInventory implements Inventory {
}
@Override
public abstract boolean canPlayerUse(PlayerEntity player);
public boolean canPlayerUse(PlayerEntity player) {
return true;
}
@Override
public void clear() {

View File

@ -26,6 +26,9 @@
"advancements.twine.large_backpack.title": "Go big or go home!",
"advancements.twine.large_backpack.description": "Construct a Large Backpack by combing a Small Backpack and a Gold Ingot in a Smithing Table",
"advancements.twine.barrel_boat.title": "Off-Brand Chest-Boat",
"advancements.twine.barrel_boat.description": "Put a Barrel in a Boat",
"advancements.twine.diviner.title": "Divination",
"advancements.twine.diviner.description": "Construct a Diviner with a Crafting Table",

View File

@ -0,0 +1,19 @@
{
"display": {
"icon": {
"item": "minecraft:oak_boat"
},
"title": {
"translate": "advancements.twine.barrel_boat.title"
},
"description": {
"translate": "advancements.twine.barrel_boat.description"
}
},
"parent": "twine:chest_boat",
"criteria": {
"chest_boat": {
"trigger": "twine:barrel_boat"
}
}
}