#1476: Add MenuType ViewBuilder

This commit is contained in:
Miles Holder 2024-12-18 07:49:12 +11:00 committed by md_5
parent c818af1fe7
commit 643b231025
No known key found for this signature in database
GPG Key ID: E8E901AC7C617C11
18 changed files with 546 additions and 161 deletions

View File

@ -106,8 +106,8 @@
+ containerSynchronizer.sendSlotChange(containerMenu, s, getMainHandItem()); + containerSynchronizer.sendSlotChange(containerMenu, s, getMainHandItem());
+ }); + });
+ containerSynchronizer.sendSlotChange(inventoryMenu, ContainerPlayer.SHIELD_SLOT, getOffhandItem()); + containerSynchronizer.sendSlotChange(inventoryMenu, ContainerPlayer.SHIELD_SLOT, getOffhandItem());
+ } }
+
+ // Yes, this doesn't match Vanilla, but it's the best we can do for now. + // Yes, this doesn't match Vanilla, but it's the best we can do for now.
+ // If this is an issue, PRs are welcome + // If this is an issue, PRs are welcome
+ public final BlockPosition getSpawnPoint(WorldServer worldserver) { + public final BlockPosition getSpawnPoint(WorldServer worldserver) {
@ -144,9 +144,9 @@
+ } + }
+ +
+ return blockposition; + return blockposition;
} + }
+ // CraftBukkit end + // CraftBukkit end
+
@Override @Override
public BlockPosition adjustSpawnLocation(WorldServer worldserver, BlockPosition blockposition) { public BlockPosition adjustSpawnLocation(WorldServer worldserver, BlockPosition blockposition) {
AxisAlignedBB axisalignedbb = this.getDimensions(EntityPose.STANDING).makeBoundingBox(Vec3D.ZERO); AxisAlignedBB axisalignedbb = this.getDimensions(EntityPose.STANDING).makeBoundingBox(Vec3D.ZERO);
@ -328,7 +328,15 @@
public void setExperiencePoints(int i) { public void setExperiencePoints(int i) {
float f = (float) this.getXpNeededForNextLevel(); float f = (float) this.getXpNeededForNextLevel();
float f1 = (f - 1.0F) / f; 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 @Override
public void tick() { public void tick() {
@ -340,7 +348,7 @@
this.tickClientLoadTimeout(); this.tickClientLoadTimeout();
this.gameMode.tick(); this.gameMode.tick();
this.wardenSpawnTracker.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) { 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.lastSentHealth = this.getHealth();
this.lastSentFood = this.foodData.getFoodLevel(); this.lastSentFood = this.foodData.getFoodLevel();
this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F; this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F;
@@ -851,6 +1019,12 @@ @@ -851,6 +1020,12 @@
this.updateScoreForCriteria(IScoreboardCriteria.EXPERIENCE, MathHelper.ceil((float) this.lastRecordedExperience)); this.updateScoreForCriteria(IScoreboardCriteria.EXPERIENCE, MathHelper.ceil((float) this.lastRecordedExperience));
} }
@ -362,7 +370,7 @@
if (this.experienceLevel != this.lastRecordedLevel) { if (this.experienceLevel != this.lastRecordedLevel) {
this.lastRecordedLevel = this.experienceLevel; this.lastRecordedLevel = this.experienceLevel;
this.updateScoreForCriteria(IScoreboardCriteria.LEVEL, MathHelper.ceil((float) this.lastRecordedLevel)); this.updateScoreForCriteria(IScoreboardCriteria.LEVEL, MathHelper.ceil((float) this.lastRecordedLevel));
@@ -865,6 +1039,20 @@ @@ -865,6 +1040,20 @@
CriterionTriggers.LOCATION.trigger(this); CriterionTriggers.LOCATION.trigger(this);
} }
@ -383,7 +391,7 @@
} catch (Throwable throwable) { } catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking player"); CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking player");
CrashReportSystemDetails crashreportsystemdetails = crashreport.addCategory("Player being ticked"); 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.level().getDifficulty() == EnumDifficulty.PEACEFUL && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) {
if (this.tickCount % 20 == 0) { if (this.tickCount % 20 == 0) {
if (this.getHealth() < this.getMaxHealth()) { if (this.getHealth() < this.getMaxHealth()) {
@ -392,7 +400,7 @@
} }
float f = this.foodData.getSaturationLevel(); float f = this.foodData.getSaturationLevel();
@@ -946,7 +1134,8 @@ @@ -946,7 +1135,8 @@
} }
private void updateScoreForCriteria(IScoreboardCriteria iscoreboardcriteria, int i) { private void updateScoreForCriteria(IScoreboardCriteria iscoreboardcriteria, int i) {
@ -402,7 +410,7 @@
scoreaccess.set(i); scoreaccess.set(i);
}); });
} }
@@ -955,9 +1144,47 @@ @@ -955,9 +1145,47 @@
public void die(DamageSource damagesource) { public void die(DamageSource damagesource) {
this.gameEvent(GameEvent.ENTITY_DIE); this.gameEvent(GameEvent.ENTITY_DIE);
boolean flag = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); boolean flag = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
@ -452,7 +460,7 @@
this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> { this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> {
boolean flag1 = true; boolean flag1 = true;
@@ -988,12 +1215,18 @@ @@ -988,12 +1216,18 @@
if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) { if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) {
this.tellNeutralMobsThatIDied(); this.tellNeutralMobsThatIDied();
} }
@ -475,7 +483,7 @@
EntityLiving entityliving = this.getKillCredit(); EntityLiving entityliving = this.getKillCredit();
if (entityliving != null) { if (entityliving != null) {
@@ -1028,10 +1261,12 @@ @@ -1028,10 +1262,12 @@
public void awardKillScore(Entity entity, DamageSource damagesource) { public void awardKillScore(Entity entity, DamageSource damagesource) {
if (entity != this) { if (entity != this) {
super.awardKillScore(entity, damagesource); super.awardKillScore(entity, damagesource);
@ -490,7 +498,7 @@
} else { } else {
this.awardStat(StatisticList.MOB_KILLS); this.awardStat(StatisticList.MOB_KILLS);
} }
@@ -1049,7 +1284,8 @@ @@ -1049,7 +1285,8 @@
int i = scoreboardteam.getColor().getId(); int i = scoreboardteam.getColor().getId();
if (i >= 0 && i < aiscoreboardcriteria.length) { if (i >= 0 && i < aiscoreboardcriteria.length) {
@ -500,7 +508,7 @@
} }
} }
@@ -1093,10 +1329,16 @@ @@ -1093,10 +1330,16 @@
} }
private boolean isPvpAllowed() { private boolean isPvpAllowed() {
@ -519,7 +527,7 @@
BlockPosition blockposition = this.getRespawnPosition(); BlockPosition blockposition = this.getRespawnPosition();
float f = this.getRespawnAngle(); float f = this.getRespawnAngle();
boolean flag1 = this.isRespawnForced(); boolean flag1 = this.isRespawnForced();
@@ -1108,13 +1350,32 @@ @@ -1108,13 +1351,32 @@
if (optional.isPresent()) { if (optional.isPresent()) {
EntityPlayer.RespawnPosAngle entityplayer_respawnposangle = (EntityPlayer.RespawnPosAngle) optional.get(); EntityPlayer.RespawnPosAngle entityplayer_respawnposangle = (EntityPlayer.RespawnPosAngle) optional.get();
@ -555,7 +563,7 @@
} }
public static Optional<EntityPlayer.RespawnPosAngle> findRespawnAndUseSpawnBlock(WorldServer worldserver, BlockPosition blockposition, float f, boolean flag, boolean flag1) { public static Optional<EntityPlayer.RespawnPosAngle> findRespawnAndUseSpawnBlock(WorldServer worldserver, BlockPosition blockposition, float f, boolean flag, boolean flag1) {
@@ -1129,11 +1390,11 @@ @@ -1129,11 +1391,11 @@
} }
return optional.map((vec3d) -> { return optional.map((vec3d) -> {
@ -569,7 +577,7 @@
}); });
} else if (!flag) { } else if (!flag) {
return Optional.empty(); return Optional.empty();
@@ -1142,7 +1403,7 @@ @@ -1142,7 +1404,7 @@
IBlockData iblockdata1 = worldserver.getBlockState(blockposition.above()); IBlockData iblockdata1 = worldserver.getBlockState(blockposition.above());
boolean flag3 = iblockdata1.getBlock().isPossibleToRespawnInThis(iblockdata1); boolean flag3 = iblockdata1.getBlock().isPossibleToRespawnInThis(iblockdata1);
@ -578,7 +586,7 @@
} }
} }
@@ -1160,6 +1421,7 @@ @@ -1160,6 +1422,7 @@
@Nullable @Nullable
@Override @Override
public EntityPlayer teleport(TeleportTransition teleporttransition) { public EntityPlayer teleport(TeleportTransition teleporttransition) {
@ -586,7 +594,7 @@
if (this.isRemoved()) { if (this.isRemoved()) {
return null; return null;
} else { } else {
@@ -1169,18 +1431,38 @@ @@ -1169,18 +1432,38 @@
WorldServer worldserver = teleporttransition.newLevel(); WorldServer worldserver = teleporttransition.newLevel();
WorldServer worldserver1 = this.serverLevel(); WorldServer worldserver1 = this.serverLevel();
@ -628,7 +636,7 @@
this.isChangingDimension = true; this.isChangingDimension = true;
WorldData worlddata = worldserver.getLevelData(); WorldData worlddata = worldserver.getLevelData();
@@ -1191,17 +1473,31 @@ @@ -1191,17 +1474,31 @@
playerlist.sendPlayerPermissionLevel(this); playerlist.sendPlayerPermissionLevel(this);
worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
this.unsetRemoved(); this.unsetRemoved();
@ -662,7 +670,7 @@
this.connection.resetPosition(); this.connection.resetPosition();
worldserver.addDuringTeleport(this); worldserver.addDuringTeleport(this);
gameprofilerfiller.pop(); gameprofilerfiller.pop();
@@ -1215,11 +1511,29 @@ @@ -1215,11 +1512,29 @@
this.lastSentExp = -1; this.lastSentExp = -1;
this.lastSentHealth = -1.0F; this.lastSentHealth = -1.0F;
this.lastSentFood = -1; this.lastSentFood = -1;
@ -692,7 +700,7 @@
@Override @Override
public void forceSetRotation(float f, float f1) { public void forceSetRotation(float f, float f1) {
this.connection.send(new ClientboundPlayerRotationPacket(f, f1)); this.connection.send(new ClientboundPlayerRotationPacket(f, f1));
@@ -1228,13 +1542,21 @@ @@ -1228,13 +1543,21 @@
public void triggerDimensionChangeTriggers(WorldServer worldserver) { public void triggerDimensionChangeTriggers(WorldServer worldserver) {
ResourceKey<World> resourcekey = worldserver.dimension(); ResourceKey<World> resourcekey = worldserver.dimension();
ResourceKey<World> resourcekey1 = this.level().dimension(); ResourceKey<World> resourcekey1 = this.level().dimension();
@ -717,7 +725,7 @@
this.enteredNetherPosition = null; this.enteredNetherPosition = null;
} }
@@ -1251,19 +1573,17 @@ @@ -1251,19 +1574,17 @@
this.containerMenu.broadcastChanges(); this.containerMenu.broadcastChanges();
} }
@ -741,7 +749,7 @@
if (this.level().isDay()) { if (this.level().isDay()) {
return Either.left(EntityHuman.EnumBedResult.NOT_POSSIBLE_NOW); return Either.left(EntityHuman.EnumBedResult.NOT_POSSIBLE_NOW);
} else { } else {
@@ -1280,7 +1600,36 @@ @@ -1280,7 +1601,36 @@
} }
} }
@ -779,7 +787,7 @@
this.awardStat(StatisticList.SLEEP_IN_BED); this.awardStat(StatisticList.SLEEP_IN_BED);
CriterionTriggers.SLEPT_IN_BED.trigger(this); CriterionTriggers.SLEPT_IN_BED.trigger(this);
}); });
@@ -1293,9 +1642,8 @@ @@ -1293,9 +1643,8 @@
return either; return either;
} }
} }
@ -790,7 +798,7 @@
} }
@Override @Override
@@ -1322,13 +1670,31 @@ @@ -1322,13 +1671,31 @@
@Override @Override
public void stopSleepInBed(boolean flag, boolean flag1) { 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)); this.connection.send(new PacketPlayOutOpenSignEditor(tileentitysign.getBlockPos(), flag));
} }
@ -834,7 +842,7 @@
} }
@Override @Override
@@ -1396,13 +1763,35 @@ @@ -1396,13 +1764,35 @@
if (itileinventory == null) { if (itileinventory == null) {
return OptionalInt.empty(); return OptionalInt.empty();
} else { } else {
@ -870,7 +878,7 @@
if (container == null) { if (container == null) {
if (this.isSpectator()) { if (this.isSpectator()) {
this.displayClientMessage(IChatBaseComponent.translatable("container.spectatorCantOpen").withStyle(EnumChatFormat.RED), true); this.displayClientMessage(IChatBaseComponent.translatable("container.spectatorCantOpen").withStyle(EnumChatFormat.RED), true);
@@ -1410,9 +1799,11 @@ @@ -1410,9 +1800,11 @@
return OptionalInt.empty(); return OptionalInt.empty();
} else { } else {
@ -884,7 +892,7 @@
return OptionalInt.of(this.containerCounter); return OptionalInt.of(this.containerCounter);
} }
} }
@@ -1425,15 +1816,26 @@ @@ -1425,15 +1817,26 @@
@Override @Override
public void openHorseInventory(EntityHorseAbstract entityhorseabstract, IInventory iinventory) { public void openHorseInventory(EntityHorseAbstract entityhorseabstract, IInventory iinventory) {
@ -913,7 +921,7 @@
this.initMenu(this.containerMenu); this.initMenu(this.containerMenu);
} }
@@ -1456,6 +1858,7 @@ @@ -1456,6 +1859,7 @@
@Override @Override
public void closeContainer() { public void closeContainer() {
@ -921,7 +929,7 @@
this.connection.send(new PacketPlayOutCloseWindow(this.containerMenu.containerId)); this.connection.send(new PacketPlayOutCloseWindow(this.containerMenu.containerId));
this.doCloseContainer(); this.doCloseContainer();
} }
@@ -1485,19 +1888,19 @@ @@ -1485,19 +1889,19 @@
i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F);
if (i > 0) { if (i > 0) {
this.awardStat(StatisticList.SWIM_ONE_CM, i); this.awardStat(StatisticList.SWIM_ONE_CM, i);
@ -944,7 +952,7 @@
} }
} else if (this.onClimbable()) { } else if (this.onClimbable()) {
if (d1 > 0.0D) { if (d1 > 0.0D) {
@@ -1508,13 +1911,13 @@ @@ -1508,13 +1912,13 @@
if (i > 0) { if (i > 0) {
if (this.isSprinting()) { if (this.isSprinting()) {
this.awardStat(StatisticList.SPRINT_ONE_CM, i); this.awardStat(StatisticList.SPRINT_ONE_CM, i);
@ -961,7 +969,7 @@
} }
} }
} else if (this.isFallFlying()) { } else if (this.isFallFlying()) {
@@ -1557,7 +1960,7 @@ @@ -1557,7 +1961,7 @@
@Override @Override
public void awardStat(Statistic<?> statistic, int i) { public void awardStat(Statistic<?> statistic, int i) {
this.stats.increment(this, statistic, i); this.stats.increment(this, statistic, i);
@ -970,7 +978,7 @@
scoreaccess.add(i); scoreaccess.add(i);
}); });
} }
@@ -1565,7 +1968,7 @@ @@ -1565,7 +1969,7 @@
@Override @Override
public void resetStat(Statistic<?> statistic) { public void resetStat(Statistic<?> statistic) {
this.stats.setValue(this, statistic, 0); this.stats.setValue(this, statistic, 0);
@ -979,7 +987,7 @@
} }
@Override @Override
@@ -1597,9 +2000,9 @@ @@ -1597,9 +2001,9 @@
super.jumpFromGround(); super.jumpFromGround();
this.awardStat(StatisticList.JUMP); this.awardStat(StatisticList.JUMP);
if (this.isSprinting()) { if (this.isSprinting()) {
@ -991,7 +999,7 @@
} }
} }
@@ -1625,6 +2028,7 @@ @@ -1625,6 +2029,7 @@
public void resetSentInfo() { public void resetSentInfo() {
this.lastSentHealth = -1.0E8F; this.lastSentHealth = -1.0E8F;
@ -999,7 +1007,7 @@
} }
@Override @Override
@@ -1661,7 +2065,7 @@ @@ -1661,7 +2066,7 @@
this.onUpdateAbilities(); this.onUpdateAbilities();
if (flag) { if (flag) {
this.getAttributes().assignBaseValues(entityplayer.getAttributes()); this.getAttributes().assignBaseValues(entityplayer.getAttributes());
@ -1008,7 +1016,7 @@
this.setHealth(entityplayer.getHealth()); this.setHealth(entityplayer.getHealth());
this.foodData = entityplayer.foodData; this.foodData = entityplayer.foodData;
Iterator iterator = entityplayer.getActiveEffects().iterator(); Iterator iterator = entityplayer.getActiveEffects().iterator();
@@ -1669,7 +2073,7 @@ @@ -1669,7 +2074,7 @@
while (iterator.hasNext()) { while (iterator.hasNext()) {
MobEffect mobeffect = (MobEffect) iterator.next(); MobEffect mobeffect = (MobEffect) iterator.next();
@ -1017,7 +1025,7 @@
} }
this.getInventory().replaceWith(entityplayer.getInventory()); this.getInventory().replaceWith(entityplayer.getInventory());
@@ -1680,7 +2084,7 @@ @@ -1680,7 +2085,7 @@
this.portalProcess = entityplayer.portalProcess; this.portalProcess = entityplayer.portalProcess;
} else { } else {
this.getAttributes().assignBaseValues(entityplayer.getAttributes()); this.getAttributes().assignBaseValues(entityplayer.getAttributes());
@ -1026,7 +1034,7 @@
if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || entityplayer.isSpectator()) { if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || entityplayer.isSpectator()) {
this.getInventory().replaceWith(entityplayer.getInventory()); this.getInventory().replaceWith(entityplayer.getInventory());
this.experienceLevel = entityplayer.experienceLevel; this.experienceLevel = entityplayer.experienceLevel;
@@ -1696,7 +2100,7 @@ @@ -1696,7 +2101,7 @@
this.lastSentExp = -1; this.lastSentExp = -1;
this.lastSentHealth = -1.0F; this.lastSentHealth = -1.0F;
this.lastSentFood = -1; this.lastSentFood = -1;
@ -1035,7 +1043,7 @@
this.seenCredits = entityplayer.seenCredits; this.seenCredits = entityplayer.seenCredits;
this.enteredNetherPosition = entityplayer.enteredNetherPosition; this.enteredNetherPosition = entityplayer.enteredNetherPosition;
this.chunkTrackingView = entityplayer.chunkTrackingView; this.chunkTrackingView = entityplayer.chunkTrackingView;
@@ -1752,7 +2156,7 @@ @@ -1752,7 +2157,7 @@
} }
@Override @Override
@ -1044,7 +1052,7 @@
if (this.isSleeping()) { if (this.isSleeping()) {
this.stopSleepInBed(true, true); this.stopSleepInBed(true, true);
} }
@@ -1761,7 +2165,7 @@ @@ -1761,7 +2166,7 @@
this.setCamera(this); this.setCamera(this);
} }
@ -1053,7 +1061,7 @@
if (flag1) { if (flag1) {
this.setYHeadRot(set.contains(Relative.Y_ROT) ? this.getYHeadRot() + f : f); this.setYHeadRot(set.contains(Relative.Y_ROT) ? this.getYHeadRot() + f : f);
@@ -1878,6 +2282,16 @@ @@ -1878,6 +2283,16 @@
} }
public void updateOptions(ClientInformation clientinformation) { public void updateOptions(ClientInformation clientinformation) {
@ -1070,7 +1078,7 @@
this.language = clientinformation.language(); this.language = clientinformation.language();
this.requestedViewDistance = clientinformation.viewDistance(); this.requestedViewDistance = clientinformation.viewDistance();
this.chatVisibility = clientinformation.chatVisibility(); this.chatVisibility = clientinformation.chatVisibility();
@@ -1962,7 +2376,7 @@ @@ -1962,7 +2377,7 @@
if (world instanceof WorldServer) { if (world instanceof WorldServer) {
WorldServer worldserver = (WorldServer) world; WorldServer worldserver = (WorldServer) world;
@ -1079,7 +1087,7 @@
} }
if (entity != null) { if (entity != null) {
@@ -1999,11 +2413,11 @@ @@ -1999,11 +2414,11 @@
@Nullable @Nullable
public IChatBaseComponent getTabListDisplayName() { public IChatBaseComponent getTabListDisplayName() {
@ -1093,7 +1101,7 @@
} }
@Override @Override
@@ -2046,6 +2460,32 @@ @@ -2046,6 +2461,32 @@
} }
public void setRespawnPosition(ResourceKey<World> resourcekey, @Nullable BlockPosition blockposition, float f, boolean flag, boolean flag1) { public void setRespawnPosition(ResourceKey<World> resourcekey, @Nullable BlockPosition blockposition, float f, boolean flag, boolean flag1) {
@ -1126,7 +1134,7 @@
if (blockposition != null) { if (blockposition != null) {
boolean flag2 = blockposition.equals(this.respawnPosition) && resourcekey.equals(this.respawnDimension); boolean flag2 = blockposition.equals(this.respawnPosition) && resourcekey.equals(this.respawnDimension);
@@ -2088,12 +2528,38 @@ @@ -2088,12 +2529,38 @@
} }
@Override @Override
@ -1166,7 +1174,7 @@
this.level().addFreshEntity(entityitem); this.level().addFreshEntity(entityitem);
ItemStack itemstack1 = entityitem.getItem(); ItemStack itemstack1 = entityitem.getItem();
@@ -2375,10 +2841,12 @@ @@ -2375,10 +2842,12 @@
return TicketType.ENDER_PEARL.timeout(); return TicketType.ENDER_PEARL.timeout();
} }
@ -1182,7 +1190,7 @@
} }
private static float calculateLookAtYaw(Vec3D vec3d, BlockPosition blockposition) { 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); return (float) MathHelper.wrapDegrees(MathHelper.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D);
} }
} }

View File

@ -21,7 +21,7 @@
public abstract class Container { public abstract class Container {
private static final Logger LOGGER = LogUtils.getLogger(); private static final Logger LOGGER = LogUtils.getLogger();
@@ -67,6 +81,27 @@ @@ -67,6 +81,28 @@
private ContainerSynchronizer synchronizer; private ContainerSynchronizer synchronizer;
private boolean suppressRemoteUpdates; private boolean suppressRemoteUpdates;
@ -44,12 +44,13 @@
+ Preconditions.checkState(this.title == null, "Title already set"); + Preconditions.checkState(this.title == null, "Title already set");
+ this.title = title; + this.title = title;
+ } + }
+ public void startOpen() {}
+ // CraftBukkit end + // CraftBukkit end
+ +
protected Container(@Nullable Containers<?> containers, int i) { protected Container(@Nullable Containers<?> containers, int i) {
this.carried = ItemStack.EMPTY; this.carried = ItemStack.EMPTY;
this.remoteSlots = NonNullList.create(); this.remoteSlots = NonNullList.create();
@@ -192,6 +227,15 @@ @@ -192,6 +228,15 @@
} }
@ -65,7 +66,7 @@
public void removeSlotListener(ICrafting icrafting) { public void removeSlotListener(ICrafting icrafting) {
this.containerListeners.remove(icrafting); this.containerListeners.remove(icrafting);
} }
@@ -417,7 +461,7 @@ @@ -417,7 +462,7 @@
} }
} else if (this.quickcraftStatus == 2) { } else if (this.quickcraftStatus == 2) {
if (!this.quickcraftSlots.isEmpty()) { if (!this.quickcraftSlots.isEmpty()) {
@ -74,7 +75,7 @@
k = ((Slot) this.quickcraftSlots.iterator().next()).index; k = ((Slot) this.quickcraftSlots.iterator().next()).index;
this.resetQuickCraft(); this.resetQuickCraft();
this.doClick(k, this.quickcraftType, InventoryClickType.PICKUP, entityhuman); this.doClick(k, this.quickcraftType, InventoryClickType.PICKUP, entityhuman);
@@ -433,6 +477,7 @@ @@ -433,6 +478,7 @@
l = this.getCarried().getCount(); l = this.getCarried().getCount();
Iterator iterator = this.quickcraftSlots.iterator(); Iterator iterator = this.quickcraftSlots.iterator();
@ -82,7 +83,7 @@
while (iterator.hasNext()) { while (iterator.hasNext()) {
Slot slot1 = (Slot) iterator.next(); Slot slot1 = (Slot) iterator.next();
ItemStack itemstack2 = this.getCarried(); ItemStack itemstack2 = this.getCarried();
@@ -443,12 +488,48 @@ @@ -443,12 +489,48 @@
int l1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemstack1) + j1, k1); int l1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemstack1) + j1, k1);
l -= l1 - j1; l -= l1 - j1;
@ -134,7 +135,7 @@
} }
this.resetQuickCraft(); this.resetQuickCraft();
@@ -466,8 +547,11 @@ @@ -466,8 +548,11 @@
if (i == -999) { if (i == -999) {
if (!this.getCarried().isEmpty()) { if (!this.getCarried().isEmpty()) {
if (clickaction == ClickAction.PRIMARY) { if (clickaction == ClickAction.PRIMARY) {
@ -147,7 +148,7 @@
} else { } else {
entityhuman.drop(this.getCarried().split(1), true); entityhuman.drop(this.getCarried().split(1), true);
} }
@@ -530,6 +614,15 @@ @@ -530,6 +615,15 @@
} }
slot.setChanged(); slot.setChanged();
@ -163,7 +164,7 @@
} }
} else { } else {
int j2; int j2;
@@ -662,8 +755,9 @@ @@ -662,8 +756,9 @@
ItemStack itemstack = this.getCarried(); ItemStack itemstack = this.getCarried();
if (!itemstack.isEmpty()) { if (!itemstack.isEmpty()) {
@ -174,7 +175,7 @@
} }
} }
@@ -893,6 +987,11 @@ @@ -893,6 +988,11 @@
} }
public ItemStack getCarried() { public ItemStack getCarried() {

View File

@ -1,6 +1,6 @@
--- a/net/minecraft/world/inventory/ContainerChest.java --- a/net/minecraft/world/inventory/ContainerChest.java
+++ b/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.entity.player.PlayerInventory;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -36,21 +36,28 @@
+ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); + bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return bukkitEntity; + return bukkitEntity;
+ } + }
+
+ @Override
+ public void startOpen() {
+ this.container.startOpen(this.player.player);
+ }
+ // CraftBukkit end + // CraftBukkit end
private ContainerChest(Containers<?> containers, int i, PlayerInventory playerinventory, int j) { private ContainerChest(Containers<?> containers, int i, PlayerInventory playerinventory, int j) {
this(containers, i, playerinventory, new InventorySubcontainer(9 * j), 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.container = iinventory;
this.containerRows = j; 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 + // CraftBukkit start - Save player
+ this.player = playerinventory; + this.player = playerinventory;
+ // CraftBukkit end + // CraftBukkit end
boolean flag = true; boolean flag = true;
this.addChestGrid(iinventory, 8, 18); this.addChestGrid(iinventory, 8, 18);
@@ -72,6 +104,7 @@ @@ -72,6 +109,7 @@
@Override @Override
public boolean stillValid(EntityHuman entityhuman) { public boolean stillValid(EntityHuman entityhuman) {

View File

@ -37,7 +37,15 @@
this.addStandardInventorySlots(playerinventory, 108, 84); 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() { private void playTradeSound() {

View File

@ -1,6 +1,6 @@
--- a/net/minecraft/world/inventory/ContainerShulkerBox.java --- a/net/minecraft/world/inventory/ContainerShulkerBox.java
+++ b/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.entity.player.PlayerInventory;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -26,19 +26,26 @@
+ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), new CraftInventory(this.container), this); + bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), new CraftInventory(this.container), this);
+ return bukkitEntity; + return bukkitEntity;
+ } + }
+
+ @Override
+ public void startOpen() {
+ container.startOpen(player.player);
+ }
+ // CraftBukkit end + // CraftBukkit end
public ContainerShulkerBox(int i, PlayerInventory playerinventory) { public ContainerShulkerBox(int i, PlayerInventory playerinventory) {
this(i, playerinventory, new InventorySubcontainer(27)); this(i, playerinventory, new InventorySubcontainer(27));
@@ -19,6 +38,7 @@ @@ -19,7 +43,8 @@
super(Containers.SHULKER_BOX, i); super(Containers.SHULKER_BOX, i);
checkContainerSize(iinventory, 27); checkContainerSize(iinventory, 27);
this.container = iinventory; this.container = iinventory;
- iinventory.startOpen(playerinventory.player);
+ this.player = playerinventory; // CraftBukkit - save 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 flag = true;
boolean flag1 = true; boolean flag1 = true;
@@ -34,6 +54,7 @@
@@ -34,6 +59,7 @@
@Override @Override
public boolean stillValid(EntityHuman entityhuman) { public boolean stillValid(EntityHuman entityhuman) {

View File

@ -1,6 +1,11 @@
--- a/net/minecraft/world/level/block/BlockChest.java --- a/net/minecraft/world/level/block/BlockChest.java
+++ b/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<TileEntityChest, Optional<ITileInventory>> MENU_PROVIDER_COMBINER = new DoubleBlockFinder.Combiner<TileEntityChest, Optional<ITileInventory>>() {
+ public static final DoubleBlockFinder.Combiner<TileEntityChest, Optional<ITileInventory>> MENU_PROVIDER_COMBINER = new DoubleBlockFinder.Combiner<TileEntityChest, Optional<ITileInventory>>() { // PAIL private -> public
public Optional<ITileInventory> acceptDouble(final TileEntityChest tileentitychest, final TileEntityChest tileentitychest1) { public Optional<ITileInventory> acceptDouble(final TileEntityChest tileentitychest, final TileEntityChest tileentitychest1) {
final InventoryLargeChest inventorylargechest = new InventoryLargeChest(tileentitychest, tileentitychest1); final InventoryLargeChest inventorylargechest = new InventoryLargeChest(tileentitychest, tileentitychest1);

View File

@ -22,6 +22,7 @@ import net.minecraft.world.entity.EnumMainHand;
import net.minecraft.world.entity.player.EntityHuman; import net.minecraft.world.entity.player.EntityHuman;
import net.minecraft.world.entity.projectile.EntityFireworks; import net.minecraft.world.entity.projectile.EntityFireworks;
import net.minecraft.world.inventory.Container; import net.minecraft.world.inventory.Container;
import net.minecraft.world.inventory.ContainerMerchant;
import net.minecraft.world.inventory.Containers; import net.minecraft.world.inventory.Containers;
import net.minecraft.world.item.ItemCooldown; import net.minecraft.world.item.ItemCooldown;
import net.minecraft.world.item.crafting.CraftingManager; 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.CraftItemStack;
import org.bukkit.craftbukkit.inventory.CraftMerchantCustom; import org.bukkit.craftbukkit.inventory.CraftMerchantCustom;
import org.bukkit.craftbukkit.inventory.CraftRecipe; import org.bukkit.craftbukkit.inventory.CraftRecipe;
import org.bukkit.craftbukkit.inventory.util.CraftMenus;
import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.entity.Firework; import org.bukkit.entity.Firework;
@ -403,6 +405,11 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
// Now open the window // Now open the window
Containers<?> windowType = CraftContainer.getNotchInventoryType(inventory.getTopInventory()); 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(); String title = inventory.getTitle();
player.connection.send(new PacketPlayOutOpenWindow(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); player.connection.send(new PacketPlayOutOpenWindow(container.containerId, windowType, CraftChatMessage.fromString(title)[0]));
player.containerMenu = container; player.containerMenu = container;

View File

@ -127,7 +127,7 @@ public class CraftContainer extends Container {
if (menu == null) { if (menu == null) {
return Containers.GENERIC_9x3; return Containers.GENERIC_9x3;
} else { } else {
return ((CraftMenuType<?>) menu).getHandle(); return ((CraftMenuType<?, ?>) menu).getHandle();
} }
} }
} }

View File

@ -1,29 +1,25 @@
package org.bukkit.craftbukkit.inventory; package org.bukkit.craftbukkit.inventory;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import java.util.function.Supplier; import java.util.function.Supplier;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries; 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 net.minecraft.world.inventory.Containers;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.inventory.util.CraftMenus; import org.bukkit.craftbukkit.inventory.util.CraftMenus;
import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.MenuType; import org.bukkit.inventory.MenuType;
import org.bukkit.inventory.view.builder.InventoryViewBuilder;
public class CraftMenuType<V extends InventoryView> implements MenuType.Typed<V>, Handleable<Containers<?>> { public class CraftMenuType<V extends InventoryView, B extends InventoryViewBuilder<V>> implements MenuType.Typed<V, B>, Handleable<Containers<?>> {
private final NamespacedKey key; private final NamespacedKey key;
private final Containers<?> handle; private final Containers<?> handle;
private final Supplier<CraftMenus.MenuTypeData<V>> typeData; private final Supplier<CraftMenus.MenuTypeData<V, B>> typeData;
public CraftMenuType(NamespacedKey key, Containers<?> handle) { public CraftMenuType(NamespacedKey key, Containers<?> handle) {
this.key = key; this.key = key;
@ -38,28 +34,23 @@ public class CraftMenuType<V extends InventoryView> implements MenuType.Typed<V>
@Override @Override
public V create(final HumanEntity player, final String title) { public V create(final HumanEntity player, final String title) {
Preconditions.checkArgument(player != null, "The given player must not be null"); return builder().title(title).build(player);
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();
} }
@Override @Override
public Typed<InventoryView> typed() { public B builder() {
return typeData.get().viewBuilder().get();
}
@Override
public Typed<InventoryView, InventoryViewBuilder<InventoryView>> typed() {
return this.typed(InventoryView.class); return this.typed(InventoryView.class);
} }
@Override @Override
public <V extends InventoryView> Typed<V> typed(Class<V> clazz) { public <V extends InventoryView, B extends InventoryViewBuilder<V>> Typed<V, B> typed(Class<V> clazz) {
if (clazz.isAssignableFrom(typeData.get().viewClass())) { if (clazz.isAssignableFrom(typeData.get().viewClass())) {
return (Typed<V>) this; return (Typed<V, B>) this;
} }
throw new IllegalArgumentException("Cannot type InventoryView " + this.key.toString() + " to InventoryView type " + clazz.getSimpleName()); throw new IllegalArgumentException("Cannot type InventoryView " + this.key.toString() + " to InventoryView type " + clazz.getSimpleName());

View File

@ -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);
}
}

View File

@ -1,15 +1,20 @@
package org.bukkit.craftbukkit.inventory.util; package org.bukkit.craftbukkit.inventory.util;
import static org.bukkit.craftbukkit.inventory.util.CraftMenuBuilder.*; import java.util.function.Supplier;
import net.minecraft.network.chat.IChatBaseComponent; import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow;
import net.minecraft.world.TileInventory; import net.minecraft.server.level.EntityPlayer;
import net.minecraft.world.entity.npc.EntityVillager;
import net.minecraft.world.inventory.ContainerAnvil; import net.minecraft.world.inventory.ContainerAnvil;
import net.minecraft.world.inventory.ContainerCartography; import net.minecraft.world.inventory.ContainerCartography;
import net.minecraft.world.inventory.ContainerEnchantTable; import net.minecraft.world.inventory.ContainerEnchantTable;
import net.minecraft.world.inventory.ContainerGrindstone; import net.minecraft.world.inventory.ContainerGrindstone;
import net.minecraft.world.inventory.ContainerMerchant;
import net.minecraft.world.inventory.ContainerSmithing; import net.minecraft.world.inventory.ContainerSmithing;
import net.minecraft.world.inventory.ContainerStonecutter; import net.minecraft.world.inventory.ContainerStonecutter;
import net.minecraft.world.inventory.ContainerWorkbench; 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.Blocks;
import net.minecraft.world.level.block.entity.CrafterBlockEntity; import net.minecraft.world.level.block.entity.CrafterBlockEntity;
import net.minecraft.world.level.block.entity.TileEntityBeacon; 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.TileEntityLectern;
import net.minecraft.world.level.block.entity.TileEntitySmoker; import net.minecraft.world.level.block.entity.TileEntitySmoker;
import org.bukkit.craftbukkit.inventory.CraftMenuType; 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.InventoryView;
import org.bukkit.inventory.MenuType; import org.bukkit.inventory.MenuType;
import org.bukkit.inventory.view.AnvilView; 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.LoomView;
import org.bukkit.inventory.view.MerchantView; import org.bukkit.inventory.view.MerchantView;
import org.bukkit.inventory.view.StonecutterView; import org.bukkit.inventory.view.StonecutterView;
import org.bukkit.inventory.view.builder.InventoryViewBuilder;
public final class CraftMenus { public final class CraftMenus {
public record MenuTypeData<V extends InventoryView>(Class<V> viewClass, CraftMenuBuilder menuBuilder) { public record MenuTypeData<V extends InventoryView, B extends InventoryViewBuilder<V>>(Class<V> viewClass, Supplier<B> 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 <V extends InventoryView> MenuTypeData<V> 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 <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuTypeData<V, B> 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 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 // this needs to be removed when inventory creation is overhauled
if (menuType == MenuType.GENERIC_3X3) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { if (menuType == MenuType.ENCHANTMENT) {
return asType(new MenuTypeData<>(EnchantmentView.class, (player, type) -> { return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, ContainerEnchantTable::new)));
return new TileInventory((syncId, inventory, human) -> {
return worldAccess(ContainerEnchantTable::new).build(player, type);
}, IChatBaseComponent.empty()).createMenu(player.nextContainerCounter(), player.getInventory(), player);
}));
} }
if (menuType == MenuType.FURNACE) { 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) { 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 // We really don't need to be creating a tile entity for hopper but currently InventoryType doesn't have capacity
// to understand otherwise // to understand otherwise
if (menuType == MenuType.HOPPER) { 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 // 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) { 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) { if (menuType == MenuType.LOOM) {
return asType(new MenuTypeData<>(LoomView.class, STANDARD)); return asType(new MenuTypeData<>(LoomView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));
} }
if (menuType == MenuType.MERCHANT) { 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) { 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) { 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) { 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) { 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 <V extends InventoryView> MenuTypeData<V> asType(MenuTypeData<?> data) { private static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuTypeData<V, B> asType(MenuTypeData<?, ?> data) {
return (MenuTypeData<V>) data; return (MenuTypeData<V, B>) data;
} }
} }

View File

@ -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<V extends InventoryView> implements InventoryViewBuilder<V> {
protected final Containers<?> handle;
protected boolean checkReachable = false;
protected String title = null;
public CraftAbstractInventoryViewBuilder(Containers<?> handle) {
this.handle = handle;
}
@NotNull
@Override
public InventoryViewBuilder<V> 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);
}

View File

@ -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<V extends InventoryView> extends CraftAbstractInventoryViewBuilder<V> implements LocationInventoryViewBuilder<V> {
protected World world;
protected BlockPosition position;
public CraftAbstractLocationInventoryViewBuilder(final Containers<?> handle) {
super(handle);
}
@Override
public LocationInventoryViewBuilder<V> checkReachable(final boolean checkReachable) {
super.checkReachable = checkReachable;
return this;
}
@Override
public LocationInventoryViewBuilder<V> 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;
}
}

View File

@ -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<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
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<V> copy() {
CraftAccessLocationInventoryViewBuilder<V> 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);
}
}

View File

@ -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<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
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<V> copy() {
final CraftBlockEntityInventoryViewBuilder<V> 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);
}
}

View File

@ -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<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
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<? extends TileEntityChest> result = chest.combine(super.world.getBlockState(super.position), super.world, super.position, false);
if (result instanceof DoubleBlockFinder.Result.Single<? extends TileEntityChest>) {
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<V> copy() {
final CraftDoubleChestInventoryViewBuilder<V> copy = new CraftDoubleChestInventoryViewBuilder<>(super.handle);
copy.world = this.world;
copy.position = this.position;
copy.checkReachable = super.checkReachable;
copy.title = title;
return copy;
}
}

View File

@ -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<V extends InventoryView> extends CraftAbstractInventoryViewBuilder<V> implements MerchantInventoryViewBuilder<V> {
private IMerchant merchant;
public CraftMerchantInventoryViewBuilder(final Containers<?> handle) {
super(handle);
}
@Override
public MerchantInventoryViewBuilder<V> merchant(final Merchant merchant) {
this.merchant = ((CraftMerchant) merchant).getMerchant();
return this;
}
@NotNull
@Override
public MerchantInventoryViewBuilder<V> 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<V> copy() {
CraftMerchantInventoryViewBuilder<V> copy = new CraftMerchantInventoryViewBuilder<>(super.handle);
copy.checkReachable = super.checkReachable;
copy.merchant = this.merchant;
copy.title = title;
return copy;
}
}

View File

@ -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<V extends InventoryView> extends CraftAbstractInventoryViewBuilder<V> {
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<V> copy() {
final CraftStandardInventoryViewBuilder<V> copy = new CraftStandardInventoryViewBuilder<>(handle);
copy.title = this.title;
return copy;
}
}