diff --git a/patches/api/0007-Villager-shops.patch b/patches/api/0007-Villager-shops.patch new file mode 100644 index 000000000..edfa9c688 --- /dev/null +++ b/patches/api/0007-Villager-shops.patch @@ -0,0 +1,39 @@ +From 7f69da2581011dde6ac74c582689857039f0b417 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 11 May 2019 02:12:41 -0500 +Subject: [PATCH] Villager shops + +--- + src/main/java/org/bukkit/entity/EntityType.java | 1 + + src/main/java/org/bukkit/entity/VillagerShop.java | 7 +++++++ + 2 files changed, 8 insertions(+) + create mode 100644 src/main/java/org/bukkit/entity/VillagerShop.java + +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index 527cb045..ebe5d0e8 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -271,6 +271,7 @@ public enum EntityType implements Keyed { + */ + LIGHTNING("lightning_bolt", LightningStrike.class, -1, false), + PLAYER("player", Player.class, -1, false), ++ VILLAGER_SHOP("villager_shop", VillagerShop.class, -1), + /** + * An unknown entity without an Entity Class + */ +diff --git a/src/main/java/org/bukkit/entity/VillagerShop.java b/src/main/java/org/bukkit/entity/VillagerShop.java +new file mode 100644 +index 00000000..57b0503b +--- /dev/null ++++ b/src/main/java/org/bukkit/entity/VillagerShop.java +@@ -0,0 +1,7 @@ ++package org.bukkit.entity; ++ ++/** ++ * Represents a villager shop ++ */ ++public interface VillagerShop extends AbstractVillager { ++} +-- +2.20.1 + diff --git a/patches/server/0014-Villager-shops.patch b/patches/server/0014-Villager-shops.patch new file mode 100644 index 000000000..f0f39fed5 --- /dev/null +++ b/patches/server/0014-Villager-shops.patch @@ -0,0 +1,322 @@ +From a506f042b4448e27fce1e3ceae3b77bbdc9c654f Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 11 May 2019 01:31:50 -0500 +Subject: [PATCH] Villager shops + +--- + .../net/minecraft/server/EntityTypes.java | 9 + + .../server/EntityVillagerAbstract.java | 1 + + .../minecraft/server/EntityVillagerShop.java | 227 ++++++++++++++++++ + .../minecraft/server/NavigationAbstract.java | 2 + + .../entity/CraftAbstractVillager.java | 2 +- + 5 files changed, 240 insertions(+), 1 deletion(-) + create mode 100644 src/main/java/net/minecraft/server/EntityVillagerShop.java + +diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java +index 181e92980..24bcbce01 100644 +--- a/src/main/java/net/minecraft/server/EntityTypes.java ++++ b/src/main/java/net/minecraft/server/EntityTypes.java +@@ -118,6 +118,7 @@ public class EntityTypes { + public static final EntityTypes LIGHTNING_BOLT = a("lightning_bolt", EntityTypes.a.a(EnumCreatureType.MISC).b().a(0.0F, 0.0F)); + public static final EntityTypes PLAYER = a("player", EntityTypes.a.a(EnumCreatureType.MISC).b().a().a(0.6F, 1.8F)); + public static final EntityTypes FISHING_BOBBER = a("fishing_bobber", EntityTypes.a.a(EnumCreatureType.MISC).b().a().a(0.25F, 0.25F)); ++ public static final EntityTypes VILLAGER_SHOP = register("villager_shop", "villager", EntityTypes.a.a(EntityVillagerShop::new, EnumCreatureType.CREATURE).a(0.6F, 1.95F)); + private final EntityTypes.b aZ; + private final EnumCreatureType ba; + private final boolean bb; +@@ -137,6 +138,14 @@ public class EntityTypes { + return (EntityTypes) IRegistry.a((IRegistry) IRegistry.ENTITY_TYPE, s, (Object) entitytypes_a.a(s)); + } + ++ // Purpur start ++ private static EntityTypes register(String name, String extendFrom, EntityTypes.a entitytypes_a) { ++ Map> dataTypes = (Map>) DataConverterRegistry.a().getSchema(DataFixUtils.makeKey(SharedConstants.a().getWorldVersion())).findChoiceType(DataConverterTypes.o).types(); // entity_tree ++ dataTypes.put("minecraft:" + name, dataTypes.get("minecraft:" + extendFrom)); ++ return a(name, entitytypes_a); ++ } ++ // Purpur end ++ + public static MinecraftKey getName(EntityTypes entitytypes) { + return IRegistry.ENTITY_TYPE.getKey(entitytypes); + } +diff --git a/src/main/java/net/minecraft/server/EntityVillagerAbstract.java b/src/main/java/net/minecraft/server/EntityVillagerAbstract.java +index 7cc31be17..4fd1b0eca 100644 +--- a/src/main/java/net/minecraft/server/EntityVillagerAbstract.java ++++ b/src/main/java/net/minecraft/server/EntityVillagerAbstract.java +@@ -54,6 +54,7 @@ public abstract class EntityVillagerAbstract extends EntityAgeable implements NP + return this.tradingPlayer; + } + ++ public boolean hasTrader() { return dX(); } // Purpur - OBFHELPER + public boolean dX() { + return this.tradingPlayer != null; + } +diff --git a/src/main/java/net/minecraft/server/EntityVillagerShop.java b/src/main/java/net/minecraft/server/EntityVillagerShop.java +new file mode 100644 +index 000000000..d45165fd7 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/EntityVillagerShop.java +@@ -0,0 +1,227 @@ ++package net.minecraft.server; ++ ++import com.mojang.datafixers.Dynamic; ++ ++import javax.annotation.Nullable; ++import java.util.EnumSet; ++ ++public class EntityVillagerShop extends EntityVillagerAbstract { ++ private static final DataWatcherObject VILLAGER_DATA = DataWatcher.a(EntityVillagerShop.class, DataWatcherRegistry.q); ++ ++ private BlockPosition home; ++ ++ public EntityVillagerShop(EntityTypes entitytypes, World world) { ++ this(EntityTypes.VILLAGER, world, VillagerType.c); ++ } ++ ++ public EntityVillagerShop(EntityTypes entitytypes, World world, VillagerType villagertype) { ++ super(entitytypes, world); ++ setCanPickupLoot(false); ++ setVillagerData(getVillagerData().withType(villagertype).withProfession(VillagerProfession.NONE)); ++ } ++ ++ @Override ++ public void setPosition(double x, double y, double z) { ++ super.setPosition(x, y, z); ++ if (home == null) { ++ home = new BlockPosition(x, y, z); ++ } ++ } ++ ++ @Override ++ public boolean isTypeNotPersistent(double d) { ++ return false; // don't despawn ++ } ++ ++ @Override ++ protected void initDatawatcher() { ++ super.initDatawatcher(); ++ this.datawatcher.register(VILLAGER_DATA, new VillagerData(VillagerType.c, VillagerProfession.NONE, 1)); ++ } ++ ++ public void setVillagerData(VillagerData villagerdata) { ++ datawatcher.set(VILLAGER_DATA, villagerdata); ++ } ++ ++ public VillagerData getVillagerData() { ++ return datawatcher.get(VILLAGER_DATA); ++ } ++ ++ @Override ++ protected void initAttributes() { ++ super.initAttributes(); ++ this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.5D); ++ this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(48.0D); ++ } ++ ++ @Override ++ protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalTradeWithPlayer(this)); ++ this.goalSelector.a(1, new PathfinderGoalLookAtTradingPlayer(this)); ++ this.goalSelector.a(2, new WanderCloseToHome(this, 16.0D, 0.35D)); ++ this.goalSelector.a(9, new PathfinderGoalInteract(this, EntityHuman.class, 3.0F, 1.0F)); ++ this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); ++ } ++ ++ @Override ++ public void b(NBTTagCompound nbttagcompound) { // write/save ++ super.b(nbttagcompound); ++ nbttagcompound.set("VillagerData", getVillagerData().a(DynamicOpsNBT.a)); ++ } ++ ++ @Override ++ public void a(NBTTagCompound nbttagcompound) { // read/load ++ super.a(nbttagcompound); ++ if (nbttagcompound.hasKeyOfType("VillagerData", 10)) { ++ setVillagerData(new VillagerData(new Dynamic<>(DynamicOpsNBT.a, nbttagcompound.get("VillagerData")))); ++ } ++ setCanPickupLoot(false); ++ } ++ ++ @Override ++ public int dV() { // getExp ++ return 0; ++ } ++ ++ @Override ++ public boolean dZ() { // showProfessionProgressBar ++ return false; ++ } ++ ++ @Override ++ public boolean a(EntityHuman entityhuman, EnumHand enumhand) { // processInteract ++ ItemStack itemstack = entityhuman.b(enumhand); ++ if (itemstack.getItem() == Items.NAME_TAG) { ++ itemstack.a(entityhuman, this, enumhand); ++ return true; ++ } ++ if (itemstack.getItem() != Items.VILLAGER_SPAWN_EGG && this.isAlive() && !this.dX() && !this.isSleeping()) { ++ if (enumhand == EnumHand.MAIN_HAND) { ++ entityhuman.a(StatisticList.TALKED_TO_VILLAGER); ++ } ++ //if (!getOffers().isEmpty()) { ++ setTradingPlayer(entityhuman); ++ openTrade(entityhuman, getScoreboardDisplayName(), getVillagerData().getLevel()); ++ return true; ++ //} ++ } ++ return super.a(entityhuman, enumhand); ++ } ++ ++ @Nullable ++ @Override ++ protected SoundEffect getSoundAmbient() { ++ return isSleeping() ? null : (hasTrader() ? SoundEffects.ENTITY_VILLAGER_TRADE : SoundEffects.ENTITY_VILLAGER_AMBIENT); ++ } ++ ++ @Override ++ protected SoundEffect getSoundHurt(DamageSource damagesource) { ++ return SoundEffects.ENTITY_VILLAGER_HURT; ++ } ++ ++ @Override ++ protected SoundEffect getSoundDeath() { ++ return SoundEffects.ENTITY_VILLAGER_DEATH; ++ } ++ ++ @Override ++ public void e(BlockPosition blockposition) { // sleepInBed ++ super.e(blockposition); ++ } ++ ++ @Override ++ protected void ef() { // setupTradeOffers ++ // do not do anything ++ } ++ ++ @Override ++ protected void a(MerchantRecipeList list, VillagerTrades.IMerchantRecipeOption[] option, int size) { // addTradeOffers ++ // do not do anything ++ } ++ ++ @Override ++ protected void b(MerchantRecipe merchantrecipe) { // processRecipeRewards ++ // do nothing ++ } ++ ++ @Override ++ protected void a(EntityItem entityitem) { // updateEquipmentIfNeeded ++ // do not pick up items ++ } ++ ++ @Override ++ public boolean a_(int i, ItemStack itemstack) { // setItem ++ return false; // do not set items in own inventory ++ } ++ ++ @Override ++ public void setLastDamager(@Nullable EntityLiving entityliving) { ++ if (isAlive() && entityliving instanceof EntityHuman) { ++ world.broadcastEntityEffect(this, (byte) 13); // mad particles ++ } ++ super.setLastDamager(entityliving); ++ } ++ ++ @Override ++ public void die(DamageSource damagesource) { ++ super.die(damagesource); ++ } ++ ++ @Override ++ public EntityVillagerShop createChild(EntityAgeable entityageable) { ++ return null; // shop workers don't breed ++ } ++ ++ @Override ++ public GroupDataEntity prepare(GeneratorAccess generatoraccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) { ++ if (enummobspawn == EnumMobSpawn.BREEDING) { ++ setVillagerData(getVillagerData().withProfession(VillagerProfession.NONE)); ++ } ++ if (enummobspawn == EnumMobSpawn.COMMAND || enummobspawn == EnumMobSpawn.SPAWN_EGG || enummobspawn == EnumMobSpawn.SPAWNER) { ++ setVillagerData(getVillagerData().withType(VillagerType.a(generatoraccess.getBiome(new BlockPosition(this))))); ++ } ++ return super.prepare(generatoraccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); ++ } ++ ++ public void setHome(BlockPosition homePos) { ++ this.home = homePos; ++ } ++ ++ public BlockPosition getHome() { ++ return home; ++ } ++ ++ static class WanderCloseToHome extends PathfinderGoal { ++ final EntityVillagerShop villager; ++ final double range; ++ final double speed; ++ ++ private WanderCloseToHome(EntityVillagerShop villager, double range, double speed) { ++ this.villager = villager; ++ this.range = range; ++ this.speed = speed; ++ this.a(EnumSet.of(Type.MOVE)); ++ } ++ ++ @Override ++ public boolean a() { // shouldExecute ++ return villager.navigation.hasNoPath(); ++ } ++ ++ @Override ++ public void e() { // tick ++ if (!villager.navigation.hasNoPath()) { ++ return; // already on a path ++ } ++ BlockPosition home = villager.getHome(); ++ if (!home.a(villager.ch(), range)) { ++ Vec3D direction = new Vec3D(home).add(-villager.locX, -villager.locY, -villager.locZ).d(); // normalize ++ Vec3D target = direction.a(10.0D).add(villager.locX, villager.locY, villager.locZ); // scale ++ villager.navigation.setDestination(target.x, target.y, target.z, speed); ++ } else { ++ villager.navigation.setDestination(home.getX(), home.getY(), home.getZ(), speed); ++ } ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/NavigationAbstract.java b/src/main/java/net/minecraft/server/NavigationAbstract.java +index 583f2c5ad..87cb34519 100644 +--- a/src/main/java/net/minecraft/server/NavigationAbstract.java ++++ b/src/main/java/net/minecraft/server/NavigationAbstract.java +@@ -126,6 +126,7 @@ public abstract class NavigationAbstract { + } + } + ++ public boolean setDestination(double x, double y, double z, double speed) { return a(x, y, z, speed); } // Purpur - OBFHELPER + public boolean a(double d0, double d1, double d2, double d3) { + return this.a(this.a(d0, d1, d2), d3); + } +@@ -280,6 +281,7 @@ public abstract class NavigationAbstract { + + } + ++ public boolean hasNoPath() { return n(); } // Purpur - OBFHELPER + public boolean n() { + return this.c == null || this.c.b(); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java +index 18520fec0..307331e37 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java +@@ -20,7 +20,7 @@ public class CraftAbstractVillager extends CraftAgeable implements AbstractVilla + + @Override + public EntityVillagerAbstract getHandle() { +- return (EntityVillager) entity; ++ return (EntityVillagerAbstract) entity; // Purpur + } + + @Override +-- +2.20.1 +