From 379abbe86aa21bae0fbb90dec5357cf5da587245 Mon Sep 17 00:00:00 2001 From: haykam821 <24855774+haykam821@users.noreply.github.com> Date: Wed, 20 Dec 2023 13:01:38 -0500 Subject: [PATCH 1/5] Add tree decoration --- .../xyz/nucleoid/extras/NucleoidExtras.java | 1 + .../xyz/nucleoid/extras/lobby/NEBlocks.java | 4 + .../xyz/nucleoid/extras/lobby/NEItems.java | 30 +++- .../extras/lobby/NEPointOfInterestTypes.java | 24 +++ .../lobby/block/TreeDecorationBlock.java | 34 ++++ .../block/TreeDecorationBlockEntity.java | 152 ++++++++++++++++++ .../extras/lobby/item/tater/TaterBoxItem.java | 25 +++ .../nucleoid/extras/lobby/tree/Ornament.java | 23 +++ .../extras/lobby/tree/OrnamentModel.java | 68 ++++++++ .../extras/lobby/tree/TreeDecoration.java | 43 +++++ .../data/nucleoid_extras/lang/en_us.json | 1 + 11 files changed, 401 insertions(+), 4 deletions(-) create mode 100644 src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java create mode 100644 src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlock.java create mode 100644 src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java create mode 100644 src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java create mode 100644 src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java create mode 100644 src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java diff --git a/src/main/java/xyz/nucleoid/extras/NucleoidExtras.java b/src/main/java/xyz/nucleoid/extras/NucleoidExtras.java index 6767596..4643ed2 100644 --- a/src/main/java/xyz/nucleoid/extras/NucleoidExtras.java +++ b/src/main/java/xyz/nucleoid/extras/NucleoidExtras.java @@ -40,6 +40,7 @@ public void onInitialize() { NEItems.register(); NEEntities.register(); NECriteria.register(); + NEPointOfInterestTypes.register(); ChatFilter.register(); CommandAliases.register(); diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java b/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java index c2f1157..f0d5e90 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java @@ -58,6 +58,7 @@ public class NEBlocks { public static final Block IRON_LAUNCH_PAD = new LaunchPadBlock(AbstractBlock.Settings.copy(Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE).strength(100).noCollision(), Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE); public static final Block CONTRIBUTOR_STATUE = new ContributorStatueBlock(AbstractBlock.Settings.copy(Blocks.SMOOTH_STONE).strength(100)); + public static final Block TREE_DECORATION = new TreeDecorationBlock(AbstractBlock.Settings.copy(Blocks.COARSE_DIRT).strength(100)); public static final Block INFINITE_DISPENSER = new InfiniteDispenserBlock(AbstractBlock.Settings.copy(Blocks.DISPENSER).strength(100)); public static final Block INFINITE_DROPPER = new InfiniteDropperBlock(AbstractBlock.Settings.copy(Blocks.DROPPER).strength(100)); @@ -428,6 +429,7 @@ public class NEBlocks { public static final BlockEntityType LAUNCH_PAD_ENTITY = FabricBlockEntityTypeBuilder.create(LaunchPadBlockEntity::new, GOLD_LAUNCH_PAD, IRON_LAUNCH_PAD).build(); public static final BlockEntityType CONTRIBUTOR_STATUE_ENTITY = FabricBlockEntityTypeBuilder.create(ContributorStatueBlockEntity::new, CONTRIBUTOR_STATUE).build(); + public static final BlockEntityType TREE_DECORATION_ENTITY = FabricBlockEntityTypeBuilder.create(TreeDecorationBlockEntity::new, TREE_DECORATION).build(); public static final BlockEntityType TATEROID_ENTITY = FabricBlockEntityTypeBuilder.create(TateroidBlockEntity::new, TATEROID, RED_TATEROID, ORANGE_TATEROID, YELLOW_TATEROID, GREEN_TATEROID, BLUE_TATEROID, PURPLE_TATEROID).build(); public static final BlockEntityType DAYLIGHT_DETECTOR_TATER_ENTITY = FabricBlockEntityTypeBuilder.create(DaylightDetectorTaterBlockEntity::new, DAYLIGHT_DETECTOR_TATER, INVERTED_DAYLIGHT_DETECTOR_TATER).build(); public static final BlockEntityType BELL_TATER_ENTITY = FabricBlockEntityTypeBuilder.create(BellTaterBlockEntity::new, BELL_TATER).build(); @@ -526,6 +528,7 @@ public static void register() { register("gold_launch_pad", GOLD_LAUNCH_PAD); register("iron_launch_pad", IRON_LAUNCH_PAD); register("contributor_statue", CONTRIBUTOR_STATUE); + register("tree_decoration", TREE_DECORATION); register("infinite_dispenser", INFINITE_DISPENSER); register("infinite_dropper", INFINITE_DROPPER); register("snake_block", SNAKE_BLOCK); @@ -859,6 +862,7 @@ public static void register() { registerBlockEntity("launch_pad", LAUNCH_PAD_ENTITY); registerBlockEntity("contributor_statue", CONTRIBUTOR_STATUE_ENTITY); + registerBlockEntity("tree_decoration", TREE_DECORATION_ENTITY); registerBlockEntity("tateroid", TATEROID_ENTITY); registerBlockEntity("daylight_detector_tater", DAYLIGHT_DETECTOR_TATER_ENTITY); registerBlockEntity("bell_tater", BELL_TATER_ENTITY); diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java index 7c21b87..118e7be 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java @@ -16,18 +16,23 @@ import net.minecraft.item.Items; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; +import net.minecraft.registry.tag.BlockTags; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import xyz.nucleoid.extras.NucleoidExtras; import xyz.nucleoid.extras.NucleoidExtrasConfig; +import xyz.nucleoid.extras.lobby.block.TreeDecorationBlockEntity; import xyz.nucleoid.extras.lobby.block.tater.TinyPotatoBlock; import xyz.nucleoid.extras.lobby.item.*; import xyz.nucleoid.extras.lobby.item.tater.CreativeTaterBoxItem; @@ -53,6 +58,7 @@ public class NEItems { entries.add(NEItems.GOLD_LAUNCH_PAD); entries.add(NEItems.IRON_LAUNCH_PAD); entries.add(NEItems.CONTRIBUTOR_STATUE); + entries.add(NEItems.TREE_DECORATION); entries.add(NEItems.INFINITE_DISPENSER); entries.add(NEItems.INFINITE_DROPPER); entries.add(NEItems.SNAKE_BLOCK); @@ -103,6 +109,7 @@ public class NEItems { public static final Item IRON_LAUNCH_PAD = createSimple(NEBlocks.IRON_LAUNCH_PAD, Items.HEAVY_WEIGHTED_PRESSURE_PLATE); public static final Item CONTRIBUTOR_STATUE = createSimple(NEBlocks.CONTRIBUTOR_STATUE, Items.SMOOTH_STONE); + public static final Item TREE_DECORATION = createSimple(NEBlocks.TREE_DECORATION, Items.COARSE_DIRT); public static final Item INFINITE_DISPENSER = createSimple(NEBlocks.INFINITE_DISPENSER, Items.DISPENSER); public static final Item INFINITE_DROPPER = createSimple(NEBlocks.INFINITE_DROPPER, Items.DROPPER); @@ -462,6 +469,7 @@ public static void register() { register("gold_launch_pad", GOLD_LAUNCH_PAD); register("iron_launch_pad", IRON_LAUNCH_PAD); register("contributor_statue", CONTRIBUTOR_STATUE); + register("tree_decoration", TREE_DECORATION); register("infinite_dispenser", INFINITE_DISPENSER); register("infinite_dropper", INFINITE_DROPPER); register("snake_block", SNAKE_BLOCK); @@ -843,11 +851,25 @@ private static void onPlayerJoin(ServerPlayNetworkHandler handler, PacketSender private static ActionResult onUseBlock(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult) { if (!player.getWorld().isClient() && hitResult != null && hand == Hand.MAIN_HAND) { - ItemStack stack = player.getStackInHand(hand); - BlockPos pos = hitResult.getBlockPos(); + var stack = player.getStackInHand(hand); + var pos = hitResult.getBlockPos(); - PlayerLobbyState state = PlayerLobbyState.get(player); - state.collectTaterFromBlock(world, pos, stack, player); + var lobbyState = PlayerLobbyState.get(player); + + if (lobbyState.collectTaterFromBlock(world, pos, stack, player) == ActionResult.PASS && !(stack.getItem() instanceof TaterBoxItem) && hitResult.getSide() != Direction.UP) { + var state = world.getBlockState(pos); + + if (state.isIn(BlockTags.LEAVES)) { + var serverWorld = (ServerWorld) world; + var blockEntity = TreeDecorationBlockEntity.findNearestTreeDecoration(serverWorld, pos); + + if (blockEntity.isPresent() && blockEntity.get().placeOrnament((ServerPlayerEntity) player, serverWorld, hand, hitResult)) { + return ActionResult.SUCCESS; + } + } + + return ActionResult.PASS; + } } return ActionResult.PASS; diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java b/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java new file mode 100644 index 0000000..70ae5c1 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java @@ -0,0 +1,24 @@ +package xyz.nucleoid.extras.lobby; + +import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper; +import net.minecraft.block.Block; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.world.poi.PointOfInterestType; + +public class NEPointOfInterestTypes { + public static final RegistryKey TREE_DECORATION = of("tree_decoration"); + + public static void register() { + register(TREE_DECORATION, 0, 1, NEBlocks.TREE_DECORATION); + } + + private static RegistryKey of(String id) { + return RegistryKey.of(RegistryKeys.POINT_OF_INTEREST_TYPE, new Identifier(id)); + } + + private static PointOfInterestType register(RegistryKey key, int ticketCount, int searchDistance, Block... blocks) { + return PointOfInterestHelper.register(key.getValue(), ticketCount, searchDistance, blocks); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlock.java new file mode 100644 index 0000000..9976065 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlock.java @@ -0,0 +1,34 @@ +package xyz.nucleoid.extras.lobby.block; + +import eu.pb4.polymer.core.api.block.PolymerBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.BlockWithEntity; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityTicker; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import xyz.nucleoid.extras.lobby.NEBlocks; + +public class TreeDecorationBlock extends BlockWithEntity implements PolymerBlock { + public TreeDecorationBlock(Settings settings) { + super(settings); + } + + @Override + public Block getPolymerBlock(BlockState state) { + return Blocks.COARSE_DIRT; + } + + @Override + public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new TreeDecorationBlockEntity(pos, state); + } + + @Override + public BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { + return world.isClient() ? null : BlockWithEntity.checkType(type, NEBlocks.TREE_DECORATION_ENTITY, TreeDecorationBlockEntity::tick); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java new file mode 100644 index 0000000..25ec141 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java @@ -0,0 +1,152 @@ +package xyz.nucleoid.extras.lobby.block; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.common.base.Predicates; + +import eu.pb4.polymer.virtualentity.api.ElementHolder; +import eu.pb4.polymer.virtualentity.api.attachment.BlockBoundAttachment; +import eu.pb4.polymer.virtualentity.api.attachment.HolderAttachment; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtOps; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.event.GameEvent; +import net.minecraft.world.poi.PointOfInterestStorage; +import xyz.nucleoid.extras.lobby.NEBlocks; +import xyz.nucleoid.extras.lobby.NEPointOfInterestTypes; +import xyz.nucleoid.extras.lobby.item.tater.TaterBoxItem; +import xyz.nucleoid.extras.lobby.tree.Ornament; +import xyz.nucleoid.extras.lobby.tree.OrnamentModel; +import xyz.nucleoid.extras.lobby.tree.TreeDecoration; + +public class TreeDecorationBlockEntity extends BlockEntity { + private static final Logger LOGGER = LogManager.getLogger(TreeDecorationBlockEntity.class); + + private static final String DECORATION_KEY = "decoration"; + + private static final int SEARCH_RADIUS = 32; + + private TreeDecoration data = TreeDecoration.createEmpty(); + private final Map ornamentsToModels = new HashMap<>(); + + private final ElementHolder holder = new ElementHolder(); + private HolderAttachment attachment; + + public TreeDecorationBlockEntity(BlockPos pos, BlockState state) { + super(NEBlocks.TREE_DECORATION_ENTITY, pos, state); + } + + private void setData(TreeDecoration data) { + this.data = data; + + // Add models that have been added to the data + for (var ornament : data.getOrnaments()) { + if (!this.ornamentsToModels.containsKey(ornament)) { + var model = new OrnamentModel(ornament, world.getTime()); + + model.addToHolder(this.holder); + this.ornamentsToModels.put(ornament, model); + } + } + + // Remove models that are no longer in the data + this.ornamentsToModels.entrySet().removeIf(entry -> { + if (!data.getOrnaments().contains(entry.getKey())) { + entry.getValue().removeFromHolder(this.holder); + return true; + } + + return false; + }); + } + + private void addOrnament(Ornament ornament) { + this.setData(this.data.withOrnament(ornament)); + this.markDirty(); + } + + public boolean placeOrnament(ServerPlayerEntity player, ServerWorld world, Hand hand, BlockHitResult hitResult) { + var item = TaterBoxItem.getPrimaryCollectedTater(player).asItem(); + if (item == Items.AIR) return false; + + var pos = hitResult.getPos(); + var offset = pos.subtract(this.pos.toCenterPos()); + + float yaw = player.getYaw() - 180; + float hookYaw = MathHelper.wrapDegrees(player.getRandom().nextFloat() * 360); + + this.addOrnament(new Ornament(item, offset, yaw, hookYaw, player.getUuid())); + + world.emitGameEvent(player, GameEvent.ENTITY_PLACE, pos); + + float pitch = 1.3f + player.getRandom().nextFloat() * 0.2f; + world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_CHAIN_PLACE, SoundCategory.BLOCKS, 0.5f, pitch); + + return true; + } + + @Override + public void readNbt(NbtCompound nbt) { + super.readNbt(nbt); + + if (nbt.contains(DECORATION_KEY, NbtElement.COMPOUND_TYPE)) { + TreeDecoration.CODEC.parse(NbtOps.INSTANCE, nbt.getCompound(DECORATION_KEY)) + .resultOrPartial(LOGGER::error) + .ifPresent(this::setData); + } + } + + @Override + protected void writeNbt(NbtCompound nbt) { + super.writeNbt(nbt); + + TreeDecoration.CODEC.encodeStart(NbtOps.INSTANCE, this.data) + .resultOrPartial(LOGGER::error) + .ifPresent(element -> { + nbt.put(DECORATION_KEY, element); + }); + } + + @Override + public void markRemoved() { + super.markRemoved(); + this.holder.destroy(); + } + + public static void tick(World world, BlockPos pos, BlockState state, TreeDecorationBlockEntity blockEntity) { + for (var model : blockEntity.ornamentsToModels.values()) { + model.updateTransformations(world.getTime(), false); + } + + if (blockEntity.attachment == null && world instanceof ServerWorld serverWorld) { + blockEntity.attachment = BlockBoundAttachment.ofTicking(blockEntity.holder, serverWorld, pos); + } + } + + public static Optional findNearestTreeDecoration(ServerWorld world, BlockPos pos) { + return world.getPointOfInterestStorage() + .getNearestPosition(poiType -> { + return poiType.matchesKey(NEPointOfInterestTypes.TREE_DECORATION); + }, Predicates.alwaysTrue(), pos, SEARCH_RADIUS, PointOfInterestStorage.OccupationStatus.ANY) + .flatMap(decorationPos -> { + return world.getBlockEntity(decorationPos, NEBlocks.TREE_DECORATION_ENTITY); + }); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/item/tater/TaterBoxItem.java b/src/main/java/xyz/nucleoid/extras/lobby/item/tater/TaterBoxItem.java index 993891f..be311d1 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/item/tater/TaterBoxItem.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/item/tater/TaterBoxItem.java @@ -23,6 +23,7 @@ import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.extras.NucleoidExtras; +import xyz.nucleoid.extras.lobby.NEBlocks; import xyz.nucleoid.extras.lobby.PlayerLobbyState; import xyz.nucleoid.extras.lobby.block.tater.CubicPotatoBlock; import xyz.nucleoid.extras.lobby.block.tater.TinyPotatoBlock; @@ -234,4 +235,28 @@ public static void setSelectedTater(ItemStack stack, @Nullable Identifier select tag.putString(SELECTED_TATER_KEY, selectedTaterId.toString()); } } + + public static Block getPrimaryCollectedTater(ServerPlayerEntity player) { + var inventory = player.getInventory(); + + // Check any tater boxes in the inventory for a selected tater + for (int slot = 0; slot < inventory.size(); slot++) { + var stack = inventory.getStack(slot); + + if (stack.getItem() instanceof TaterBoxItem) { + var selectedTater = getSelectedTater(stack); + if (selectedTater != null) return selectedTater; + } + } + + var collectedTaters = new ArrayList<>(PlayerLobbyState.get(player).collectedTaters); + + if (collectedTaters.isEmpty()) { + // If no taters collected at all, fall back to tiny potato + return NEBlocks.TINY_POTATO; + } else { + // Use a random tater that has already been collected + return Util.getRandom(collectedTaters, player.getRandom()); + } + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java new file mode 100644 index 0000000..d5d16b4 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java @@ -0,0 +1,23 @@ +package xyz.nucleoid.extras.lobby.tree; + +import java.util.UUID; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.item.Item; +import net.minecraft.registry.Registries; +import net.minecraft.util.math.Vec3d; +import xyz.nucleoid.extras.util.ExtraCodecs; + +public record Ornament(Item item, Vec3d offset, float yaw, float hookYaw, UUID owner) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group( + Registries.ITEM.getCodec().fieldOf("item").forGetter(Ornament::item), + Vec3d.CODEC.fieldOf("offset").forGetter(Ornament::offset), + Codec.FLOAT.fieldOf("yaw").forGetter(Ornament::yaw), + Codec.FLOAT.fieldOf("hook_yaw").forGetter(Ornament::hookYaw), + ExtraCodecs.STRING_UUID.fieldOf("owner").forGetter(Ornament::owner) + ).apply(instance, Ornament::new) + ); +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java new file mode 100644 index 0000000..49950bd --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java @@ -0,0 +1,68 @@ +package xyz.nucleoid.extras.lobby.tree; + +import org.joml.Matrix4f; + +import eu.pb4.polymer.virtualentity.api.ElementHolder; +import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; +import net.minecraft.item.Items; +import net.minecraft.util.math.MathHelper; + +public final class OrnamentModel { + private final Ornament ornament; + + private final ItemDisplayElement hook; + private final ItemDisplayElement item; + + public OrnamentModel(Ornament ornament, long time) { + this.ornament = ornament; + + this.hook = new ItemDisplayElement(Items.TRIPWIRE_HOOK); + + this.hook.setOffset(ornament.offset()); + this.hook.setInterpolationDuration(1); + + this.item = new ItemDisplayElement(ornament.item()); + + this.item.setOffset(ornament.offset()); + this.item.setInterpolationDuration(1); + + this.updateTransformations(time, true); + } + + public void updateTransformations(long time, boolean initial) { + float rotationX = (float) Math.sin(time / 12f) * 0.04f; + + float hookRotationY = -this.ornament.hookYaw() * MathHelper.RADIANS_PER_DEGREE + MathHelper.PI; + float rotationY = -this.ornament.yaw() * MathHelper.RADIANS_PER_DEGREE + MathHelper.PI; + + Matrix4f hookTransformation = new Matrix4f() + .rotateZ(rotationX) + .rotateY(hookRotationY) + .scale(0.5f) + .translate(0, -4 / 32f, 0); + + this.hook.setTransformation(hookTransformation); + + Matrix4f itemTransformation = new Matrix4f() + .rotateZ(rotationX) + .rotateY(rotationY) + .translate(0, -3 / 32f, 0); + + this.item.setTransformation(itemTransformation); + + if (!initial) { + this.hook.startInterpolation(); + this.item.startInterpolation(); + } + } + + public void addToHolder(ElementHolder holder) { + holder.addElement(this.hook); + holder.addElement(this.item); + } + + public void removeFromHolder(ElementHolder holder) { + holder.removeElement(this.hook); + holder.removeElement(this.item); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java new file mode 100644 index 0000000..35d37a2 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java @@ -0,0 +1,43 @@ +package xyz.nucleoid.extras.lobby.tree; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public final class TreeDecoration { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group( + Ornament.CODEC.listOf().fieldOf("ornaments").forGetter(t -> t.ornaments) + ).apply(instance, TreeDecoration::new) + ); + + private final List ornaments; + + private TreeDecoration(List ornaments) { + this.ornaments = ornaments; + } + + public Collection getOrnaments() { + return this.ornaments; + } + + public TreeDecoration withOrnament(Ornament ornament) { + List ornaments = new ArrayList<>(this.ornaments); + + // Remove existing ornaments with the same owner + ornaments.removeIf(ornamentx -> { + return ornamentx.owner().equals(ornament.owner()); + }); + + ornaments.add(ornament); + + return new TreeDecoration(ornaments); + } + + public static TreeDecoration createEmpty() { + return new TreeDecoration(List.of()); + } +} diff --git a/src/main/resources/data/nucleoid_extras/lang/en_us.json b/src/main/resources/data/nucleoid_extras/lang/en_us.json index e64c352..c4c0004 100644 --- a/src/main/resources/data/nucleoid_extras/lang/en_us.json +++ b/src/main/resources/data/nucleoid_extras/lang/en_us.json @@ -30,6 +30,7 @@ "block.nucleoid_extras.contributor_statue": "Contributor Statue (Lobby only!)", "block.nucleoid_extras.contributor_statue.contributor": "Contributor: %s", "block.nucleoid_extras.contributor_statue.contributor_id": "Contributor ID: %s", + "block.nucleoid_extras.tree_decoration": "Tree Decoration (Lobby only!)", "block.nucleoid_extras.infinite_dispenser": "Infinite Dispenser (Lobby only!)", "block.nucleoid_extras.infinite_dropper": "Infinite Dropper (Lobby only!)", "block.nucleoid_extras.snake_block": "Snake Block (Lobby only!)", From e112f3d7ee0770078f377bedf961a630ef2ea3b6 Mon Sep 17 00:00:00 2001 From: haykam821 <24855774+haykam821@users.noreply.github.com> Date: Sat, 23 Dec 2023 19:57:48 -0500 Subject: [PATCH 2/5] Allow players to remove ornaments --- .../block/TreeDecorationBlockEntity.java | 14 ++++- .../nucleoid/extras/lobby/tree/Ornament.java | 5 ++ .../extras/lobby/tree/OrnamentModel.java | 62 ++++++++++++++++--- .../extras/lobby/tree/TreeDecoration.java | 10 ++- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java index 25ec141..89fc463 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java @@ -59,7 +59,7 @@ private void setData(TreeDecoration data) { // Add models that have been added to the data for (var ornament : data.getOrnaments()) { if (!this.ornamentsToModels.containsKey(ornament)) { - var model = new OrnamentModel(ornament, world.getTime()); + var model = new OrnamentModel(this, ornament); model.addToHolder(this.holder); this.ornamentsToModels.put(ornament, model); @@ -82,6 +82,16 @@ private void addOrnament(Ornament ornament) { this.markDirty(); } + public void removeOrnament(Ornament ornament) { + this.setData(this.data.exceptOrnament(ornament)); + this.markDirty(); + + var pos = this.pos.toCenterPos().add(ornament.offset()); + + float pitch = 1.3f + world.getRandom().nextFloat() * 0.2f; + world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_CHAIN_BREAK, SoundCategory.BLOCKS, 0.5f, pitch); + } + public boolean placeOrnament(ServerPlayerEntity player, ServerWorld world, Hand hand, BlockHitResult hitResult) { var item = TaterBoxItem.getPrimaryCollectedTater(player).asItem(); if (item == Items.AIR) return false; @@ -132,7 +142,7 @@ public void markRemoved() { public static void tick(World world, BlockPos pos, BlockState state, TreeDecorationBlockEntity blockEntity) { for (var model : blockEntity.ornamentsToModels.values()) { - model.updateTransformations(world.getTime(), false); + model.tick(); } if (blockEntity.attachment == null && world instanceof ServerWorld serverWorld) { diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java index d5d16b4..f9b8741 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java @@ -7,6 +7,7 @@ import net.minecraft.item.Item; import net.minecraft.registry.Registries; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.math.Vec3d; import xyz.nucleoid.extras.util.ExtraCodecs; @@ -20,4 +21,8 @@ public record Ornament(Item item, Vec3d offset, float yaw, float hookYaw, UUID o ExtraCodecs.STRING_UUID.fieldOf("owner").forGetter(Ornament::owner) ).apply(instance, Ornament::new) ); + + public boolean canBeRemovedBy(ServerPlayerEntity player) { + return player.getUuid().equals(this.owner) || player.isCreative(); + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java index 49950bd..5b022c4 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java @@ -3,48 +3,83 @@ import org.joml.Matrix4f; import eu.pb4.polymer.virtualentity.api.ElementHolder; +import eu.pb4.polymer.virtualentity.api.elements.InteractionElement; import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; +import eu.pb4.polymer.virtualentity.api.elements.VirtualElement.InteractionHandler; import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.math.MathHelper; +import xyz.nucleoid.extras.lobby.block.TreeDecorationBlockEntity; -public final class OrnamentModel { +public final class OrnamentModel implements InteractionHandler { + private final TreeDecorationBlockEntity blockEntity; private final Ornament ornament; private final ItemDisplayElement hook; private final ItemDisplayElement item; - public OrnamentModel(Ornament ornament, long time) { + private final InteractionElement interaction; + + private int wobbleTicks = 0; + private float wobbleStrength = 0; + + public OrnamentModel(TreeDecorationBlockEntity blockEntity, Ornament ornament) { + this.blockEntity = blockEntity; this.ornament = ornament; this.hook = new ItemDisplayElement(Items.TRIPWIRE_HOOK); this.hook.setOffset(ornament.offset()); this.hook.setInterpolationDuration(1); + this.hook.setInvisible(true); this.item = new ItemDisplayElement(ornament.item()); this.item.setOffset(ornament.offset()); this.item.setInterpolationDuration(1); + this.item.setInvisible(true); + + this.interaction = new InteractionElement(this); + + this.interaction.setOffset(ornament.offset().subtract(0, 0.6, 0)); + this.interaction.setSize(8 / 16f, 11 / 16f); - this.updateTransformations(time, true); + this.updateTransformations(true); } - public void updateTransformations(long time, boolean initial) { - float rotationX = (float) Math.sin(time / 12f) * 0.04f; + @Override + public void attack(ServerPlayerEntity player) { + this.wobbleTicks = 10; + this.wobbleStrength = Math.min(this.wobbleStrength + 10, 60); + + if (this.ornament.canBeRemovedBy(player) && this.wobbleStrength > 40) { + this.blockEntity.removeOrnament(ornament); + } + } + + private void updateTransformations(boolean initial) { + long time = this.blockEntity.getWorld().getTime(); + float rotation; + + if (this.wobbleTicks > 0) { + rotation = MathHelper.RADIANS_PER_DEGREE * MathHelper.sin(this.wobbleTicks) * this.wobbleTicks * this.wobbleStrength / 10.0f; + } else { + rotation = (float) Math.sin(time / 12f) * 0.04f; + } float hookRotationY = -this.ornament.hookYaw() * MathHelper.RADIANS_PER_DEGREE + MathHelper.PI; float rotationY = -this.ornament.yaw() * MathHelper.RADIANS_PER_DEGREE + MathHelper.PI; - Matrix4f hookTransformation = new Matrix4f() - .rotateZ(rotationX) + var hookTransformation = new Matrix4f() + .rotateZ(rotation) .rotateY(hookRotationY) .scale(0.5f) .translate(0, -4 / 32f, 0); this.hook.setTransformation(hookTransformation); - Matrix4f itemTransformation = new Matrix4f() - .rotateZ(rotationX) + var itemTransformation = new Matrix4f() + .rotateZ(rotation) .rotateY(rotationY) .translate(0, -3 / 32f, 0); @@ -56,13 +91,22 @@ public void updateTransformations(long time, boolean initial) { } } + public void tick() { + if (this.wobbleTicks > 0) this.wobbleTicks -= 1; + if (this.wobbleStrength > 0) this.wobbleStrength -= 1; + + this.updateTransformations(false); + } + public void addToHolder(ElementHolder holder) { holder.addElement(this.hook); holder.addElement(this.item); + holder.addElement(this.interaction); } public void removeFromHolder(ElementHolder holder) { holder.removeElement(this.hook); holder.removeElement(this.item); + holder.removeElement(this.interaction); } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java index 35d37a2..a7ebd3d 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java @@ -25,7 +25,7 @@ public Collection getOrnaments() { } public TreeDecoration withOrnament(Ornament ornament) { - List ornaments = new ArrayList<>(this.ornaments); + var ornaments = new ArrayList<>(this.ornaments); // Remove existing ornaments with the same owner ornaments.removeIf(ornamentx -> { @@ -37,6 +37,14 @@ public TreeDecoration withOrnament(Ornament ornament) { return new TreeDecoration(ornaments); } + public TreeDecoration exceptOrnament(Ornament ornament) { + var ornaments = new ArrayList<>(this.ornaments); + + ornaments.remove(ornament); + + return new TreeDecoration(ornaments); + } + public static TreeDecoration createEmpty() { return new TreeDecoration(List.of()); } From 785ca38b15bd6b92ef9479dd8c7ecb661bd6b309 Mon Sep 17 00:00:00 2001 From: haykam821 <24855774+haykam821@users.noreply.github.com> Date: Sat, 23 Dec 2023 20:21:43 -0500 Subject: [PATCH 3/5] Allow players to interact with ornaments to see additional details --- .../nucleoid/extras/lobby/tree/Ornament.java | 13 ++++++++ .../extras/lobby/tree/OrnamentModel.java | 32 +++++++++++++++++-- .../data/nucleoid_extras/lang/en_us.json | 2 ++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java index f9b8741..5f28476 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/Ornament.java @@ -2,16 +2,21 @@ import java.util.UUID; +import com.mojang.authlib.GameProfile; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.item.Item; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; import xyz.nucleoid.extras.util.ExtraCodecs; public record Ornament(Item item, Vec3d offset, float yaw, float hookYaw, UUID owner) { + private static final Text UNKNOWN_OWNER = Text.translatable("commands.banlist.entry.unknown"); + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Registries.ITEM.getCodec().fieldOf("item").forGetter(Ornament::item), @@ -22,6 +27,14 @@ public record Ornament(Item item, Vec3d offset, float yaw, float hookYaw, UUID o ).apply(instance, Ornament::new) ); + public Text getOwnerName(MinecraftServer server) { + return server.getUserCache() + .getByUuid(owner) + .map(GameProfile::getName) + .map(Text::literal) + .orElse(UNKNOWN_OWNER); + } + public boolean canBeRemovedBy(ServerPlayerEntity player) { return player.getUuid().equals(this.owner) || player.isCreative(); } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java index 5b022c4..75da964 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java @@ -6,8 +6,14 @@ import eu.pb4.polymer.virtualentity.api.elements.InteractionElement; import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; import eu.pb4.polymer.virtualentity.api.elements.VirtualElement.InteractionHandler; +import net.minecraft.block.Block; import net.minecraft.item.Items; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.Hand; import net.minecraft.util.math.MathHelper; import xyz.nucleoid.extras.lobby.block.TreeDecorationBlockEntity; @@ -47,10 +53,32 @@ public OrnamentModel(TreeDecorationBlockEntity blockEntity, Ornament ornament) { this.updateTransformations(true); } + private void wobble(ServerPlayerEntity player, boolean careful) { + this.wobbleTicks = 10; + this.wobbleStrength = Math.min(this.wobbleStrength + 10, careful ? 20 : 60); + + var pos = this.blockEntity.getPos().toCenterPos().add(this.ornament.offset()); + float pitch = 1.3f + player.getRandom().nextFloat() * 0.2f; + + player.getWorld().playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_CHAIN_HIT, SoundCategory.BLOCKS, 0.5f, pitch); + } + + @Override + public void interact(ServerPlayerEntity player, Hand hand) { + this.wobble(player, true); + + MinecraftServer server = this.blockEntity.getWorld().getServer(); + Text ownerName = this.ornament.getOwnerName(server); + + Block block = Block.getBlockFromItem(this.ornament.item()); + Text itemName = block.getName(); + + player.sendMessage(Text.translatable("text.nucleoid_extras.ornament.details", itemName, ownerName), true); + } + @Override public void attack(ServerPlayerEntity player) { - this.wobbleTicks = 10; - this.wobbleStrength = Math.min(this.wobbleStrength + 10, 60); + this.wobble(player, false); if (this.ornament.canBeRemovedBy(player) && this.wobbleStrength > 40) { this.blockEntity.removeOrnament(ornament); diff --git a/src/main/resources/data/nucleoid_extras/lang/en_us.json b/src/main/resources/data/nucleoid_extras/lang/en_us.json index c4c0004..da6f733 100644 --- a/src/main/resources/data/nucleoid_extras/lang/en_us.json +++ b/src/main/resources/data/nucleoid_extras/lang/en_us.json @@ -383,6 +383,8 @@ "text.nucleoid_extras.lobby_items": "Do not use this block outside of lobby!", "text.nucleoid_extras.lobby_only": "(Lobby Only!)", + "text.nucleoid_extras.ornament.details": "This %s ornament was placed by %s", + "text.nucleoid_extras.statistics.web_url": "Click here to check out all the stats for this game!", "text.nucleoid_extras.statistics.bundle_header": "Statistics for %s", "text.nucleoid_extras.statistics.stat": "%s: %s", From 2499d4e0c284677aa0d86ef1b43130a0dfdc6c47 Mon Sep 17 00:00:00 2001 From: haykam821 <24855774+haykam821@users.noreply.github.com> Date: Sat, 23 Dec 2023 20:46:15 -0500 Subject: [PATCH 4/5] Restrict ornament placement positions that would intersect with a block --- .../java/xyz/nucleoid/extras/lobby/NEItems.java | 2 +- .../lobby/block/TreeDecorationBlockEntity.java | 15 +++++++++++++++ .../nucleoid/extras/lobby/tree/OrnamentModel.java | 14 ++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java index 118e7be..df3d413 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java @@ -856,7 +856,7 @@ private static ActionResult onUseBlock(PlayerEntity player, World world, Hand ha var lobbyState = PlayerLobbyState.get(player); - if (lobbyState.collectTaterFromBlock(world, pos, stack, player) == ActionResult.PASS && !(stack.getItem() instanceof TaterBoxItem) && hitResult.getSide() != Direction.UP) { + if (lobbyState.collectTaterFromBlock(world, pos, stack, player) == ActionResult.PASS && !(stack.getItem() instanceof TaterBoxItem)) { var state = world.getBlockState(pos); if (state.isIn(BlockTags.LEAVES)) { diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java index 89fc463..7a677d7 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java @@ -25,6 +25,7 @@ import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; @@ -97,6 +98,20 @@ public boolean placeOrnament(ServerPlayerEntity player, ServerWorld world, Hand if (item == Items.AIR) return false; var pos = hitResult.getPos(); + var side = hitResult.getSide(); + + if (side == Direction.UP) { + return false; + } else if (side != Direction.DOWN) { + var blockPos = hitResult.getBlockPos(); + var belowPos = blockPos.add(side.getOffsetX(), side.getOffsetY() - 1, side.getOffsetZ()); + + if (world.getBlockState(belowPos).isFullCube(world, belowPos)) { + double minY = blockPos.getY() + OrnamentModel.HEIGHT; + pos = pos.withAxis(Direction.Axis.Y, Math.max(minY, pos.getY())); + } + } + var offset = pos.subtract(this.pos.toCenterPos()); float yaw = player.getYaw() - 180; diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java index 75da964..a398d29 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/OrnamentModel.java @@ -15,9 +15,13 @@ import net.minecraft.text.Text; import net.minecraft.util.Hand; import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; import xyz.nucleoid.extras.lobby.block.TreeDecorationBlockEntity; public final class OrnamentModel implements InteractionHandler { + public static final float WIDTH = 8 / 16f; + public static final float HEIGHT = 11 / 16f; + private final TreeDecorationBlockEntity blockEntity; private final Ornament ornament; @@ -48,7 +52,7 @@ public OrnamentModel(TreeDecorationBlockEntity blockEntity, Ornament ornament) { this.interaction = new InteractionElement(this); this.interaction.setOffset(ornament.offset().subtract(0, 0.6, 0)); - this.interaction.setSize(8 / 16f, 11 / 16f); + this.interaction.setSize(WIDTH, HEIGHT); this.updateTransformations(true); } @@ -85,8 +89,14 @@ public void attack(ServerPlayerEntity player) { } } + private long getTime() { + World world = this.blockEntity.getWorld(); + + return world == null ? 0 : world.getTime(); + } + private void updateTransformations(boolean initial) { - long time = this.blockEntity.getWorld().getTime(); + long time = this.getTime(); float rotation; if (this.wobbleTicks > 0) { From fb54749639a90d17afecff2cfdd52d6b38daf324 Mon Sep 17 00:00:00 2001 From: haykam821 <24855774+haykam821@users.noreply.github.com> Date: Sat, 23 Dec 2023 21:02:50 -0500 Subject: [PATCH 5/5] Allow customizing the block tag that ornaments can be placed on --- .../xyz/nucleoid/extras/lobby/NEItems.java | 14 ++++-------- .../extras/lobby/NEPointOfInterestTypes.java | 4 ++-- .../block/TreeDecorationBlockEntity.java | 6 ++++- .../extras/lobby/tree/TreeDecoration.java | 22 ++++++++++++++----- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java index df3d413..2231084 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java @@ -857,18 +857,12 @@ private static ActionResult onUseBlock(PlayerEntity player, World world, Hand ha var lobbyState = PlayerLobbyState.get(player); if (lobbyState.collectTaterFromBlock(world, pos, stack, player) == ActionResult.PASS && !(stack.getItem() instanceof TaterBoxItem)) { - var state = world.getBlockState(pos); + var serverWorld = (ServerWorld) world; + var blockEntity = TreeDecorationBlockEntity.findNearestTreeDecoration(serverWorld, pos); - if (state.isIn(BlockTags.LEAVES)) { - var serverWorld = (ServerWorld) world; - var blockEntity = TreeDecorationBlockEntity.findNearestTreeDecoration(serverWorld, pos); - - if (blockEntity.isPresent() && blockEntity.get().placeOrnament((ServerPlayerEntity) player, serverWorld, hand, hitResult)) { - return ActionResult.SUCCESS; - } + if (blockEntity.isPresent() && blockEntity.get().placeOrnament((ServerPlayerEntity) player, serverWorld, hand, hitResult)) { + return ActionResult.SUCCESS; } - - return ActionResult.PASS; } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java b/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java index 70ae5c1..8fcd19d 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEPointOfInterestTypes.java @@ -4,8 +4,8 @@ import net.minecraft.block.Block; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; -import net.minecraft.util.Identifier; import net.minecraft.world.poi.PointOfInterestType; +import xyz.nucleoid.extras.NucleoidExtras; public class NEPointOfInterestTypes { public static final RegistryKey TREE_DECORATION = of("tree_decoration"); @@ -15,7 +15,7 @@ public static void register() { } private static RegistryKey of(String id) { - return RegistryKey.of(RegistryKeys.POINT_OF_INTEREST_TYPE, new Identifier(id)); + return RegistryKey.of(RegistryKeys.POINT_OF_INTEREST_TYPE, NucleoidExtras.identifier(id)); } private static PointOfInterestType register(RegistryKey key, int ticketCount, int searchDistance, Block... blocks) { diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java index 7a677d7..bbcb54b 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/TreeDecorationBlockEntity.java @@ -97,13 +97,17 @@ public boolean placeOrnament(ServerPlayerEntity player, ServerWorld world, Hand var item = TaterBoxItem.getPrimaryCollectedTater(player).asItem(); if (item == Items.AIR) return false; + var blockPos = hitResult.getBlockPos(); + + var state = world.getBlockState(blockPos); + if (!state.isIn(this.data.getSupportedBlocks())) return false; + var pos = hitResult.getPos(); var side = hitResult.getSide(); if (side == Direction.UP) { return false; } else if (side != Direction.DOWN) { - var blockPos = hitResult.getBlockPos(); var belowPos = blockPos.add(side.getOffsetX(), side.getOffsetY() - 1, side.getOffsetZ()); if (world.getBlockState(belowPos).isFullCube(world, belowPos)) { diff --git a/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java b/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java index a7ebd3d..b47491b 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/tree/TreeDecoration.java @@ -7,23 +7,35 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.block.Block; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.registry.tag.TagKey; + public final class TreeDecoration { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Ornament.CODEC.listOf().fieldOf("ornaments").forGetter(t -> t.ornaments) + Ornament.CODEC.listOf().fieldOf("ornaments").forGetter(t -> t.ornaments), + TagKey.codec(RegistryKeys.BLOCK).fieldOf("supported_blocks").forGetter(TreeDecoration::getSupportedBlocks) ).apply(instance, TreeDecoration::new) ); private final List ornaments; + private final TagKey supportedBlocks; - private TreeDecoration(List ornaments) { + private TreeDecoration(List ornaments, TagKey supportedBlocks) { this.ornaments = ornaments; + this.supportedBlocks = supportedBlocks; } public Collection getOrnaments() { return this.ornaments; } + public TagKey getSupportedBlocks() { + return this.supportedBlocks; + } + public TreeDecoration withOrnament(Ornament ornament) { var ornaments = new ArrayList<>(this.ornaments); @@ -34,7 +46,7 @@ public TreeDecoration withOrnament(Ornament ornament) { ornaments.add(ornament); - return new TreeDecoration(ornaments); + return new TreeDecoration(ornaments, this.supportedBlocks); } public TreeDecoration exceptOrnament(Ornament ornament) { @@ -42,10 +54,10 @@ public TreeDecoration exceptOrnament(Ornament ornament) { ornaments.remove(ornament); - return new TreeDecoration(ornaments); + return new TreeDecoration(ornaments, this.supportedBlocks); } public static TreeDecoration createEmpty() { - return new TreeDecoration(List.of()); + return new TreeDecoration(List.of(), BlockTags.LEAVES); } }