Skip to content

Commit 268f8fc

Browse files
committed
add gui, villager hoppers and custom villager data storage
1 parent 51429b4 commit 268f8fc

16 files changed

+393
-60
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package me.clickism.clickvillagers;
2+
3+
import org.jetbrains.annotations.Nullable;
4+
5+
import java.util.UUID;
6+
7+
public interface ClaimedVillagerData {
8+
@Nullable
9+
UUID clickVillagers_Fabric$getOwner();
10+
void clickVillagers_Fabric$setOwner(@Nullable UUID owner);
11+
}

src/main/java/me/clickism/clickvillagers/PickupHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import net.minecraft.component.type.NbtComponent;
77
import net.minecraft.entity.Entity;
88
import net.minecraft.entity.EntityType;
9+
import net.minecraft.entity.LivingEntity;
910
import net.minecraft.entity.mob.ZombieVillagerEntity;
1011
import net.minecraft.entity.passive.VillagerEntity;
1112
import net.minecraft.item.ItemStack;
@@ -15,6 +16,7 @@
1516
import net.minecraft.text.Style;
1617
import net.minecraft.text.Text;
1718
import net.minecraft.util.Formatting;
19+
import net.minecraft.village.VillagerDataContainer;
1820
import net.minecraft.village.VillagerProfession;
1921
import net.minecraft.world.World;
2022
import org.jetbrains.annotations.Nullable;
@@ -29,7 +31,7 @@ private enum PickupVillagerType {
2931
VILLAGER, ZOMBIE_VILLAGER
3032
}
3133

32-
public static ItemStack toItemStack(Entity entity) {
34+
public static <T extends LivingEntity & VillagerDataContainer> ItemStack toItemStack(T entity) {
3335
NbtCompound nbt = new NbtCompound();
3436
entity.writeNbt(nbt);
3537
PickupVillagerType type = entity instanceof VillagerEntity
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package me.clickism.clickvillagers;
2+
3+
import net.minecraft.entity.LivingEntity;
4+
import net.minecraft.village.VillagerDataContainer;
5+
import org.jetbrains.annotations.Nullable;
6+
import java.util.UUID;
7+
8+
public class VillagerHandler<T extends LivingEntity & VillagerDataContainer> {
9+
protected final T entity;
10+
public VillagerHandler(T entity) {
11+
this.entity = entity;
12+
}
13+
14+
public T getEntity() {
15+
return entity;
16+
}
17+
18+
public void setOwner(UUID uuid) {
19+
((ClaimedVillagerData) entity.getVillagerData()).clickVillagers_Fabric$setOwner(uuid);
20+
}
21+
22+
@Nullable
23+
public UUID getOwner() {
24+
return ((ClaimedVillagerData) entity.getVillagerData()).clickVillagers_Fabric$getOwner();
25+
}
26+
27+
public boolean isOwner(UUID uuid) {
28+
return uuid.equals(getOwner());
29+
}
30+
}

src/main/java/me/clickism/clickvillagers/VillagerTextures.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
public class VillagerTextures {
1818

19-
private static final String DEFAULT_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNkZmRlNmUyYTQ2YjQ4Y2MxODJkOGQwZGJlMjE5Mzc4YjkxMGYyMjQwZTg2OWZiNzIyNDU5MTFhNjUwNzRkMyJ9fX0=";
20-
private static final String BABY_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTczNDQ4OTE4OTUxNywKICAicHJvZmlsZUlkIiA6ICJjNWY3OWQ3ODkyNDA0ZGMwOGVhZjZiZDVlNGM4ZGYyYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJMb25naG9ybnM3MDkiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2Q3Nzg4ODI2YjlhYzRkZWFmMzgzYjM4Nzk0NzA4NTIxMTQ0N2VkNTBmZGMyMWJmNzFjMjMwMDQ4ZGQ1OTg2ZiIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9";
21-
private static final String ZOMBIE_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGM3NTA1ZjIyNGQ1MTY0YTExN2Q4YzY5ZjAxNWY5OWVmZjQzNDQ3MWM4YTJkZjkwNzA5NmM0MjQyYzM1MjRlOCJ9fX0=";
22-
23-
private static final Map<VillagerProfession, String> TEXTURE_MAP = Map.ofEntries(
19+
public static final String DEFAULT_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNkZmRlNmUyYTQ2YjQ4Y2MxODJkOGQwZGJlMjE5Mzc4YjkxMGYyMjQwZTg2OWZiNzIyNDU5MTFhNjUwNzRkMyJ9fX0=";
20+
public static final String BABY_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTczNDQ4OTE4OTUxNywKICAicHJvZmlsZUlkIiA6ICJjNWY3OWQ3ODkyNDA0ZGMwOGVhZjZiZDVlNGM4ZGYyYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJMb25naG9ybnM3MDkiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2Q3Nzg4ODI2YjlhYzRkZWFmMzgzYjM4Nzk0NzA4NTIxMTQ0N2VkNTBmZGMyMWJmNzFjMjMwMDQ4ZGQ1OTg2ZiIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9";
21+
public static final String ZOMBIE_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGM3NTA1ZjIyNGQ1MTY0YTExN2Q4YzY5ZjAxNWY5OWVmZjQzNDQ3MWM4YTJkZjkwNzA5NmM0MjQyYzM1MjRlOCJ9fX0=";
22+
23+
public static final Map<VillagerProfession, String> TEXTURE_MAP = Map.ofEntries(
2424
Map.entry(VillagerProfession.FISHERMAN, "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWMxNWU1ZmI1NmZhMTZiMDc0N2IxYmNiMDUzMzVmNTVkMWZhMzE1NjFjMDgyYjVlMzY0M2RiNTU2NTQxMDg1MiJ9fX0="),
2525
Map.entry(VillagerProfession.ARMORER, "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjUyMmRiOTJmMTg4ZWJjNzcxM2NmMzViNGNiYWVkMWNmZTI2NDJhNTk4NmMzYmRlOTkzZjVjZmIzNzI3NjY0YyJ9fX0="),
2626
Map.entry(VillagerProfession.BUTCHER, "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzY3NzRkMmRmNTE1ZWNlYWU5ZWVkMjkxYzFiNDBmOTRhZGY3MWRmMGFiODFjNzE5MTQwMmUxYTQ1YjNhMjA4NyJ9fX0="),

src/main/java/me/clickism/clickvillagers/callback/VillagerPlaceCallback.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,13 @@
33
import me.clickism.clickvillagers.PickupHandler;
44
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
55
import net.minecraft.entity.Entity;
6-
import net.minecraft.entity.EntityType;
7-
import net.minecraft.entity.SpawnReason;
86
import net.minecraft.entity.player.PlayerEntity;
97
import net.minecraft.item.ItemStack;
10-
import net.minecraft.server.world.ServerWorld;
118
import net.minecraft.util.ActionResult;
129
import net.minecraft.util.Hand;
1310
import net.minecraft.util.hit.BlockHitResult;
14-
import net.minecraft.util.hit.HitResult;
1511
import net.minecraft.util.math.BlockPos;
16-
import net.minecraft.util.math.Direction;
1712
import net.minecraft.world.World;
18-
import net.minecraft.world.event.GameEvent;
19-
20-
import java.util.Objects;
2113

2214
public class VillagerPlaceCallback implements UseBlockCallback {
2315

src/main/java/me/clickism/clickvillagers/callback/VillagerUseEntityCallback.java

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package me.clickism.clickvillagers.callback;
22

33
import me.clickism.clickvillagers.AnchorHandler;
4+
import me.clickism.clickvillagers.VillagerHandler;
45
import me.clickism.clickvillagers.PickupHandler;
6+
import me.clickism.clickvillagers.gui.VillagerClaimGui;
7+
import me.clickism.clickvillagers.gui.VillagerEditMenu;
58
import me.clickism.clickvillagers.util.MessageType;
69
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
710
import net.minecraft.entity.Entity;
811
import net.minecraft.entity.LivingEntity;
9-
import net.minecraft.entity.mob.ZombieVillagerEntity;
10-
import net.minecraft.entity.passive.VillagerEntity;
1112
import net.minecraft.entity.player.PlayerEntity;
1213
import net.minecraft.entity.player.PlayerInventory;
14+
import net.minecraft.item.Item;
1315
import net.minecraft.item.ItemStack;
1416
import net.minecraft.item.Items;
17+
import net.minecraft.registry.tag.ItemTags;
18+
import net.minecraft.server.network.ServerPlayerEntity;
1519
import net.minecraft.sound.SoundCategory;
1620
import net.minecraft.sound.SoundEvents;
1721
import net.minecraft.text.Style;
@@ -20,8 +24,10 @@
2024
import net.minecraft.util.Formatting;
2125
import net.minecraft.util.Hand;
2226
import net.minecraft.util.hit.EntityHitResult;
27+
import net.minecraft.village.VillagerDataContainer;
2328
import net.minecraft.world.World;
2429
import org.jetbrains.annotations.Nullable;
30+
import java.util.UUID;
2531

2632
public class VillagerUseEntityCallback implements UseEntityCallback {
2733
private static final MessageType PICKUP_MESSAGE = new MessageType(
@@ -42,21 +48,54 @@ public ActionResult interact(PlayerEntity player, World world, Hand hand, Entity
4248
if (!hand.equals(Hand.MAIN_HAND)) return ActionResult.PASS;
4349
if (!player.isSneaking()) return ActionResult.PASS;
4450
if (player.isSpectator()) return ActionResult.PASS;
45-
if (!(entity instanceof VillagerEntity) && !(entity instanceof ZombieVillagerEntity)) return ActionResult.PASS;
51+
if (!(entity instanceof LivingEntity && entity instanceof VillagerDataContainer)) return ActionResult.PASS;
4652
if (hitResult == null) return ActionResult.CONSUME;
4753
PlayerInventory inventory = player.getInventory();
48-
if (inventory.getMainHandStack().getItem().equals(Items.SHEARS)) {
54+
ItemStack itemStack = inventory.getMainHandStack();
55+
Item item = itemStack.getItem();
56+
if (item.equals(Items.SHEARS)) {
4957
handleAnchor((LivingEntity) entity, player);
5058
return ActionResult.CONSUME;
5159
}
52-
handlePickup(player, entity);
53-
return ActionResult.PASS;
60+
var villager = (LivingEntity & VillagerDataContainer) entity;
61+
VillagerHandler<?> villagerHandler = new VillagerHandler<>(villager);
62+
if (itemStack.isIn(ItemTags.SHOVELS)) {
63+
handleClaim(player, villagerHandler);
64+
return ActionResult.CONSUME;
65+
}
66+
if (villagerHandler.isOwner(player.getUuid())) {
67+
handleEdit(player, villagerHandler);
68+
return ActionResult.CONSUME;
69+
}
70+
handlePickup(player, villagerHandler);
71+
return ActionResult.CONSUME;
72+
}
73+
74+
private void handleClaim(PlayerEntity player, VillagerHandler<?> villagerHandler) {
75+
UUID owner = villagerHandler.getOwner();
76+
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
77+
var villager = villagerHandler.getEntity();
78+
if (owner == null) {
79+
// Allow claim
80+
new VillagerClaimGui<>(serverPlayer, villager).open();
81+
return;
82+
}
83+
if (villagerHandler.isOwner(player.getUuid())) {
84+
// Open Edit Menu
85+
handleEdit(player, villagerHandler);
86+
return;
87+
}
88+
MessageType.WARN.send(player, Text.literal("This villager is already claimed."));
89+
}
90+
91+
private void handleEdit(PlayerEntity player, VillagerHandler<?> villagerHandler) {
92+
new VillagerEditMenu<>((ServerPlayerEntity) player, villagerHandler.getEntity()).open();
5493
}
5594

56-
private void handlePickup(PlayerEntity player, Entity entity) {
95+
private void handlePickup(PlayerEntity player, VillagerHandler<?> villagerHandler) {
5796
PlayerInventory inventory = player.getInventory();
58-
PICKUP_MESSAGE.sendActionbar(player, Text.literal("You picked a villager up."));
59-
ItemStack itemStack = PickupHandler.toItemStack(entity);
97+
PICKUP_MESSAGE.sendActionbar(player, Text.literal("You picked a villager up"));
98+
ItemStack itemStack = PickupHandler.toItemStack(villagerHandler.getEntity());
6099
int selectedSlot = inventory.selectedSlot;
61100
if (inventory.getStack(selectedSlot).isEmpty()) {
62101
inventory.insertStack(selectedSlot, itemStack);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package me.clickism.clickvillagers.gui;
2+
3+
import eu.pb4.sgui.api.elements.GuiElement;
4+
import eu.pb4.sgui.api.elements.GuiElementBuilder;
5+
import eu.pb4.sgui.api.gui.GuiInterface;
6+
import net.minecraft.item.ItemStack;
7+
import net.minecraft.item.Items;
8+
import net.minecraft.sound.SoundCategory;
9+
import net.minecraft.sound.SoundEvents;
10+
import net.minecraft.text.Text;
11+
import net.minecraft.util.Formatting;
12+
13+
public class BackButton extends GuiElement {
14+
private static final ItemStack item = new GuiElementBuilder(Items.MAP)
15+
.setItemName(Text.literal("◀ ").formatted(Formatting.WHITE)
16+
.append(Text.literal("BACK").formatted(Formatting.WHITE, Formatting.BOLD)))
17+
.addLoreLine(Text.literal("Go back to the previous menu.").formatted(Formatting.GRAY))
18+
.asStack();
19+
20+
public BackButton(GuiInterface previous) {
21+
super(item, (index, type, action, gui) -> {
22+
previous.open();
23+
previous.getPlayer().playSoundToPlayer(SoundEvents.UI_LOOM_SELECT_PATTERN, SoundCategory.MASTER, 1, 1);
24+
});
25+
}
26+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package me.clickism.clickvillagers.gui;
2+
3+
import eu.pb4.sgui.api.elements.GuiElementBuilder;
4+
import eu.pb4.sgui.api.elements.GuiElementInterface;
5+
import eu.pb4.sgui.api.gui.SimpleGui;
6+
import net.minecraft.item.Items;
7+
import net.minecraft.screen.ScreenHandlerType;
8+
import net.minecraft.server.network.ServerPlayerEntity;
9+
import net.minecraft.text.Text;
10+
import net.minecraft.util.Formatting;
11+
12+
public abstract class DecoratedGui extends SimpleGui {
13+
private static final GuiElementInterface BLACK = new GuiElementBuilder(Items.BLACK_STAINED_GLASS_PANE)
14+
.setItemName(Text.literal("x").formatted(Formatting.GRAY))
15+
.hideDefaultTooltip()
16+
.build();
17+
private static final GuiElementInterface GRAY = new GuiElementBuilder(Items.GRAY_STAINED_GLASS_PANE)
18+
.setItemName(Text.literal("x").formatted(Formatting.GRAY))
19+
.hideDefaultTooltip()
20+
.build();
21+
22+
public DecoratedGui(ServerPlayerEntity player) {
23+
super(ScreenHandlerType.GENERIC_9X3, player, false);
24+
addBackground();
25+
}
26+
27+
protected void addBackground() {
28+
for (int i = 0; i < size; i++) {
29+
if ((i / 9) % 2 == 0) {
30+
setSlot(i, GRAY);
31+
} else {
32+
setSlot(i, BLACK);
33+
}
34+
}
35+
}
36+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package me.clickism.clickvillagers.gui;
2+
3+
import eu.pb4.sgui.api.elements.GuiElement;
4+
import eu.pb4.sgui.api.elements.GuiElementBuilder;
5+
import eu.pb4.sgui.api.gui.GuiInterface;
6+
import me.clickism.clickvillagers.util.MessageType;
7+
import net.minecraft.entity.LivingEntity;
8+
import net.minecraft.item.Item;
9+
import net.minecraft.item.Items;
10+
import net.minecraft.server.network.ServerPlayerEntity;
11+
import net.minecraft.text.Text;
12+
import net.minecraft.util.Formatting;
13+
import net.minecraft.village.VillagerDataContainer;
14+
import net.minecraft.village.VillagerType;
15+
import java.util.List;
16+
17+
public class VillagerBiomeChangeMenu<T extends LivingEntity & VillagerDataContainer> extends VillagerGui<T> {
18+
19+
private record VillagerBiome(VillagerType type, Item icon) {
20+
}
21+
22+
private static final List<VillagerBiome> BIOMES = List.of(
23+
new VillagerBiome(VillagerType.PLAINS, Items.OAK_SAPLING),
24+
new VillagerBiome(VillagerType.DESERT, Items.DEAD_BUSH),
25+
new VillagerBiome(VillagerType.JUNGLE, Items.JUNGLE_SAPLING),
26+
new VillagerBiome(VillagerType.SNOW, Items.FERN),
27+
new VillagerBiome(VillagerType.SAVANNA, Items.ACACIA_SAPLING),
28+
new VillagerBiome(VillagerType.SWAMP, Items.BLUE_ORCHID),
29+
new VillagerBiome(VillagerType.TAIGA, Items.SPRUCE_SAPLING)
30+
);
31+
32+
public VillagerBiomeChangeMenu(ServerPlayerEntity player, T villager, GuiInterface previous) {
33+
super(player, villager);
34+
setSlot(18, new BackButton(previous));
35+
setTitle(Text.literal("🌲 ").formatted(Formatting.DARK_GRAY)
36+
.append(Text.literal("Choose Villager's Biome").formatted(Formatting.DARK_GRAY, Formatting.BOLD)));
37+
int i = 10;
38+
for (VillagerBiome biome : BIOMES) {
39+
setSlot(i, getBiomeButton(biome.type, biome.icon, previous));
40+
i++;
41+
}
42+
}
43+
44+
private GuiElement getBiomeButton(VillagerType type, Item icon, GuiInterface previous) {
45+
GuiElementBuilder builder = new GuiElementBuilder(icon)
46+
.setItemName(Text.literal(type.toString().toUpperCase()).formatted(Formatting.GREEN, Formatting.BOLD))
47+
.addLoreLine(Text.literal("Click to change the villager's biome.").formatted(Formatting.DARK_GREEN))
48+
.setCallback((index, t, action, gui) -> {
49+
if (villager.isRemoved()) return;
50+
villager.setVillagerData(villager.getVillagerData().withType(type));
51+
MessageType.CONFIRM.send(player, Text.literal("You changed the villager's biome to " + type + "."));
52+
new VillagerBiomeChangeMenu<>(player, villager, previous).open();
53+
});
54+
if (villager.getVillagerData().getType().equals(type)) {
55+
builder.glow();
56+
}
57+
return builder.build();
58+
}
59+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package me.clickism.clickvillagers.gui;
2+
3+
import eu.pb4.sgui.api.elements.GuiElementBuilder;
4+
import me.clickism.clickvillagers.VillagerHandler;
5+
import me.clickism.clickvillagers.util.MessageType;
6+
import net.minecraft.entity.LivingEntity;
7+
import net.minecraft.item.Items;
8+
import net.minecraft.server.network.ServerPlayerEntity;
9+
import net.minecraft.text.Text;
10+
import net.minecraft.util.Formatting;
11+
import net.minecraft.village.VillagerDataContainer;
12+
13+
public class VillagerClaimGui<T extends LivingEntity & VillagerDataContainer> extends VillagerGui<T> {
14+
15+
public VillagerClaimGui(ServerPlayerEntity player, T villager) {
16+
super(player, villager);
17+
setTitle(Text.literal("🔒 Claim Villager").formatted(Formatting.DARK_GRAY, Formatting.BOLD));
18+
setSlot(13, new GuiElementBuilder(Items.GOLDEN_SHOVEL)
19+
.setItemName(Text.literal("🔒 ").formatted(Formatting.GOLD)
20+
.append(Text.literal("CLAIM VILLAGER").formatted(Formatting.GOLD, Formatting.BOLD)))
21+
.hideDefaultTooltip()
22+
.addLoreLine(Text.literal("Click to claim this villager.").formatted(Formatting.YELLOW))
23+
.setCallback((index, type, action, gui) -> {
24+
MessageType.CONFIRM.send(player, Text.literal("You claimed this villager."));
25+
new VillagerHandler<>(villager).setOwner(player.getUuid());
26+
gui.close();
27+
})
28+
.build());
29+
}
30+
}

0 commit comments

Comments
 (0)