diff --git a/nms-patches/net/minecraft/server/level/EntityPlayer.patch b/nms-patches/net/minecraft/server/level/EntityPlayer.patch index f93ce72b6..85cfb4238 100644 --- a/nms-patches/net/minecraft/server/level/EntityPlayer.patch +++ b/nms-patches/net/minecraft/server/level/EntityPlayer.patch @@ -106,8 +106,8 @@ + containerSynchronizer.sendSlotChange(containerMenu, s, getMainHandItem()); + }); + containerSynchronizer.sendSlotChange(inventoryMenu, ContainerPlayer.SHIELD_SLOT, getOffhandItem()); -+ } -+ + } + + // Yes, this doesn't match Vanilla, but it's the best we can do for now. + // If this is an issue, PRs are welcome + public final BlockPosition getSpawnPoint(WorldServer worldserver) { @@ -144,9 +144,9 @@ + } + + return blockposition; - } ++ } + // CraftBukkit end - ++ @Override public BlockPosition adjustSpawnLocation(WorldServer worldserver, BlockPosition blockposition) { AxisAlignedBB axisalignedbb = this.getDimensions(EntityPose.STANDING).makeBoundingBox(Vec3D.ZERO); @@ -328,7 +328,15 @@ public void setExperiencePoints(int i) { float f = (float) this.getXpNeededForNextLevel(); float f1 = (f - 1.0F) / f; -@@ -744,6 +907,11 @@ +@@ -714,6 +877,7 @@ + public void initMenu(Container container) { + container.addSlotListener(this.containerListener); + container.setSynchronizer(this.containerSynchronizer); ++ container.startOpen(); // CraftBukkit - don't force startOpen until container actually opens + } + + public void initInventoryMenu() { +@@ -744,6 +908,11 @@ @Override public void tick() { @@ -340,7 +348,7 @@ this.tickClientLoadTimeout(); this.gameMode.tick(); this.wardenSpawnTracker.tick(); -@@ -820,7 +988,7 @@ +@@ -820,7 +989,7 @@ } if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) { @@ -349,7 +357,7 @@ this.lastSentHealth = this.getHealth(); this.lastSentFood = this.foodData.getFoodLevel(); this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F; -@@ -851,6 +1019,12 @@ +@@ -851,6 +1020,12 @@ this.updateScoreForCriteria(IScoreboardCriteria.EXPERIENCE, MathHelper.ceil((float) this.lastRecordedExperience)); } @@ -362,7 +370,7 @@ if (this.experienceLevel != this.lastRecordedLevel) { this.lastRecordedLevel = this.experienceLevel; this.updateScoreForCriteria(IScoreboardCriteria.LEVEL, MathHelper.ceil((float) this.lastRecordedLevel)); -@@ -865,6 +1039,20 @@ +@@ -865,6 +1040,20 @@ CriterionTriggers.LOCATION.trigger(this); } @@ -383,7 +391,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking player"); CrashReportSystemDetails crashreportsystemdetails = crashreport.addCategory("Player being ticked"); -@@ -893,7 +1081,7 @@ +@@ -893,7 +1082,7 @@ if (this.level().getDifficulty() == EnumDifficulty.PEACEFUL && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) { if (this.tickCount % 20 == 0) { if (this.getHealth() < this.getMaxHealth()) { @@ -392,7 +400,7 @@ } float f = this.foodData.getSaturationLevel(); -@@ -946,7 +1134,8 @@ +@@ -946,7 +1135,8 @@ } private void updateScoreForCriteria(IScoreboardCriteria iscoreboardcriteria, int i) { @@ -402,7 +410,7 @@ scoreaccess.set(i); }); } -@@ -955,9 +1144,47 @@ +@@ -955,9 +1145,47 @@ public void die(DamageSource damagesource) { this.gameEvent(GameEvent.ENTITY_DIE); boolean flag = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); @@ -452,7 +460,7 @@ this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> { boolean flag1 = true; -@@ -988,12 +1215,18 @@ +@@ -988,12 +1216,18 @@ if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) { this.tellNeutralMobsThatIDied(); } @@ -475,7 +483,7 @@ EntityLiving entityliving = this.getKillCredit(); if (entityliving != null) { -@@ -1028,10 +1261,12 @@ +@@ -1028,10 +1262,12 @@ public void awardKillScore(Entity entity, DamageSource damagesource) { if (entity != this) { super.awardKillScore(entity, damagesource); @@ -490,7 +498,7 @@ } else { this.awardStat(StatisticList.MOB_KILLS); } -@@ -1049,7 +1284,8 @@ +@@ -1049,7 +1285,8 @@ int i = scoreboardteam.getColor().getId(); if (i >= 0 && i < aiscoreboardcriteria.length) { @@ -500,7 +508,7 @@ } } -@@ -1093,10 +1329,16 @@ +@@ -1093,10 +1330,16 @@ } private boolean isPvpAllowed() { @@ -519,7 +527,7 @@ BlockPosition blockposition = this.getRespawnPosition(); float f = this.getRespawnAngle(); boolean flag1 = this.isRespawnForced(); -@@ -1108,13 +1350,32 @@ +@@ -1108,13 +1351,32 @@ if (optional.isPresent()) { EntityPlayer.RespawnPosAngle entityplayer_respawnposangle = (EntityPlayer.RespawnPosAngle) optional.get(); @@ -555,7 +563,7 @@ } public static Optional findRespawnAndUseSpawnBlock(WorldServer worldserver, BlockPosition blockposition, float f, boolean flag, boolean flag1) { -@@ -1129,11 +1390,11 @@ +@@ -1129,11 +1391,11 @@ } return optional.map((vec3d) -> { @@ -569,7 +577,7 @@ }); } else if (!flag) { return Optional.empty(); -@@ -1142,7 +1403,7 @@ +@@ -1142,7 +1404,7 @@ IBlockData iblockdata1 = worldserver.getBlockState(blockposition.above()); boolean flag3 = iblockdata1.getBlock().isPossibleToRespawnInThis(iblockdata1); @@ -578,7 +586,7 @@ } } -@@ -1160,6 +1421,7 @@ +@@ -1160,6 +1422,7 @@ @Nullable @Override public EntityPlayer teleport(TeleportTransition teleporttransition) { @@ -586,7 +594,7 @@ if (this.isRemoved()) { return null; } else { -@@ -1169,18 +1431,38 @@ +@@ -1169,18 +1432,38 @@ WorldServer worldserver = teleporttransition.newLevel(); WorldServer worldserver1 = this.serverLevel(); @@ -628,7 +636,7 @@ this.isChangingDimension = true; WorldData worlddata = worldserver.getLevelData(); -@@ -1191,17 +1473,31 @@ +@@ -1191,17 +1474,31 @@ playerlist.sendPlayerPermissionLevel(this); worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); this.unsetRemoved(); @@ -662,7 +670,7 @@ this.connection.resetPosition(); worldserver.addDuringTeleport(this); gameprofilerfiller.pop(); -@@ -1215,11 +1511,29 @@ +@@ -1215,11 +1512,29 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -692,7 +700,7 @@ @Override public void forceSetRotation(float f, float f1) { this.connection.send(new ClientboundPlayerRotationPacket(f, f1)); -@@ -1228,13 +1542,21 @@ +@@ -1228,13 +1543,21 @@ public void triggerDimensionChangeTriggers(WorldServer worldserver) { ResourceKey resourcekey = worldserver.dimension(); ResourceKey resourcekey1 = this.level().dimension(); @@ -717,7 +725,7 @@ this.enteredNetherPosition = null; } -@@ -1251,19 +1573,17 @@ +@@ -1251,19 +1574,17 @@ this.containerMenu.broadcastChanges(); } @@ -741,7 +749,7 @@ if (this.level().isDay()) { return Either.left(EntityHuman.EnumBedResult.NOT_POSSIBLE_NOW); } else { -@@ -1280,7 +1600,36 @@ +@@ -1280,7 +1601,36 @@ } } @@ -779,7 +787,7 @@ this.awardStat(StatisticList.SLEEP_IN_BED); CriterionTriggers.SLEPT_IN_BED.trigger(this); }); -@@ -1293,9 +1642,8 @@ +@@ -1293,9 +1643,8 @@ return either; } } @@ -790,7 +798,7 @@ } @Override -@@ -1322,13 +1670,31 @@ +@@ -1322,13 +1671,31 @@ @Override public void stopSleepInBed(boolean flag, boolean flag1) { @@ -823,7 +831,7 @@ } } -@@ -1387,8 +1753,9 @@ +@@ -1387,8 +1754,9 @@ this.connection.send(new PacketPlayOutOpenSignEditor(tileentitysign.getBlockPos(), flag)); } @@ -834,7 +842,7 @@ } @Override -@@ -1396,13 +1763,35 @@ +@@ -1396,13 +1764,35 @@ if (itileinventory == null) { return OptionalInt.empty(); } else { @@ -870,7 +878,7 @@ if (container == null) { if (this.isSpectator()) { this.displayClientMessage(IChatBaseComponent.translatable("container.spectatorCantOpen").withStyle(EnumChatFormat.RED), true); -@@ -1410,9 +1799,11 @@ +@@ -1410,9 +1800,11 @@ return OptionalInt.empty(); } else { @@ -884,7 +892,7 @@ return OptionalInt.of(this.containerCounter); } } -@@ -1425,15 +1816,26 @@ +@@ -1425,15 +1817,26 @@ @Override public void openHorseInventory(EntityHorseAbstract entityhorseabstract, IInventory iinventory) { @@ -913,7 +921,7 @@ this.initMenu(this.containerMenu); } -@@ -1456,6 +1858,7 @@ +@@ -1456,6 +1859,7 @@ @Override public void closeContainer() { @@ -921,7 +929,7 @@ this.connection.send(new PacketPlayOutCloseWindow(this.containerMenu.containerId)); this.doCloseContainer(); } -@@ -1485,19 +1888,19 @@ +@@ -1485,19 +1889,19 @@ i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); if (i > 0) { this.awardStat(StatisticList.SWIM_ONE_CM, i); @@ -944,7 +952,7 @@ } } else if (this.onClimbable()) { if (d1 > 0.0D) { -@@ -1508,13 +1911,13 @@ +@@ -1508,13 +1912,13 @@ if (i > 0) { if (this.isSprinting()) { this.awardStat(StatisticList.SPRINT_ONE_CM, i); @@ -961,7 +969,7 @@ } } } else if (this.isFallFlying()) { -@@ -1557,7 +1960,7 @@ +@@ -1557,7 +1961,7 @@ @Override public void awardStat(Statistic statistic, int i) { this.stats.increment(this, statistic, i); @@ -970,7 +978,7 @@ scoreaccess.add(i); }); } -@@ -1565,7 +1968,7 @@ +@@ -1565,7 +1969,7 @@ @Override public void resetStat(Statistic statistic) { this.stats.setValue(this, statistic, 0); @@ -979,7 +987,7 @@ } @Override -@@ -1597,9 +2000,9 @@ +@@ -1597,9 +2001,9 @@ super.jumpFromGround(); this.awardStat(StatisticList.JUMP); if (this.isSprinting()) { @@ -991,7 +999,7 @@ } } -@@ -1625,6 +2028,7 @@ +@@ -1625,6 +2029,7 @@ public void resetSentInfo() { this.lastSentHealth = -1.0E8F; @@ -999,7 +1007,7 @@ } @Override -@@ -1661,7 +2065,7 @@ +@@ -1661,7 +2066,7 @@ this.onUpdateAbilities(); if (flag) { this.getAttributes().assignBaseValues(entityplayer.getAttributes()); @@ -1008,7 +1016,7 @@ this.setHealth(entityplayer.getHealth()); this.foodData = entityplayer.foodData; Iterator iterator = entityplayer.getActiveEffects().iterator(); -@@ -1669,7 +2073,7 @@ +@@ -1669,7 +2074,7 @@ while (iterator.hasNext()) { MobEffect mobeffect = (MobEffect) iterator.next(); @@ -1017,7 +1025,7 @@ } this.getInventory().replaceWith(entityplayer.getInventory()); -@@ -1680,7 +2084,7 @@ +@@ -1680,7 +2085,7 @@ this.portalProcess = entityplayer.portalProcess; } else { this.getAttributes().assignBaseValues(entityplayer.getAttributes()); @@ -1026,7 +1034,7 @@ if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || entityplayer.isSpectator()) { this.getInventory().replaceWith(entityplayer.getInventory()); this.experienceLevel = entityplayer.experienceLevel; -@@ -1696,7 +2100,7 @@ +@@ -1696,7 +2101,7 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -1035,7 +1043,7 @@ this.seenCredits = entityplayer.seenCredits; this.enteredNetherPosition = entityplayer.enteredNetherPosition; this.chunkTrackingView = entityplayer.chunkTrackingView; -@@ -1752,7 +2156,7 @@ +@@ -1752,7 +2157,7 @@ } @Override @@ -1044,7 +1052,7 @@ if (this.isSleeping()) { this.stopSleepInBed(true, true); } -@@ -1761,7 +2165,7 @@ +@@ -1761,7 +2166,7 @@ this.setCamera(this); } @@ -1053,7 +1061,7 @@ if (flag1) { this.setYHeadRot(set.contains(Relative.Y_ROT) ? this.getYHeadRot() + f : f); -@@ -1878,6 +2282,16 @@ +@@ -1878,6 +2283,16 @@ } public void updateOptions(ClientInformation clientinformation) { @@ -1070,7 +1078,7 @@ this.language = clientinformation.language(); this.requestedViewDistance = clientinformation.viewDistance(); this.chatVisibility = clientinformation.chatVisibility(); -@@ -1962,7 +2376,7 @@ +@@ -1962,7 +2377,7 @@ if (world instanceof WorldServer) { WorldServer worldserver = (WorldServer) world; @@ -1079,7 +1087,7 @@ } if (entity != null) { -@@ -1999,11 +2413,11 @@ +@@ -1999,11 +2414,11 @@ @Nullable public IChatBaseComponent getTabListDisplayName() { @@ -1093,7 +1101,7 @@ } @Override -@@ -2046,6 +2460,32 @@ +@@ -2046,6 +2461,32 @@ } public void setRespawnPosition(ResourceKey resourcekey, @Nullable BlockPosition blockposition, float f, boolean flag, boolean flag1) { @@ -1126,7 +1134,7 @@ if (blockposition != null) { boolean flag2 = blockposition.equals(this.respawnPosition) && resourcekey.equals(this.respawnDimension); -@@ -2088,12 +2528,38 @@ +@@ -2088,12 +2529,38 @@ } @Override @@ -1166,7 +1174,7 @@ this.level().addFreshEntity(entityitem); ItemStack itemstack1 = entityitem.getItem(); -@@ -2375,10 +2841,12 @@ +@@ -2375,10 +2842,12 @@ return TicketType.ENDER_PEARL.timeout(); } @@ -1182,7 +1190,7 @@ } private static float calculateLookAtYaw(Vec3D vec3d, BlockPosition blockposition) { -@@ -2387,4 +2855,146 @@ +@@ -2387,4 +2856,146 @@ return (float) MathHelper.wrapDegrees(MathHelper.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); } } diff --git a/nms-patches/net/minecraft/world/inventory/Container.patch b/nms-patches/net/minecraft/world/inventory/Container.patch index 89229c657..808c39995 100644 --- a/nms-patches/net/minecraft/world/inventory/Container.patch +++ b/nms-patches/net/minecraft/world/inventory/Container.patch @@ -21,7 +21,7 @@ public abstract class Container { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -67,6 +81,27 @@ +@@ -67,6 +81,28 @@ private ContainerSynchronizer synchronizer; private boolean suppressRemoteUpdates; @@ -44,12 +44,13 @@ + Preconditions.checkState(this.title == null, "Title already set"); + this.title = title; + } ++ public void startOpen() {} + // CraftBukkit end + protected Container(@Nullable Containers containers, int i) { this.carried = ItemStack.EMPTY; this.remoteSlots = NonNullList.create(); -@@ -192,6 +227,15 @@ +@@ -192,6 +228,15 @@ } @@ -65,7 +66,7 @@ public void removeSlotListener(ICrafting icrafting) { this.containerListeners.remove(icrafting); } -@@ -417,7 +461,7 @@ +@@ -417,7 +462,7 @@ } } else if (this.quickcraftStatus == 2) { if (!this.quickcraftSlots.isEmpty()) { @@ -74,7 +75,7 @@ k = ((Slot) this.quickcraftSlots.iterator().next()).index; this.resetQuickCraft(); this.doClick(k, this.quickcraftType, InventoryClickType.PICKUP, entityhuman); -@@ -433,6 +477,7 @@ +@@ -433,6 +478,7 @@ l = this.getCarried().getCount(); Iterator iterator = this.quickcraftSlots.iterator(); @@ -82,7 +83,7 @@ while (iterator.hasNext()) { Slot slot1 = (Slot) iterator.next(); ItemStack itemstack2 = this.getCarried(); -@@ -443,12 +488,48 @@ +@@ -443,12 +489,48 @@ int l1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemstack1) + j1, k1); l -= l1 - j1; @@ -134,7 +135,7 @@ } this.resetQuickCraft(); -@@ -466,8 +547,11 @@ +@@ -466,8 +548,11 @@ if (i == -999) { if (!this.getCarried().isEmpty()) { if (clickaction == ClickAction.PRIMARY) { @@ -147,7 +148,7 @@ } else { entityhuman.drop(this.getCarried().split(1), true); } -@@ -530,6 +614,15 @@ +@@ -530,6 +615,15 @@ } slot.setChanged(); @@ -163,7 +164,7 @@ } } else { int j2; -@@ -662,8 +755,9 @@ +@@ -662,8 +756,9 @@ ItemStack itemstack = this.getCarried(); if (!itemstack.isEmpty()) { @@ -174,7 +175,7 @@ } } -@@ -893,6 +987,11 @@ +@@ -893,6 +988,11 @@ } public ItemStack getCarried() { diff --git a/nms-patches/net/minecraft/world/inventory/ContainerChest.patch b/nms-patches/net/minecraft/world/inventory/ContainerChest.patch index cdc889f17..50356f611 100644 --- a/nms-patches/net/minecraft/world/inventory/ContainerChest.patch +++ b/nms-patches/net/minecraft/world/inventory/ContainerChest.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/ContainerChest.java +++ b/net/minecraft/world/inventory/ContainerChest.java -@@ -6,10 +6,39 @@ +@@ -6,10 +6,44 @@ import net.minecraft.world.entity.player.PlayerInventory; import net.minecraft.world.item.ItemStack; @@ -36,21 +36,28 @@ + bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); + return bukkitEntity; + } ++ ++ @Override ++ public void startOpen() { ++ this.container.startOpen(this.player.player); ++ } + // CraftBukkit end private ContainerChest(Containers containers, int i, PlayerInventory playerinventory, int j) { this(containers, i, playerinventory, new InventorySubcontainer(9 * j), j); -@@ -53,6 +82,9 @@ +@@ -52,7 +86,10 @@ + checkContainerSize(iinventory, j * 9); this.container = iinventory; this.containerRows = j; - iinventory.startOpen(playerinventory.player); +- iinventory.startOpen(playerinventory.player); ++ // iinventory.startOpen(playerinventory.player); // CraftBukkit - don't startOpen until menu actually opens + // CraftBukkit start - Save player + this.player = playerinventory; + // CraftBukkit end boolean flag = true; this.addChestGrid(iinventory, 8, 18); -@@ -72,6 +104,7 @@ +@@ -72,6 +109,7 @@ @Override public boolean stillValid(EntityHuman entityhuman) { diff --git a/nms-patches/net/minecraft/world/inventory/ContainerMerchant.patch b/nms-patches/net/minecraft/world/inventory/ContainerMerchant.patch index 6f8db52e2..dddf79e1d 100644 --- a/nms-patches/net/minecraft/world/inventory/ContainerMerchant.patch +++ b/nms-patches/net/minecraft/world/inventory/ContainerMerchant.patch @@ -37,7 +37,15 @@ this.addStandardInventorySlots(playerinventory, 108, 84); } -@@ -143,7 +159,7 @@ +@@ -62,6 +78,7 @@ + + @Override + public boolean stillValid(EntityHuman entityhuman) { ++ if (!checkReachable) return true; // CraftBukkit - checkReachable + return this.trader.stillValid(entityhuman); + } + +@@ -143,7 +160,7 @@ } private void playTradeSound() { diff --git a/nms-patches/net/minecraft/world/inventory/ContainerShulkerBox.patch b/nms-patches/net/minecraft/world/inventory/ContainerShulkerBox.patch index 5109b7b8e..ab52bd196 100644 --- a/nms-patches/net/minecraft/world/inventory/ContainerShulkerBox.patch +++ b/nms-patches/net/minecraft/world/inventory/ContainerShulkerBox.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/ContainerShulkerBox.java +++ b/net/minecraft/world/inventory/ContainerShulkerBox.java -@@ -6,10 +6,29 @@ +@@ -6,10 +6,34 @@ import net.minecraft.world.entity.player.PlayerInventory; import net.minecraft.world.item.ItemStack; @@ -26,19 +26,26 @@ + bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), new CraftInventory(this.container), this); + return bukkitEntity; + } ++ ++ @Override ++ public void startOpen() { ++ container.startOpen(player.player); ++ } + // CraftBukkit end public ContainerShulkerBox(int i, PlayerInventory playerinventory) { this(i, playerinventory, new InventorySubcontainer(27)); -@@ -19,6 +38,7 @@ +@@ -19,7 +43,8 @@ super(Containers.SHULKER_BOX, i); checkContainerSize(iinventory, 27); this.container = iinventory; +- iinventory.startOpen(playerinventory.player); + this.player = playerinventory; // CraftBukkit - save player - iinventory.startOpen(playerinventory.player); ++ // iinventory.startOpen(playerinventory.player); // CraftBukkit - don't startOpen until menu actually opens boolean flag = true; boolean flag1 = true; -@@ -34,6 +54,7 @@ + +@@ -34,6 +59,7 @@ @Override public boolean stillValid(EntityHuman entityhuman) { diff --git a/nms-patches/net/minecraft/world/level/block/BlockChest.patch b/nms-patches/net/minecraft/world/level/block/BlockChest.patch index 6c31f92f1..01c475972 100644 --- a/nms-patches/net/minecraft/world/level/block/BlockChest.patch +++ b/nms-patches/net/minecraft/world/level/block/BlockChest.patch @@ -1,6 +1,11 @@ --- a/net/minecraft/world/level/block/BlockChest.java +++ b/net/minecraft/world/level/block/BlockChest.java -@@ -91,24 +91,7 @@ +@@ -87,28 +87,11 @@ + return Optional.empty(); + } + }; +- private static final DoubleBlockFinder.Combiner> MENU_PROVIDER_COMBINER = new DoubleBlockFinder.Combiner>() { ++ public static final DoubleBlockFinder.Combiner> MENU_PROVIDER_COMBINER = new DoubleBlockFinder.Combiner>() { // PAIL private -> public public Optional acceptDouble(final TileEntityChest tileentitychest, final TileEntityChest tileentitychest1) { final InventoryLargeChest inventorylargechest = new InventoryLargeChest(tileentitychest, tileentitychest1); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index ae7cc82d6..e9c3b40e6 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -22,6 +22,7 @@ import net.minecraft.world.entity.EnumMainHand; import net.minecraft.world.entity.player.EntityHuman; import net.minecraft.world.entity.projectile.EntityFireworks; import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.ContainerMerchant; import net.minecraft.world.inventory.Containers; import net.minecraft.world.item.ItemCooldown; import net.minecraft.world.item.crafting.CraftingManager; @@ -49,6 +50,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryView; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.inventory.CraftMerchantCustom; import org.bukkit.craftbukkit.inventory.CraftRecipe; +import org.bukkit.craftbukkit.inventory.util.CraftMenus; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.Firework; @@ -403,6 +405,11 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { // Now open the window Containers windowType = CraftContainer.getNotchInventoryType(inventory.getTopInventory()); + // we can open these now delegeate for now + if (windowType == Containers.MERCHANT) { + CraftMenus.openMerchantMenu(player, (ContainerMerchant) container); + return; + } String title = inventory.getTitle(); player.connection.send(new PacketPlayOutOpenWindow(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); player.containerMenu = container; diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java index 576ed605b..bd4745255 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java @@ -127,7 +127,7 @@ public class CraftContainer extends Container { if (menu == null) { return Containers.GENERIC_9x3; } else { - return ((CraftMenuType) menu).getHandle(); + return ((CraftMenuType) menu).getHandle(); } } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java index 52c983356..a372a3628 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java @@ -1,29 +1,25 @@ package org.bukkit.craftbukkit.inventory; -import com.google.common.base.Preconditions; import com.google.common.base.Suppliers; import java.util.function.Supplier; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.world.inventory.Container; import net.minecraft.world.inventory.Containers; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.craftbukkit.CraftRegistry; -import org.bukkit.craftbukkit.entity.CraftHumanEntity; import org.bukkit.craftbukkit.inventory.util.CraftMenus; -import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.MenuType; +import org.bukkit.inventory.view.builder.InventoryViewBuilder; -public class CraftMenuType implements MenuType.Typed, Handleable> { +public class CraftMenuType> implements MenuType.Typed, Handleable> { private final NamespacedKey key; private final Containers handle; - private final Supplier> typeData; + private final Supplier> typeData; public CraftMenuType(NamespacedKey key, Containers handle) { this.key = key; @@ -38,28 +34,23 @@ public class CraftMenuType implements MenuType.Typed @Override public V create(final HumanEntity player, final String title) { - Preconditions.checkArgument(player != null, "The given player must not be null"); - Preconditions.checkArgument(title != null, "The given title must not be null"); - Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity"); - final CraftHumanEntity craftHuman = (CraftHumanEntity) player; - Preconditions.checkArgument(craftHuman.getHandle() instanceof EntityPlayer, "The given player must be an EntityPlayer"); - final EntityPlayer serverPlayer = (EntityPlayer) craftHuman.getHandle(); - - final Container container = typeData.get().menuBuilder().build(serverPlayer, this.handle); - container.setTitle(CraftChatMessage.fromString(title)[0]); - container.checkReachable = false; - return (V) container.getBukkitView(); + return builder().title(title).build(player); } @Override - public Typed typed() { + public B builder() { + return typeData.get().viewBuilder().get(); + } + + @Override + public Typed> typed() { return this.typed(InventoryView.class); } @Override - public Typed typed(Class clazz) { + public > Typed typed(Class clazz) { if (clazz.isAssignableFrom(typeData.get().viewClass())) { - return (Typed) this; + return (Typed) this; } throw new IllegalArgumentException("Cannot type InventoryView " + this.key.toString() + " to InventoryView type " + clazz.getSimpleName()); diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenuBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenuBuilder.java deleted file mode 100644 index dd4880b16..000000000 --- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenuBuilder.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bukkit.craftbukkit.inventory.util; - -import net.minecraft.core.BlockPosition; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.world.ITileInventory; -import net.minecraft.world.entity.player.PlayerInventory; -import net.minecraft.world.inventory.Container; -import net.minecraft.world.inventory.ContainerAccess; -import net.minecraft.world.inventory.Containers; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.IBlockData; - -public interface CraftMenuBuilder { - - Container build(EntityPlayer player, Containers type); - - static CraftMenuBuilder worldAccess(LocationBoundContainerBuilder builder) { - return (EntityPlayer player, Containers type) -> { - return builder.build(player.nextContainerCounter(), player.getInventory(), ContainerAccess.create(player.level(), player.blockPosition())); - }; - } - - static CraftMenuBuilder tileEntity(TileEntityObjectBuilder objectBuilder, Block block) { - return (EntityPlayer player, Containers type) -> { - return objectBuilder.build(player.blockPosition(), block.defaultBlockState()).createMenu(player.nextContainerCounter(), player.getInventory(), player); - }; - } - - interface TileEntityObjectBuilder { - - ITileInventory build(BlockPosition blockPosition, IBlockData blockData); - } - - interface LocationBoundContainerBuilder { - - Container build(int syncId, PlayerInventory inventory, ContainerAccess access); - } -} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java index e63d3f3e5..79f507783 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java @@ -1,15 +1,20 @@ package org.bukkit.craftbukkit.inventory.util; -import static org.bukkit.craftbukkit.inventory.util.CraftMenuBuilder.*; -import net.minecraft.network.chat.IChatBaseComponent; -import net.minecraft.world.TileInventory; +import java.util.function.Supplier; +import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.entity.npc.EntityVillager; import net.minecraft.world.inventory.ContainerAnvil; import net.minecraft.world.inventory.ContainerCartography; import net.minecraft.world.inventory.ContainerEnchantTable; import net.minecraft.world.inventory.ContainerGrindstone; +import net.minecraft.world.inventory.ContainerMerchant; import net.minecraft.world.inventory.ContainerSmithing; import net.minecraft.world.inventory.ContainerStonecutter; import net.minecraft.world.inventory.ContainerWorkbench; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.item.trading.IMerchant; +import net.minecraft.world.item.trading.MerchantRecipeList; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.CrafterBlockEntity; import net.minecraft.world.level.block.entity.TileEntityBeacon; @@ -21,6 +26,12 @@ import net.minecraft.world.level.block.entity.TileEntityHopper; import net.minecraft.world.level.block.entity.TileEntityLectern; import net.minecraft.world.level.block.entity.TileEntitySmoker; import org.bukkit.craftbukkit.inventory.CraftMenuType; +import org.bukkit.craftbukkit.inventory.CraftMerchant; +import org.bukkit.craftbukkit.inventory.view.builder.CraftAccessLocationInventoryViewBuilder; +import org.bukkit.craftbukkit.inventory.view.builder.CraftBlockEntityInventoryViewBuilder; +import org.bukkit.craftbukkit.inventory.view.builder.CraftDoubleChestInventoryViewBuilder; +import org.bukkit.craftbukkit.inventory.view.builder.CraftMerchantInventoryViewBuilder; +import org.bukkit.craftbukkit.inventory.view.builder.CraftStandardInventoryViewBuilder; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.MenuType; import org.bukkit.inventory.view.AnvilView; @@ -33,83 +44,110 @@ import org.bukkit.inventory.view.LecternView; import org.bukkit.inventory.view.LoomView; import org.bukkit.inventory.view.MerchantView; import org.bukkit.inventory.view.StonecutterView; +import org.bukkit.inventory.view.builder.InventoryViewBuilder; public final class CraftMenus { - public record MenuTypeData(Class viewClass, CraftMenuBuilder menuBuilder) { + public record MenuTypeData>(Class viewClass, Supplier viewBuilder) { } - private static final CraftMenuBuilder STANDARD = (player, menuType) -> menuType.create(player.nextContainerCounter(), player.getInventory()); + // This is a temporary measure that will likely be removed with the rewrite of HumanEntity#open[] methods + public static void openMerchantMenu(EntityPlayer player, ContainerMerchant merchant) { + final IMerchant minecraftMerchant = ((CraftMerchant) merchant.getBukkitView().getMerchant()).getMerchant(); + int level = 1; + if (minecraftMerchant instanceof EntityVillager villager) { + level = villager.getVillagerData().getLevel(); + } + minecraftMerchant.setTradingPlayer(player); - public static MenuTypeData getMenuTypeData(CraftMenuType menuType) { + player.connection.send(new PacketPlayOutOpenWindow(merchant.containerId, Containers.MERCHANT, merchant.getTitle())); + player.containerMenu = merchant; + player.initMenu(merchant); + // Copy IMerchant#openTradingScreen + MerchantRecipeList merchantrecipelist = minecraftMerchant.getOffers(); + + if (!merchantrecipelist.isEmpty()) { + player.sendMerchantOffers(merchant.containerId, merchantrecipelist, level, minecraftMerchant.getVillagerXp(), minecraftMerchant.showProgressBar(), minecraftMerchant.canRestock()); + } + // End Copy IMerchant#openTradingScreen + } + + public static > MenuTypeData getMenuTypeData(CraftMenuType menuType) { + final Containers handle = menuType.getHandle(); + // this sucks horribly but it should work for now + if (menuType == MenuType.GENERIC_9X6) { + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftDoubleChestInventoryViewBuilder<>(handle))); + } + if (menuType == MenuType.GENERIC_9X3) { + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, null))); + } // this isn't ideal as both dispenser and dropper are 3x3, InventoryType can't currently handle generic 3x3s with size 9 // this needs to be removed when inventory creation is overhauled if (menuType == MenuType.GENERIC_3X3) { - return asType(new MenuTypeData<>(InventoryView.class, tileEntity(TileEntityDispenser::new, Blocks.DISPENSER))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.DISPENSER, TileEntityDispenser::new))); } if (menuType == MenuType.CRAFTER_3X3) { - return asType(new MenuTypeData<>(CrafterView.class, tileEntity(CrafterBlockEntity::new, Blocks.CRAFTER))); + return asType(new MenuTypeData<>(CrafterView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CRAFTER, CrafterBlockEntity::new))); } if (menuType == MenuType.ANVIL) { - return asType(new MenuTypeData<>(AnvilView.class, worldAccess(ContainerAnvil::new))); + return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerAnvil::new))); } if (menuType == MenuType.BEACON) { - return asType(new MenuTypeData<>(BeaconView.class, tileEntity(TileEntityBeacon::new, Blocks.BEACON))); + return asType(new MenuTypeData<>(BeaconView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BEACON, TileEntityBeacon::new))); } if (menuType == MenuType.BLAST_FURNACE) { - return asType(new MenuTypeData<>(FurnaceView.class, tileEntity(TileEntityBlastFurnace::new, Blocks.BLAST_FURNACE))); + return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BLAST_FURNACE, TileEntityBlastFurnace::new))); } if (menuType == MenuType.BREWING_STAND) { - return asType(new MenuTypeData<>(BrewingStandView.class, tileEntity(TileEntityBrewingStand::new, Blocks.BREWING_STAND))); + return asType(new MenuTypeData<>(BrewingStandView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BREWING_STAND, TileEntityBrewingStand::new))); } if (menuType == MenuType.CRAFTING) { - return asType(new MenuTypeData<>(InventoryView.class, worldAccess(ContainerWorkbench::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerWorkbench::new))); } if (menuType == MenuType.ENCHANTMENT) { - return asType(new MenuTypeData<>(EnchantmentView.class, (player, type) -> { - return new TileInventory((syncId, inventory, human) -> { - return worldAccess(ContainerEnchantTable::new).build(player, type); - }, IChatBaseComponent.empty()).createMenu(player.nextContainerCounter(), player.getInventory(), player); - })); + return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerEnchantTable::new))); } if (menuType == MenuType.FURNACE) { - return asType(new MenuTypeData<>(FurnaceView.class, tileEntity(TileEntityFurnaceFurnace::new, Blocks.FURNACE))); + return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.FURNACE, TileEntityFurnaceFurnace::new))); } if (menuType == MenuType.GRINDSTONE) { - return asType(new MenuTypeData<>(InventoryView.class, worldAccess(ContainerGrindstone::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerGrindstone::new))); } // We really don't need to be creating a tile entity for hopper but currently InventoryType doesn't have capacity // to understand otherwise if (menuType == MenuType.HOPPER) { - return asType(new MenuTypeData<>(InventoryView.class, tileEntity(TileEntityHopper::new, Blocks.HOPPER))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.HOPPER, TileEntityHopper::new))); } // We also don't need to create a tile entity for lectern, but again InventoryType isn't smart enough to know any better if (menuType == MenuType.LECTERN) { - return asType(new MenuTypeData<>(LecternView.class, tileEntity(TileEntityLectern::new, Blocks.LECTERN))); + return asType(new MenuTypeData<>(LecternView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.LECTERN, TileEntityLectern::new))); } if (menuType == MenuType.LOOM) { - return asType(new MenuTypeData<>(LoomView.class, STANDARD)); + return asType(new MenuTypeData<>(LoomView.class, () -> new CraftStandardInventoryViewBuilder<>(handle))); } if (menuType == MenuType.MERCHANT) { - return asType(new MenuTypeData<>(MerchantView.class, STANDARD)); + return asType(new MenuTypeData<>(MerchantView.class, () -> new CraftMerchantInventoryViewBuilder<>(handle))); + } + if (menuType == MenuType.SHULKER_BOX) { + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SHULKER_BOX, null))); } if (menuType == MenuType.SMITHING) { - return asType(new MenuTypeData<>(InventoryView.class, worldAccess(ContainerSmithing::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerSmithing::new))); } if (menuType == MenuType.SMOKER) { - return asType(new MenuTypeData<>(FurnaceView.class, tileEntity(TileEntitySmoker::new, Blocks.SMOKER))); + return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SMOKER, TileEntitySmoker::new))); } if (menuType == MenuType.CARTOGRAPHY_TABLE) { - return asType(new MenuTypeData<>(InventoryView.class, worldAccess(ContainerCartography::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerCartography::new))); } if (menuType == MenuType.STONECUTTER) { - return asType(new MenuTypeData<>(StonecutterView.class, worldAccess(ContainerStonecutter::new))); + return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerStonecutter::new))); } - return asType(new MenuTypeData<>(InventoryView.class, STANDARD)); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftStandardInventoryViewBuilder<>(handle))); } - private static MenuTypeData asType(MenuTypeData data) { - return (MenuTypeData) data; + private static > MenuTypeData asType(MenuTypeData data) { + return (MenuTypeData) data; } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java new file mode 100644 index 000000000..ce9dd2254 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java @@ -0,0 +1,47 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import com.google.common.base.Preconditions; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.Containers; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.view.builder.InventoryViewBuilder; +import org.jetbrains.annotations.NotNull; + +public abstract class CraftAbstractInventoryViewBuilder implements InventoryViewBuilder { + + protected final Containers handle; + + protected boolean checkReachable = false; + protected String title = null; + + public CraftAbstractInventoryViewBuilder(Containers handle) { + this.handle = handle; + } + + @NotNull + @Override + public InventoryViewBuilder title(@NotNull final String title) { + this.title = title; + return this; + } + + @Override + public V build(final HumanEntity player) { + Preconditions.checkArgument(player != null, "The given player must not be null"); + Preconditions.checkArgument(this.title != null, "The given title must not be null"); + Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity"); + final CraftHumanEntity craftHuman = (CraftHumanEntity) player; + Preconditions.checkArgument(craftHuman.getHandle() instanceof EntityPlayer, "The given player must be an EntityPlayer"); + final EntityPlayer serverPlayer = (EntityPlayer) craftHuman.getHandle(); + final Container container = buildContainer(serverPlayer); + container.checkReachable = this.checkReachable; + container.setTitle(CraftChatMessage.fromString(title)[0]); + return (V) container.getBukkitView(); + } + + protected abstract Container buildContainer(EntityPlayer player); +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java new file mode 100644 index 000000000..5fc1fcd94 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java @@ -0,0 +1,36 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import com.google.common.base.Preconditions; +import net.minecraft.core.BlockPosition; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.level.World; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder; + +public abstract class CraftAbstractLocationInventoryViewBuilder extends CraftAbstractInventoryViewBuilder implements LocationInventoryViewBuilder { + + protected World world; + protected BlockPosition position; + + public CraftAbstractLocationInventoryViewBuilder(final Containers handle) { + super(handle); + } + + @Override + public LocationInventoryViewBuilder checkReachable(final boolean checkReachable) { + super.checkReachable = checkReachable; + return this; + } + + @Override + public LocationInventoryViewBuilder location(final Location location) { + Preconditions.checkArgument(location != null, "The provided location must not be null"); + Preconditions.checkArgument(location.getWorld() != null, "The provided location must be associated with a world"); + this.world = ((CraftWorld) location.getWorld()).getHandle(); + this.position = CraftLocation.toBlockPosition(location); + return this; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java new file mode 100644 index 000000000..2165be873 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java @@ -0,0 +1,46 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.entity.player.PlayerInventory; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.ContainerAccess; +import net.minecraft.world.inventory.Containers; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder; + +public class CraftAccessLocationInventoryViewBuilder extends CraftAbstractLocationInventoryViewBuilder { + + private final CraftAccessContainerObjectBuilder containerBuilder; + + public CraftAccessLocationInventoryViewBuilder(final Containers handle, CraftAccessContainerObjectBuilder containerBuilder) { + super(handle); + this.containerBuilder = containerBuilder; + } + + @Override + protected Container buildContainer(final EntityPlayer player) { + ContainerAccess access; + if (super.position == null) { + access = ContainerAccess.create(player.level(), player.blockPosition()); + } else { + access = ContainerAccess.create(super.world, super.position); + } + + return this.containerBuilder.build(player.nextContainerCounter(), player.getInventory(), access); + } + + @Override + public LocationInventoryViewBuilder copy() { + CraftAccessLocationInventoryViewBuilder copy = new CraftAccessLocationInventoryViewBuilder<>(this.handle, this.containerBuilder); + copy.world = super.world; + copy.position = super.position; + copy.checkReachable = super.checkReachable; + copy.title = title; + return copy; + } + + public interface CraftAccessContainerObjectBuilder { + + Container build(final int syncId, final PlayerInventory inventory, ContainerAccess access); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java new file mode 100644 index 000000000..4b4ef06cc --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java @@ -0,0 +1,74 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import net.minecraft.core.BlockPosition; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.ITileInventory; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.inventory.ITileEntityContainer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.block.state.IBlockData; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder; + +public class CraftBlockEntityInventoryViewBuilder extends CraftAbstractLocationInventoryViewBuilder { + + private final Block block; + private final CraftTileInventoryBuilder builder; + + public CraftBlockEntityInventoryViewBuilder(final Containers handle, final Block block, final CraftTileInventoryBuilder builder) { + super(handle); + this.block = block; + this.builder = builder; + } + + @Override + protected Container buildContainer(final EntityPlayer player) { + if (this.world == null) { + this.world = player.level(); + } + + if (this.position == null) { + this.position = player.blockPosition(); + } + + final TileEntity entity = this.world.getBlockEntity(position); + if (!(entity instanceof ITileEntityContainer container)) { + return buildFakeTile(player); + } + + final Container atBlock = container.createMenu(player.nextContainerCounter(), player.getInventory(), player); + if (atBlock.getType() != super.handle) { + return buildFakeTile(player); + } + + return atBlock; + } + + private Container buildFakeTile(EntityPlayer player) { + if (this.builder == null) { + return handle.create(player.nextContainerCounter(), player.getInventory()); + } + final ITileInventory inventory = this.builder.build(this.position, this.block.defaultBlockState()); + if (inventory instanceof TileEntity tile) { + tile.setLevel(this.world); + } + return inventory.createMenu(player.nextContainerCounter(), player.getInventory(), player); + } + + @Override + public LocationInventoryViewBuilder copy() { + final CraftBlockEntityInventoryViewBuilder copy = new CraftBlockEntityInventoryViewBuilder<>(super.handle, this.block, this.builder); + copy.world = this.world; + copy.position = this.position; + copy.checkReachable = super.checkReachable; + copy.title = title; + return copy; + } + + public interface CraftTileInventoryBuilder { + + ITileInventory build(BlockPosition blockPosition, IBlockData blockData); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java new file mode 100644 index 000000000..309ab69ae --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java @@ -0,0 +1,48 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.ITileInventory; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.level.block.BlockChest; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.DoubleBlockFinder; +import net.minecraft.world.level.block.entity.TileEntityChest; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder; + +public class CraftDoubleChestInventoryViewBuilder extends CraftAbstractLocationInventoryViewBuilder { + + public CraftDoubleChestInventoryViewBuilder(final Containers handle) { + super(handle); + } + + @Override + protected Container buildContainer(final EntityPlayer player) { + if (super.world == null) { + return handle.create(player.nextContainerCounter(), player.getInventory()); + } + + BlockChest chest = (BlockChest) Blocks.CHEST; + final DoubleBlockFinder.Result result = chest.combine(super.world.getBlockState(super.position), super.world, super.position, false); + if (result instanceof DoubleBlockFinder.Result.Single) { + return handle.create(player.nextContainerCounter(), player.getInventory()); + } + + final ITileInventory combined = result.apply(BlockChest.MENU_PROVIDER_COMBINER).orElse(null); + if (combined == null) { + return handle.create(player.nextContainerCounter(), player.getInventory()); + } + return combined.createMenu(player.nextContainerCounter(), player.getInventory(), player); + } + + @Override + public LocationInventoryViewBuilder copy() { + final CraftDoubleChestInventoryViewBuilder copy = new CraftDoubleChestInventoryViewBuilder<>(super.handle); + copy.world = this.world; + copy.position = this.position; + copy.checkReachable = super.checkReachable; + copy.title = title; + return copy; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java new file mode 100644 index 000000000..2a69190a7 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java @@ -0,0 +1,74 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import com.google.common.base.Preconditions; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.ContainerMerchant; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.item.trading.IMerchant; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.inventory.CraftMerchant; +import org.bukkit.craftbukkit.inventory.CraftMerchantCustom; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.Merchant; +import org.bukkit.inventory.view.builder.MerchantInventoryViewBuilder; +import org.jetbrains.annotations.NotNull; + +public class CraftMerchantInventoryViewBuilder extends CraftAbstractInventoryViewBuilder implements MerchantInventoryViewBuilder { + + private IMerchant merchant; + + public CraftMerchantInventoryViewBuilder(final Containers handle) { + super(handle); + } + + @Override + public MerchantInventoryViewBuilder merchant(final Merchant merchant) { + this.merchant = ((CraftMerchant) merchant).getMerchant(); + return this; + } + + @NotNull + @Override + public MerchantInventoryViewBuilder checkReachable(final boolean checkReachable) { + super.checkReachable = checkReachable; + return this; + } + + @Override + public V build(final HumanEntity player) { + Preconditions.checkArgument(player != null, "The given player must not be null"); + Preconditions.checkArgument(this.title != null, "The given title must not be null"); + Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity"); + final CraftHumanEntity craftHuman = (CraftHumanEntity) player; + Preconditions.checkArgument(craftHuman.getHandle() instanceof EntityPlayer, "The given player must be an EntityPlayer"); + final EntityPlayer serverPlayer = (EntityPlayer) craftHuman.getHandle(); + + final ContainerMerchant container; + if (this.merchant == null) { + container = new ContainerMerchant(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), new CraftMerchantCustom(title).getMerchant()); + } else { + container = new ContainerMerchant(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), this.merchant); + } + + container.checkReachable = super.checkReachable; + container.setTitle(CraftChatMessage.fromString(title)[0]); + return (V) container.getBukkitView(); + } + + @Override + protected Container buildContainer(final EntityPlayer player) { + throw new UnsupportedOperationException("buildContainer is not supported for CraftMerchantInventoryViewBuilder"); + } + + @Override + public MerchantInventoryViewBuilder copy() { + CraftMerchantInventoryViewBuilder copy = new CraftMerchantInventoryViewBuilder<>(super.handle); + copy.checkReachable = super.checkReachable; + copy.merchant = this.merchant; + copy.title = title; + return copy; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java new file mode 100644 index 000000000..d0ef7400e --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java @@ -0,0 +1,26 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.Containers; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.view.builder.InventoryViewBuilder; + +public class CraftStandardInventoryViewBuilder extends CraftAbstractInventoryViewBuilder { + + public CraftStandardInventoryViewBuilder(final Containers handle) { + super(handle); + } + + @Override + protected Container buildContainer(final EntityPlayer player) { + return super.handle.create(player.nextContainerCounter(), player.getInventory()); + } + + @Override + public InventoryViewBuilder copy() { + final CraftStandardInventoryViewBuilder copy = new CraftStandardInventoryViewBuilder<>(handle); + copy.title = this.title; + return copy; + } +}