From a419776f3c019f0daf0914b2a161f3c0a54500be Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Wed, 26 Nov 2014 08:32:16 +1100 Subject: [PATCH] Update to Minecraft 1.8 For more information please see http://www.spigotmc.org/ By: Thinkofdeath --- paper-server/.gitignore | 2 + paper-server/makePatches.sh | 16 + .../nms-patches/BiomeTheEndDecorator.patch | 11 + paper-server/nms-patches/Block.patch | 23 + .../nms-patches/BlockBloodStone.patch | 28 + .../nms-patches/BlockButtonAbstract.patch | 111 ++ paper-server/nms-patches/BlockCactus.patch | 31 + paper-server/nms-patches/BlockCake.patch | 22 + paper-server/nms-patches/BlockCocoa.patch | 35 + paper-server/nms-patches/BlockCommand.patch | 34 + paper-server/nms-patches/BlockCrops.patch | 35 + .../nms-patches/BlockDaylightDetector.patch | 10 + .../nms-patches/BlockDiodeAbstract.patch | 30 + paper-server/nms-patches/BlockDispenser.patch | 18 + paper-server/nms-patches/BlockDoor.patch | 43 + paper-server/nms-patches/BlockDragonEgg.patch | 30 + paper-server/nms-patches/BlockDropper.patch | 41 + .../nms-patches/BlockEnderPortal.patch | 22 + paper-server/nms-patches/BlockFire.patch | 110 ++ paper-server/nms-patches/BlockFlowing.patch | 83 + paper-server/nms-patches/BlockGrass.patch | 77 + paper-server/nms-patches/BlockIce.patch | 15 + paper-server/nms-patches/BlockLeaves.patch | 26 + paper-server/nms-patches/BlockLever.patch | 32 + .../nms-patches/BlockMinecartDetector.patch | 29 + .../nms-patches/BlockMobSpawner.patch | 22 + .../nms-patches/BlockMonsterEggs.patch | 20 + paper-server/nms-patches/BlockMushroom.patch | 57 + paper-server/nms-patches/BlockMycel.patch | 58 + .../nms-patches/BlockNetherWart.patch | 12 + paper-server/nms-patches/BlockOre.patch | 42 + paper-server/nms-patches/BlockPiston.patch | 76 + paper-server/nms-patches/BlockPortal.patch | 53 + .../nms-patches/BlockPoweredRail.patch | 25 + .../BlockPressurePlateAbstract.patch | 31 + .../BlockPressurePlateBinary.patch | 38 + .../BlockPressurePlateWeighted.patch | 43 + paper-server/nms-patches/BlockPumpkin.patch | 117 ++ .../nms-patches/BlockRedstoneLamp.patch | 47 + .../nms-patches/BlockRedstoneOre.patch | 102 ++ .../nms-patches/BlockRedstoneTorch.patch | 55 + .../nms-patches/BlockRedstoneWire.patch | 27 + paper-server/nms-patches/BlockReed.patch | 18 + paper-server/nms-patches/BlockSapling.patch | 125 ++ paper-server/nms-patches/BlockSkull.patch | 133 ++ paper-server/nms-patches/BlockSnow.patch | 14 + paper-server/nms-patches/BlockSoil.patch | 52 + .../nms-patches/BlockStationary.patch | 40 + paper-server/nms-patches/BlockStem.patch | 41 + paper-server/nms-patches/BlockTrapdoor.patch | 31 + paper-server/nms-patches/BlockTripwire.patch | 52 + .../nms-patches/BlockTripwireHook.patch | 29 + paper-server/nms-patches/BlockVine.patch | 76 + paper-server/nms-patches/Chunk.patch | 169 ++ .../nms-patches/ChunkProviderServer.patch | 348 ++++ .../nms-patches/ChunkRegionLoader.patch | 131 ++ paper-server/nms-patches/ChunkSection.patch | 21 + .../CommandBlockListenerAbstract.patch | 162 ++ paper-server/nms-patches/Container.patch | 204 +++ paper-server/nms-patches/ContainerAnvil.patch | 51 + .../nms-patches/ContainerAnvilInventory.patch | 58 + .../nms-patches/ContainerBeacon.patch | 47 + .../nms-patches/ContainerBrewingStand.patch | 52 + paper-server/nms-patches/ContainerChest.patch | 59 + .../nms-patches/ContainerDispenser.patch | 54 + .../nms-patches/ContainerEnchantTable.patch | 170 ++ .../ContainerEnchantTableInventory.patch | 58 + .../nms-patches/ContainerFurnace.patch | 51 + .../nms-patches/ContainerHopper.patch | 44 + paper-server/nms-patches/ContainerHorse.patch | 36 + .../nms-patches/ContainerMerchant.patch | 36 + .../nms-patches/ContainerPlayer.patch | 74 + .../nms-patches/ContainerWorkbench.patch | 79 + paper-server/nms-patches/ControllerLook.patch | 23 + paper-server/nms-patches/ControllerMove.patch | 12 + .../nms-patches/CraftingManager.patch | 57 + paper-server/nms-patches/CrashReport.patch | 10 + .../nms-patches/DedicatedServer.patch | 162 ++ .../nms-patches/DispenseBehaviorArmor.patch | 59 + .../nms-patches/DispenseBehaviorBoat.patch | 54 + .../DispenseBehaviorBonemeal.patch | 44 + .../DispenseBehaviorEmptyBucket.patch | 44 + .../DispenseBehaviorFilledBucket.patch | 65 + .../DispenseBehaviorFireball.patch | 55 + .../DispenseBehaviorFlintAndSteel.patch | 57 + .../nms-patches/DispenseBehaviorItem.patch | 76 + .../DispenseBehaviorMinecart.patch | 58 + .../DispenseBehaviorMonsterEgg.patch | 61 + .../DispenseBehaviorProjectile.patch | 54 + .../nms-patches/DispenseBehaviorTNT.patch | 56 + paper-server/nms-patches/Enchantment.patch | 19 + paper-server/nms-patches/Entity.patch | 578 +++++++ paper-server/nms-patches/EntityAgeable.patch | 48 + paper-server/nms-patches/EntityArrow.patch | 106 ++ paper-server/nms-patches/EntityBoat.patch | 249 +++ paper-server/nms-patches/EntityChicken.patch | 14 + paper-server/nms-patches/EntityCow.patch | 42 + paper-server/nms-patches/EntityCreature.patch | 31 + paper-server/nms-patches/EntityCreeper.patch | 104 ++ .../EntityDamageSourceIndirect.patch | 14 + paper-server/nms-patches/EntityEgg.patch | 65 + .../nms-patches/EntityEnderCrystal.patch | 43 + .../nms-patches/EntityEnderDragon.patch | 330 ++++ .../nms-patches/EntityEnderPearl.patch | 50 + paper-server/nms-patches/EntityEnderman.patch | 34 + .../nms-patches/EntityExperienceOrb.patch | 82 + .../nms-patches/EntityFallingBlock.patch | 44 + paper-server/nms-patches/EntityFireball.patch | 111 ++ .../nms-patches/EntityFishingHook.patch | 159 ++ paper-server/nms-patches/EntityHanging.patch | 111 ++ paper-server/nms-patches/EntityHorse.patch | 140 ++ paper-server/nms-patches/EntityHuman.patch | 383 +++++ .../nms-patches/EntityInsentient.patch | 164 ++ .../nms-patches/EntityIronGolem.patch | 11 + paper-server/nms-patches/EntityItem.patch | 115 ++ .../nms-patches/EntityItemFrame.patch | 15 + .../nms-patches/EntityLargeFireball.patch | 38 + paper-server/nms-patches/EntityLeash.patch | 61 + .../nms-patches/EntityLightning.patch | 111 ++ paper-server/nms-patches/EntityLiving.patch | 440 +++++ .../nms-patches/EntityMinecartAbstract.patch | 231 +++ .../EntityMinecartCommandBlockListener.patch | 10 + .../nms-patches/EntityMinecartContainer.patch | 61 + paper-server/nms-patches/EntityMonster.patch | 26 + .../nms-patches/EntityMushroomCow.patch | 26 + paper-server/nms-patches/EntityOcelot.patch | 30 + paper-server/nms-patches/EntityPainting.patch | 10 + paper-server/nms-patches/EntityPig.patch | 29 + paper-server/nms-patches/EntityPlayer.patch | 542 ++++++ paper-server/nms-patches/EntityPotion.patch | 70 + .../nms-patches/EntityProjectile.patch | 31 + paper-server/nms-patches/EntitySheep.patch | 54 + paper-server/nms-patches/EntitySkeleton.patch | 60 + paper-server/nms-patches/EntitySlime.patch | 40 + .../nms-patches/EntitySmallFireball.patch | 39 + paper-server/nms-patches/EntitySnowman.patch | 42 + paper-server/nms-patches/EntitySpider.patch | 11 + paper-server/nms-patches/EntitySquid.patch | 37 + .../nms-patches/EntityTNTPrimed.patch | 52 + .../nms-patches/EntityThrownExpBottle.patch | 22 + .../nms-patches/EntityTrackerEntry.patch | 176 ++ paper-server/nms-patches/EntityVillager.patch | 19 + paper-server/nms-patches/EntityWither.patch | 78 + .../nms-patches/EntityWitherSkull.patch | 36 + paper-server/nms-patches/EntityWolf.patch | 87 + paper-server/nms-patches/EntityZombie.patch | 108 ++ .../nms-patches/ExpirableListEntry.patch | 42 + paper-server/nms-patches/Explosion.patch | 127 ++ paper-server/nms-patches/FoodMetaData.patch | 66 + .../nms-patches/HandshakeListener.patch | 69 + paper-server/nms-patches/IDataManager.patch | 18 + paper-server/nms-patches/IInventory.patch | 31 + paper-server/nms-patches/IRecipe.patch | 9 + .../nms-patches/InventoryCraftResult.patch | 48 + .../nms-patches/InventoryCrafting.patch | 64 + .../nms-patches/InventoryEnderChest.patch | 51 + .../nms-patches/InventoryHorseChest.patch | 63 + .../nms-patches/InventoryLargeChest.patch | 66 + .../nms-patches/InventoryMerchant.patch | 59 + .../nms-patches/InventorySubcontainer.patch | 59 + paper-server/nms-patches/ItemBoat.patch | 17 + paper-server/nms-patches/ItemBow.patch | 49 + paper-server/nms-patches/ItemBucket.patch | 102 ++ paper-server/nms-patches/ItemDye.patch | 28 + paper-server/nms-patches/ItemFireball.patch | 19 + paper-server/nms-patches/ItemFishingRod.patch | 31 + .../nms-patches/ItemFlintAndSteel.patch | 47 + paper-server/nms-patches/ItemHanging.patch | 41 + paper-server/nms-patches/ItemLeash.patch | 35 + paper-server/nms-patches/ItemMapEmpty.patch | 24 + paper-server/nms-patches/ItemMinecart.patch | 16 + paper-server/nms-patches/ItemMonsterEgg.patch | 25 + paper-server/nms-patches/ItemStack.patch | 219 +++ paper-server/nms-patches/ItemWaterLily.patch | 18 + paper-server/nms-patches/ItemWorldMap.patch | 75 + paper-server/nms-patches/JsonList.patch | 33 + paper-server/nms-patches/LoginListener.patch | 35 + paper-server/nms-patches/MethodProfiler.patch | 135 ++ .../nms-patches/MinecraftServer.patch | 726 ++++++++ paper-server/nms-patches/MobEffectList.patch | 74 + .../nms-patches/MobSpawnerAbstract.patch | 38 + .../NameReferencingFileConverter.patch | 76 + paper-server/nms-patches/NetworkManager.patch | 20 + paper-server/nms-patches/Packet.patch | 14 + .../nms-patches/PacketDataSerializer.patch | 122 ++ .../nms-patches/PacketPlayInBlockPlace.patch | 32 + .../nms-patches/PacketPlayInCloseWindow.patch | 29 + .../nms-patches/PacketStatusListener.patch | 113 ++ paper-server/nms-patches/Path.patch | 11 + .../nms-patches/PathfinderGoalBreakDoor.patch | 15 + .../nms-patches/PathfinderGoalBreed.patch | 23 + .../PathfinderGoalDefendVillage.patch | 11 + .../nms-patches/PathfinderGoalEatTile.patch | 34 + .../PathfinderGoalEndermanPickupBlock.patch | 17 + .../PathfinderGoalEndermanPlaceBlock.patch | 15 + .../PathfinderGoalGhastAttackTarget.patch | 12 + .../PathfinderGoalHurtByTarget.patch | 19 + .../nms-patches/PathfinderGoalMakeLove.patch | 11 + ...athfinderGoalNearestAttackableTarget.patch | 11 + ...oalNearestAttackableTargetInsentient.patch | 11 + .../PathfinderGoalOwnerHurtByTarget.patch | 11 + .../PathfinderGoalOwnerHurtTarget.patch | 11 + .../nms-patches/PathfinderGoalPanic.patch | 15 + .../nms-patches/PathfinderGoalSelector.patch | 32 + .../PathfinderGoalSilverfishHideInBlock.patch | 14 + .../PathfinderGoalSilverfishWakeOthers.patch | 14 + .../nms-patches/PathfinderGoalSit.patch | 11 + .../nms-patches/PathfinderGoalTame.patch | 31 + .../PathfinderGoalTargetNearestPlayer.patch | 11 + paper-server/nms-patches/PlayerChunk.patch | 104 ++ paper-server/nms-patches/PlayerChunkMap.patch | 208 +++ .../nms-patches/PlayerConnection.patch | 1458 +++++++++++++++++ .../nms-patches/PlayerDatFileConverter.patch | 33 + .../nms-patches/PlayerInteractManager.patch | 289 ++++ .../nms-patches/PlayerInventory.patch | 100 ++ paper-server/nms-patches/PlayerList.patch | 788 +++++++++ paper-server/nms-patches/PlayerSelector.patch | 14 + paper-server/nms-patches/PortalCreator.patch | 102 ++ .../nms-patches/PortalTravelAgent.patch | 273 +++ .../nms-patches/PropertyManager.patch | 94 ++ paper-server/nms-patches/RecipeArmorDye.patch | 18 + .../nms-patches/RecipeBookClone.patch | 17 + .../nms-patches/RecipeFireworks.patch | 21 + paper-server/nms-patches/RecipeMapClone.patch | 17 + paper-server/nms-patches/RecipeRepair.patch | 39 + .../RecipesBannerInnerClass1.patch | 17 + .../RecipesBannerInnerClass2.patch | 17 + paper-server/nms-patches/RecipesFurnace.patch | 49 + paper-server/nms-patches/RegionFile.patch | 81 + .../RemoteControlCommandListener.patch | 15 + .../nms-patches/ScoreboardServer.patch | 126 ++ .../nms-patches/SecondaryWorldServer.patch | 15 + paper-server/nms-patches/ShapedRecipes.patch | 77 + .../nms-patches/ShapelessRecipes.patch | 35 + .../nms-patches/SlotFurnaceResult.patch | 31 + .../nms-patches/SpawnerCreature.patch | 109 ++ .../nms-patches/StatisticManager.patch | 15 + .../nms-patches/SwitchHelperLogVariant.patch | 9 + .../nms-patches/ThreadCommandReader.patch | 43 + .../nms-patches/ThreadPlayerLookupUUID.patch | 72 + paper-server/nms-patches/TileEntity.patch | 24 + .../nms-patches/TileEntityBeacon.patch | 54 + .../nms-patches/TileEntityBrewingStand.patch | 94 ++ .../nms-patches/TileEntityChest.patch | 104 ++ .../TileEntityCommandListener.patch | 10 + .../nms-patches/TileEntityDispenser.patch | 63 + .../nms-patches/TileEntityFurnace.patch | 183 +++ .../nms-patches/TileEntityHopper.patch | 154 ++ paper-server/nms-patches/TileEntityNote.patch | 16 + .../nms-patches/TileEntityPiston.patch | 10 + .../nms-patches/TileEntityRecordPlayer.patch | 14 + .../nms-patches/TileEntitySkull.patch | 13 + paper-server/nms-patches/Village.patch | 11 + paper-server/nms-patches/VillageSiege.patch | 11 + paper-server/nms-patches/World.patch | 560 +++++++ paper-server/nms-patches/WorldBorder.patch | 25 + .../nms-patches/WorldGenGroundBush.patch | 14 + .../WorldGenMegaTreeAbstract.patch | 11 + .../nms-patches/WorldGenVillagePiece.patch | 11 + .../nms-patches/WorldGenVillagePieces.patch | 0 .../nms-patches/WorldGenWitchHut.patch | 11 + paper-server/nms-patches/WorldManager.patch | 28 + paper-server/nms-patches/WorldMap.patch | 95 ++ .../nms-patches/WorldMapHumanTracker.patch | 31 + .../nms-patches/WorldNBTStorage.patch | 123 ++ paper-server/nms-patches/WorldServer.patch | 550 +++++++ paper-server/pom.xml | 31 +- .../java/org/bukkit/craftbukkit/CraftArt.java | 12 +- .../org/bukkit/craftbukkit/CraftChunk.java | 62 +- .../craftbukkit/CraftOfflinePlayer.java | 2 +- .../craftbukkit/CraftProfileBanEntry.java | 2 +- .../craftbukkit/CraftProfileBanList.java | 2 +- .../org/bukkit/craftbukkit/CraftServer.java | 200 +-- .../bukkit/craftbukkit/CraftStatistic.java | 16 +- .../bukkit/craftbukkit/CraftTravelAgent.java | 15 +- .../org/bukkit/craftbukkit/CraftWorld.java | 86 +- .../bukkit/craftbukkit/block/CraftBanner.java | 105 ++ .../bukkit/craftbukkit/block/CraftBlock.java | 119 +- .../craftbukkit/block/CraftBlockState.java | 3 +- .../bukkit/craftbukkit/block/CraftChest.java | 9 +- .../craftbukkit/block/CraftDispenser.java | 3 +- .../craftbukkit/block/CraftDropper.java | 3 +- .../craftbukkit/block/CraftJukebox.java | 15 +- .../craftbukkit/block/CraftNoteBlock.java | 7 +- .../bukkit/craftbukkit/block/CraftSign.java | 30 +- .../bukkit/craftbukkit/block/CraftSkull.java | 4 +- .../craftbukkit/chunkio/ChunkIOProvider.java | 6 +- .../command/CraftBlockCommandSender.java | 2 +- .../CraftRemoteConsoleCommandSender.java | 3 +- .../command/VanillaCommandWrapper.java | 68 +- .../craftbukkit/entity/CraftArmorStand.java | 214 +++ .../bukkit/craftbukkit/entity/CraftArrow.java | 2 +- .../craftbukkit/entity/CraftCreature.java | 13 +- .../craftbukkit/entity/CraftEnderman.java | 7 +- .../craftbukkit/entity/CraftEndermite.java | 23 + .../craftbukkit/entity/CraftEntity.java | 50 +- .../craftbukkit/entity/CraftFallingSand.java | 4 +- .../bukkit/craftbukkit/entity/CraftFish.java | 3 +- .../craftbukkit/entity/CraftGuardian.java | 23 + .../craftbukkit/entity/CraftHanging.java | 29 +- .../bukkit/craftbukkit/entity/CraftHorse.java | 2 +- .../craftbukkit/entity/CraftHumanEntity.java | 45 +- .../craftbukkit/entity/CraftLivingEntity.java | 49 +- .../craftbukkit/entity/CraftPainting.java | 4 +- .../craftbukkit/entity/CraftPlayer.java | 140 +- .../craftbukkit/entity/CraftRabbit.java | 23 + .../bukkit/craftbukkit/entity/CraftSheep.java | 5 +- .../entity/CraftTameableAnimal.java | 2 +- .../craftbukkit/entity/CraftVillager.java | 10 +- .../craftbukkit/entity/CraftWaterMob.java | 3 +- .../bukkit/craftbukkit/entity/CraftWolf.java | 5 +- .../craftbukkit/event/CraftEventFactory.java | 63 +- .../generator/CustomChunkGenerator.java | 70 +- .../generator/NormalChunkGenerator.java | 48 +- .../craftbukkit/inventory/CraftContainer.java | 36 +- .../craftbukkit/inventory/CraftInventory.java | 9 +- .../inventory/CraftInventoryCrafting.java | 2 +- .../inventory/CraftInventoryCustom.java | 61 +- .../inventory/CraftInventoryDoubleChest.java | 4 +- .../inventory/CraftInventoryEnchanting.java | 12 + .../inventory/CraftItemFactory.java | 2 + .../craftbukkit/inventory/CraftItemStack.java | 38 +- .../inventory/CraftMetaBanner.java | 196 +++ .../craftbukkit/inventory/CraftMetaBook.java | 51 +- .../inventory/CraftMetaCharge.java | 5 +- .../craftbukkit/inventory/CraftMetaSkull.java | 3 +- .../craftbukkit/map/CraftMapCanvas.java | 2 +- .../craftbukkit/map/CraftMapRenderer.java | 7 +- .../CraftBlockProjectileSource.java | 24 +- .../craftbukkit/scoreboard/CraftCriteria.java | 3 - .../scoreboard/CraftScoreboard.java | 8 +- .../craftbukkit/updater/ArtifactDetails.java | 128 -- .../craftbukkit/updater/AutoUpdater.java | 127 -- .../updater/BukkitDLUpdaterService.java | 102 -- .../util/BlockStateListPopulator.java | 7 + .../craftbukkit/util/CraftChatMessage.java | 45 +- .../craftbukkit/util/CraftMagicNumbers.java | 11 +- .../craftbukkit/util/LazyPlayerSet.java | 50 +- .../craftbukkit/util/MojangNameLookup.java | 6 +- .../util/TerminalConsoleWriterThread.java | 2 +- .../main/resources/configurations/bukkit.yml | 7 - .../test/java/org/bukkit/DyeColorsTest.java | 5 +- .../test/java/org/bukkit/PerMaterialTest.java | 11 +- .../craftbukkit/inventory/ItemMetaTest.java | 14 +- .../updater/BukkitDLUpdaterServiceTest.java | 32 - .../bukkit/support/AbstractTestingBase.java | 55 +- .../org/bukkit/support/DummyEnchantments.java | 2 +- 347 files changed, 22151 insertions(+), 1209 deletions(-) create mode 100755 paper-server/makePatches.sh create mode 100644 paper-server/nms-patches/BiomeTheEndDecorator.patch create mode 100644 paper-server/nms-patches/Block.patch create mode 100644 paper-server/nms-patches/BlockBloodStone.patch create mode 100644 paper-server/nms-patches/BlockButtonAbstract.patch create mode 100644 paper-server/nms-patches/BlockCactus.patch create mode 100644 paper-server/nms-patches/BlockCake.patch create mode 100644 paper-server/nms-patches/BlockCocoa.patch create mode 100644 paper-server/nms-patches/BlockCommand.patch create mode 100644 paper-server/nms-patches/BlockCrops.patch create mode 100644 paper-server/nms-patches/BlockDaylightDetector.patch create mode 100644 paper-server/nms-patches/BlockDiodeAbstract.patch create mode 100644 paper-server/nms-patches/BlockDispenser.patch create mode 100644 paper-server/nms-patches/BlockDoor.patch create mode 100644 paper-server/nms-patches/BlockDragonEgg.patch create mode 100644 paper-server/nms-patches/BlockDropper.patch create mode 100644 paper-server/nms-patches/BlockEnderPortal.patch create mode 100644 paper-server/nms-patches/BlockFire.patch create mode 100644 paper-server/nms-patches/BlockFlowing.patch create mode 100644 paper-server/nms-patches/BlockGrass.patch create mode 100644 paper-server/nms-patches/BlockIce.patch create mode 100644 paper-server/nms-patches/BlockLeaves.patch create mode 100644 paper-server/nms-patches/BlockLever.patch create mode 100644 paper-server/nms-patches/BlockMinecartDetector.patch create mode 100644 paper-server/nms-patches/BlockMobSpawner.patch create mode 100644 paper-server/nms-patches/BlockMonsterEggs.patch create mode 100644 paper-server/nms-patches/BlockMushroom.patch create mode 100644 paper-server/nms-patches/BlockMycel.patch create mode 100644 paper-server/nms-patches/BlockNetherWart.patch create mode 100644 paper-server/nms-patches/BlockOre.patch create mode 100644 paper-server/nms-patches/BlockPiston.patch create mode 100644 paper-server/nms-patches/BlockPortal.patch create mode 100644 paper-server/nms-patches/BlockPoweredRail.patch create mode 100644 paper-server/nms-patches/BlockPressurePlateAbstract.patch create mode 100644 paper-server/nms-patches/BlockPressurePlateBinary.patch create mode 100644 paper-server/nms-patches/BlockPressurePlateWeighted.patch create mode 100644 paper-server/nms-patches/BlockPumpkin.patch create mode 100644 paper-server/nms-patches/BlockRedstoneLamp.patch create mode 100644 paper-server/nms-patches/BlockRedstoneOre.patch create mode 100644 paper-server/nms-patches/BlockRedstoneTorch.patch create mode 100644 paper-server/nms-patches/BlockRedstoneWire.patch create mode 100644 paper-server/nms-patches/BlockReed.patch create mode 100644 paper-server/nms-patches/BlockSapling.patch create mode 100644 paper-server/nms-patches/BlockSkull.patch create mode 100644 paper-server/nms-patches/BlockSnow.patch create mode 100644 paper-server/nms-patches/BlockSoil.patch create mode 100644 paper-server/nms-patches/BlockStationary.patch create mode 100644 paper-server/nms-patches/BlockStem.patch create mode 100644 paper-server/nms-patches/BlockTrapdoor.patch create mode 100644 paper-server/nms-patches/BlockTripwire.patch create mode 100644 paper-server/nms-patches/BlockTripwireHook.patch create mode 100644 paper-server/nms-patches/BlockVine.patch create mode 100644 paper-server/nms-patches/Chunk.patch create mode 100644 paper-server/nms-patches/ChunkProviderServer.patch create mode 100644 paper-server/nms-patches/ChunkRegionLoader.patch create mode 100644 paper-server/nms-patches/ChunkSection.patch create mode 100644 paper-server/nms-patches/CommandBlockListenerAbstract.patch create mode 100644 paper-server/nms-patches/Container.patch create mode 100644 paper-server/nms-patches/ContainerAnvil.patch create mode 100644 paper-server/nms-patches/ContainerAnvilInventory.patch create mode 100644 paper-server/nms-patches/ContainerBeacon.patch create mode 100644 paper-server/nms-patches/ContainerBrewingStand.patch create mode 100644 paper-server/nms-patches/ContainerChest.patch create mode 100644 paper-server/nms-patches/ContainerDispenser.patch create mode 100644 paper-server/nms-patches/ContainerEnchantTable.patch create mode 100644 paper-server/nms-patches/ContainerEnchantTableInventory.patch create mode 100644 paper-server/nms-patches/ContainerFurnace.patch create mode 100644 paper-server/nms-patches/ContainerHopper.patch create mode 100644 paper-server/nms-patches/ContainerHorse.patch create mode 100644 paper-server/nms-patches/ContainerMerchant.patch create mode 100644 paper-server/nms-patches/ContainerPlayer.patch create mode 100644 paper-server/nms-patches/ContainerWorkbench.patch create mode 100644 paper-server/nms-patches/ControllerLook.patch create mode 100644 paper-server/nms-patches/ControllerMove.patch create mode 100644 paper-server/nms-patches/CraftingManager.patch create mode 100644 paper-server/nms-patches/CrashReport.patch create mode 100644 paper-server/nms-patches/DedicatedServer.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorArmor.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorBoat.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorBonemeal.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorEmptyBucket.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorFilledBucket.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorFireball.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorFlintAndSteel.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorItem.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorMinecart.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorMonsterEgg.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorProjectile.patch create mode 100644 paper-server/nms-patches/DispenseBehaviorTNT.patch create mode 100644 paper-server/nms-patches/Enchantment.patch create mode 100644 paper-server/nms-patches/Entity.patch create mode 100644 paper-server/nms-patches/EntityAgeable.patch create mode 100644 paper-server/nms-patches/EntityArrow.patch create mode 100644 paper-server/nms-patches/EntityBoat.patch create mode 100644 paper-server/nms-patches/EntityChicken.patch create mode 100644 paper-server/nms-patches/EntityCow.patch create mode 100644 paper-server/nms-patches/EntityCreature.patch create mode 100644 paper-server/nms-patches/EntityCreeper.patch create mode 100644 paper-server/nms-patches/EntityDamageSourceIndirect.patch create mode 100644 paper-server/nms-patches/EntityEgg.patch create mode 100644 paper-server/nms-patches/EntityEnderCrystal.patch create mode 100644 paper-server/nms-patches/EntityEnderDragon.patch create mode 100644 paper-server/nms-patches/EntityEnderPearl.patch create mode 100644 paper-server/nms-patches/EntityEnderman.patch create mode 100644 paper-server/nms-patches/EntityExperienceOrb.patch create mode 100644 paper-server/nms-patches/EntityFallingBlock.patch create mode 100644 paper-server/nms-patches/EntityFireball.patch create mode 100644 paper-server/nms-patches/EntityFishingHook.patch create mode 100644 paper-server/nms-patches/EntityHanging.patch create mode 100644 paper-server/nms-patches/EntityHorse.patch create mode 100644 paper-server/nms-patches/EntityHuman.patch create mode 100644 paper-server/nms-patches/EntityInsentient.patch create mode 100644 paper-server/nms-patches/EntityIronGolem.patch create mode 100644 paper-server/nms-patches/EntityItem.patch create mode 100644 paper-server/nms-patches/EntityItemFrame.patch create mode 100644 paper-server/nms-patches/EntityLargeFireball.patch create mode 100644 paper-server/nms-patches/EntityLeash.patch create mode 100644 paper-server/nms-patches/EntityLightning.patch create mode 100644 paper-server/nms-patches/EntityLiving.patch create mode 100644 paper-server/nms-patches/EntityMinecartAbstract.patch create mode 100644 paper-server/nms-patches/EntityMinecartCommandBlockListener.patch create mode 100644 paper-server/nms-patches/EntityMinecartContainer.patch create mode 100644 paper-server/nms-patches/EntityMonster.patch create mode 100644 paper-server/nms-patches/EntityMushroomCow.patch create mode 100644 paper-server/nms-patches/EntityOcelot.patch create mode 100644 paper-server/nms-patches/EntityPainting.patch create mode 100644 paper-server/nms-patches/EntityPig.patch create mode 100644 paper-server/nms-patches/EntityPlayer.patch create mode 100644 paper-server/nms-patches/EntityPotion.patch create mode 100644 paper-server/nms-patches/EntityProjectile.patch create mode 100644 paper-server/nms-patches/EntitySheep.patch create mode 100644 paper-server/nms-patches/EntitySkeleton.patch create mode 100644 paper-server/nms-patches/EntitySlime.patch create mode 100644 paper-server/nms-patches/EntitySmallFireball.patch create mode 100644 paper-server/nms-patches/EntitySnowman.patch create mode 100644 paper-server/nms-patches/EntitySpider.patch create mode 100644 paper-server/nms-patches/EntitySquid.patch create mode 100644 paper-server/nms-patches/EntityTNTPrimed.patch create mode 100644 paper-server/nms-patches/EntityThrownExpBottle.patch create mode 100644 paper-server/nms-patches/EntityTrackerEntry.patch create mode 100644 paper-server/nms-patches/EntityVillager.patch create mode 100644 paper-server/nms-patches/EntityWither.patch create mode 100644 paper-server/nms-patches/EntityWitherSkull.patch create mode 100644 paper-server/nms-patches/EntityWolf.patch create mode 100644 paper-server/nms-patches/EntityZombie.patch create mode 100644 paper-server/nms-patches/ExpirableListEntry.patch create mode 100644 paper-server/nms-patches/Explosion.patch create mode 100644 paper-server/nms-patches/FoodMetaData.patch create mode 100644 paper-server/nms-patches/HandshakeListener.patch create mode 100644 paper-server/nms-patches/IDataManager.patch create mode 100644 paper-server/nms-patches/IInventory.patch create mode 100644 paper-server/nms-patches/IRecipe.patch create mode 100644 paper-server/nms-patches/InventoryCraftResult.patch create mode 100644 paper-server/nms-patches/InventoryCrafting.patch create mode 100644 paper-server/nms-patches/InventoryEnderChest.patch create mode 100644 paper-server/nms-patches/InventoryHorseChest.patch create mode 100644 paper-server/nms-patches/InventoryLargeChest.patch create mode 100644 paper-server/nms-patches/InventoryMerchant.patch create mode 100644 paper-server/nms-patches/InventorySubcontainer.patch create mode 100644 paper-server/nms-patches/ItemBoat.patch create mode 100644 paper-server/nms-patches/ItemBow.patch create mode 100644 paper-server/nms-patches/ItemBucket.patch create mode 100644 paper-server/nms-patches/ItemDye.patch create mode 100644 paper-server/nms-patches/ItemFireball.patch create mode 100644 paper-server/nms-patches/ItemFishingRod.patch create mode 100644 paper-server/nms-patches/ItemFlintAndSteel.patch create mode 100644 paper-server/nms-patches/ItemHanging.patch create mode 100644 paper-server/nms-patches/ItemLeash.patch create mode 100644 paper-server/nms-patches/ItemMapEmpty.patch create mode 100644 paper-server/nms-patches/ItemMinecart.patch create mode 100644 paper-server/nms-patches/ItemMonsterEgg.patch create mode 100644 paper-server/nms-patches/ItemStack.patch create mode 100644 paper-server/nms-patches/ItemWaterLily.patch create mode 100644 paper-server/nms-patches/ItemWorldMap.patch create mode 100644 paper-server/nms-patches/JsonList.patch create mode 100644 paper-server/nms-patches/LoginListener.patch create mode 100644 paper-server/nms-patches/MethodProfiler.patch create mode 100644 paper-server/nms-patches/MinecraftServer.patch create mode 100644 paper-server/nms-patches/MobEffectList.patch create mode 100644 paper-server/nms-patches/MobSpawnerAbstract.patch create mode 100644 paper-server/nms-patches/NameReferencingFileConverter.patch create mode 100644 paper-server/nms-patches/NetworkManager.patch create mode 100644 paper-server/nms-patches/Packet.patch create mode 100644 paper-server/nms-patches/PacketDataSerializer.patch create mode 100644 paper-server/nms-patches/PacketPlayInBlockPlace.patch create mode 100644 paper-server/nms-patches/PacketPlayInCloseWindow.patch create mode 100644 paper-server/nms-patches/PacketStatusListener.patch create mode 100644 paper-server/nms-patches/Path.patch create mode 100644 paper-server/nms-patches/PathfinderGoalBreakDoor.patch create mode 100644 paper-server/nms-patches/PathfinderGoalBreed.patch create mode 100644 paper-server/nms-patches/PathfinderGoalDefendVillage.patch create mode 100644 paper-server/nms-patches/PathfinderGoalEatTile.patch create mode 100644 paper-server/nms-patches/PathfinderGoalEndermanPickupBlock.patch create mode 100644 paper-server/nms-patches/PathfinderGoalEndermanPlaceBlock.patch create mode 100644 paper-server/nms-patches/PathfinderGoalGhastAttackTarget.patch create mode 100644 paper-server/nms-patches/PathfinderGoalHurtByTarget.patch create mode 100644 paper-server/nms-patches/PathfinderGoalMakeLove.patch create mode 100644 paper-server/nms-patches/PathfinderGoalNearestAttackableTarget.patch create mode 100644 paper-server/nms-patches/PathfinderGoalNearestAttackableTargetInsentient.patch create mode 100644 paper-server/nms-patches/PathfinderGoalOwnerHurtByTarget.patch create mode 100644 paper-server/nms-patches/PathfinderGoalOwnerHurtTarget.patch create mode 100644 paper-server/nms-patches/PathfinderGoalPanic.patch create mode 100644 paper-server/nms-patches/PathfinderGoalSelector.patch create mode 100644 paper-server/nms-patches/PathfinderGoalSilverfishHideInBlock.patch create mode 100644 paper-server/nms-patches/PathfinderGoalSilverfishWakeOthers.patch create mode 100644 paper-server/nms-patches/PathfinderGoalSit.patch create mode 100644 paper-server/nms-patches/PathfinderGoalTame.patch create mode 100644 paper-server/nms-patches/PathfinderGoalTargetNearestPlayer.patch create mode 100644 paper-server/nms-patches/PlayerChunk.patch create mode 100644 paper-server/nms-patches/PlayerChunkMap.patch create mode 100644 paper-server/nms-patches/PlayerConnection.patch create mode 100644 paper-server/nms-patches/PlayerDatFileConverter.patch create mode 100644 paper-server/nms-patches/PlayerInteractManager.patch create mode 100644 paper-server/nms-patches/PlayerInventory.patch create mode 100644 paper-server/nms-patches/PlayerList.patch create mode 100644 paper-server/nms-patches/PlayerSelector.patch create mode 100644 paper-server/nms-patches/PortalCreator.patch create mode 100644 paper-server/nms-patches/PortalTravelAgent.patch create mode 100644 paper-server/nms-patches/PropertyManager.patch create mode 100644 paper-server/nms-patches/RecipeArmorDye.patch create mode 100644 paper-server/nms-patches/RecipeBookClone.patch create mode 100644 paper-server/nms-patches/RecipeFireworks.patch create mode 100644 paper-server/nms-patches/RecipeMapClone.patch create mode 100644 paper-server/nms-patches/RecipeRepair.patch create mode 100644 paper-server/nms-patches/RecipesBannerInnerClass1.patch create mode 100644 paper-server/nms-patches/RecipesBannerInnerClass2.patch create mode 100644 paper-server/nms-patches/RecipesFurnace.patch create mode 100644 paper-server/nms-patches/RegionFile.patch create mode 100644 paper-server/nms-patches/RemoteControlCommandListener.patch create mode 100644 paper-server/nms-patches/ScoreboardServer.patch create mode 100644 paper-server/nms-patches/SecondaryWorldServer.patch create mode 100644 paper-server/nms-patches/ShapedRecipes.patch create mode 100644 paper-server/nms-patches/ShapelessRecipes.patch create mode 100644 paper-server/nms-patches/SlotFurnaceResult.patch create mode 100644 paper-server/nms-patches/SpawnerCreature.patch create mode 100644 paper-server/nms-patches/StatisticManager.patch create mode 100644 paper-server/nms-patches/SwitchHelperLogVariant.patch create mode 100644 paper-server/nms-patches/ThreadCommandReader.patch create mode 100644 paper-server/nms-patches/ThreadPlayerLookupUUID.patch create mode 100644 paper-server/nms-patches/TileEntity.patch create mode 100644 paper-server/nms-patches/TileEntityBeacon.patch create mode 100644 paper-server/nms-patches/TileEntityBrewingStand.patch create mode 100644 paper-server/nms-patches/TileEntityChest.patch create mode 100644 paper-server/nms-patches/TileEntityCommandListener.patch create mode 100644 paper-server/nms-patches/TileEntityDispenser.patch create mode 100644 paper-server/nms-patches/TileEntityFurnace.patch create mode 100644 paper-server/nms-patches/TileEntityHopper.patch create mode 100644 paper-server/nms-patches/TileEntityNote.patch create mode 100644 paper-server/nms-patches/TileEntityPiston.patch create mode 100644 paper-server/nms-patches/TileEntityRecordPlayer.patch create mode 100644 paper-server/nms-patches/TileEntitySkull.patch create mode 100644 paper-server/nms-patches/Village.patch create mode 100644 paper-server/nms-patches/VillageSiege.patch create mode 100644 paper-server/nms-patches/World.patch create mode 100644 paper-server/nms-patches/WorldBorder.patch create mode 100644 paper-server/nms-patches/WorldGenGroundBush.patch create mode 100644 paper-server/nms-patches/WorldGenMegaTreeAbstract.patch create mode 100644 paper-server/nms-patches/WorldGenVillagePiece.patch create mode 100644 paper-server/nms-patches/WorldGenVillagePieces.patch create mode 100644 paper-server/nms-patches/WorldGenWitchHut.patch create mode 100644 paper-server/nms-patches/WorldManager.patch create mode 100644 paper-server/nms-patches/WorldMap.patch create mode 100644 paper-server/nms-patches/WorldMapHumanTracker.patch create mode 100644 paper-server/nms-patches/WorldNBTStorage.patch create mode 100644 paper-server/nms-patches/WorldServer.patch create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/updater/ArtifactDetails.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/updater/AutoUpdater.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java delete mode 100644 paper-server/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java diff --git a/paper-server/.gitignore b/paper-server/.gitignore index c3faf57741..73c16b1d53 100644 --- a/paper-server/.gitignore +++ b/paper-server/.gitignore @@ -5,12 +5,14 @@ # netbeans /nbproject +nb*.xml # we use maven! /build.xml # maven /target +dependency-reduced-pom.xml # vim .*.sw[a-p] diff --git a/paper-server/makePatches.sh b/paper-server/makePatches.sh new file mode 100755 index 0000000000..771e39f804 --- /dev/null +++ b/paper-server/makePatches.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +if [ -z "$1" ] +then + echo "Please run this script again with the clean decompile sources as an argument. In most cases this will be ../work/decompile-XXXX" + exit +fi + +rm -f nms-patches/* + +for file in $(ls src/main/java/net/minecraft/server) +do + echo "Diffing $file" + dos2unix -q $1/net/minecraft/server/$file $1/net/minecraft/server/$file + diff -u $1/net/minecraft/server/$file src/main/java/net/minecraft/server/$file > nms-patches/"$(echo $file | cut -d. -f1)".patch +done diff --git a/paper-server/nms-patches/BiomeTheEndDecorator.patch b/paper-server/nms-patches/BiomeTheEndDecorator.patch new file mode 100644 index 0000000000..6c957c2a05 --- /dev/null +++ b/paper-server/nms-patches/BiomeTheEndDecorator.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BiomeTheEndDecorator.java 2014-11-27 08:59:46.501422728 +1100 ++++ src/main/java/net/minecraft/server/BiomeTheEndDecorator.java 2014-11-27 08:42:10.136850942 +1100 +@@ -21,7 +21,7 @@ + EntityEnderDragon entityenderdragon = new EntityEnderDragon(this.a); + + entityenderdragon.setPositionRotation(0.0D, 128.0D, 0.0D, this.b.nextFloat() * 360.0F, 0.0F); +- this.a.addEntity(entityenderdragon); ++ this.a.addEntity(entityenderdragon, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - add SpawnReason + } + + } diff --git a/paper-server/nms-patches/Block.patch b/paper-server/nms-patches/Block.patch new file mode 100644 index 0000000000..fc44dc750b --- /dev/null +++ b/paper-server/nms-patches/Block.patch @@ -0,0 +1,23 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Block.java 2014-11-27 08:59:46.537422569 +1100 ++++ src/main/java/net/minecraft/server/Block.java 2014-11-27 08:42:10.172850872 +1100 +@@ -295,7 +295,8 @@ + int j = this.getDropCount(i, world.random); + + for (int k = 0; k < j; ++k) { +- if (world.random.nextFloat() <= f) { ++ // CraftBukkit - <= to < to allow for plugins to completely disable block drops from explosions ++ if (world.random.nextFloat() < f) { + Item item = this.getDropType(iblockdata, world.random, i); + + if (item != null) { +@@ -920,4 +921,10 @@ + private static void a(int i, String s, Block block) { + a(i, new MinecraftKey(s), block); + } ++ ++ // CraftBukkit start ++ public int getExpDrop(World world, IBlockData data, int enchantmentLevel) { ++ return 0; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/BlockBloodStone.patch b/paper-server/nms-patches/BlockBloodStone.patch new file mode 100644 index 0000000000..82233f90e0 --- /dev/null +++ b/paper-server/nms-patches/BlockBloodStone.patch @@ -0,0 +1,28 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockBloodStone.java 2014-11-27 08:59:46.505422709 +1100 ++++ src/main/java/net/minecraft/server/BlockBloodStone.java 2014-11-27 08:42:10.124850965 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockBloodStone extends Block { + + public BlockBloodStone() { +@@ -10,4 +12,17 @@ + public MaterialMapColor g(IBlockData iblockdata) { + return MaterialMapColor.K; + } ++ ++ // CraftBukkit start ++ @Override ++ public void doPhysics(World world, BlockPosition position, IBlockData iblockdata, Block block) { ++ if (block != null && block.isPowerSource()) { ++ org.bukkit.block.Block bl = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()); ++ int power = bl.getBlockPower(); ++ ++ BlockRedstoneEvent event = new BlockRedstoneEvent(bl, power, power); ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/BlockButtonAbstract.patch b/paper-server/nms-patches/BlockButtonAbstract.patch new file mode 100644 index 0000000000..b41c8016fa --- /dev/null +++ b/paper-server/nms-patches/BlockButtonAbstract.patch @@ -0,0 +1,111 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockButtonAbstract.java 2014-11-27 08:59:46.505422709 +1100 ++++ src/main/java/net/minecraft/server/BlockButtonAbstract.java 2014-11-27 08:42:10.160850895 +1100 +@@ -3,6 +3,11 @@ + import java.util.List; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.event.block.BlockRedstoneEvent; ++import org.bukkit.event.entity.EntityInteractEvent; ++// CraftBukkit end ++ + public abstract class BlockButtonAbstract extends Block { + + public static final BlockStateDirection FACING = BlockStateDirection.of("facing"); +@@ -122,6 +127,19 @@ + if (((Boolean) iblockdata.get(BlockButtonAbstract.POWERED)).booleanValue()) { + return true; + } else { ++ // CraftBukkit start ++ boolean powered = ((Boolean) iblockdata.get(POWERED)); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ int old = (powered) ? 15 : 0; ++ int current = (!powered) ? 15 : 0; ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, old, current); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ if ((eventRedstone.getNewCurrent() > 0) != (!powered)) { ++ return true; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, iblockdata.set(BlockButtonAbstract.POWERED, Boolean.valueOf(true)), 3); + world.b(blockposition, blockposition); + world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "random.click", 0.3F, 0.6F); +@@ -159,6 +177,16 @@ + if (this.M) { + this.f(world, blockposition, iblockdata); + } else { ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, 15, 0); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ if (eventRedstone.getNewCurrent() > 0) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition, iblockdata.set(BlockButtonAbstract.POWERED, Boolean.valueOf(false))); + this.b(world, blockposition, (EnumDirection) iblockdata.get(BlockButtonAbstract.FACING)); + world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "random.click", 0.3F, 0.5F); +@@ -192,8 +220,42 @@ + List list = world.a(EntityArrow.class, new AxisAlignedBB((double) blockposition.getX() + this.minX, (double) blockposition.getY() + this.minY, (double) blockposition.getZ() + this.minZ, (double) blockposition.getX() + this.maxX, (double) blockposition.getY() + this.maxY, (double) blockposition.getZ() + this.maxZ)); + boolean flag = !list.isEmpty(); + boolean flag1 = ((Boolean) iblockdata.get(BlockButtonAbstract.POWERED)).booleanValue(); ++ ++ // CraftBukkit start - Call interact event when arrows turn on wooden buttons ++ if (flag1 != flag && flag) { ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ boolean allowed = false; ++ ++ // If all of the events are cancelled block the button press, else allow ++ for (Object object : list) { ++ if (object != null) { ++ EntityInteractEvent event = new EntityInteractEvent(((Entity) object).getBukkitEntity(), block); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ allowed = true; ++ break; ++ } ++ } ++ } ++ ++ if (!allowed) { ++ return; ++ } ++ } ++ // CraftBukkit end + + if (flag && !flag1) { ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, 0, 15); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ if (eventRedstone.getNewCurrent() <= 0) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition, iblockdata.set(BlockButtonAbstract.POWERED, Boolean.valueOf(true))); + this.b(world, blockposition, (EnumDirection) iblockdata.get(BlockButtonAbstract.FACING)); + world.b(blockposition, blockposition); +@@ -201,6 +263,16 @@ + } + + if (!flag && flag1) { ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, 15, 0); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ if (eventRedstone.getNewCurrent() > 0) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition, iblockdata.set(BlockButtonAbstract.POWERED, Boolean.valueOf(false))); + this.b(world, blockposition, (EnumDirection) iblockdata.get(BlockButtonAbstract.FACING)); + world.b(blockposition, blockposition); diff --git a/paper-server/nms-patches/BlockCactus.patch b/paper-server/nms-patches/BlockCactus.patch new file mode 100644 index 0000000000..7159a89ee6 --- /dev/null +++ b/paper-server/nms-patches/BlockCactus.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockCactus.java 2014-11-27 08:59:46.509422692 +1100 ++++ src/main/java/net/minecraft/server/BlockCactus.java 2014-11-27 08:42:10.152850911 +1100 +@@ -3,6 +3,8 @@ + import java.util.Iterator; + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockCactus extends Block { + + public static final BlockStateInteger AGE = BlockStateInteger.of("age", 0, 15); +@@ -31,7 +33,8 @@ + world.setTypeUpdate(blockposition1, this.getBlockData()); + IBlockData iblockdata1 = iblockdata.set(BlockCactus.AGE, Integer.valueOf(0)); + +- world.setTypeAndData(blockposition, iblockdata1, 4); ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), this, 0); // CraftBukkit ++ // world.setTypeAndData(blockposition, iblockdata1, 4); // CraftBukkit + this.doPhysics(world, blockposition1, iblockdata1, this); + } else { + world.setTypeAndData(blockposition, iblockdata.set(BlockCactus.AGE, Integer.valueOf(j + 1)), 4); +@@ -83,7 +86,9 @@ + } + + public void a(World world, BlockPosition blockposition, IBlockData iblockdata, Entity entity) { ++ CraftEventFactory.blockDamage = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); // CraftBukkit + entity.damageEntity(DamageSource.CACTUS, 1.0F); ++ CraftEventFactory.blockDamage = null; // CraftBukkit + } + + public IBlockData fromLegacyData(int i) { diff --git a/paper-server/nms-patches/BlockCake.patch b/paper-server/nms-patches/BlockCake.patch new file mode 100644 index 0000000000..facc1d4f00 --- /dev/null +++ b/paper-server/nms-patches/BlockCake.patch @@ -0,0 +1,22 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockCake.java 2014-11-27 08:59:46.509422692 +1100 ++++ src/main/java/net/minecraft/server/BlockCake.java 2014-11-27 08:42:10.168850880 +1100 +@@ -54,7 +54,18 @@ + + private void b(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman) { + if (entityhuman.j(false)) { +- entityhuman.getFoodData().eat(2, 0.1F); ++ // CraftBukkit start ++ // entityhuman.getFoodData().eat(2, 0.1F); ++ int oldFoodLevel = entityhuman.getFoodData().foodLevel; ++ ++ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(entityhuman, 2 + oldFoodLevel); ++ ++ if (!event.isCancelled()) { ++ entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F); ++ } ++ ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutUpdateHealth(((EntityPlayer) entityhuman).getBukkitEntity().getScaledHealth(), entityhuman.getFoodData().foodLevel, entityhuman.getFoodData().saturationLevel)); ++ // CraftBukkit end + int i = ((Integer) iblockdata.get(BlockCake.BITES)).intValue(); + + if (i < 6) { diff --git a/paper-server/nms-patches/BlockCocoa.patch b/paper-server/nms-patches/BlockCocoa.patch new file mode 100644 index 0000000000..40006fffc5 --- /dev/null +++ b/paper-server/nms-patches/BlockCocoa.patch @@ -0,0 +1,35 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockCocoa.java 2014-11-27 08:59:46.513422674 +1100 ++++ src/main/java/net/minecraft/server/BlockCocoa.java 2014-11-27 08:42:10.152850911 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockCocoa extends BlockDirectional implements IBlockFragilePlantElement { + + public static final BlockStateInteger AGE = BlockStateInteger.of("age", 0, 2); +@@ -19,7 +21,10 @@ + int i = ((Integer) iblockdata.get(BlockCocoa.AGE)).intValue(); + + if (i < 2) { +- world.setTypeAndData(blockposition, iblockdata.set(BlockCocoa.AGE, Integer.valueOf(i + 1)), 2); ++ // CraftBukkit start ++ IBlockData data = iblockdata.set(AGE, Integer.valueOf(i + 1)); ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, toLegacyData(data)); ++ // CraftBukkit end + } + } + +@@ -125,7 +130,10 @@ + } + + public void b(World world, Random random, BlockPosition blockposition, IBlockData iblockdata) { +- world.setTypeAndData(blockposition, iblockdata.set(BlockCocoa.AGE, Integer.valueOf(((Integer) iblockdata.get(BlockCocoa.AGE)).intValue() + 1)), 2); ++ // CraftBukkit start ++ IBlockData data = iblockdata.set(AGE, Integer.valueOf(((Integer) iblockdata.get(AGE)).intValue() + 1)); ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, toLegacyData(data)); ++ // CraftBukkit end + } + + public IBlockData fromLegacyData(int i) { diff --git a/paper-server/nms-patches/BlockCommand.patch b/paper-server/nms-patches/BlockCommand.patch new file mode 100644 index 0000000000..e7fe808da5 --- /dev/null +++ b/paper-server/nms-patches/BlockCommand.patch @@ -0,0 +1,34 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockCommand.java 2014-11-27 08:59:46.513422674 +1100 ++++ src/main/java/net/minecraft/server/BlockCommand.java 2014-11-27 08:42:10.152850911 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockCommand extends BlockContainer { + + public static final BlockStateBoolean TRIGGERED = BlockStateBoolean.of("triggered"); +@@ -19,11 +21,20 @@ + if (!world.isStatic) { + boolean flag = world.isBlockIndirectlyPowered(blockposition); + boolean flag1 = ((Boolean) iblockdata.get(BlockCommand.TRIGGERED)).booleanValue(); ++ ++ // CraftBukkit start ++ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ int old = flag1 ? 15 : 0; ++ int current = flag ? 15 : 0; ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bukkitBlock, old, current); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ // CraftBukkit end + +- if (flag && !flag1) { ++ if (eventRedstone.getNewCurrent() > 0 && !(eventRedstone.getOldCurrent() > 0)) { // CraftBukkit + world.setTypeAndData(blockposition, iblockdata.set(BlockCommand.TRIGGERED, Boolean.valueOf(true)), 4); + world.a(blockposition, (Block) this, this.a(world)); +- } else if (!flag && flag1) { ++ } else if (!(eventRedstone.getNewCurrent() > 0) && eventRedstone.getOldCurrent() > 0) { // CraftBukkit + world.setTypeAndData(blockposition, iblockdata.set(BlockCommand.TRIGGERED, Boolean.valueOf(false)), 4); + } + } diff --git a/paper-server/nms-patches/BlockCrops.patch b/paper-server/nms-patches/BlockCrops.patch new file mode 100644 index 0000000000..fde60f42df --- /dev/null +++ b/paper-server/nms-patches/BlockCrops.patch @@ -0,0 +1,35 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockCrops.java 2014-11-27 08:59:46.517422657 +1100 ++++ src/main/java/net/minecraft/server/BlockCrops.java 2014-11-27 08:42:10.160850895 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockCrops extends BlockPlant implements IBlockFragilePlantElement { + + public static final BlockStateInteger AGE = BlockStateInteger.of("age", 0, 7); +@@ -31,7 +33,10 @@ + float f = a((Block) this, world, blockposition); + + if (random.nextInt((int) (25.0F / f) + 1) == 0) { +- world.setTypeAndData(blockposition, iblockdata.set(BlockCrops.AGE, Integer.valueOf(i + 1)), 2); ++ // CraftBukkit start ++ IBlockData data = iblockdata.set(AGE, Integer.valueOf(i + 1)); ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, toLegacyData(data)); ++ // CraftBukkit end + } + } + } +@@ -45,7 +50,10 @@ + i = 7; + } + +- world.setTypeAndData(blockposition, iblockdata.set(BlockCrops.AGE, Integer.valueOf(i)), 2); ++ // CraftBukkit start ++ IBlockData data = iblockdata.set(AGE, Integer.valueOf(i)); ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, toLegacyData(data)); ++ // CraftBukkit end + } + + protected static float a(Block block, World world, BlockPosition blockposition) { diff --git a/paper-server/nms-patches/BlockDaylightDetector.patch b/paper-server/nms-patches/BlockDaylightDetector.patch new file mode 100644 index 0000000000..7f37a071ab --- /dev/null +++ b/paper-server/nms-patches/BlockDaylightDetector.patch @@ -0,0 +1,10 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockDaylightDetector.java 2014-11-27 08:59:46.517422657 +1100 ++++ src/main/java/net/minecraft/server/BlockDaylightDetector.java 2014-11-27 08:42:10.164850887 +1100 +@@ -41,6 +41,7 @@ + } + + if (((Integer) iblockdata.get(BlockDaylightDetector.POWER)).intValue() != i) { ++ i = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), ((Integer) iblockdata.get(POWER)), i).getNewCurrent(); // CraftBukkit - Call BlockRedstoneEvent + world.setTypeAndData(blockposition, iblockdata.set(BlockDaylightDetector.POWER, Integer.valueOf(i)), 3); + } + diff --git a/paper-server/nms-patches/BlockDiodeAbstract.patch b/paper-server/nms-patches/BlockDiodeAbstract.patch new file mode 100644 index 0000000000..f0c210d8a8 --- /dev/null +++ b/paper-server/nms-patches/BlockDiodeAbstract.patch @@ -0,0 +1,30 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockDiodeAbstract.java 2014-11-27 08:59:46.517422657 +1100 ++++ src/main/java/net/minecraft/server/BlockDiodeAbstract.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public abstract class BlockDiodeAbstract extends BlockDirectional { + + protected final boolean M; +@@ -31,8 +33,18 @@ + boolean flag = this.e(world, blockposition, iblockdata); + + if (this.M && !flag) { ++ // CraftBukkit start ++ if (CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), 15, 0).getNewCurrent() != 0) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, this.k(iblockdata), 2); + } else if (!this.M) { ++ // CraftBukkit start ++ if (CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), 0, 15).getNewCurrent() != 15) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, this.e(iblockdata), 2); + if (!flag) { + world.a(blockposition, this.e(iblockdata).getBlock(), this.m(iblockdata), -1); diff --git a/paper-server/nms-patches/BlockDispenser.patch b/paper-server/nms-patches/BlockDispenser.patch new file mode 100644 index 0000000000..35ad0d5874 --- /dev/null +++ b/paper-server/nms-patches/BlockDispenser.patch @@ -0,0 +1,18 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockDispenser.java 2014-11-27 08:59:46.521422639 +1100 ++++ src/main/java/net/minecraft/server/BlockDispenser.java 2014-11-27 08:42:10.084851043 +1100 +@@ -8,6 +8,7 @@ + public static final BlockStateBoolean TRIGGERED = BlockStateBoolean.of("triggered"); + public static final RegistryDefault M = new RegistryDefault(new DispenseBehaviorItem()); + protected Random N = new Random(); ++ public static boolean eventFired = false; // CraftBukkit + + protected BlockDispenser() { + super(Material.STONE); +@@ -78,6 +79,7 @@ + + if (idispensebehavior != IDispenseBehavior.a) { + ItemStack itemstack1 = idispensebehavior.a(sourceblock, itemstack); ++ eventFired = false; // CraftBukkit - reset event status + + tileentitydispenser.setItem(i, itemstack1.count == 0 ? null : itemstack1); + } diff --git a/paper-server/nms-patches/BlockDoor.patch b/paper-server/nms-patches/BlockDoor.patch new file mode 100644 index 0000000000..a14fff0ff3 --- /dev/null +++ b/paper-server/nms-patches/BlockDoor.patch @@ -0,0 +1,43 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockDoor.java 2014-11-27 08:59:46.521422639 +1100 ++++ src/main/java/net/minecraft/server/BlockDoor.java 2014-11-27 08:42:10.156850903 +1100 +@@ -3,6 +3,8 @@ + import com.google.common.base.Predicate; + import java.util.Random; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockDoor extends Block { + + public static final BlockStateDirection FACING = BlockStateDirection.of("facing", (Predicate) EnumDirectionLimit.HORIZONTAL); +@@ -151,9 +153,21 @@ + this.b(world, blockposition, iblockdata, 0); + } + } else { +- boolean flag1 = world.isBlockIndirectlyPowered(blockposition) || world.isBlockIndirectlyPowered(blockposition2); ++ // CraftBukkit start ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.block.Block bukkitBlock = bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ org.bukkit.block.Block blockTop = bworld.getBlockAt(blockposition2.getX(), blockposition2.getY(), blockposition2.getZ()); ++ ++ int power = bukkitBlock.getBlockPower(); ++ int powerTop = blockTop.getBlockPower(); ++ if (powerTop > power) power = powerTop; ++ int oldPower = (Boolean)iblockdata2.get(POWERED) ? 15 : 0; ++ ++ if (oldPower == 0 ^ power == 0) { ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bukkitBlock, oldPower, power); ++ world.getServer().getPluginManager().callEvent(eventRedstone); + +- if ((flag1 || block.isPowerSource()) && block != this && flag1 != ((Boolean) iblockdata2.get(BlockDoor.POWERED)).booleanValue()) { ++ boolean flag1 = eventRedstone.getNewCurrent() > 0; + world.setTypeAndData(blockposition2, iblockdata2.set(BlockDoor.POWERED, Boolean.valueOf(flag1)), 2); + if (flag1 != ((Boolean) iblockdata.get(BlockDoor.OPEN)).booleanValue()) { + world.setTypeAndData(blockposition, iblockdata.set(BlockDoor.OPEN, Boolean.valueOf(flag1)), 2); +@@ -161,6 +175,7 @@ + world.a((EntityHuman) null, flag1 ? 1003 : 1006, blockposition, 0); + } + } ++ // CraftBukkit end + } + } + diff --git a/paper-server/nms-patches/BlockDragonEgg.patch b/paper-server/nms-patches/BlockDragonEgg.patch new file mode 100644 index 0000000000..d2415b9b9a --- /dev/null +++ b/paper-server/nms-patches/BlockDragonEgg.patch @@ -0,0 +1,30 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockDragonEgg.java 2014-11-27 08:59:46.525422622 +1100 ++++ src/main/java/net/minecraft/server/BlockDragonEgg.java 2014-11-27 08:42:10.152850911 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.event.block.BlockFromToEvent; // CraftBukkit ++ + public class BlockDragonEgg extends Block { + + public BlockDragonEgg() { +@@ -61,6 +63,18 @@ + BlockPosition blockposition1 = blockposition.a(world.random.nextInt(16) - world.random.nextInt(16), world.random.nextInt(8) - world.random.nextInt(8), world.random.nextInt(16) - world.random.nextInt(16)); + + if (world.getType(blockposition1).getBlock().material == Material.AIR) { ++ // CraftBukkit start ++ org.bukkit.block.Block from = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ org.bukkit.block.Block to = world.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()); ++ BlockFromToEvent event = new BlockFromToEvent(from, to); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ blockposition1 = new BlockPosition(event.getToBlock().getX(), event.getToBlock().getY(), event.getToBlock().getZ()); ++ // CraftBukkit end + if (world.isStatic) { + for (int j = 0; j < 128; ++j) { + double d0 = world.random.nextDouble(); diff --git a/paper-server/nms-patches/BlockDropper.patch b/paper-server/nms-patches/BlockDropper.patch new file mode 100644 index 0000000000..43df579c1a --- /dev/null +++ b/paper-server/nms-patches/BlockDropper.patch @@ -0,0 +1,41 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockDropper.java 2014-11-27 08:59:46.525422622 +1100 ++++ src/main/java/net/minecraft/server/BlockDropper.java 2014-11-27 08:42:10.124850965 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.inventory.InventoryMoveItemEvent; ++// CraftBukkit end ++ + public class BlockDropper extends BlockDispenser { + + private final IDispenseBehavior O = new DispenseBehaviorItem(); +@@ -38,8 +43,25 @@ + itemstack1 = null; + } + } else { +- itemstack1 = TileEntityHopper.addItem(iinventory, itemstack.cloneItemStack().a(1), enumdirection.opposite()); +- if (itemstack1 == null) { ++ // CraftBukkit start - Fire event when pushing items into other inventories ++ CraftItemStack oitemstack = CraftItemStack.asCraftMirror(itemstack.cloneItemStack().a(1)); ++ ++ org.bukkit.inventory.Inventory destinationInventory; ++ // Have to special case large chests as they work oddly ++ if (iinventory instanceof InventoryLargeChest) { ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory); ++ } else { ++ destinationInventory = iinventory.getOwner().getInventory(); ++ } ++ ++ InventoryMoveItemEvent event = new InventoryMoveItemEvent(tileentitydispenser.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); ++ world.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return; ++ } ++ itemstack1 = TileEntityHopper.addItem(iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection.opposite()); ++ if (event.getItem().equals(oitemstack) && itemstack1 == null) { ++ // CraftBukkit end + itemstack1 = itemstack.cloneItemStack(); + if (--itemstack1.count == 0) { + itemstack1 = null; diff --git a/paper-server/nms-patches/BlockEnderPortal.patch b/paper-server/nms-patches/BlockEnderPortal.patch new file mode 100644 index 0000000000..ae5743c2a7 --- /dev/null +++ b/paper-server/nms-patches/BlockEnderPortal.patch @@ -0,0 +1,22 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockEnderPortal.java 2014-11-27 08:59:46.529422604 +1100 ++++ src/main/java/net/minecraft/server/BlockEnderPortal.java 2014-11-27 08:42:10.104851005 +1100 +@@ -3,6 +3,8 @@ + import java.util.List; + import java.util.Random; + ++import org.bukkit.event.entity.EntityPortalEnterEvent; // CraftBukkit ++ + public class BlockEnderPortal extends BlockContainer { + + protected BlockEnderPortal(Material material) { +@@ -36,6 +38,10 @@ + + public void a(World world, BlockPosition blockposition, IBlockData iblockdata, Entity entity) { + if (entity.vehicle == null && entity.passenger == null && !world.isStatic) { ++ // CraftBukkit start - Entity in portal ++ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent(event); ++ // CraftBukkit end + entity.c(1); + } + diff --git a/paper-server/nms-patches/BlockFire.patch b/paper-server/nms-patches/BlockFire.patch new file mode 100644 index 0000000000..0abc00c033 --- /dev/null +++ b/paper-server/nms-patches/BlockFire.patch @@ -0,0 +1,110 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockFire.java 2014-11-27 08:59:46.529422604 +1100 ++++ src/main/java/net/minecraft/server/BlockFire.java 2014-11-27 08:42:10.168850880 +1100 +@@ -4,6 +4,12 @@ + import java.util.Map; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.block.BlockBurnEvent; ++import org.bukkit.event.block.BlockSpreadEvent; ++// CraftBukkit end ++ + public class BlockFire extends Block { + + public static final BlockStateInteger AGE = BlockStateInteger.of("age", 0, 15); +@@ -109,7 +115,7 @@ + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (world.getGameRules().getBoolean("doFireTick")) { + if (!this.canPlace(world, blockposition)) { +- world.setAir(blockposition); ++ fireExtinguished(world, blockposition); // CraftBukkit - invalid place location + } + + Block block = world.getType(blockposition.down()).getBlock(); +@@ -120,7 +126,7 @@ + } + + if (!flag && world.S() && this.d(world, blockposition)) { +- world.setAir(blockposition); ++ fireExtinguished(world, blockposition); // CraftBukkit - extinguished by rain + } else { + int i = ((Integer) iblockdata.get(BlockFire.AGE)).intValue(); + +@@ -186,7 +192,26 @@ + l1 = 15; + } + +- world.setTypeAndData(blockposition1, iblockdata.set(BlockFire.AGE, Integer.valueOf(l1)), 3); ++ // CraftBukkit start - Call to stop spread of fire ++ if (world.getType(blockposition1) != Blocks.FIRE) { ++ if (CraftEventFactory.callBlockIgniteEvent(world, i1, k1, j1, i, j, k).isCancelled()) { ++ continue; ++ } ++ ++ org.bukkit.Server server = world.getServer(); ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.block.BlockState blockState = bworld.getBlockAt(i1, k1, j1).getState(); ++ blockState.setTypeId(Block.getId(this)); ++ blockState.setData(new org.bukkit.material.MaterialData(Block.getId(this), (byte) l1)); ++ ++ BlockSpreadEvent spreadEvent = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(i, j, k), blockState); ++ server.getPluginManager().callEvent(spreadEvent); ++ ++ if (!spreadEvent.isCancelled()) { ++ blockState.update(true); ++ } ++ } ++ // CraftBukkit end + } + } + } +@@ -223,6 +248,17 @@ + + if (random.nextInt(i) < k) { + IBlockData iblockdata = world.getType(blockposition); ++ ++ // CraftBukkit start ++ org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ BlockBurnEvent event = new BlockBurnEvent(theBlock); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + + if (random.nextInt(j + 10) < 5 && !world.isRainingAt(blockposition)) { + int l = j + random.nextInt(5) / 4; +@@ -290,7 +326,7 @@ + + public void doPhysics(World world, BlockPosition blockposition, IBlockData iblockdata, Block block) { + if (!World.a((IBlockAccess) world, blockposition.down()) && !this.e(world, blockposition)) { +- world.setAir(blockposition); ++ fireExtinguished(world, blockposition); // CraftBukkit - fuel block gone + } + + } +@@ -298,7 +334,7 @@ + public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { + if (world.worldProvider.getDimension() > 0 || !Blocks.PORTAL.d(world, blockposition)) { + if (!World.a((IBlockAccess) world, blockposition.down()) && !this.e(world, blockposition)) { +- world.setAir(blockposition); ++ fireExtinguished(world, blockposition); // CraftBukkit - fuel block broke + } else { + world.a(blockposition, (Block) this, this.a(world) + world.random.nextInt(10)); + } +@@ -320,4 +356,12 @@ + protected BlockStateList getStateList() { + return new BlockStateList(this, new IBlockState[] { BlockFire.AGE, BlockFire.NORTH, BlockFire.EAST, BlockFire.SOUTH, BlockFire.WEST, BlockFire.UPPER, BlockFire.FLIP, BlockFire.ALT}); + } ++ ++ // CraftBukkit start ++ private void fireExtinguished(World world, BlockPosition position) { ++ if (!CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), Blocks.AIR).isCancelled()) { ++ world.setAir(position); ++ } ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/BlockFlowing.patch b/paper-server/nms-patches/BlockFlowing.patch new file mode 100644 index 0000000000..84b3101d8d --- /dev/null +++ b/paper-server/nms-patches/BlockFlowing.patch @@ -0,0 +1,83 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockFlowing.java 2014-11-27 08:59:46.529422604 +1100 ++++ src/main/java/net/minecraft/server/BlockFlowing.java 2014-11-27 08:42:10.112850989 +1100 +@@ -5,6 +5,11 @@ + import java.util.Random; + import java.util.Set; + ++// CraftBukkit start ++import org.bukkit.block.BlockFace; ++import org.bukkit.event.block.BlockFromToEvent; ++// CraftBukkit end ++ + public class BlockFlowing extends BlockFluids { + + int a; +@@ -18,7 +23,12 @@ + } + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { +- int i = ((Integer) iblockdata.get(BlockFlowing.LEVEL)).intValue(); ++ // CraftBukkit start ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.Server server = world.getServer(); ++ org.bukkit.block.Block source = bworld == null ? null : bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ // CraftBukkit end ++ int i = ((Integer) iblockdata.get(LEVEL)).intValue(); + byte b0 = 1; + + if (this.material == Material.LAVA && !world.worldProvider.n()) { +@@ -88,17 +98,25 @@ + IBlockData iblockdata2 = world.getType(blockposition.down()); + + if (this.h(world, blockposition.down(), iblockdata2)) { +- if (this.material == Material.LAVA && world.getType(blockposition.down()).getBlock().getMaterial() == Material.WATER) { +- world.setTypeUpdate(blockposition.down(), Blocks.STONE.getBlockData()); +- this.fizz(world, blockposition.down()); +- return; +- } ++ // CraftBukkit start - Send "down" to the server ++ BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN); ++ if (server != null) { ++ server.getPluginManager().callEvent(event); ++ } ++ if (!event.isCancelled()) { ++ if (this.material == Material.LAVA && world.getType(blockposition.down()).getBlock().getMaterial() == Material.WATER) { ++ world.setTypeUpdate(blockposition.down(), Blocks.STONE.getBlockData()); ++ this.fizz(world, blockposition.down()); ++ return; ++ } + +- if (i >= 8) { +- this.flow(world, blockposition.down(), iblockdata2, i); +- } else { +- this.flow(world, blockposition.down(), iblockdata2, i + 8); ++ if (i >= 8) { ++ this.flow(world, blockposition.down(), iblockdata2, i); ++ } else { ++ this.flow(world, blockposition.down(), iblockdata2, i + 8); ++ } + } ++ // CraftBukkit end + } else if (i >= 0 && (i == 0 || this.g(world, blockposition.down(), iblockdata2))) { + Set set = this.e(world, blockposition); + +@@ -115,8 +133,17 @@ + + while (iterator1.hasNext()) { + EnumDirection enumdirection1 = (EnumDirection) iterator1.next(); +- +- this.flow(world, blockposition.shift(enumdirection1), world.getType(blockposition.shift(enumdirection1)), k); ++ ++ // CraftBukkit start ++ BlockFromToEvent event = new BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1)); ++ if (server != null) { ++ server.getPluginManager().callEvent(event); ++ } ++ ++ if (!event.isCancelled()) { ++ this.flow(world, blockposition.shift(enumdirection1), world.getType(blockposition.shift(enumdirection1)), k); ++ } ++ // CraftBukkit end + } + } + diff --git a/paper-server/nms-patches/BlockGrass.patch b/paper-server/nms-patches/BlockGrass.patch new file mode 100644 index 0000000000..b52f01fd6c --- /dev/null +++ b/paper-server/nms-patches/BlockGrass.patch @@ -0,0 +1,77 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockGrass.java 2014-11-27 08:59:46.533422586 +1100 ++++ src/main/java/net/minecraft/server/BlockGrass.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,14 @@ + + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.block.BlockState; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.event.block.BlockSpreadEvent; ++import org.bukkit.event.block.BlockFadeEvent; ++// CraftBukkit end ++ + public class BlockGrass extends Block implements IBlockFragilePlantElement { + + public static final BlockStateBoolean SNOWY = BlockStateBoolean.of("snowy"); +@@ -22,7 +30,19 @@ + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (!world.isStatic) { + if (world.getLightLevel(blockposition.up()) < 4 && world.getType(blockposition.up()).getBlock().n() > 2) { +- world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData()); ++ // CraftBukkit start ++ // world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData()); ++ org.bukkit.World bworld = world.getWorld(); ++ BlockState blockState = bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()).getState(); ++ blockState.setType(CraftMagicNumbers.getMaterial(Blocks.DIRT)); ++ ++ BlockFadeEvent event = new BlockFadeEvent(blockState.getBlock(), blockState); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } else { + if (world.getLightLevel(blockposition.up()) >= 9) { + for (int i = 0; i < 4; ++i) { +@@ -31,7 +51,19 @@ + IBlockData iblockdata1 = world.getType(blockposition1); + + if (iblockdata1.getBlock() == Blocks.DIRT && iblockdata1.get(BlockDirt.VARIANT) == EnumDirtVariant.DIRT && world.getLightLevel(blockposition1.up()) >= 4 && block.n() <= 2) { +- world.setTypeUpdate(blockposition1, Blocks.GRASS.getBlockData()); ++ // CraftBukkit start ++ // world.setTypeUpdate(blockposition1, Blocks.GRASS.getBlockData()); ++ org.bukkit.World bworld = world.getWorld(); ++ BlockState blockState = bworld.getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()).getState(); ++ blockState.setType(CraftMagicNumbers.getMaterial(Blocks.GRASS)); ++ ++ BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), blockState); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } + } + } +@@ -74,13 +106,15 @@ + IBlockData iblockdata1 = blockflowers.getBlockData().set(blockflowers.l(), enumflowervarient); + + if (blockflowers.f(world, blockposition2, iblockdata1)) { +- world.setTypeAndData(blockposition2, iblockdata1, 3); ++ // world.setTypeAndData(blockposition2, iblockdata1, 3); // CraftBukkit ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), iblockdata1.getBlock(), iblockdata1.getBlock().toLegacyData(iblockdata1)); // CraftBukkit + } + } else { + IBlockData iblockdata2 = Blocks.TALLGRASS.getBlockData().set(BlockLongGrass.TYPE, EnumTallGrassType.GRASS); + + if (Blocks.TALLGRASS.f(world, blockposition2, iblockdata2)) { +- world.setTypeAndData(blockposition2, iblockdata2, 3); ++ // world.setTypeAndData(blockposition2, iblockdata2, 3); // CRaftBukkit ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), iblockdata2.getBlock(), iblockdata2.getBlock().toLegacyData(iblockdata2)); // CraftBukkit + } + } + } diff --git a/paper-server/nms-patches/BlockIce.patch b/paper-server/nms-patches/BlockIce.patch new file mode 100644 index 0000000000..91033f00ba --- /dev/null +++ b/paper-server/nms-patches/BlockIce.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockIce.java 2014-11-27 08:59:46.533422586 +1100 ++++ src/main/java/net/minecraft/server/BlockIce.java 2014-11-27 08:42:10.168850880 +1100 +@@ -44,6 +44,12 @@ + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (world.b(EnumSkyBlock.BLOCK, blockposition) > 11 - this.n()) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), world.worldProvider.n() ? Blocks.AIR : Blocks.WATER).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ + if (world.worldProvider.n()) { + world.setAir(blockposition); + } else { diff --git a/paper-server/nms-patches/BlockLeaves.patch b/paper-server/nms-patches/BlockLeaves.patch new file mode 100644 index 0000000000..067c58081f --- /dev/null +++ b/paper-server/nms-patches/BlockLeaves.patch @@ -0,0 +1,26 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockLeaves.java 2014-11-27 08:59:46.537422569 +1100 ++++ src/main/java/net/minecraft/server/BlockLeaves.java 2014-11-27 08:42:10.132850949 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.event.block.LeavesDecayEvent; // CraftBukkit ++ + public abstract class BlockLeaves extends BlockTransparent { + + public static final BlockStateBoolean DECAYABLE = BlockStateBoolean.of("decayable"); +@@ -128,6 +130,14 @@ + } + + private void d(World world, BlockPosition blockposition) { ++ // CraftBukkit start ++ LeavesDecayEvent event = new LeavesDecayEvent(world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.b(world, blockposition, world.getType(blockposition), 0); + world.setAir(blockposition); + } diff --git a/paper-server/nms-patches/BlockLever.patch b/paper-server/nms-patches/BlockLever.patch new file mode 100644 index 0000000000..fa9482b1eb --- /dev/null +++ b/paper-server/nms-patches/BlockLever.patch @@ -0,0 +1,32 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockLever.java 2014-11-27 08:59:46.541422551 +1100 ++++ src/main/java/net/minecraft/server/BlockLever.java 2014-11-27 08:42:10.168850880 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Iterator; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockLever extends Block { + + public static final BlockStateEnum FACING = BlockStateEnum.of("facing", EnumLeverPosition.class); +@@ -144,6 +146,20 @@ + if (world.isStatic) { + return true; + } else { ++ // CraftBukkit start - Interact Lever ++ boolean powered = (Boolean)iblockdata.get(POWERED); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ int old = (powered) ? 15 : 0; ++ int current = (!powered) ? 15 : 0; ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, old, current); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ if ((eventRedstone.getNewCurrent() > 0) != (!powered)) { ++ return true; ++ } ++ // CraftBukkit end ++ + iblockdata = iblockdata.a(BlockLever.POWERED); + world.setTypeAndData(blockposition, iblockdata, 3); + world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "random.click", 0.3F, ((Boolean) iblockdata.get(BlockLever.POWERED)).booleanValue() ? 0.6F : 0.5F); diff --git a/paper-server/nms-patches/BlockMinecartDetector.patch b/paper-server/nms-patches/BlockMinecartDetector.patch new file mode 100644 index 0000000000..4e33f43103 --- /dev/null +++ b/paper-server/nms-patches/BlockMinecartDetector.patch @@ -0,0 +1,29 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockMinecartDetector.java 2014-11-27 08:59:46.541422551 +1100 ++++ src/main/java/net/minecraft/server/BlockMinecartDetector.java 2014-11-27 08:42:10.124850965 +1100 +@@ -4,6 +4,8 @@ + import java.util.List; + import java.util.Random; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockMinecartDetector extends BlockMinecartTrackAbstract { + + public static final BlockStateEnum SHAPE = BlockStateEnum.a("shape", EnumTrackPosition.class, (Predicate) (new BlockMinecartDetectorInnerClass1())); +@@ -55,6 +57,17 @@ + if (!list.isEmpty()) { + flag1 = true; + } ++ ++ // CraftBukkit start ++ if (flag != flag1) { ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, flag ? 15 : 0, flag1 ? 15 : 0); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ flag1 = eventRedstone.getNewCurrent() > 0; ++ } ++ // CraftBukkit end + + if (flag1 && !flag) { + world.setTypeAndData(blockposition, iblockdata.set(BlockMinecartDetector.POWERED, Boolean.valueOf(true)), 3); diff --git a/paper-server/nms-patches/BlockMobSpawner.patch b/paper-server/nms-patches/BlockMobSpawner.patch new file mode 100644 index 0000000000..5be7f790df --- /dev/null +++ b/paper-server/nms-patches/BlockMobSpawner.patch @@ -0,0 +1,22 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockMobSpawner.java 2014-11-27 08:59:46.541422551 +1100 ++++ src/main/java/net/minecraft/server/BlockMobSpawner.java 2014-11-27 08:42:10.172850872 +1100 +@@ -22,9 +22,19 @@ + + public void dropNaturally(World world, BlockPosition blockposition, IBlockData iblockdata, float f, int i) { + super.dropNaturally(world, blockposition, iblockdata, f, i); ++ /* CraftBukkit start - Delegate to getExpDrop + int j = 15 + world.random.nextInt(15) + world.random.nextInt(15); + + this.dropExperience(world, blockposition, j); ++ */ ++ } ++ ++ @Override ++ public int getExpDrop(World world, IBlockData iblockdata, int enchantmentLevel) { ++ int j = 15 + world.random.nextInt(15) + world.random.nextInt(15); ++ ++ return j; ++ // CraftBukkit end + } + + public boolean c() { diff --git a/paper-server/nms-patches/BlockMonsterEggs.patch b/paper-server/nms-patches/BlockMonsterEggs.patch new file mode 100644 index 0000000000..9260842fa0 --- /dev/null +++ b/paper-server/nms-patches/BlockMonsterEggs.patch @@ -0,0 +1,20 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockMonsterEggs.java 2014-11-27 08:59:46.545422534 +1100 ++++ src/main/java/net/minecraft/server/BlockMonsterEggs.java 2014-11-27 08:42:10.136850942 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; // CraftBukkit ++ + public class BlockMonsterEggs extends Block { + + public static final BlockStateEnum VARIANT = BlockStateEnum.of("variant", EnumMonsterEggVarient.class); +@@ -50,7 +52,7 @@ + EntitySilverfish entitysilverfish = new EntitySilverfish(world); + + entitysilverfish.setPositionRotation((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, 0.0F, 0.0F); +- world.addEntity(entitysilverfish); ++ world.addEntity(entitysilverfish, SpawnReason.SILVERFISH_BLOCK); // CraftBukkit - add SpawnReason + entitysilverfish.y(); + } + diff --git a/paper-server/nms-patches/BlockMushroom.patch b/paper-server/nms-patches/BlockMushroom.patch new file mode 100644 index 0000000000..5f2477b71d --- /dev/null +++ b/paper-server/nms-patches/BlockMushroom.patch @@ -0,0 +1,57 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockMushroom.java 2014-11-27 08:59:46.545422534 +1100 ++++ src/main/java/net/minecraft/server/BlockMushroom.java 2014-11-27 08:42:10.100851012 +1100 +@@ -3,6 +3,12 @@ + import java.util.Iterator; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.TreeType; ++import org.bukkit.block.BlockState; ++import org.bukkit.event.block.BlockSpreadEvent; ++// CraftBukkit end ++ + public class BlockMushroom extends BlockPlant implements IBlockFragilePlantElement { + + protected BlockMushroom() { +@@ -13,6 +19,7 @@ + } + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { ++ final int sourceX = blockposition.getX(), sourceY = blockposition.getY(), sourceZ = blockposition.getZ(); // CraftBukkit + if (random.nextInt(25) == 0) { + int i = 5; + boolean flag = true; +@@ -39,8 +46,20 @@ + blockposition2 = blockposition.a(random.nextInt(3) - 1, random.nextInt(2) - random.nextInt(2), random.nextInt(3) - 1); + } + +- if (world.isEmpty(blockposition2) && this.f(world, blockposition2, this.getBlockData())) { +- world.setTypeAndData(blockposition2, this.getBlockData(), 2); ++ if (world.isEmpty(blockposition2) && this.f(world, blockposition2, this.getBlockData())) { ++ // CraftBukkit start ++ // world.setTypeAndData(blockposition2, this.getBlockData(), 2); ++ org.bukkit.World bworld = world.getWorld(); ++ BlockState blockState = bworld.getBlockAt(blockposition2.getX(), blockposition2.getY(), blockposition2.getZ()).getState(); ++ blockState.setType(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(this)); // nms: this.id, 0, 2 ++ ++ BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(sourceX, sourceY, sourceZ), blockState); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } + } + +@@ -69,8 +88,10 @@ + WorldGenHugeMushroom worldgenhugemushroom = null; + + if (this == Blocks.BROWN_MUSHROOM) { ++ BlockSapling.treeType = TreeType.BROWN_MUSHROOM; // CraftBukkit + worldgenhugemushroom = new WorldGenHugeMushroom(0); + } else if (this == Blocks.RED_MUSHROOM) { ++ BlockSapling.treeType = TreeType.RED_MUSHROOM; // CraftBukkit + worldgenhugemushroom = new WorldGenHugeMushroom(1); + } + diff --git a/paper-server/nms-patches/BlockMycel.patch b/paper-server/nms-patches/BlockMycel.patch new file mode 100644 index 0000000000..0a0bd4fb6d --- /dev/null +++ b/paper-server/nms-patches/BlockMycel.patch @@ -0,0 +1,58 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockMycel.java 2014-11-27 08:59:46.549422516 +1100 ++++ src/main/java/net/minecraft/server/BlockMycel.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,13 @@ + + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.block.BlockState; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.event.block.BlockFadeEvent; ++import org.bukkit.event.block.BlockSpreadEvent; ++// CraftBukkit end ++ + public class BlockMycel extends Block { + + public static final BlockStateBoolean SNOWY = BlockStateBoolean.of("snowy"); +@@ -22,7 +29,19 @@ + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (!world.isStatic) { + if (world.getLightLevel(blockposition.up()) < 4 && world.getType(blockposition.up()).getBlock().n() > 2) { +- world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData().set(BlockDirt.VARIANT, EnumDirtVariant.DIRT)); ++ // CraftBukkit start ++ // world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData().set(BlockDirt.VARIANT, EnumDirtVariant.DIRT)); ++ org.bukkit.World bworld = world.getWorld(); ++ BlockState blockState = bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()).getState(); ++ blockState.setType(CraftMagicNumbers.getMaterial(Blocks.DIRT)); ++ ++ BlockFadeEvent event = new BlockFadeEvent(blockState.getBlock(), blockState); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } else { + if (world.getLightLevel(blockposition.up()) >= 9) { + for (int i = 0; i < 4; ++i) { +@@ -31,7 +50,19 @@ + Block block = world.getType(blockposition1.up()).getBlock(); + + if (iblockdata1.getBlock() == Blocks.DIRT && iblockdata1.get(BlockDirt.VARIANT) == EnumDirtVariant.DIRT && world.getLightLevel(blockposition1.up()) >= 4 && block.n() <= 2) { +- world.setTypeUpdate(blockposition1, this.getBlockData()); ++ // CraftBukkit start ++ // world.setTypeUpdate(blockposition1, this.getBlockData()); ++ org.bukkit.World bworld = world.getWorld(); ++ BlockState blockState = bworld.getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()).getState(); ++ blockState.setType(CraftMagicNumbers.getMaterial(this)); ++ ++ BlockSpreadEvent event = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), blockState); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/BlockNetherWart.patch b/paper-server/nms-patches/BlockNetherWart.patch new file mode 100644 index 0000000000..c6f458ebf9 --- /dev/null +++ b/paper-server/nms-patches/BlockNetherWart.patch @@ -0,0 +1,12 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockNetherWart.java 2014-11-27 08:59:46.549422516 +1100 ++++ src/main/java/net/minecraft/server/BlockNetherWart.java 2014-11-27 08:42:10.140850934 +1100 +@@ -28,7 +28,8 @@ + + if (i < 3 && random.nextInt(10) == 0) { + iblockdata = iblockdata.set(BlockNetherWart.AGE, Integer.valueOf(i + 1)); +- world.setTypeAndData(blockposition, iblockdata, 2); ++ // world.setTypeAndData(blockposition, iblockdata, 2); // CraftBukkit ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, toLegacyData(iblockdata)); // CraftBukkit + } + + super.b(world, blockposition, iblockdata, random); diff --git a/paper-server/nms-patches/BlockOre.patch b/paper-server/nms-patches/BlockOre.patch new file mode 100644 index 0000000000..473fcbafd8 --- /dev/null +++ b/paper-server/nms-patches/BlockOre.patch @@ -0,0 +1,42 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockOre.java 2014-11-27 08:59:46.549422516 +1100 ++++ src/main/java/net/minecraft/server/BlockOre.java 2014-11-27 08:42:10.144850927 +1100 +@@ -33,6 +33,7 @@ + + public void dropNaturally(World world, BlockPosition blockposition, IBlockData iblockdata, float f, int i) { + super.dropNaturally(world, blockposition, iblockdata, f, i); ++ /* CraftBukkit start - Delegated to getExpDrop + if (this.getDropType(iblockdata, world.random, i) != Item.getItemOf(this)) { + int j = 0; + +@@ -50,7 +51,31 @@ + + this.dropExperience(world, blockposition, j); + } ++ // */ ++ } ++ ++ @Override ++ public int getExpDrop(World world, IBlockData iblockdata, int i) { ++ if (this.getDropType(iblockdata, world.random, i) != Item.getItemOf(this)) { ++ int j = 0; ++ ++ if (this == Blocks.COAL_ORE) { ++ j = MathHelper.nextInt(world.random, 0, 2); ++ } else if (this == Blocks.DIAMOND_ORE) { ++ j = MathHelper.nextInt(world.random, 3, 7); ++ } else if (this == Blocks.EMERALD_ORE) { ++ j = MathHelper.nextInt(world.random, 3, 7); ++ } else if (this == Blocks.LAPIS_ORE) { ++ j = MathHelper.nextInt(world.random, 2, 5); ++ } else if (this == Blocks.QUARTZ_ORE) { ++ j = MathHelper.nextInt(world.random, 2, 5); ++ } ++ ++ return j; ++ } + ++ return 0; ++ // CraftBukkit end + } + + public int getDropData(World world, BlockPosition blockposition) { diff --git a/paper-server/nms-patches/BlockPiston.patch b/paper-server/nms-patches/BlockPiston.patch new file mode 100644 index 0000000000..816eebdc40 --- /dev/null +++ b/paper-server/nms-patches/BlockPiston.patch @@ -0,0 +1,76 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPiston.java 2014-11-27 08:59:46.553422499 +1100 ++++ src/main/java/net/minecraft/server/BlockPiston.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,6 +1,16 @@ + package net.minecraft.server; + ++import java.util.AbstractList; ++import java.util.Collection; ++import java.util.Iterator; + import java.util.List; ++import java.util.ListIterator; ++ ++// CraftBukkit start ++import org.bukkit.craftbukkit.block.CraftBlock; ++import org.bukkit.event.block.BlockPistonRetractEvent; ++import org.bukkit.event.block.BlockPistonExtendEvent; ++// CraftBukkit end + + public class BlockPiston extends Block { + +@@ -52,10 +62,19 @@ + boolean flag = this.b(world, blockposition, enumdirection); + + if (flag && !((Boolean) iblockdata.get(BlockPiston.EXTENDED)).booleanValue()) { +- if ((new PistonExtendsChecker(world, blockposition, enumdirection, true)).a()) { ++ if ((new PistonExtendsChecker(world, blockposition, enumdirection, true)).a()) { + world.playBlockAction(blockposition, this, 0, enumdirection.a()); + } + } else if (!flag && ((Boolean) iblockdata.get(BlockPiston.EXTENDED)).booleanValue()) { ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, CraftBlock.notchToBlockFace(enumdirection)); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.valueOf(false)), 2); + world.playBlockAction(blockposition, this, 1, enumdirection.a()); + } +@@ -286,6 +305,35 @@ + if (!pistonextendschecker.a()) { + return false; + } else { ++ final org.bukkit.block.Block bblock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ final List moved = pistonextendschecker.getMovedBlocks(); ++ final List broken = pistonextendschecker.getBrokenBlocks(); ++ ++ List blocks = new AbstractList() { ++ ++ @Override ++ public int size() { ++ return moved.size() + broken.size(); ++ } ++ ++ @Override ++ public org.bukkit.block.Block get(int index) { ++ if (index >= size() || index < 0) { ++ throw new ArrayIndexOutOfBoundsException(index); ++ } ++ BlockPosition pos = (BlockPosition) (index < moved.size() ? moved.get(index) : broken.get(index - moved.size())); ++ return bblock.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); ++ } ++ }; ++ ++ BlockPistonExtendEvent event = new BlockPistonExtendEvent(bblock, blocks, CraftBlock.notchToBlockFace(enumdirection)); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end + int i = list.size() + list1.size(); + Block[] ablock = new Block[i]; + EnumDirection enumdirection1 = flag ? enumdirection : enumdirection.opposite(); diff --git a/paper-server/nms-patches/BlockPortal.patch b/paper-server/nms-patches/BlockPortal.patch new file mode 100644 index 0000000000..d575fc788a --- /dev/null +++ b/paper-server/nms-patches/BlockPortal.patch @@ -0,0 +1,53 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPortal.java 2014-11-27 08:59:46.553422499 +1100 ++++ src/main/java/net/minecraft/server/BlockPortal.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.event.entity.EntityPortalEnterEvent; // CraftBukkit ++ + public class BlockPortal extends BlockHalfTransparent { + + public static final BlockStateEnum AXIS = BlockStateEnum.of("axis", EnumAxis.class, new EnumAxis[] { EnumAxis.X, EnumAxis.Z}); +@@ -24,7 +26,8 @@ + } + + if (i > 0 && !world.getType(blockposition1.up()).getBlock().isOccluding()) { +- Entity entity = ItemMonsterEgg.a(world, 57, (double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 1.1D, (double) blockposition1.getZ() + 0.5D); ++ // CraftBukkit - set spawn reason to NETHER_PORTAL ++ Entity entity = ItemMonsterEgg.spawnCreature(world, 57, (double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 1.1D, (double) blockposition1.getZ() + 0.5D, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NETHER_PORTAL); + + if (entity != null) { + entity.portalCooldown = entity.ar(); +@@ -66,14 +69,16 @@ + PortalCreator portalcreator = new PortalCreator(world, blockposition, EnumAxis.X); + + if (portalcreator.b() && PortalCreator.a(portalcreator) == 0) { +- portalcreator.c(); +- return true; ++ // CraftBukkit start - return portalcreator ++ return portalcreator.c(); ++ // return true; + } else { + PortalCreator portalcreator1 = new PortalCreator(world, blockposition, EnumAxis.Z); + + if (portalcreator1.b() && PortalCreator.a(portalcreator1) == 0) { +- portalcreator1.c(); +- return true; ++ return portalcreator1.c(); ++ // return true; ++ // CraftBukkit end + } else { + return false; + } +@@ -104,6 +109,10 @@ + + public void a(World world, BlockPosition blockposition, IBlockData iblockdata, Entity entity) { + if (entity.vehicle == null && entity.passenger == null) { ++ // CraftBukkit start - Entity in portal ++ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent(event); ++ // CraftBukkit end + entity.aq(); + } + diff --git a/paper-server/nms-patches/BlockPoweredRail.patch b/paper-server/nms-patches/BlockPoweredRail.patch new file mode 100644 index 0000000000..a43bdf2291 --- /dev/null +++ b/paper-server/nms-patches/BlockPoweredRail.patch @@ -0,0 +1,25 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPoweredRail.java 2014-11-27 08:59:46.557422481 +1100 ++++ src/main/java/net/minecraft/server/BlockPoweredRail.java 2014-11-27 08:42:10.124850965 +1100 +@@ -2,6 +2,8 @@ + + import com.google.common.base.Predicate; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockPoweredRail extends BlockMinecartTrackAbstract { + + public static final BlockStateEnum SHAPE = BlockStateEnum.a("shape", EnumTrackPosition.class, (Predicate) (new BlockPoweredRailInnerClass1())); +@@ -108,6 +110,13 @@ + boolean flag1 = world.isBlockIndirectlyPowered(blockposition) || this.a(world, blockposition, iblockdata, true, 0) || this.a(world, blockposition, iblockdata, false, 0); + + if (flag1 != flag) { ++ // CraftBukkit start ++ int power = (Boolean)iblockdata.get(POWERED) ? 15 : 0; ++ int newPower = CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), power, 15 - power).getNewCurrent(); ++ if (newPower == power) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, iblockdata.set(BlockPoweredRail.POWERED, Boolean.valueOf(flag1)), 3); + world.applyPhysics(blockposition.down(), this); + if (((EnumTrackPosition) iblockdata.get(BlockPoweredRail.SHAPE)).c()) { diff --git a/paper-server/nms-patches/BlockPressurePlateAbstract.patch b/paper-server/nms-patches/BlockPressurePlateAbstract.patch new file mode 100644 index 0000000000..a226e9c44e --- /dev/null +++ b/paper-server/nms-patches/BlockPressurePlateAbstract.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPressurePlateAbstract.java 2014-11-27 08:59:46.557422481 +1100 ++++ src/main/java/net/minecraft/server/BlockPressurePlateAbstract.java 2014-11-27 08:42:10.144850927 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public abstract class BlockPressurePlateAbstract extends Block { + + protected BlockPressurePlateAbstract(Material material) { +@@ -90,6 +92,19 @@ + int j = this.e(world, blockposition); + boolean flag = i > 0; + boolean flag1 = j > 0; ++ ++ // CraftBukkit start - Interact Pressure Plate ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); ++ ++ if (flag != flag1) { ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), i, j); ++ manager.callEvent(eventRedstone); ++ ++ flag1 = eventRedstone.getNewCurrent() > 0; ++ j = eventRedstone.getNewCurrent(); ++ } ++ // CraftBukkit end + + if (i != j) { + iblockdata = this.a(iblockdata, j); diff --git a/paper-server/nms-patches/BlockPressurePlateBinary.patch b/paper-server/nms-patches/BlockPressurePlateBinary.patch new file mode 100644 index 0000000000..a1d38a1640 --- /dev/null +++ b/paper-server/nms-patches/BlockPressurePlateBinary.patch @@ -0,0 +1,38 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPressurePlateBinary.java 2014-11-27 08:59:46.557422481 +1100 ++++ src/main/java/net/minecraft/server/BlockPressurePlateBinary.java 2014-11-27 08:42:10.152850911 +1100 +@@ -3,6 +3,8 @@ + import java.util.Iterator; + import java.util.List; + ++import org.bukkit.event.entity.EntityInteractEvent; // CraftBukkit ++ + public class BlockPressurePlateBinary extends BlockPressurePlateAbstract { + + public static final BlockStateBoolean POWERED = BlockStateBoolean.of("powered"); +@@ -44,6 +46,26 @@ + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); ++ ++ // CraftBukkit start - Call interact event when turning on a pressure plate ++ if (this.e(world.getType(blockposition)) == 0) { ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); ++ org.bukkit.event.Cancellable cancellable; ++ ++ if (entity instanceof EntityHuman) { ++ cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent((EntityHuman) entity, org.bukkit.event.block.Action.PHYSICAL, blockposition, null, null); ++ } else { ++ cancellable = new EntityInteractEvent(entity.getBukkitEntity(), bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ manager.callEvent((EntityInteractEvent) cancellable); ++ } ++ ++ // We only want to block turning the plate on if all events are cancelled ++ if (cancellable.isCancelled()) { ++ continue; ++ } ++ } ++ // CraftBukkit end + + if (!entity.aH()) { + return 15; diff --git a/paper-server/nms-patches/BlockPressurePlateWeighted.patch b/paper-server/nms-patches/BlockPressurePlateWeighted.patch new file mode 100644 index 0000000000..bd07b6a644 --- /dev/null +++ b/paper-server/nms-patches/BlockPressurePlateWeighted.patch @@ -0,0 +1,43 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPressurePlateWeighted.java 2014-11-27 08:59:46.561422463 +1100 ++++ src/main/java/net/minecraft/server/BlockPressurePlateWeighted.java 2014-11-27 08:42:10.160850895 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.EntityInteractEvent; // CraftBukkit ++ + public class BlockPressurePlateWeighted extends BlockPressurePlateAbstract { + + public static final BlockStateInteger POWER = BlockStateInteger.of("power", 0, 15); +@@ -12,7 +14,31 @@ + } + + protected int e(World world, BlockPosition blockposition) { +- int i = Math.min(world.a(Entity.class, this.a(blockposition)).size(), this.b); ++ // CraftBukkit start ++ //int i = Math.min(world.a(Entity.class, this.a(blockposition)).size(), this.b); ++ int i = 0; ++ java.util.Iterator iterator = world.a(Entity.class, this.a(blockposition)).iterator(); ++ ++ while (iterator.hasNext()) { ++ Entity entity = (Entity) iterator.next(); ++ ++ org.bukkit.event.Cancellable cancellable; ++ ++ if (entity instanceof EntityHuman) { ++ cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent((EntityHuman) entity, org.bukkit.event.block.Action.PHYSICAL, blockposition, null, null); ++ } else { ++ cancellable = new EntityInteractEvent(entity.getBukkitEntity(), world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent((EntityInteractEvent) cancellable); ++ } ++ ++ // We only want to block turning the plate on if all events are cancelled ++ if (!cancellable.isCancelled()) { ++ i++; ++ } ++ } ++ ++ i = Math.min(i, this.b); ++ // CraftBukkit end + + if (i > 0) { + float f = (float) Math.min(this.b, i) / (float) this.b; diff --git a/paper-server/nms-patches/BlockPumpkin.patch b/paper-server/nms-patches/BlockPumpkin.patch new file mode 100644 index 0000000000..abf3e858a7 --- /dev/null +++ b/paper-server/nms-patches/BlockPumpkin.patch @@ -0,0 +1,117 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockPumpkin.java 2014-11-27 08:59:46.561422463 +1100 ++++ src/main/java/net/minecraft/server/BlockPumpkin.java 2014-11-27 08:42:10.108850996 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.util.BlockStateListPopulator; ++import org.bukkit.event.block.BlockRedstoneEvent; ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; ++// CraftBukkit end ++ + public class BlockPumpkin extends BlockDirectional { + + private ShapeDetector snowGolemPart; +@@ -29,31 +35,45 @@ + int j; + + if ((shapedetectorcollection = this.getDetectorSnowGolem().a(world, blockposition)) != null) { ++ BlockStateListPopulator blockList = new BlockStateListPopulator(world.getWorld()); // CraftBukkit - Use BlockStateListPopulator + for (i = 0; i < this.getDetectorSnowGolem().b(); ++i) { + ShapeDetectorBlock shapedetectorblock = shapedetectorcollection.a(0, i, 0); + +- world.setTypeAndData(shapedetectorblock.d(), Blocks.AIR.getBlockData(), 2); ++ // CraftBukkit start ++ // world.setTypeAndData(shapedetectorblock.d(), Blocks.AIR.getBlockData(), 2); ++ BlockPosition pos = shapedetectorblock.d(); ++ blockList.setTypeId(pos.getX(), pos.getY(), pos.getZ(), 0); ++ // CraftBukkit end + } + + EntitySnowman entitysnowman = new EntitySnowman(world); + BlockPosition blockposition1 = shapedetectorcollection.a(0, 2, 0).d(); + + entitysnowman.setPositionRotation((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.05D, (double) blockposition1.getZ() + 0.5D, 0.0F, 0.0F); +- world.addEntity(entitysnowman); ++ // CraftBukkit start ++ if (world.addEntity(entitysnowman, SpawnReason.BUILD_SNOWMAN)) { ++ blockList.updateList(); + +- for (j = 0; j < 120; ++j) { +- world.addParticle(EnumParticle.SNOW_SHOVEL, (double) blockposition1.getX() + world.random.nextDouble(), (double) blockposition1.getY() + world.random.nextDouble() * 2.5D, (double) blockposition1.getZ() + world.random.nextDouble(), 0.0D, 0.0D, 0.0D, new int[0]); +- } ++ for (j = 0; j < 120; ++j) { ++ world.addParticle(EnumParticle.SNOW_SHOVEL, (double) blockposition1.getX() + world.random.nextDouble(), (double) blockposition1.getY() + world.random.nextDouble() * 2.5D, (double) blockposition1.getZ() + world.random.nextDouble(), 0.0D, 0.0D, 0.0D, new int[0]); ++ } + +- for (j = 0; j < this.getDetectorSnowGolem().b(); ++j) { +- ShapeDetectorBlock shapedetectorblock1 = shapedetectorcollection.a(0, j, 0); ++ for (j = 0; j < this.getDetectorSnowGolem().b(); ++j) { ++ ShapeDetectorBlock shapedetectorblock1 = shapedetectorcollection.a(0, j, 0); + +- world.update(shapedetectorblock1.d(), Blocks.AIR); ++ world.update(shapedetectorblock1.d(), Blocks.AIR); ++ } + } ++ // CraftBukkit end + } else if ((shapedetectorcollection = this.getDetectorIronGolem().a(world, blockposition)) != null) { ++ BlockStateListPopulator blockList = new BlockStateListPopulator(world.getWorld()); // CraftBukkit - Use BlockStateListPopulator + for (i = 0; i < this.getDetectorIronGolem().c(); ++i) { + for (int k = 0; k < this.getDetectorIronGolem().b(); ++k) { +- world.setTypeAndData(shapedetectorcollection.a(i, k, 0).d(), Blocks.AIR.getBlockData(), 2); ++ // CraftBukkit start ++ // world.setTypeAndData(shapedetectorcollection.a(i, k, 0).d(), Blocks.AIR.getBlockData(), 2); ++ BlockPosition pos = shapedetectorcollection.a(i, k, 0).d(); ++ blockList.setTypeId(pos.getX(), pos.getY(), pos.getZ(), 0); ++ // CraftBukkit end + } + } + +@@ -62,22 +82,38 @@ + + entityirongolem.setPlayerCreated(true); + entityirongolem.setPositionRotation((double) blockposition2.getX() + 0.5D, (double) blockposition2.getY() + 0.05D, (double) blockposition2.getZ() + 0.5D, 0.0F, 0.0F); +- world.addEntity(entityirongolem); +- +- for (j = 0; j < 120; ++j) { +- world.addParticle(EnumParticle.SNOWBALL, (double) blockposition2.getX() + world.random.nextDouble(), (double) blockposition2.getY() + world.random.nextDouble() * 3.9D, (double) blockposition2.getZ() + world.random.nextDouble(), 0.0D, 0.0D, 0.0D, new int[0]); +- } ++ // CraftBukkit start ++ if (world.addEntity(entityirongolem, SpawnReason.BUILD_IRONGOLEM)) { ++ blockList.updateList(); ++ ++ for (j = 0; j < 120; ++j) { ++ world.addParticle(EnumParticle.SNOWBALL, (double) blockposition2.getX() + world.random.nextDouble(), (double) blockposition2.getY() + world.random.nextDouble() * 3.9D, (double) blockposition2.getZ() + world.random.nextDouble(), 0.0D, 0.0D, 0.0D, new int[0]); ++ } + +- for (j = 0; j < this.getDetectorIronGolem().c(); ++j) { +- for (int l = 0; l < this.getDetectorIronGolem().b(); ++l) { +- ShapeDetectorBlock shapedetectorblock2 = shapedetectorcollection.a(j, l, 0); ++ for (j = 0; j < this.getDetectorIronGolem().c(); ++j) { ++ for (int l = 0; l < this.getDetectorIronGolem().b(); ++l) { ++ ShapeDetectorBlock shapedetectorblock2 = shapedetectorcollection.a(j, l, 0); + +- world.update(shapedetectorblock2.d(), Blocks.AIR); ++ world.update(shapedetectorblock2.d(), Blocks.AIR); ++ } + } + } ++ // CraftBukkit end + } ++ } + ++ // CraftBukkit start ++ @Override ++ public void doPhysics(World world, BlockPosition position, IBlockData data, Block block) { ++ if (block != null && block.isPowerSource()) { ++ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()); ++ int power = bukkitBlock.getBlockPower(); ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bukkitBlock, power, power); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ } + } ++ // CraftBukkit end + + public boolean canPlace(World world, BlockPosition blockposition) { + return world.getType(blockposition).getBlock().material.isReplaceable() && World.a((IBlockAccess) world, blockposition.down()); diff --git a/paper-server/nms-patches/BlockRedstoneLamp.patch b/paper-server/nms-patches/BlockRedstoneLamp.patch new file mode 100644 index 0000000000..66c8128089 --- /dev/null +++ b/paper-server/nms-patches/BlockRedstoneLamp.patch @@ -0,0 +1,47 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockRedstoneLamp.java 2014-11-27 08:59:46.565422446 +1100 ++++ src/main/java/net/minecraft/server/BlockRedstoneLamp.java 2014-11-27 08:42:10.140850934 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockRedstoneLamp extends Block { + + private final boolean a; +@@ -20,6 +22,11 @@ + if (this.a && !world.isBlockIndirectlyPowered(blockposition)) { + world.setTypeAndData(blockposition, Blocks.REDSTONE_LAMP.getBlockData(), 2); + } else if (!this.a && world.isBlockIndirectlyPowered(blockposition)) { ++ // CraftBukkit start ++ if (CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), 0, 15).getNewCurrent() != 15) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, Blocks.LIT_REDSTONE_LAMP.getBlockData(), 2); + } + +@@ -31,6 +38,11 @@ + if (this.a && !world.isBlockIndirectlyPowered(blockposition)) { + world.a(blockposition, (Block) this, 4); + } else if (!this.a && world.isBlockIndirectlyPowered(blockposition)) { ++ // CraftBukkit start ++ if (CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), 0, 15).getNewCurrent() != 15) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, Blocks.LIT_REDSTONE_LAMP.getBlockData(), 2); + } + +@@ -40,6 +52,11 @@ + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (!world.isStatic) { + if (this.a && !world.isBlockIndirectlyPowered(blockposition)) { ++ // CraftBukkit start ++ if (CraftEventFactory.callRedstoneChange(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), 15, 0).getNewCurrent() != 0) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, Blocks.REDSTONE_LAMP.getBlockData(), 2); + } + diff --git a/paper-server/nms-patches/BlockRedstoneOre.patch b/paper-server/nms-patches/BlockRedstoneOre.patch new file mode 100644 index 0000000000..fcc0a63783 --- /dev/null +++ b/paper-server/nms-patches/BlockRedstoneOre.patch @@ -0,0 +1,102 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockRedstoneOre.java 2014-11-27 08:59:46.565422446 +1100 ++++ src/main/java/net/minecraft/server/BlockRedstoneOre.java 2014-11-27 08:42:10.112850989 +1100 +@@ -2,6 +2,11 @@ + + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityInteractEvent; ++// CraftBukkit end ++ + public class BlockRedstoneOre extends Block { + + private final boolean a; +@@ -20,23 +25,44 @@ + } + + public void attack(World world, BlockPosition blockposition, EntityHuman entityhuman) { +- this.d(world, blockposition); ++ this.d(world, blockposition, entityhuman); // CraftBukkit - add entityhuman + super.attack(world, blockposition, entityhuman); + } + +- public void a(World world, BlockPosition blockposition, Entity entity) { +- this.d(world, blockposition); +- super.a(world, blockposition, entity); ++ public void a(World world, BlockPosition blockposition, Entity entity) { ++ // CraftBukkit start ++ // this.d(world, blockposition); ++ // super.a(world, blockposition, entity); ++ if (entity instanceof EntityHuman) { ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent((EntityHuman) entity, org.bukkit.event.block.Action.PHYSICAL, blockposition, null, null); ++ if (!event.isCancelled()) { ++ this.d(world, blockposition, entity); // add entity ++ super.a(world, blockposition, entity); ++ } ++ } else { ++ EntityInteractEvent event = new EntityInteractEvent(entity.getBukkitEntity(), world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent(event); ++ if (!event.isCancelled()) { ++ this.d(world, blockposition, entity); // add entity ++ super.a(world, blockposition, entity); ++ } ++ } ++ // CraftBukkit end + } + + public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumDirection enumdirection, float f, float f1, float f2) { +- this.d(world, blockposition); ++ this.d(world, blockposition, entityhuman); // CraftBukkit - add entityhuman + return super.interact(world, blockposition, iblockdata, entityhuman, enumdirection, f, f1, f2); + } + +- private void d(World world, BlockPosition blockposition) { ++ private void d(World world, BlockPosition blockposition, Entity entity) { // CraftBukkit - add Entity + this.e(world, blockposition); + if (this == Blocks.REDSTONE_ORE) { ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition.getX(), blockposition.getY(), blockposition.getZ(), Blocks.LIT_REDSTONE_ORE, 0).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition, Blocks.LIT_REDSTONE_ORE.getBlockData()); + } + +@@ -44,6 +70,11 @@ + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (this == Blocks.LIT_REDSTONE_ORE) { ++ // CraftBukkit start ++ if (CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), Blocks.REDSTONE_ORE).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition, Blocks.REDSTONE_ORE.getBlockData()); + } + +@@ -63,12 +94,24 @@ + + public void dropNaturally(World world, BlockPosition blockposition, IBlockData iblockdata, float f, int i) { + super.dropNaturally(world, blockposition, iblockdata, f, i); ++ /* CraftBukkit start - Delegated to getExpDrop + if (this.getDropType(iblockdata, world.random, i) != Item.getItemOf(this)) { + int j = 1 + world.random.nextInt(5); + + this.dropExperience(world, blockposition, j); + } ++ // */ ++ } + ++ @Override ++ public int getExpDrop(World world, IBlockData data, int i) { ++ if (this.getDropType(data, world.random, i) != Item.getItemOf(this)) { ++ int j = 1 + world.random.nextInt(5); ++ ++ return j; ++ } ++ return 0; ++ // CraftBukkit end + } + + private void e(World world, BlockPosition blockposition) { diff --git a/paper-server/nms-patches/BlockRedstoneTorch.patch b/paper-server/nms-patches/BlockRedstoneTorch.patch new file mode 100644 index 0000000000..6051659314 --- /dev/null +++ b/paper-server/nms-patches/BlockRedstoneTorch.patch @@ -0,0 +1,55 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockRedstoneTorch.java 2014-11-27 08:59:46.565422446 +1100 ++++ src/main/java/net/minecraft/server/BlockRedstoneTorch.java 2014-11-27 08:42:10.156850903 +1100 +@@ -6,6 +6,8 @@ + import java.util.Map; + import java.util.Random; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockRedstoneTorch extends BlockTorch { + + private static Map b = Maps.newHashMap(); +@@ -95,9 +97,26 @@ + while (list != null && !list.isEmpty() && world.getTime() - ((RedstoneUpdateInfo) list.get(0)).b > 60L) { + list.remove(0); + } ++ ++ // CraftBukkit start ++ org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ int oldCurrent = this.isOn ? 15 : 0; ++ ++ BlockRedstoneEvent event = new BlockRedstoneEvent(block, oldCurrent, oldCurrent); ++ // CraftBukkit end + + if (this.isOn) { + if (flag) { ++ // CraftBukkit start ++ if (oldCurrent != 0) { ++ event.setNewCurrent(0); ++ manager.callEvent(event); ++ if (event.getNewCurrent() != 0) { ++ return; ++ } ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, Blocks.UNLIT_REDSTONE_TORCH.getBlockData().set(BlockRedstoneTorch.FACING, iblockdata.get(BlockRedstoneTorch.FACING)), 3); + if (this.a(world, blockposition, true)) { + world.makeSound((double) ((float) blockposition.getX() + 0.5F), (double) ((float) blockposition.getY() + 0.5F), (double) ((float) blockposition.getZ() + 0.5F), "random.fizz", 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); +@@ -114,6 +133,16 @@ + } + } + } else if (!flag && !this.a(world, blockposition, false)) { ++ // CraftBukkit start ++ if (oldCurrent != 15) { ++ event.setNewCurrent(15); ++ manager.callEvent(event); ++ if (event.getNewCurrent() != 15) { ++ return; ++ } ++ } ++ // CraftBukkit end ++ + world.setTypeAndData(blockposition, Blocks.REDSTONE_TORCH.getBlockData().set(BlockRedstoneTorch.FACING, iblockdata.get(BlockRedstoneTorch.FACING)), 3); + } + diff --git a/paper-server/nms-patches/BlockRedstoneWire.patch b/paper-server/nms-patches/BlockRedstoneWire.patch new file mode 100644 index 0000000000..79e7b08fef --- /dev/null +++ b/paper-server/nms-patches/BlockRedstoneWire.patch @@ -0,0 +1,27 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockRedstoneWire.java 2014-11-27 08:59:46.569422428 +1100 ++++ src/main/java/net/minecraft/server/BlockRedstoneWire.java 2014-11-27 08:42:10.136850942 +1100 +@@ -8,6 +8,8 @@ + import java.util.Random; + import java.util.Set; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockRedstoneWire extends Block { + + public static final BlockStateEnum NORTH = BlockStateEnum.of("north", EnumRedstoneWireConnection.class); +@@ -123,6 +125,15 @@ + if (k > j - 1) { + j = k; + } ++ ++ // CraftBukkit start ++ if (i != j) { ++ BlockRedstoneEvent event = new BlockRedstoneEvent(world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), i, j); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ j = event.getNewCurrent(); ++ } ++ // CraftBukkit end + + if (i != j) { + iblockdata = iblockdata.set(BlockRedstoneWire.POWER, Integer.valueOf(j)); diff --git a/paper-server/nms-patches/BlockReed.patch b/paper-server/nms-patches/BlockReed.patch new file mode 100644 index 0000000000..667af180f5 --- /dev/null +++ b/paper-server/nms-patches/BlockReed.patch @@ -0,0 +1,18 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockReed.java 2014-11-27 08:59:46.569422428 +1100 ++++ src/main/java/net/minecraft/server/BlockReed.java 2014-11-27 08:42:10.120850973 +1100 +@@ -29,8 +29,13 @@ + int j = ((Integer) iblockdata.get(BlockReed.AGE)).intValue(); + + if (j == 15) { +- world.setTypeUpdate(blockposition.up(), this.getBlockData()); +- world.setTypeAndData(blockposition, iblockdata.set(BlockReed.AGE, Integer.valueOf(0)), 4); ++ // CraftBukkit start ++ // world.setTypeUpdate(blockposition.up(), this.getBlockData()); ++ // world.setTypeAndData(blockposition, iblockdata.set(BlockReed.AGE, Integer.valueOf(0)), 4); ++ BlockPosition upPos = blockposition.up(); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, upPos.getX(), upPos.getY(), upPos.getZ(), this, 0); ++ // CraftBukkit end ++ + } else { + world.setTypeAndData(blockposition, iblockdata.set(BlockReed.AGE, Integer.valueOf(j + 1)), 4); + } diff --git a/paper-server/nms-patches/BlockSapling.patch b/paper-server/nms-patches/BlockSapling.patch new file mode 100644 index 0000000000..5212c9d9a5 --- /dev/null +++ b/paper-server/nms-patches/BlockSapling.patch @@ -0,0 +1,125 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockSapling.java 2014-11-27 08:59:46.573422410 +1100 ++++ src/main/java/net/minecraft/server/BlockSapling.java 2014-11-27 08:42:10.108850996 +1100 +@@ -2,10 +2,20 @@ + + import java.util.Random; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.Location; ++import org.bukkit.TreeType; ++import org.bukkit.block.BlockState; ++import org.bukkit.event.world.StructureGrowEvent; ++// CraftBukkit end ++ + public class BlockSapling extends BlockPlant implements IBlockFragilePlantElement { + + public static final BlockStateEnum TYPE = BlockStateEnum.of("type", EnumLogVariant.class); + public static final BlockStateInteger STAGE = BlockStateInteger.of("stage", 0, 1); ++ public static TreeType treeType; // CraftBukkit + + protected BlockSapling() { + this.j(this.blockStateList.getBlockData().set(BlockSapling.TYPE, EnumLogVariant.OAK).set(BlockSapling.STAGE, Integer.valueOf(0))); +@@ -19,7 +29,30 @@ + if (!world.isStatic) { + super.b(world, blockposition, iblockdata, random); + if (world.getLightLevel(blockposition.up()) >= 9 && random.nextInt(7) == 0) { ++ // CraftBukkit start ++ world.captureTreeGeneration = true; ++ // CraftBukkit end + this.grow(world, blockposition, iblockdata, random); ++ // CraftBukkit start ++ world.captureTreeGeneration = false; ++ if (world.capturedBlockStates.size() > 0) { ++ TreeType treeType = BlockSapling.treeType; ++ BlockSapling.treeType = null; ++ Location location = new Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ List blocks = (List) world.capturedBlockStates.clone(); ++ world.capturedBlockStates.clear(); ++ StructureGrowEvent event = null; ++ if (treeType != null) { ++ event = new StructureGrowEvent(location, treeType, false, null, blocks); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ } ++ if (event == null || !event.isCancelled()) { ++ for (BlockState blockstate : blocks) { ++ blockstate.update(true); ++ } ++ } ++ } ++ // CraftBukkit end + } + + } +@@ -35,7 +68,17 @@ + } + + public void e(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { +- Object object = random.nextInt(10) == 0 ? new WorldGenBigTree(true) : new WorldGenTrees(true); ++ // CraftBukkit start - Turn ternary operator into if statement to set treeType ++ // Object object = random.nextInt(10) == 0 ? new WorldGenBigTree(true) : new WorldGenTrees(true); ++ Object object; ++ if (random.nextInt(10) == 0) { ++ treeType = TreeType.BIG_TREE; ++ object = new WorldGenBigTree(true); ++ } else { ++ treeType = TreeType.TREE; ++ object = new WorldGenTrees(true); ++ } ++ // CraftBukkit end + int i = 0; + int j = 0; + boolean flag = false; +@@ -46,6 +89,7 @@ + for (i = 0; i >= -1; --i) { + for (j = 0; j >= -1; --j) { + if (this.a(world, blockposition.a(i, 0, j), EnumLogVariant.SPRUCE) && this.a(world, blockposition.a(i + 1, 0, j), EnumLogVariant.SPRUCE) && this.a(world, blockposition.a(i, 0, j + 1), EnumLogVariant.SPRUCE) && this.a(world, blockposition.a(i + 1, 0, j + 1), EnumLogVariant.SPRUCE)) { ++ treeType = TreeType.MEGA_REDWOOD; // CraftBukkit + object = new WorldGenMegaTree(false, random.nextBoolean()); + flag = true; + break label78; +@@ -56,11 +100,13 @@ + if (!flag) { + j = 0; + i = 0; ++ treeType = TreeType.REDWOOD; // CraftBukkit + object = new WorldGenTaiga2(true); + } + break; + + case 2: ++ treeType = TreeType.BIRCH; // CraftBukkit + object = new WorldGenForest(true, false); + break; + +@@ -69,6 +115,7 @@ + for (i = 0; i >= -1; --i) { + for (j = 0; j >= -1; --j) { + if (this.a(world, blockposition.a(i, 0, j), EnumLogVariant.JUNGLE) && this.a(world, blockposition.a(i + 1, 0, j), EnumLogVariant.JUNGLE) && this.a(world, blockposition.a(i, 0, j + 1), EnumLogVariant.JUNGLE) && this.a(world, blockposition.a(i + 1, 0, j + 1), EnumLogVariant.JUNGLE)) { ++ treeType = TreeType.JUNGLE; // CraftBukkit + object = new WorldGenJungleTree(true, 10, 20, EnumLogVariant.JUNGLE.a(), EnumLogVariant.JUNGLE.a()); + flag = true; + break label93; +@@ -79,11 +126,13 @@ + if (!flag) { + j = 0; + i = 0; ++ treeType = TreeType.SMALL_JUNGLE; // CraftBukkit + object = new WorldGenTrees(true, 4 + random.nextInt(7), EnumLogVariant.JUNGLE.a(), EnumLogVariant.JUNGLE.a(), false); + } + break; + + case 4: ++ treeType = TreeType.ACACIA; // CraftBukki + object = new WorldGenAcaciaTree(true); + break; + +@@ -92,6 +141,7 @@ + for (i = 0; i >= -1; --i) { + for (j = 0; j >= -1; --j) { + if (this.a(world, blockposition.a(i, 0, j), EnumLogVariant.DARK_OAK) && this.a(world, blockposition.a(i + 1, 0, j), EnumLogVariant.DARK_OAK) && this.a(world, blockposition.a(i, 0, j + 1), EnumLogVariant.DARK_OAK) && this.a(world, blockposition.a(i + 1, 0, j + 1), EnumLogVariant.DARK_OAK)) { ++ treeType = TreeType.DARK_OAK; // CraftBukkit + object = new WorldGenForestTree(true); + flag = true; + break label108; diff --git a/paper-server/nms-patches/BlockSkull.patch b/paper-server/nms-patches/BlockSkull.patch new file mode 100644 index 0000000000..0bebb84d91 --- /dev/null +++ b/paper-server/nms-patches/BlockSkull.patch @@ -0,0 +1,133 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockSkull.java 2014-11-27 08:59:46.573422410 +1100 ++++ src/main/java/net/minecraft/server/BlockSkull.java 2014-11-27 08:42:10.156850903 +1100 +@@ -4,6 +4,11 @@ + import java.util.Iterator; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.util.BlockStateListPopulator; ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; ++// CraftBukkit end ++ + public class BlockSkull extends BlockContainer { + + public static final BlockStateDirection FACING = BlockStateDirection.of("facing"); +@@ -69,8 +74,25 @@ + + return tileentity instanceof TileEntitySkull ? ((TileEntitySkull) tileentity).getSkullType() : super.getDropData(world, blockposition); + } ++ ++ // CraftBukkit start - Special case dropping so we can get info from the tile entity ++ public void dropNaturally(World world, BlockPosition blockposition, IBlockData iblockdata, float f, int i) { ++ if (world.random.nextFloat() < f) { ++ ItemStack itemstack = new ItemStack(Items.SKULL, 1, this.getDropData(world, blockposition)); ++ TileEntitySkull tileentityskull = (TileEntitySkull) world.getTileEntity(blockposition); ++ ++ if (tileentityskull.getSkullType() == 3 && tileentityskull.getGameProfile() != null) { ++ itemstack.setTag(new NBTTagCompound()); ++ NBTTagCompound nbttagcompound = new NBTTagCompound(); ++ ++ GameProfileSerializer.serialize(nbttagcompound, tileentityskull.getGameProfile()); ++ itemstack.getTag().set("SkullOwner", nbttagcompound); ++ } + +- public void dropNaturally(World world, BlockPosition blockposition, IBlockData iblockdata, float f, int i) {} ++ a(world, blockposition, itemstack); ++ } ++ } ++ // CraftBukkit end + + public void a(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman) { + if (entityhuman.abilities.canInstantlyBuild) { +@@ -83,7 +105,10 @@ + + public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) { + if (!world.isStatic) { +- if (!((Boolean) iblockdata.get(BlockSkull.NODROP)).booleanValue()) { ++ // CraftBukkit start - Drop item in code above, not here ++ // if (!((Boolean) iblockdata.get(BlockSkull.NODROP)).booleanValue()) { ++ if (false) { ++ // CraftBukkit end + TileEntity tileentity = world.getTileEntity(blockposition); + + if (tileentity instanceof TileEntitySkull) { +@@ -120,19 +145,30 @@ + ShapeDetectorCollection shapedetectorcollection = shapedetector.a(world, blockposition); + + if (shapedetectorcollection != null) { ++ // CraftBukkit start - Use BlockStateListPopulator ++ BlockStateListPopulator blockList = new BlockStateListPopulator(world.getWorld()); + int i; + + for (i = 0; i < 3; ++i) { + ShapeDetectorBlock shapedetectorblock = shapedetectorcollection.a(i, 0, 0); + +- world.setTypeAndData(shapedetectorblock.d(), shapedetectorblock.a().set(BlockSkull.NODROP, Boolean.valueOf(true)), 2); ++ // CraftBukkit start ++ // world.setTypeAndData(shapedetectorblock.d(), shapedetectorblock.a().set(BlockSkull.NODROP, Boolean.valueOf(true)), 2); ++ BlockPosition pos = shapedetectorblock.d(); ++ IBlockData data = shapedetectorblock.a().set(BlockSkull.NODROP, Boolean.valueOf(true)); ++ blockList.setTypeAndData(pos.getX(), pos.getY(), pos.getZ(), data.getBlock(), data.getBlock().toLegacyData(data), 2); ++ // CraftBukkit end + } + + for (i = 0; i < shapedetector.c(); ++i) { + for (int j = 0; j < shapedetector.b(); ++j) { + ShapeDetectorBlock shapedetectorblock1 = shapedetectorcollection.a(i, j, 0); + +- world.setTypeAndData(shapedetectorblock1.d(), Blocks.AIR.getBlockData(), 2); ++ // CraftBukkit start ++ // world.setTypeAndData(shapedetectorblock1.d(), Blocks.AIR.getBlockData(), 2); ++ BlockPosition pos = shapedetectorblock1.d(); ++ blockList.setTypeAndData(pos.getX(), pos.getY(), pos.getZ(), Blocks.AIR, 0, 2); ++ // CraftBukkit end + } + } + +@@ -145,28 +181,31 @@ + entitywither.n(); + Iterator iterator = world.a(EntityHuman.class, entitywither.getBoundingBox().grow(50.0D, 50.0D, 50.0D)).iterator(); + +- while (iterator.hasNext()) { +- EntityHuman entityhuman = (EntityHuman) iterator.next(); ++ // CraftBukkit start ++ if (world.addEntity(entitywither, SpawnReason.BUILD_WITHER)) { ++ while (iterator.hasNext()) { ++ EntityHuman entityhuman = (EntityHuman) iterator.next(); + +- entityhuman.b((Statistic) AchievementList.I); +- } +- +- world.addEntity(entitywither); ++ entityhuman.b((Statistic) AchievementList.I); ++ } ++ ++ blockList.updateList(); + +- int k; ++ int k; + +- for (k = 0; k < 120; ++k) { +- world.addParticle(EnumParticle.SNOWBALL, (double) blockposition1.getX() + world.random.nextDouble(), (double) (blockposition1.getY() - 2) + world.random.nextDouble() * 3.9D, (double) blockposition1.getZ() + world.random.nextDouble(), 0.0D, 0.0D, 0.0D, new int[0]); +- } ++ for (k = 0; k < 120; ++k) { ++ world.addParticle(EnumParticle.SNOWBALL, (double) blockposition1.getX() + world.random.nextDouble(), (double) (blockposition1.getY() - 2) + world.random.nextDouble() * 3.9D, (double) blockposition1.getZ() + world.random.nextDouble(), 0.0D, 0.0D, 0.0D, new int[0]); ++ } + +- for (k = 0; k < shapedetector.c(); ++k) { +- for (int l = 0; l < shapedetector.b(); ++l) { +- ShapeDetectorBlock shapedetectorblock2 = shapedetectorcollection.a(k, l, 0); ++ for (k = 0; k < shapedetector.c(); ++k) { ++ for (int l = 0; l < shapedetector.b(); ++l) { ++ ShapeDetectorBlock shapedetectorblock2 = shapedetectorcollection.a(k, l, 0); + +- world.update(shapedetectorblock2.d(), Blocks.AIR); ++ world.update(shapedetectorblock2.d(), Blocks.AIR); ++ } + } + } +- ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/BlockSnow.patch b/paper-server/nms-patches/BlockSnow.patch new file mode 100644 index 0000000000..5727d5a58c --- /dev/null +++ b/paper-server/nms-patches/BlockSnow.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockSnow.java 2014-11-27 08:59:46.577422392 +1100 ++++ src/main/java/net/minecraft/server/BlockSnow.java 2014-11-27 08:42:10.144850927 +1100 +@@ -85,6 +85,11 @@ + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (world.b(EnumSkyBlock.BLOCK, blockposition) > 11) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), Blocks.AIR).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.b(world, blockposition, world.getType(blockposition), 0); + world.setAir(blockposition); + } diff --git a/paper-server/nms-patches/BlockSoil.patch b/paper-server/nms-patches/BlockSoil.patch new file mode 100644 index 0000000000..cd0c3d504d --- /dev/null +++ b/paper-server/nms-patches/BlockSoil.patch @@ -0,0 +1,52 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockSoil.java 2014-11-27 08:59:46.577422392 +1100 ++++ src/main/java/net/minecraft/server/BlockSoil.java 2014-11-27 08:42:10.168850880 +1100 +@@ -3,6 +3,11 @@ + import java.util.Iterator; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.event.entity.EntityInteractEvent; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++// CraftBukkit end ++ + public class BlockSoil extends Block { + + public static final BlockStateInteger MOISTURE = BlockStateInteger.of("moisture", 0, 7); +@@ -34,6 +39,12 @@ + if (i > 0) { + world.setTypeAndData(blockposition, iblockdata.set(BlockSoil.MOISTURE, Integer.valueOf(i - 1)), 2); + } else if (!this.d(world, blockposition)) { ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ if (CraftEventFactory.callBlockFadeEvent(block, Blocks.DIRT).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData()); + } + } else if (i < 7) { +@@ -49,6 +60,24 @@ + return; + } + ++ // CraftBukkit start - Interact soil ++ org.bukkit.event.Cancellable cancellable; ++ if (entity instanceof EntityHuman) { ++ cancellable = CraftEventFactory.callPlayerInteractEvent((EntityHuman) entity, org.bukkit.event.block.Action.PHYSICAL, blockposition, null, null); ++ } else { ++ cancellable = new EntityInteractEvent(entity.getBukkitEntity(), world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent((EntityInteractEvent) cancellable); ++ } ++ ++ if (cancellable.isCancelled()) { ++ return; ++ } ++ ++ if (CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition.getX(), blockposition.getY(), blockposition.getZ(), Blocks.DIRT, 0).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ + world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData()); + } + diff --git a/paper-server/nms-patches/BlockStationary.patch b/paper-server/nms-patches/BlockStationary.patch new file mode 100644 index 0000000000..5ffd0a2e54 --- /dev/null +++ b/paper-server/nms-patches/BlockStationary.patch @@ -0,0 +1,40 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockStationary.java 2014-11-27 08:59:46.577422392 +1100 ++++ src/main/java/net/minecraft/server/BlockStationary.java 2014-11-27 08:42:10.152850911 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockStationary extends BlockFluids { + + protected BlockStationary(Material material) { +@@ -41,6 +43,13 @@ + + if (block.material == Material.AIR) { + if (this.e(world, blockposition1)) { ++ // CraftBukkit start - Prevent lava putting something on fire ++ if (world.getType(blockposition1) != Blocks.FIRE) { ++ if (CraftEventFactory.callBlockIgniteEvent(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) { ++ continue; ++ } ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition1, Blocks.FIRE.getBlockData()); + return; + } +@@ -53,6 +62,14 @@ + BlockPosition blockposition2 = blockposition.a(random.nextInt(3) - 1, 0, random.nextInt(3) - 1); + + if (world.isEmpty(blockposition2.up()) && this.m(world, blockposition2)) { ++ // CraftBukkit start - Prevent lava putting something on fire ++ BlockPosition up = blockposition2.up(); ++ if (world.getType(up) != Blocks.FIRE) { ++ if (CraftEventFactory.callBlockIgniteEvent(world, up.getX(), up.getY(), up.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) { ++ continue; ++ } ++ } ++ // CraftBukkit end + world.setTypeUpdate(blockposition2.up(), Blocks.FIRE.getBlockData()); + } + } diff --git a/paper-server/nms-patches/BlockStem.patch b/paper-server/nms-patches/BlockStem.patch new file mode 100644 index 0000000000..b20e09ca25 --- /dev/null +++ b/paper-server/nms-patches/BlockStem.patch @@ -0,0 +1,41 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockStem.java 2014-11-27 08:59:46.581422375 +1100 ++++ src/main/java/net/minecraft/server/BlockStem.java 2014-11-27 08:42:10.152850911 +1100 +@@ -4,6 +4,8 @@ + import java.util.Iterator; + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockStem extends BlockPlant implements IBlockFragilePlantElement { + + public static final BlockStateInteger AGE = BlockStateInteger.of("age", 0, 7); +@@ -50,7 +52,8 @@ + + if (i < 7) { + iblockdata = iblockdata.set(BlockStem.AGE, Integer.valueOf(i + 1)); +- world.setTypeAndData(blockposition, iblockdata, 2); ++ // world.setTypeAndData(blockposition, iblockdata, 2); // CraftBukkit ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, toLegacyData(iblockdata)); // CraftBukkit + } else { + Iterator iterator = EnumDirectionLimit.HORIZONTAL.iterator(); + +@@ -66,7 +69,8 @@ + Block block = world.getType(blockposition.down()).getBlock(); + + if (world.getType(blockposition).getBlock().material == Material.AIR && (block == Blocks.FARMLAND || block == Blocks.DIRT || block == Blocks.GRASS)) { +- world.setTypeUpdate(blockposition, this.blockFruit.getBlockData()); ++ // world.setTypeUpdate(blockposition, this.blockFruit.getBlockData()); // CraftBukkit ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.blockFruit, 0); // CraftBukkit + } + } + } +@@ -77,7 +81,8 @@ + public void g(World world, BlockPosition blockposition, IBlockData iblockdata) { + int i = ((Integer) iblockdata.get(BlockStem.AGE)).intValue() + MathHelper.nextInt(world.random, 2, 5); + +- world.setTypeAndData(blockposition, iblockdata.set(BlockStem.AGE, Integer.valueOf(Math.min(7, i))), 2); ++ // world.setTypeAndData(blockposition, iblockdata.set(BlockStem.AGE, Integer.valueOf(Math.min(7, i))), 2); ++ CraftEventFactory.handleBlockGrowEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this, Math.min(7, i)); // CraftBukkit + } + + public void h() { diff --git a/paper-server/nms-patches/BlockTrapdoor.patch b/paper-server/nms-patches/BlockTrapdoor.patch new file mode 100644 index 0000000000..8b2992a936 --- /dev/null +++ b/paper-server/nms-patches/BlockTrapdoor.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockTrapdoor.java 2014-11-27 08:59:46.581422375 +1100 ++++ src/main/java/net/minecraft/server/BlockTrapdoor.java 2014-11-27 08:42:10.124850965 +1100 +@@ -2,6 +2,8 @@ + + import com.google.common.base.Predicate; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockTrapdoor extends Block { + + public static final BlockStateDirection FACING = BlockStateDirection.of("facing", (Predicate) EnumDirectionLimit.HORIZONTAL); +@@ -101,6 +103,19 @@ + boolean flag = world.isBlockIndirectlyPowered(blockposition); + + if (flag || block.isPowerSource()) { ++ // CraftBukkit start ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.block.Block bblock = bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ int power = bblock.getBlockPower(); ++ int oldPower = (Boolean) iblockdata.get(OPEN) ? 15 : 0; ++ ++ if (oldPower == 0 ^ power == 0 || block.isPowerSource()) { ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bblock, oldPower, power); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ flag = eventRedstone.getNewCurrent() > 0; ++ } ++ // CraftBukkit end + boolean flag1 = ((Boolean) iblockdata.get(BlockTrapdoor.OPEN)).booleanValue(); + + if (flag1 != flag) { diff --git a/paper-server/nms-patches/BlockTripwire.patch b/paper-server/nms-patches/BlockTripwire.patch new file mode 100644 index 0000000000..f3954aa56a --- /dev/null +++ b/paper-server/nms-patches/BlockTripwire.patch @@ -0,0 +1,52 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockTripwire.java 2014-11-27 08:59:46.585422357 +1100 ++++ src/main/java/net/minecraft/server/BlockTripwire.java 2014-11-27 08:42:10.140850934 +1100 +@@ -4,6 +4,8 @@ + import java.util.List; + import java.util.Random; + ++import org.bukkit.event.entity.EntityInteractEvent; // CraftBukkit ++ + public class BlockTripwire extends Block { + + public static final BlockStateBoolean POWERED = BlockStateBoolean.of("powered"); +@@ -154,6 +156,40 @@ + } + } + } ++ ++ // CraftBukkit start - Call interact even when triggering connected tripwire ++ if (flag != flag1 && flag1 && (Boolean)iblockdata.get(ATTACHED)) { ++ org.bukkit.World bworld = world.getWorld(); ++ org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); ++ org.bukkit.block.Block block = bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ boolean allowed = false; ++ ++ // If all of the events are cancelled block the tripwire trigger, else allow ++ for (Object object : list) { ++ if (object != null) { ++ org.bukkit.event.Cancellable cancellable; ++ ++ if (object instanceof EntityHuman) { ++ cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent((EntityHuman) object, org.bukkit.event.block.Action.PHYSICAL, blockposition, null, null); ++ } else if (object instanceof Entity) { ++ cancellable = new EntityInteractEvent(((Entity) object).getBukkitEntity(), block); ++ manager.callEvent((EntityInteractEvent) cancellable); ++ } else { ++ continue; ++ } ++ ++ if (!cancellable.isCancelled()) { ++ allowed = true; ++ break; ++ } ++ } ++ } ++ ++ if (!allowed) { ++ return; ++ } ++ } ++ // CraftBukkit end + + if (flag1 != flag) { + iblockdata = iblockdata.set(BlockTripwire.POWERED, Boolean.valueOf(flag1)); diff --git a/paper-server/nms-patches/BlockTripwireHook.patch b/paper-server/nms-patches/BlockTripwireHook.patch new file mode 100644 index 0000000000..d4da932616 --- /dev/null +++ b/paper-server/nms-patches/BlockTripwireHook.patch @@ -0,0 +1,29 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockTripwireHook.java 2014-11-27 08:59:46.585422357 +1100 ++++ src/main/java/net/minecraft/server/BlockTripwireHook.java 2014-11-27 08:42:10.144850927 +1100 +@@ -5,6 +5,8 @@ + import java.util.Iterator; + import java.util.Random; + ++import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit ++ + public class BlockTripwireHook extends Block { + + public static final BlockStateDirection FACING = BlockStateDirection.of("facing", (Predicate) EnumDirectionLimit.HORIZONTAL); +@@ -141,6 +143,17 @@ + this.a(world, blockposition1, flag5, flag6, flag2, flag3); + } + ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(block, 15, 0); ++ world.getServer().getPluginManager().callEvent(eventRedstone); ++ ++ if (eventRedstone.getNewCurrent() > 0) { ++ return; ++ } ++ // CraftBukkit end ++ + this.a(world, blockposition, flag5, flag6, flag2, flag3); + if (!flag) { + world.setTypeAndData(blockposition, iblockdata3.set(BlockTripwireHook.FACING, enumdirection), 3); diff --git a/paper-server/nms-patches/BlockVine.patch b/paper-server/nms-patches/BlockVine.patch new file mode 100644 index 0000000000..5e920272dd --- /dev/null +++ b/paper-server/nms-patches/BlockVine.patch @@ -0,0 +1,76 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/BlockVine.java 2014-11-27 08:59:46.589422340 +1100 ++++ src/main/java/net/minecraft/server/BlockVine.java 2014-11-27 08:42:10.156850903 +1100 +@@ -3,6 +3,8 @@ + import java.util.Iterator; + import java.util.Random; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class BlockVine extends Block { + + public static final BlockStateBoolean UP = BlockStateBoolean.of("up"); +@@ -203,7 +205,13 @@ + } + + if (((Boolean) iblockdata1.get(BlockVine.NORTH)).booleanValue() || ((Boolean) iblockdata1.get(BlockVine.EAST)).booleanValue() || ((Boolean) iblockdata1.get(BlockVine.SOUTH)).booleanValue() || ((Boolean) iblockdata1.get(BlockVine.WEST)).booleanValue()) { +- world.setTypeAndData(blockposition.up(), iblockdata1, 2); ++ // CraftBukkit start - Call BlockSpreadEvent ++ // world.setTypeAndData(blockposition.up(), iblockdata1, 2); ++ BlockPosition target = blockposition.up(); ++ org.bukkit.block.Block source = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(target.getX(), target.getY(), target.getZ()); ++ CraftEventFactory.handleBlockSpreadEvent(block, source, this, toLegacyData(iblockdata1)); ++ // CraftBukkit end + } + + } +@@ -222,18 +230,30 @@ + boolean flag2 = ((Boolean) iblockdata.get(a(enumdirection2))).booleanValue(); + BlockPosition blockposition2 = blockposition1.shift(enumdirection1); + BlockPosition blockposition3 = blockposition1.shift(enumdirection2); ++ ++ // CraftBukkit start - Call BlockSpreadEvent ++ org.bukkit.block.Block source = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()); + + if (flag1 && this.c(world.getType(blockposition2).getBlock())) { +- world.setTypeAndData(blockposition1, this.getBlockData().set(a(enumdirection1), Boolean.valueOf(true)), 2); ++ // world.setTypeAndData(blockposition1, this.getBlockData().set(a(enumdirection1), Boolean.valueOf(true)), 2); ++ CraftEventFactory.handleBlockSpreadEvent(bukkitBlock, source, block, toLegacyData(this.getBlockData().set(a(enumdirection1), Boolean.valueOf(true)))); + } else if (flag2 && this.c(world.getType(blockposition3).getBlock())) { +- world.setTypeAndData(blockposition1, this.getBlockData().set(a(enumdirection2), Boolean.valueOf(true)), 2); ++ // world.setTypeAndData(blockposition1, this.getBlockData().set(a(enumdirection2), Boolean.valueOf(true)), 2); ++ CraftEventFactory.handleBlockSpreadEvent(bukkitBlock, source, block, toLegacyData(this.getBlockData().set(a(enumdirection2), Boolean.valueOf(true)))); + } else if (flag1 && world.isEmpty(blockposition2) && this.c(world.getType(blockposition.shift(enumdirection1)).getBlock())) { +- world.setTypeAndData(blockposition2, this.getBlockData().set(a(enumdirection.opposite()), Boolean.valueOf(true)), 2); ++ // world.setTypeAndData(blockposition2, this.getBlockData().set(a(enumdirection.opposite()), Boolean.valueOf(true)), 2); ++ bukkitBlock = world.getWorld().getBlockAt(blockposition2.getX(), blockposition2.getY(), blockposition2.getZ()); ++ CraftEventFactory.handleBlockSpreadEvent(bukkitBlock, source, block, toLegacyData(this.getBlockData().set(a(enumdirection.opposite()), Boolean.valueOf(true)))); + } else if (flag2 && world.isEmpty(blockposition3) && this.c(world.getType(blockposition.shift(enumdirection2)).getBlock())) { +- world.setTypeAndData(blockposition3, this.getBlockData().set(a(enumdirection.opposite()), Boolean.valueOf(true)), 2); ++ // world.setTypeAndData(blockposition3, this.getBlockData().set(a(enumdirection.opposite()), Boolean.valueOf(true)), 2); ++ bukkitBlock = world.getWorld().getBlockAt(blockposition3.getX(), blockposition3.getY(), blockposition3.getZ()); ++ CraftEventFactory.handleBlockSpreadEvent(bukkitBlock, source, block, toLegacyData(this.getBlockData().set(a(enumdirection.opposite()), Boolean.valueOf(true)))); + } else if (this.c(world.getType(blockposition1.up()).getBlock())) { +- world.setTypeAndData(blockposition1, this.getBlockData(), 2); ++ // world.setTypeAndData(blockposition1, this.getBlockData(), 2); ++ CraftEventFactory.handleBlockSpreadEvent(bukkitBlock, source, block, toLegacyData(this.getBlockData())); + } ++ // CraftBukkit end + } else if (block.material.k() && block.d()) { + world.setTypeAndData(blockposition, iblockdata.set(a(enumdirection), Boolean.valueOf(true)), 2); + } +@@ -260,7 +280,12 @@ + } + + if (((Boolean) iblockdata3.get(BlockVine.NORTH)).booleanValue() || ((Boolean) iblockdata3.get(BlockVine.EAST)).booleanValue() || ((Boolean) iblockdata3.get(BlockVine.SOUTH)).booleanValue() || ((Boolean) iblockdata3.get(BlockVine.WEST)).booleanValue()) { +- world.setTypeAndData(blockposition1, iblockdata3, 2); ++ // CraftBukkit start - Call BlockSpreadEvent ++ // world.setTypeAndData(blockposition1, iblockdata3, 2); ++ org.bukkit.block.Block source = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()); ++ CraftEventFactory.handleBlockSpreadEvent(bukkitBlock, source, this, toLegacyData(iblockdata3)); ++ // CraftBukkit end + } + } else if (block1 == this) { + iblockdata3 = iblockdata2; diff --git a/paper-server/nms-patches/Chunk.patch b/paper-server/nms-patches/Chunk.patch new file mode 100644 index 0000000000..d2f4392f86 --- /dev/null +++ b/paper-server/nms-patches/Chunk.patch @@ -0,0 +1,169 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Chunk.java 2014-11-27 08:59:46.589422340 +1100 ++++ src/main/java/net/minecraft/server/Chunk.java 2014-11-27 08:42:10.164850887 +1100 +@@ -1,6 +1,7 @@ + package net.minecraft.server; + + import com.google.common.base.Predicate; ++import com.google.common.collect.Lists; // CraftBukkit + import com.google.common.collect.Maps; + import com.google.common.collect.Queues; + import java.util.Arrays; +@@ -14,6 +15,8 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++import org.bukkit.Bukkit; // CraftBukkit ++ + public class Chunk { + + private static final Logger c = LogManager.getLogger(); +@@ -23,7 +26,7 @@ + private final boolean[] g; + private boolean h; + public final World world; +- private final int[] heightMap; ++ public final int[] heightMap; // CraftBukkit - make public + public final int locX; + public final int locZ; + private boolean k; +@@ -40,6 +43,34 @@ + private int v; + private ConcurrentLinkedQueue w; + ++ // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking ++ private int neighbors = 0x1 << 12; ++ ++ public boolean areNeighborsLoaded(final int radius) { ++ switch (radius) { ++ case 2: ++ return this.neighbors == Integer.MAX_VALUE >> 6; ++ case 1: ++ final int mask = ++ // x z offset x z offset x z offset ++ (0x1 << (1 * 5 + 1 + 12)) | (0x1 << (0 * 5 + 1 + 12)) | (0x1 << (-1 * 5 + 1 + 12)) | ++ (0x1 << (1 * 5 + 0 + 12)) | (0x1 << (0 * 5 + 0 + 12)) | (0x1 << (-1 * 5 + 0 + 12)) | ++ (0x1 << (1 * 5 + -1 + 12)) | (0x1 << (0 * 5 + -1 + 12)) | (0x1 << (-1 * 5 + -1 + 12)); ++ return (this.neighbors & mask) == mask; ++ default: ++ throw new UnsupportedOperationException(String.valueOf(radius)); ++ } ++ } ++ ++ public void setNeighborLoaded(final int x, final int z) { ++ this.neighbors |= 0x1 << (x * 5 + 12 + z); ++ } ++ ++ public void setNeighborUnloaded(final int x, final int z) { ++ this.neighbors &= ~(0x1 << (x * 5 + 12 + z)); ++ } ++ // CraftBukkit end ++ + public Chunk(World world, int i, int j) { + this.sections = new ChunkSection[16]; + this.e = new byte[256]; +@@ -60,8 +91,17 @@ + + Arrays.fill(this.f, -999); + Arrays.fill(this.e, (byte) -1); ++ ++ // CraftBukkit start ++ if (!(this instanceof EmptyChunk)) { ++ this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); ++ } + } + ++ public org.bukkit.Chunk bukkitChunk; ++ public boolean mustSave; ++ // CraftBukkit end ++ + public Chunk(World world, ChunkSnapshot chunksnapshot, int i, int j) { + this(world, i, j); + short short0 = 256; +@@ -465,7 +505,13 @@ + flag = j >= i1; + } + +- chunksection.setType(i, j & 15, k, iblockdata); ++ // CraftBukkit start - Delay removing containers until after they're cleaned up ++ if (!(block1 instanceof IContainer)) { ++ chunksection.setType(i, j & 15, k, iblockdata); ++ } ++ // CraftBukkit end ++ ++ + if (block1 != block) { + if (!this.world.isStatic) { + block1.remove(this.world, blockposition, iblockdata1); +@@ -474,6 +520,12 @@ + } + } + ++ // CraftBukkit start - Delay removing containers until after they're cleaned up ++ if (block1 instanceof IContainer) { ++ chunksection.setType(i, j & 15, k, iblockdata); ++ } ++ // CraftBukkit end ++ + if (chunksection.b(i, j & 15, k) != block) { + return null; + } else { +@@ -505,7 +557,8 @@ + } + } + +- if (!this.world.isStatic && block1 != block) { ++ // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. ++ if (!this.world.isStatic && block1 != block && (!this.world.captureBlockStates || block instanceof BlockContainer)) { + block.onPlace(this.world, blockposition, iblockdata); + } + +@@ -586,7 +639,11 @@ + int j = MathHelper.floor(entity.locZ / 16.0D); + + if (i != this.locX || j != this.locZ) { +- Chunk.c.warn("Wrong location! (" + i + ", " + j + ") should be (" + this.locX + ", " + this.locZ + "), " + entity, new Object[] { entity}); ++ // CraftBukkit start ++ Bukkit.getLogger().warning("Wrong location for " + entity + " in world '" + world.getWorld().getName() + "'!"); ++ // Chunk.c.warn("Wrong location! (" + i + ", " + j + ") should be (" + this.locX + ", " + this.locZ + "), " + entity, new Object[] { entity}); ++ Bukkit.getLogger().warning("Entity is at " + entity.locX + "," + entity.locZ + " (chunk " + i + "," + j + ") but was stored in chunk " + this.locX + "," + this.locZ); ++ // CraftBukkit end + entity.die(); + } + +@@ -673,6 +730,13 @@ + + tileentity.D(); + this.tileEntities.put(blockposition, tileentity); ++ // CraftBukkit start ++ } else { ++ System.out.println("Attempted to place a tile entity (" + tileentity + ") at " + tileentity.position.getX() + "," + tileentity.position.getY() + "," + tileentity.position.getZ() ++ + " (" + org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(getType(blockposition)) + ") where there was no entity tile!"); ++ System.out.println("Chunk coordinates: " + (this.locX * 16) + "," + (this.locZ * 16)); ++ new Exception().printStackTrace(); ++ // CraftBukkit end + } + } + +@@ -716,7 +780,21 @@ + } + + for (int i = 0; i < this.entitySlices.length; ++i) { +- this.world.c((Collection) this.entitySlices[i]); ++ // CraftBukkit start ++ List newList = Lists.newArrayList(this.entitySlices[i]); ++ java.util.Iterator iter = newList.iterator(); ++ while (iter.hasNext()) { ++ Entity entity = iter.next(); ++ ++ // Do not pass along players, as doing so can get them stuck outside of time. ++ // (which for example disables inventory icon updates and prevents block breaking) ++ if (entity instanceof EntityPlayer) { ++ iter.remove(); ++ } ++ } ++ ++ this.world.c((Collection) newList); ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/ChunkProviderServer.patch b/paper-server/nms-patches/ChunkProviderServer.patch new file mode 100644 index 0000000000..bbe662e230 --- /dev/null +++ b/paper-server/nms-patches/ChunkProviderServer.patch @@ -0,0 +1,348 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ChunkProviderServer.java 2014-11-27 08:59:46.593422322 +1100 ++++ src/main/java/net/minecraft/server/ChunkProviderServer.java 2014-11-27 08:42:10.124850965 +1100 +@@ -10,17 +10,28 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.util.Random; ++import java.util.logging.Level; ++ ++import org.bukkit.Server; ++import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; ++import org.bukkit.craftbukkit.util.LongHash; ++import org.bukkit.craftbukkit.util.LongHashSet; ++import org.bukkit.craftbukkit.util.LongObjectHashMap; ++import org.bukkit.event.world.ChunkUnloadEvent; ++// CraftBukkit end ++ + public class ChunkProviderServer implements IChunkProvider { + + private static final Logger b = LogManager.getLogger(); +- public Set unloadQueue = Collections.newSetFromMap(new ConcurrentHashMap()); ++ public LongHashSet unloadQueue = new LongHashSet(); // CraftBukkit - LongHashSet + public Chunk emptyChunk; + public IChunkProvider chunkProvider; + private IChunkLoader chunkLoader; +- public boolean forceChunkLoad = true; +- public LongHashMap chunks = new LongHashMap(); +- private List chunkList = Lists.newArrayList(); +- private WorldServer world; ++ public boolean forceChunkLoad = false; // CraftBukkit - true -> false ++ public LongObjectHashMap chunks = new LongObjectHashMap(); ++ public WorldServer world; // CraftBukkit- public + + public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, IChunkProvider ichunkprovider) { + this.emptyChunk = new EmptyChunk(worldserver, 0, 0); +@@ -30,40 +41,93 @@ + } + + public boolean isChunkLoaded(int i, int j) { +- return this.chunks.contains(ChunkCoordIntPair.a(i, j)); ++ return this.chunks.containsKey(LongHash.toLong(i, j)); // CraftBukkit + } + +- public List a() { +- return this.chunkList; ++ // CraftBukkit start - Change return type to Collection and return the values of our chunk map ++ public java.util.Collection a() { ++ // return this.chunkList; ++ return this.chunks.values(); ++ // CraftBukkit end + } + + public void queueUnload(int i, int j) { + if (this.world.worldProvider.e()) { + if (!this.world.c(i, j)) { +- this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(i, j))); ++ // CraftBukkit start ++ this.unloadQueue.add(i, j); ++ ++ Chunk c = chunks.get(LongHash.toLong(i, j)); ++ if (c != null) { ++ c.mustSave = true; ++ } ++ // CraftBukkit end + } + } else { +- this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(i, j))); ++ // CraftBukkit start ++ this.unloadQueue.add(i, j); ++ ++ Chunk c = chunks.get(LongHash.toLong(i, j)); ++ if (c != null) { ++ c.mustSave = true; ++ } ++ // CraftBukkit end + } + + } + + public void b() { +- Iterator iterator = this.chunkList.iterator(); ++ Iterator iterator = this.chunks.values().iterator(); + + while (iterator.hasNext()) { + Chunk chunk = (Chunk) iterator.next(); + + this.queueUnload(chunk.locX, chunk.locZ); + } +- ++ } ++ ++ // CraftBukkit start - Add async variant, provide compatibility ++ public Chunk getChunkIfLoaded(int x, int z) { ++ return chunks.get(LongHash.toLong(x, z)); + } + + public Chunk getChunkAt(int i, int j) { +- long k = ChunkCoordIntPair.a(i, j); +- +- this.unloadQueue.remove(Long.valueOf(k)); +- Chunk chunk = (Chunk) this.chunks.getEntry(k); ++ return getChunkAt(i, j, null); ++ } ++ ++ public Chunk getChunkAt(int i, int j, Runnable runnable) { ++ unloadQueue.remove(i, j); ++ Chunk chunk = chunks.get(LongHash.toLong(i, j)); ++ ChunkRegionLoader loader = null; ++ ++ if (this.chunkLoader instanceof ChunkRegionLoader) { ++ loader = (ChunkRegionLoader) this.chunkLoader; ++ ++ } ++ // We can only use the queue for already generated chunks ++ if (chunk == null && loader != null && loader.chunkExists(world, i, j)) { ++ if (runnable != null) { ++ ChunkIOExecutor.queueChunkLoad(world, loader, this, i, j, runnable); ++ return null; ++ } else { ++ chunk = ChunkIOExecutor.syncChunkLoad(world, loader, this, i, j); ++ } ++ } else if (chunk == null) { ++ chunk = originalGetChunkAt(i, j); ++ } ++ ++ // If we didn't load the chunk async and have a callback run it now ++ if (runnable != null) { ++ runnable.run(); ++ } ++ ++ return chunk; ++ } ++ public Chunk originalGetChunkAt(int i, int j) { ++ this.unloadQueue.remove(i, j); ++ Chunk chunk = (Chunk) this.chunks.get(LongHash.toLong(i, j)); ++ boolean newChunk = false; ++ // CraftBukkit end + + if (chunk == null) { + chunk = this.loadChunk(i, j); +@@ -78,16 +142,44 @@ + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Chunk to be generated"); + + crashreportsystemdetails.a("Location", (Object) String.format("%d,%d", new Object[] { Integer.valueOf(i), Integer.valueOf(j)})); +- crashreportsystemdetails.a("Position hash", (Object) Long.valueOf(k)); ++ crashreportsystemdetails.a("Position hash", (Object) Long.valueOf(LongHash.toLong(i, j))); // CraftBukkit - Use LongHash + crashreportsystemdetails.a("Generator", (Object) this.chunkProvider.getName()); + throw new ReportedException(crashreport); + } + } ++ newChunk = true; // CraftBukkit + } + +- this.chunks.put(k, chunk); +- this.chunkList.add(chunk); ++ this.chunks.put(LongHash.toLong(i, j), chunk); + chunk.addEntities(); ++ ++ // CraftBukkit start ++ Server server = world.getServer(); ++ if (server != null) { ++ /* ++ * If it's a new world, the first few chunks are generated inside ++ * the World constructor. We can't reliably alter that, so we have ++ * no way of creating a CraftWorld/CraftServer at that point. ++ */ ++ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(chunk.bukkitChunk, newChunk)); ++ } ++ ++ // Update neighbor counts ++ for (int x = -2; x < 3; x++) { ++ for (int z = -2; z < 3; z++) { ++ if (x == 0 && z == 0) { ++ continue; ++ } ++ ++ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); ++ if (neighbor != null) { ++ neighbor.setNeighborLoaded(-x, -z); ++ chunk.setNeighborLoaded(x, z); ++ } ++ } ++ } ++ // CraftBukkit end ++ + chunk.loadNearby(this, this, i, j); + } + +@@ -95,9 +187,22 @@ + } + + public Chunk getOrCreateChunk(int i, int j) { +- Chunk chunk = (Chunk) this.chunks.getEntry(ChunkCoordIntPair.a(i, j)); ++ // CraftBukkit start ++ Chunk chunk = (Chunk) this.chunks.get(LongHash.toLong(i, j)); + +- return chunk == null ? (!this.world.ad() && !this.forceChunkLoad ? this.emptyChunk : this.getChunkAt(i, j)) : chunk; ++ chunk = chunk == null ? (!this.world.ad() && !this.forceChunkLoad ? this.emptyChunk : this.getChunkAt(i, j)) : chunk; ++ ++ if (chunk == emptyChunk) return chunk; ++ if (i != chunk.locX || j != chunk.locZ) { ++ b.error("Chunk (" + chunk.locX + ", " + chunk.locZ + ") stored at (" + i + ", " + j + ") in world '" + world.getWorld().getName() + "'"); ++ b.error(chunk.getClass().getName()); ++ Throwable ex = new Throwable(); ++ ex.fillInStackTrace(); ++ ex.printStackTrace(); ++ } ++ ++ return chunk; ++ // CraftBukkit end + } + + public Chunk loadChunk(int i, int j) { +@@ -138,10 +243,13 @@ + try { + chunk.setLastSaved(this.world.getTime()); + this.chunkLoader.a(this.world, chunk); +- } catch (IOException ioexception) { ++ // CraftBukkit start - IOException to Exception ++ } catch (Exception ioexception) { + ChunkProviderServer.b.error("Couldn\'t save chunk", ioexception); ++ /* Remove extra exception + } catch (ExceptionWorldConflict exceptionworldconflict) { + ChunkProviderServer.b.error("Couldn\'t save chunk; already in use by another instance of Minecraft?", exceptionworldconflict); ++ // CraftBukkit end */ + } + + } +@@ -154,6 +262,30 @@ + chunk.n(); + if (this.chunkProvider != null) { + this.chunkProvider.getChunkAt(ichunkprovider, i, j); ++ ++ // CraftBukkit start ++ BlockSand.instaFall = true; ++ Random random = new Random(); ++ random.setSeed(world.getSeed()); ++ long xRand = random.nextLong() / 2L * 2L + 1L; ++ long zRand = random.nextLong() / 2L * 2L + 1L; ++ random.setSeed((long) i * xRand + (long) j * zRand ^ world.getSeed()); ++ ++ org.bukkit.World world = this.world.getWorld(); ++ if (world != null) { ++ this.world.populating = true; ++ try { ++ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) { ++ populator.populate(world, random, chunk.bukkitChunk); ++ } ++ } finally { ++ this.world.populating = false; ++ } ++ } ++ BlockSand.instaFall = false; ++ this.world.getServer().getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(chunk.bukkitChunk)); ++ // CraftBukkit end ++ + chunk.e(); + } + } +@@ -173,9 +305,12 @@ + + public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { + int i = 0; +- +- for (int j = 0; j < this.chunkList.size(); ++j) { +- Chunk chunk = (Chunk) this.chunkList.get(j); ++ ++ // CraftBukkit start ++ Iterator iterator = this.chunks.values().iterator(); ++ while (iterator.hasNext()) { ++ Chunk chunk = (Chunk) iterator.next(); ++ // CraftBukkit end + + if (flag) { + this.saveChunkNOP(chunk); +@@ -203,22 +338,42 @@ + + public boolean unloadChunks() { + if (!this.world.savingDisabled) { +- for (int i = 0; i < 100; ++i) { +- if (!this.unloadQueue.isEmpty()) { +- Long olong = (Long) this.unloadQueue.iterator().next(); +- Chunk chunk = (Chunk) this.chunks.getEntry(olong.longValue()); +- ++ // CraftBukkit start ++ Server server = this.world.getServer(); ++ for (int i = 0; i < 100 && !this.unloadQueue.isEmpty(); ++i) { ++ long chunkcoordinates = this.unloadQueue.popFirst(); ++ Chunk chunk = this.chunks.get(chunkcoordinates); ++ if (chunk == null) continue; ++ ++ ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); ++ server.getPluginManager().callEvent(event); ++ if (!event.isCancelled()) { + if (chunk != null) { + chunk.removeEntities(); + this.saveChunk(chunk); + this.saveChunkNOP(chunk); +- this.chunks.remove(olong.longValue()); +- this.chunkList.remove(chunk); ++ this.chunks.remove(chunkcoordinates); // CraftBukkit + } + +- this.unloadQueue.remove(olong); ++ // this.unloadQueue.remove(olong); ++ ++ // Update neighbor counts ++ for (int x = -2; x < 3; x++) { ++ for (int z = -2; z < 3; z++) { ++ if (x == 0 && z == 0) { ++ continue; ++ } ++ ++ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); ++ if (neighbor != null) { ++ neighbor.setNeighborUnloaded(-x, -z); ++ chunk.setNeighborUnloaded(x, z); ++ } ++ } ++ } + } +- } ++ } ++ // CraftBukkit end + + if (this.chunkLoader != null) { + this.chunkLoader.a(); +@@ -233,7 +388,8 @@ + } + + public String getName() { +- return "ServerChunkCache: " + this.chunks.count() + " Drop: " + this.unloadQueue.size(); ++ // CraftBukkit - this.chunks.count() -> .size() ++ return "ServerChunkCache: " + this.chunks.size() + " Drop: " + this.unloadQueue.size(); + } + + public List getMobsFor(EnumCreatureType enumcreaturetype, BlockPosition blockposition) { +@@ -245,7 +401,8 @@ + } + + public int getLoadedChunks() { +- return this.chunks.count(); ++ // CraftBukkit - this.chunks.count() -> this.chunks.size() ++ return this.chunks.size(); + } + + public void recreateStructures(Chunk chunk, int i, int j) {} diff --git a/paper-server/nms-patches/ChunkRegionLoader.patch b/paper-server/nms-patches/ChunkRegionLoader.patch new file mode 100644 index 0000000000..35c373ed68 --- /dev/null +++ b/paper-server/nms-patches/ChunkRegionLoader.patch @@ -0,0 +1,131 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ChunkRegionLoader.java 2014-11-27 08:59:46.593422322 +1100 ++++ src/main/java/net/minecraft/server/ChunkRegionLoader.java 2014-11-27 08:42:10.136850942 +1100 +@@ -23,8 +23,40 @@ + public ChunkRegionLoader(File file) { + this.e = file; + } ++ ++ // CraftBukkit start ++ public boolean chunkExists(World world, int i, int j) { ++ ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j); ++ ++ synchronized (this.d) { ++ if (this.c.contains(chunkcoordintpair)) { ++ for (int k = 0; k < this.b.size(); ++k) { ++ if (((PendingChunkToSave) this.b.get(k)).a.equals(chunkcoordintpair)) { ++ return true; ++ } ++ } ++ } ++ } ++ ++ return RegionFileCache.a(this.e, i, j).chunkExists(i & 31, j & 31); ++ } ++ // CraftBukkit end + ++ // CraftBukkit start - Add async variant, provide compatibility + public Chunk a(World world, int i, int j) { ++ Object[] data = loadChunk(world, i, j); ++ if (data != null) { ++ Chunk chunk = (Chunk) data[0]; ++ NBTTagCompound nbttagcompound = (NBTTagCompound) data[1]; ++ loadEntities(chunk, nbttagcompound.getCompound("Level"), world); ++ return chunk; ++ } ++ ++ return null; ++ } ++ ++ public Object[] loadChunk(World world, int i, int j) { ++ // CraftBukkit end + NBTTagCompound nbttagcompound = null; + ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j); + Object object = this.d; +@@ -53,7 +85,7 @@ + return this.a(world, i, j, nbttagcompound); + } + +- protected Chunk a(World world, int i, int j, NBTTagCompound nbttagcompound) { ++ protected Object[] a(World world, int i, int j, NBTTagCompound nbttagcompound) { // CraftBukkit - return Chunk -> Object[] + if (!nbttagcompound.hasKeyOfType("Level", 10)) { + ChunkRegionLoader.a.error("Chunk file at " + i + "," + j + " is missing level data, skipping"); + return null; +@@ -64,18 +96,42 @@ + Chunk chunk = this.a(world, nbttagcompound.getCompound("Level")); + + if (!chunk.a(i, j)) { +- ChunkRegionLoader.a.error("Chunk file at " + i + "," + j + " is in the wrong location; relocating. (Expected " + i + ", " + j + ", got " + chunk.locX + ", " + chunk.locZ + ")"); +- nbttagcompound.setInt("xPos", i); +- nbttagcompound.setInt("zPos", j); ++ a.error("Chunk file at " + i + "," + j + " is in the wrong location; relocating. (Expected " + i + ", " + j + ", got " + chunk.locX + ", " + chunk.locZ + ")"); ++ nbttagcompound.getCompound("Level").setInt("xPos", i); ++ nbttagcompound.getCompound("Level").setInt("zPos", j); ++ ++ // CraftBukkit start - Have to move tile entities since we don't load them at this stage ++ NBTTagList tileEntities = nbttagcompound.getCompound("Level").getList("TileEntities", 10); ++ if (tileEntities != null) { ++ for (int te = 0; te < tileEntities.size(); te++) { ++ NBTTagCompound tileEntity = (NBTTagCompound) tileEntities.get(te); ++ int x = tileEntity.getInt("x") - chunk.locX * 16; ++ int z = tileEntity.getInt("z") - chunk.locZ * 16; ++ tileEntity.setInt("x", i * 16 + x); ++ tileEntity.setInt("z", j * 16 + z); ++ } ++ } ++ // CraftBukkit end + chunk = this.a(world, nbttagcompound.getCompound("Level")); + } + +- return chunk; ++ // CraftBukkit start ++ Object[] data = new Object[2]; ++ data[0] = chunk; ++ data[1] = nbttagcompound; ++ return data; ++ // CraftBukkit end + } + } + + public void a(World world, Chunk chunk) { +- world.checkSession(); ++ // CraftBukkit start - "handle" exception ++ try { ++ world.checkSession(); ++ } catch (ExceptionWorldConflict ex) { ++ ex.printStackTrace(); ++ } ++ // CraftBukkit end + + try { + NBTTagCompound nbttagcompound = new NBTTagCompound(); +@@ -133,7 +189,7 @@ + return true; + } + +- public void a(PendingChunkToSave pendingchunktosave) { ++ public void a(PendingChunkToSave pendingchunktosave) throws java.io.IOException { // CraftBukkit - added throws + DataOutputStream dataoutputstream = RegionFileCache.d(this.e, pendingchunktosave.a.x, pendingchunktosave.a.z); + + NBTCompressedStreamTools.a(pendingchunktosave.b, (DataOutput) dataoutputstream); +@@ -320,7 +376,13 @@ + if (nbttagcompound.hasKeyOfType("Biomes", 7)) { + chunk.a(nbttagcompound.getByteArray("Biomes")); + } ++ ++ // CraftBukkit start - End this method here and split off entity loading to another method ++ return chunk; ++ } + ++ public void loadEntities(Chunk chunk, NBTTagCompound nbttagcompound, World world) { ++ // CraftBukkit end + NBTTagList nbttaglist1 = nbttagcompound.getList("Entities", 10); + + if (nbttaglist1 != null) { +@@ -379,6 +441,6 @@ + } + } + +- return chunk; ++ // return chunk; // CraftBukkit + } + } diff --git a/paper-server/nms-patches/ChunkSection.patch b/paper-server/nms-patches/ChunkSection.patch new file mode 100644 index 0000000000..4063d6cc3a --- /dev/null +++ b/paper-server/nms-patches/ChunkSection.patch @@ -0,0 +1,21 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ChunkSection.java 2014-11-27 08:59:46.597422305 +1100 ++++ src/main/java/net/minecraft/server/ChunkSection.java 2014-11-27 08:42:10.172850872 +1100 +@@ -19,6 +19,18 @@ + + } + ++ // CraftBukkit start ++ public ChunkSection(int y, boolean flag, char[] blockIds) { ++ this.yPos = y; ++ this.blockIds = blockIds; ++ this.emittedLight = new NibbleArray(); ++ if (flag) { ++ this.skyLight = new NibbleArray(); ++ } ++ recalcBlockCounts(); ++ } ++ // CraftBukkit end ++ + public IBlockData getType(int i, int j, int k) { + IBlockData iblockdata = (IBlockData) Block.d.a(this.blockIds[j << 8 | k << 4 | i]); + diff --git a/paper-server/nms-patches/CommandBlockListenerAbstract.patch b/paper-server/nms-patches/CommandBlockListenerAbstract.patch new file mode 100644 index 0000000000..c49fad99f0 --- /dev/null +++ b/paper-server/nms-patches/CommandBlockListenerAbstract.patch @@ -0,0 +1,162 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/CommandBlockListenerAbstract.java 2014-11-27 08:59:46.597422305 +1100 ++++ src/main/java/net/minecraft/server/CommandBlockListenerAbstract.java 2014-11-27 08:42:10.172850872 +1100 +@@ -4,6 +4,13 @@ + import java.util.Date; + import java.util.concurrent.Callable; + ++// CraftBukkit start ++import java.util.ArrayList; ++import org.apache.logging.log4j.Level; ++import org.bukkit.craftbukkit.command.VanillaCommandWrapper; ++import com.google.common.base.Joiner; ++// CraftBukkit end ++ + public abstract class CommandBlockListenerAbstract implements ICommandListener { + + private static final SimpleDateFormat a = new SimpleDateFormat("HH:mm:ss"); +@@ -13,6 +20,7 @@ + public String e = ""; + private String f = "@"; + private final CommandObjectiveExecutor g = new CommandObjectiveExecutor(); ++ protected org.bukkit.command.CommandSender sender; // CraftBukkit - add sender + + public CommandBlockListenerAbstract() {} + +@@ -79,7 +87,109 @@ + + try { + this.d = null; +- this.b = icommandhandler.a(this, this.e); ++ // this.b = icommandhandler.a(this, this.e); ++ // CraftBukkit start - Handle command block commands using Bukkit dispatcher ++ org.bukkit.command.SimpleCommandMap commandMap = minecraftserver.server.getCommandMap(); ++ Joiner joiner = Joiner.on(" "); ++ String command = this.e; ++ if (this.e.startsWith("/")) { ++ command = this.e.substring(1); ++ } ++ String[] args = command.split(" "); ++ ArrayList commands = new ArrayList(); ++ ++ // Block disallowed commands ++ if (args[0].equalsIgnoreCase("stop") || args[0].equalsIgnoreCase("kick") || args[0].equalsIgnoreCase("op") || ++ args[0].equalsIgnoreCase("deop") || args[0].equalsIgnoreCase("ban") || args[0].equalsIgnoreCase("ban-ip") || ++ args[0].equalsIgnoreCase("pardon") || args[0].equalsIgnoreCase("pardon-ip") || args[0].equalsIgnoreCase("reload")) { ++ this.b = 0; ++ return; ++ } ++ ++ // If the world has no players don't run ++ if (this.getWorld().players.isEmpty()) { ++ this.b = 0; ++ return; ++ } ++ ++ // Handle vanilla commands; ++ if (minecraftserver.server.getCommandBlockOverride(args[0])) { ++ org.bukkit.command.Command commandBlockCommand = commandMap.getCommand("minecraft:" + args[0]); ++ if (commandBlockCommand instanceof VanillaCommandWrapper) { ++ this.b = ((VanillaCommandWrapper) commandBlockCommand).dispatchVanillaCommandBlock(this, this.e); ++ return; ++ } ++ } ++ ++ // Make sure this is a valid command ++ if (commandMap.getCommand(args[0]) == null) { ++ this.b = 0; ++ return; ++ } ++ ++ // testfor command requires special handling ++ if (args[0].equalsIgnoreCase("testfor")) { ++ if (args.length < 2) { ++ this.b = 0; ++ return; ++ } ++ ++ EntityPlayer[] players = ((java.util.List)PlayerSelector.getPlayers(this, args[1], EntityPlayer.class)).toArray(new EntityPlayer[0]); ++ ++ if (players != null && players.length > 0) { ++ this.b = players.length; ++ return; ++ } else { ++ EntityPlayer player = MinecraftServer.getServer().getPlayerList().getPlayer(args[1]); ++ if (player == null) { ++ this.b = 0; ++ return; ++ } else { ++ this.b = 1; ++ return; ++ } ++ } ++ } ++ ++ commands.add(args); ++ ++ // Find positions of command block syntax, if any ++ ArrayList newCommands = new ArrayList(); ++ for (int i = 0; i < args.length; i++) { ++ if (PlayerSelector.isPattern(args[i])) { ++ for (int j = 0; j < commands.size(); j++) { ++ newCommands.addAll(this.buildCommands(commands.get(j), i)); ++ } ++ ArrayList temp = commands; ++ commands = newCommands; ++ newCommands = temp; ++ newCommands.clear(); ++ } ++ } ++ ++ int completed = 0; ++ ++ // Now dispatch all of the commands we ended up with ++ for (int i = 0; i < commands.size(); i++) { ++ try { ++ if (commandMap.dispatch(sender, joiner.join(java.util.Arrays.asList(commands.get(i))))) { ++ completed++; ++ } ++ } catch (Throwable exception) { ++ if(this instanceof TileEntityCommandListener) { ++ TileEntityCommandListener listener = (TileEntityCommandListener) this; ++ MinecraftServer.getLogger().log(Level.WARN, String.format("CommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().getX(), listener.getChunkCoordinates().getY(), listener.getChunkCoordinates().getZ()), exception); ++ } else if (this instanceof EntityMinecartCommandBlockListener) { ++ EntityMinecartCommandBlockListener listener = (EntityMinecartCommandBlockListener) this; ++ MinecraftServer.getLogger().log(Level.WARN, String.format("MinecartCommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().getX(), listener.getChunkCoordinates().getY(), listener.getChunkCoordinates().getZ()), exception); ++ } else { ++ MinecraftServer.getLogger().log(Level.WARN, String.format("Unknown CommandBlock failed to handle command"), exception); ++ } ++ } ++ } ++ ++ this.b = completed; ++ // CraftBukkit end + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.a(throwable, "Executing command block"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Command to be executed"); +@@ -91,8 +201,26 @@ + } else { + this.b = 0; + } ++ } ++ ++ // CraftBukkit start ++ private ArrayList buildCommands(String[] args, int pos) { ++ ArrayList commands = new ArrayList(); ++ EntityPlayer[] players = ((java.util.List)PlayerSelector.getPlayers(this, args[pos], EntityPlayer.class)).toArray(new EntityPlayer[0]); ++ if (players != null) { ++ for (EntityPlayer player : players) { ++ if (player.world != this.getWorld()) { ++ continue; ++ } ++ String[] command = args.clone(); ++ command[pos] = player.getName(); ++ commands.add(command); ++ } ++ } + ++ return commands; + } ++ // CraftBukkit end + + public String getName() { + return this.f; diff --git a/paper-server/nms-patches/Container.patch b/paper-server/nms-patches/Container.patch new file mode 100644 index 0000000000..4891ecc55f --- /dev/null +++ b/paper-server/nms-patches/Container.patch @@ -0,0 +1,204 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Container.java 2014-11-27 08:59:46.617422217 +1100 ++++ src/main/java/net/minecraft/server/Container.java 2014-11-27 08:42:10.156850903 +1100 +@@ -7,6 +7,17 @@ + import java.util.List; + import java.util.Set; + ++// CraftBukkit start ++import java.util.HashMap; ++import java.util.Map; ++import org.bukkit.craftbukkit.inventory.CraftInventory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.Event.Result; ++import org.bukkit.event.inventory.InventoryDragEvent; ++import org.bukkit.event.inventory.InventoryType; ++import org.bukkit.inventory.InventoryView; ++// CraftBukkit end ++ + public abstract class Container { + + public List b = Lists.newArrayList(); +@@ -17,6 +28,18 @@ + private final Set h = Sets.newHashSet(); + protected List listeners = Lists.newArrayList(); + private Set i = Sets.newHashSet(); ++ ++ // CraftBukkit start ++ public boolean checkReachable = true; ++ public abstract InventoryView getBukkitView(); ++ public void transferTo(Container other, org.bukkit.craftbukkit.entity.CraftHumanEntity player) { ++ InventoryView source = this.getBukkitView(), destination = other.getBukkitView(); ++ ((CraftInventory) source.getTopInventory()).getInventory().onClose(player); ++ ((CraftInventory) source.getBottomInventory()).getInventory().onClose(player); ++ ((CraftInventory) destination.getTopInventory()).getInventory().onOpen(player); ++ ((CraftInventory) destination.getBottomInventory()).getInventory().onOpen(player); ++ } ++ // CraftBukkit end + + public Container() {} + +@@ -124,6 +147,7 @@ + l = playerinventory.getCarried().count; + Iterator iterator = this.h.iterator(); + ++ Map draggedSlots = new HashMap(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack) + while (iterator.hasNext()) { + Slot slot1 = (Slot) iterator.next(); + +@@ -141,16 +165,49 @@ + } + + l -= itemstack2.count - j1; +- slot1.set(itemstack2); ++ // slot1.set(itemstack2); ++ draggedSlots.put(slot1.rawSlotIndex, itemstack2); // CraftBukkit - Put in map instead of setting + } + } ++ ++ // CraftBukkit start - InventoryDragEvent ++ InventoryView view = getBukkitView(); ++ org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack1); ++ newcursor.setAmount(l); ++ Map eventmap = new HashMap(); ++ for (Map.Entry ditem : draggedSlots.entrySet()) { ++ eventmap.put(ditem.getKey(), CraftItemStack.asBukkitCopy(ditem.getValue())); ++ } ++ ++ // It's essential that we set the cursor to the new value here to prevent item duplication if a plugin closes the inventory. ++ ItemStack oldCursor = playerinventory.getCarried(); ++ playerinventory.setCarried(CraftItemStack.asNMSCopy(newcursor)); ++ ++ InventoryDragEvent event = new InventoryDragEvent(view, (newcursor.getType() != org.bukkit.Material.AIR ? newcursor : null), CraftItemStack.asBukkitCopy(oldCursor), this.dragType == 1, eventmap); ++ entityhuman.world.getServer().getPluginManager().callEvent(event); ++ ++ // Whether or not a change was made to the inventory that requires an update. ++ boolean needsUpdate = event.getResult() != Result.DEFAULT; ++ ++ if (event.getResult() != Result.DENY) { ++ for (Map.Entry dslot : draggedSlots.entrySet()) { ++ view.setItem(dslot.getKey(), CraftItemStack.asBukkitCopy(dslot.getValue())); ++ } ++ // The only time the carried item will be set to null is if the inventory is closed by the server. ++ // If the inventory is closed by the server, then the cursor items are dropped. This is why we change the cursor early. ++ if (playerinventory.getCarried() != null) { ++ playerinventory.setCarried(CraftItemStack.asNMSCopy(event.getCursor())); ++ needsUpdate = true; + +- itemstack1.count = l; +- if (itemstack1.count <= 0) { +- itemstack1 = null; ++ } ++ } else { ++ playerinventory.setCarried(oldCursor); + } + +- playerinventory.setCarried(itemstack1); ++ if (needsUpdate && entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).updateInventory(this); ++ } ++ // CraftBukkit end + } + + this.d(); +@@ -173,8 +230,14 @@ + } + + if (j == 1) { +- entityhuman.drop(playerinventory.getCarried().a(1), true); +- if (playerinventory.getCarried().count == 0) { ++ // CraftBukkit start - Store a reference ++ ItemStack itemstack4 = playerinventory.getCarried(); ++ if (itemstack4.count > 0) { ++ entityhuman.drop(itemstack4.a(1), true); ++ } ++ ++ if (itemstack4.count == 0) { ++ // CraftBukkit end + playerinventory.setCarried((ItemStack) null); + } + } +@@ -223,7 +286,11 @@ + + if (itemstack4.count == 0) { + playerinventory.setCarried((ItemStack) null); ++ // CraftBukkit start - Update client cursor if we didn't empty it ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, entityhuman.inventory.getCarried())); + } ++ // CraftBukkit end + } + } else if (slot2.isAllowed(entityhuman)) { + if (itemstack4 == null) { +@@ -249,7 +316,11 @@ + itemstack4.a(k1); + if (itemstack4.count == 0) { + playerinventory.setCarried((ItemStack) null); ++ // CraftBukkit start - Update client cursor if we didn't empty it ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, entityhuman.inventory.getCarried())); + } ++ // CraftBukkit end + + itemstack1.count += k1; + } else if (itemstack4.count <= slot2.getMaxStackSize(itemstack4)) { +@@ -258,7 +329,9 @@ + } + } else if (itemstack1.getItem() == itemstack4.getItem() && itemstack4.getMaxStackSize() > 1 && (!itemstack1.usesData() || itemstack1.getData() == itemstack4.getData()) && ItemStack.equals(itemstack1, itemstack4)) { + k1 = itemstack1.count; +- if (k1 > 0 && k1 + itemstack4.count <= itemstack4.getMaxStackSize()) { ++ // CraftBukkit start - itemstack4.getMaxStackSize() -> maxStack ++ int maxStack = Math.min(itemstack4.getMaxStackSize(), slot2.getMaxStackSize()); ++ if (k1 > 0 && k1 + itemstack4.count <= maxStack) { + itemstack4.count += k1; + itemstack1 = slot2.a(k1); + if (itemstack1.count == 0) { +@@ -266,11 +339,24 @@ + } + + slot2.a(entityhuman, playerinventory.getCarried()); ++ // CraftBukkit start - Update client cursor if we didn't empty it ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, entityhuman.inventory.getCarried())); + } ++ // CraftBukkit end + } + } + + slot2.f(); ++ // CraftBukkit start - Make sure the client has the right slot contents ++ if (entityhuman instanceof EntityPlayer && slot2.getMaxStackSize() != 64) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(this.windowId, slot2.rawSlotIndex, slot2.getItem())); ++ // Updating a crafting inventory makes the client reset the result slot, have to send it again ++ if (this.getBukkitView().getType() == InventoryType.WORKBENCH || this.getBukkitView().getType() == InventoryType.CRAFTING) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutSetSlot(this.windowId, 0, this.getSlot(0).getItem())); ++ } ++ } ++ // CraftBukkit end + } + } + } else if (k == 2 && j >= 0 && j < 9) { +@@ -411,17 +497,20 @@ + if (itemstack1 != null && itemstack1.getItem() == itemstack.getItem() && (!itemstack.usesData() || itemstack.getData() == itemstack1.getData()) && ItemStack.equals(itemstack, itemstack1)) { + int l = itemstack1.count + itemstack.count; + +- if (l <= itemstack.getMaxStackSize()) { ++ // CraftBukkit start - itemstack.getMaxStackSize() -> maxStack ++ int maxStack = Math.min(itemstack.getMaxStackSize(), slot.getMaxStackSize()); ++ if (l <= maxStack) { + itemstack.count = 0; + itemstack1.count = l; + slot.f(); + flag1 = true; +- } else if (itemstack1.count < itemstack.getMaxStackSize()) { +- itemstack.count -= itemstack.getMaxStackSize() - itemstack1.count; +- itemstack1.count = itemstack.getMaxStackSize(); ++ } else if (itemstack1.count < maxStack) { ++ itemstack.count -= maxStack - itemstack1.count; ++ itemstack1.count = maxStack; + slot.f(); + flag1 = true; + } ++ // CraftBukkit end + } + + if (flag) { diff --git a/paper-server/nms-patches/ContainerAnvil.patch b/paper-server/nms-patches/ContainerAnvil.patch new file mode 100644 index 0000000000..1c0c583a7e --- /dev/null +++ b/paper-server/nms-patches/ContainerAnvil.patch @@ -0,0 +1,51 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerAnvil.java 2014-11-27 08:59:46.601422287 +1100 ++++ src/main/java/net/minecraft/server/ContainerAnvil.java 2014-11-27 08:42:10.144850927 +1100 +@@ -6,6 +6,8 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; // CraftBukkit ++ + public class ContainerAnvil extends Container { + + private static final Logger f = LogManager.getLogger(); +@@ -17,8 +19,13 @@ + private int k; + private String l; + private final EntityHuman m; ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ // CraftBukkit end + + public ContainerAnvil(PlayerInventory playerinventory, World world, BlockPosition blockposition, EntityHuman entityhuman) { ++ this.player = playerinventory; // CraftBukkit + this.j = blockposition; + this.i = world; + this.m = entityhuman; +@@ -265,6 +272,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.i.getType(this.j).getBlock() != Blocks.ANVIL ? false : entityhuman.e((double) this.j.getX() + 0.5D, (double) this.j.getY() + 0.5D, (double) this.j.getZ() + 0.5D) <= 64.0D; + } + +@@ -328,4 +336,17 @@ + static int b(ContainerAnvil containeranvil) { + return containeranvil.k; + } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ org.bukkit.craftbukkit.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryAnvil(this.h, this.g); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerAnvilInventory.patch b/paper-server/nms-patches/ContainerAnvilInventory.patch new file mode 100644 index 0000000000..16649334ad --- /dev/null +++ b/paper-server/nms-patches/ContainerAnvilInventory.patch @@ -0,0 +1,58 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerAnvilInventory.java 2014-11-27 08:59:46.597422305 +1100 ++++ src/main/java/net/minecraft/server/ContainerAnvilInventory.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,8 +1,43 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class ContainerAnvilInventory extends InventorySubcontainer { + + final ContainerAnvil a; ++ ++ // CraftBukkit start ++ public List transaction = new java.util.ArrayList(); ++ public org.bukkit.entity.Player player; ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return this.player; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } + + ContainerAnvilInventory(ContainerAnvil containeranvil, String s, boolean flag, int i) { + super(s, flag, i); +@@ -13,4 +48,11 @@ + super.update(); + this.a.a((IInventory) this); + } ++ ++ // CraftBukkit start - override inherited maxStack from InventorySubcontainer ++ @Override ++ public int getMaxStackSize() { ++ return maxStack; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerBeacon.patch b/paper-server/nms-patches/ContainerBeacon.patch new file mode 100644 index 0000000000..178e143c10 --- /dev/null +++ b/paper-server/nms-patches/ContainerBeacon.patch @@ -0,0 +1,47 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerBeacon.java 2014-11-27 08:59:46.601422287 +1100 ++++ src/main/java/net/minecraft/server/ContainerBeacon.java 2014-11-27 08:42:10.156850903 +1100 +@@ -1,11 +1,18 @@ + package net.minecraft.server; + ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; // CraftBukkit ++ + public class ContainerBeacon extends Container { + + private IInventory a; + private final SlotBeacon f; ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ // CraftBukkit end + + public ContainerBeacon(IInventory iinventory, IInventory iinventory1) { ++ player = (PlayerInventory) iinventory; // CraftBukkit - TODO: check this + this.a = iinventory1; + this.a((Slot) (this.f = new SlotBeacon(this, iinventory1, 0, 136, 110))); + byte b0 = 36; +@@ -35,6 +42,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.a.a(entityhuman); + } + +@@ -83,4 +91,17 @@ + + return itemstack; + } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ org.bukkit.craftbukkit.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryBeacon((TileEntityBeacon) this.a); // TODO - check this ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerBrewingStand.patch b/paper-server/nms-patches/ContainerBrewingStand.patch new file mode 100644 index 0000000000..b7aba135e1 --- /dev/null +++ b/paper-server/nms-patches/ContainerBrewingStand.patch @@ -0,0 +1,52 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerBrewingStand.java 2014-11-27 08:59:46.605422269 +1100 ++++ src/main/java/net/minecraft/server/ContainerBrewingStand.java 2014-11-27 08:42:10.172850872 +1100 +@@ -1,12 +1,23 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventoryBrewer; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerBrewingStand extends Container { + + private IInventory brewingStand; + private final Slot f; + private int g; ++ ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ // CraftBukkit end + + public ContainerBrewingStand(PlayerInventory playerinventory, IInventory iinventory) { ++ player = playerinventory; // CraftBukkit + this.brewingStand = iinventory; + this.a((Slot) (new SlotPotionBottle(playerinventory.player, iinventory, 0, 56, 46))); + this.a((Slot) (new SlotPotionBottle(playerinventory.player, iinventory, 1, 79, 53))); +@@ -47,6 +58,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.brewingStand.a(entityhuman); + } + +@@ -101,4 +113,17 @@ + + return itemstack; + } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventoryBrewer inventory = new CraftInventoryBrewer(this.brewingStand); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerChest.patch b/paper-server/nms-patches/ContainerChest.patch new file mode 100644 index 0000000000..7021c61b54 --- /dev/null +++ b/paper-server/nms-patches/ContainerChest.patch @@ -0,0 +1,59 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerChest.java 2014-11-27 08:59:46.605422269 +1100 ++++ src/main/java/net/minecraft/server/ContainerChest.java 2014-11-27 08:42:10.172850872 +1100 +@@ -1,15 +1,48 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventory; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerChest extends Container { + + public IInventory container; + private int f; ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventory inventory; ++ if (this.container instanceof PlayerInventory) { ++ inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryPlayer((PlayerInventory) this.container); ++ } else if (this.container instanceof InventoryLargeChest) { ++ inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) this.container); ++ } else { ++ inventory = new CraftInventory(this.container); ++ } ++ ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + + public ContainerChest(IInventory iinventory, IInventory iinventory1, EntityHuman entityhuman) { + this.container = iinventory1; + this.f = iinventory1.getSize() / 9; + iinventory1.startOpen(entityhuman); + int i = (this.f - 4) * 18; ++ ++ // CraftBukkit start - Save player ++ // TODO: Should we check to make sure it really is an InventoryPlayer? ++ this.player = (PlayerInventory) iinventory; ++ // CraftBukkit end + + int j; + int k; +@@ -33,6 +66,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.container.a(entityhuman); + } + diff --git a/paper-server/nms-patches/ContainerDispenser.patch b/paper-server/nms-patches/ContainerDispenser.patch new file mode 100644 index 0000000000..cee5477961 --- /dev/null +++ b/paper-server/nms-patches/ContainerDispenser.patch @@ -0,0 +1,54 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerDispenser.java 2014-11-27 08:59:46.605422269 +1100 ++++ src/main/java/net/minecraft/server/ContainerDispenser.java 2014-11-27 08:42:10.148850918 +1100 +@@ -1,11 +1,24 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventory; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerDispenser extends Container { + +- private IInventory items; ++ public IInventory items; // CraftBukkit - private -> public ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ // CraftBukkit end + + public ContainerDispenser(IInventory iinventory, IInventory iinventory1) { + this.items = iinventory1; ++ // CraftBukkit start - Save player ++ // TODO: Should we check to make sure it really is an InventoryPlayer? ++ this.player = (PlayerInventory)iinventory; ++ // CraftBukkit end + + int i; + int j; +@@ -29,6 +42,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.items.a(entityhuman); + } + +@@ -63,4 +77,17 @@ + + return itemstack; + } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventory inventory = new CraftInventory(this.items); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerEnchantTable.patch b/paper-server/nms-patches/ContainerEnchantTable.patch new file mode 100644 index 0000000000..f2d866d89b --- /dev/null +++ b/paper-server/nms-patches/ContainerEnchantTable.patch @@ -0,0 +1,170 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerEnchantTable.java 2014-11-27 08:59:46.609422252 +1100 ++++ src/main/java/net/minecraft/server/ContainerEnchantTable.java 2014-11-27 08:42:10.120850973 +1100 +@@ -3,15 +3,31 @@ + import java.util.List; + import java.util.Random; + ++// CraftBukkit start ++import java.util.Map; ++ ++import org.bukkit.craftbukkit.inventory.CraftInventoryEnchanting; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.enchantment.EnchantItemEvent; ++import org.bukkit.event.enchantment.PrepareItemEnchantEvent; ++import org.bukkit.entity.Player; ++// CraftBukkit end ++ + public class ContainerEnchantTable extends Container { + +- public IInventory enchantSlots = new ContainerEnchantTableInventory(this, "Enchant", true, 2); ++ // CraftBukkit - make type specific (changed from IInventory) ++ public ContainerEnchantTableInventory enchantSlots = new ContainerEnchantTableInventory(this, "Enchant", true, 2); + private World world; + private BlockPosition position; + private Random k = new Random(); + public int f; + public int[] costs = new int[3]; + public int[] h = new int[] { -1, -1, -1}; ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private Player player; ++ // CraftBukkit end + + public ContainerEnchantTable(PlayerInventory playerinventory, World world, BlockPosition blockposition) { + this.world = world; +@@ -31,7 +47,11 @@ + for (i = 0; i < 9; ++i) { + this.a(new Slot(playerinventory, i, 8 + i * 18, 142)); + } +- ++ ++ // CraftBukkit start ++ player = (Player) playerinventory.player.getBukkitEntity(); ++ enchantSlots.player = player; ++ // CraftBukkit end + } + + public void addSlotListener(ICrafting icrafting) { +@@ -67,7 +87,7 @@ + ItemStack itemstack = iinventory.getItem(0); + int i; + +- if (itemstack != null && itemstack.v()) { ++ if (itemstack != null) { // CraftBukkit - relax condition + if (!this.world.isStatic) { + i = 0; + +@@ -114,6 +134,20 @@ + this.costs[j] = 0; + } + } ++ ++ // CraftBukkit start ++ CraftItemStack item = CraftItemStack.asCraftMirror(itemstack); ++ PrepareItemEnchantEvent event = new PrepareItemEnchantEvent(player, this.getBukkitView(), this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), item, this.costs, i); ++ event.setCancelled(!itemstack.v()); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ for (i = 0; i < 3; ++i) { ++ this.costs[i] = 0; ++ } ++ return; ++ } ++ // CraftBukkit end + + for (j = 0; j < 3; ++j) { + if (this.costs[j] > 0) { +@@ -149,24 +183,56 @@ + } else if (this.costs[i] > 0 && itemstack != null && (entityhuman.expLevel >= j && entityhuman.expLevel >= this.costs[i] || entityhuman.abilities.canInstantlyBuild)) { + if (!this.world.isStatic) { + List list = this.a(itemstack, i, this.costs[i]); ++ // CraftBukkit start - Provide an empty enchantment list ++ if (list == null) { ++ list = new java.util.ArrayList(); ++ } ++ // CraftBukkit end + boolean flag = itemstack.getItem() == Items.BOOK; + + if (list != null) { +- entityhuman.b(j); ++ // CraftBukkit start ++ Map enchants = new java.util.HashMap(); ++ for (Object obj : list) { ++ WeightedRandomEnchant instance = (WeightedRandomEnchant) obj; ++ enchants.put(org.bukkit.enchantments.Enchantment.getById(instance.enchantment.id), instance.level); ++ } ++ CraftItemStack item = CraftItemStack.asCraftMirror(itemstack); ++ ++ EnchantItemEvent event = new EnchantItemEvent((Player) entityhuman.getBukkitEntity(), this.getBukkitView(), this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), item, this.costs[i], enchants, i); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ int level = event.getExpLevelCost(); ++ if (event.isCancelled() || (level > entityhuman.expLevel && !entityhuman.abilities.canInstantlyBuild) || event.getEnchantsToAdd().isEmpty()) { ++ return false; ++ } ++ + if (flag) { + itemstack.setItem(Items.ENCHANTED_BOOK); + } ++ ++ for (Map.Entry entry : event.getEnchantsToAdd().entrySet()) { ++ try { ++ if (flag) { ++ int enchantId = entry.getKey().getId(); ++ if (Enchantment.getById(enchantId) == null) { ++ continue; ++ } + +- for (int k = 0; k < list.size(); ++k) { +- WeightedRandomEnchant weightedrandomenchant = (WeightedRandomEnchant) list.get(k); +- +- if (flag) { +- Items.ENCHANTED_BOOK.a(itemstack, weightedrandomenchant); +- } else { +- itemstack.addEnchantment(weightedrandomenchant.enchantment, weightedrandomenchant.level); ++ WeightedRandomEnchant enchantment = new WeightedRandomEnchant(Enchantment.getById(enchantId), entry.getValue()); ++ Items.ENCHANTED_BOOK.a(itemstack, enchantment); ++ } else { ++ item.addUnsafeEnchantment(entry.getKey(), entry.getValue()); ++ } ++ } catch (IllegalArgumentException e) { ++ /* Just swallow invalid enchantments */ + } + } ++ ++ entityhuman.b(level); ++ // CraftBukkit end + ++ // CraftBukkit - TODO: let plugins change this + if (!entityhuman.abilities.canInstantlyBuild) { + itemstack1.count -= j; + if (itemstack1.count <= 0) { +@@ -212,6 +278,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.world.getType(this.position).getBlock() != Blocks.ENCHANTING_TABLE ? false : entityhuman.e((double) this.position.getX() + 0.5D, (double) this.position.getY() + 0.5D, (double) this.position.getZ() + 0.5D) <= 64.0D; + } + +@@ -263,5 +330,18 @@ + } + + return itemstack; ++ } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventoryEnchanting inventory = new CraftInventoryEnchanting(this.enchantSlots); ++ bukkitEntity = new CraftInventoryView(this.player, inventory, this); ++ return bukkitEntity; + } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerEnchantTableInventory.patch b/paper-server/nms-patches/ContainerEnchantTableInventory.patch new file mode 100644 index 0000000000..f2f80b3e53 --- /dev/null +++ b/paper-server/nms-patches/ContainerEnchantTableInventory.patch @@ -0,0 +1,58 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerEnchantTableInventory.java 2014-11-27 08:59:46.609422252 +1100 ++++ src/main/java/net/minecraft/server/ContainerEnchantTableInventory.java 2014-11-27 08:42:10.088851036 +1100 +@@ -1,8 +1,45 @@ + package net.minecraft.server; + +-class ContainerEnchantTableInventory extends InventorySubcontainer { ++// CraftBukkit start ++import java.util.List; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ ++// CraftBukkit -> public ++public class ContainerEnchantTableInventory extends InventorySubcontainer { + + final ContainerEnchantTable enchantTable; ++ ++ // CraftBukkit start ++ public List transaction = new java.util.ArrayList(); ++ public org.bukkit.entity.Player player; ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return this.player; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + ContainerEnchantTableInventory(ContainerEnchantTable containerenchanttable, String s, boolean flag, int i) { + super(s, flag, i); +@@ -10,7 +47,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public void update() { diff --git a/paper-server/nms-patches/ContainerFurnace.patch b/paper-server/nms-patches/ContainerFurnace.patch new file mode 100644 index 0000000000..b299ee2055 --- /dev/null +++ b/paper-server/nms-patches/ContainerFurnace.patch @@ -0,0 +1,51 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerFurnace.java 2014-11-27 08:59:46.613422234 +1100 ++++ src/main/java/net/minecraft/server/ContainerFurnace.java 2014-11-27 08:42:10.116850981 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventoryFurnace; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerFurnace extends Container { + + private final IInventory furnace; +@@ -7,12 +12,29 @@ + private int g; + private int h; + private int i; ++ ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventoryFurnace inventory = new CraftInventoryFurnace((TileEntityFurnace) this.furnace); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + + public ContainerFurnace(PlayerInventory playerinventory, IInventory iinventory) { + this.furnace = iinventory; + this.a(new Slot(iinventory, 0, 56, 17)); + this.a((Slot) (new SlotFurnaceFuel(iinventory, 1, 56, 53))); + this.a((Slot) (new SlotFurnaceResult(playerinventory.player, iinventory, 2, 116, 35))); ++ this.player = playerinventory; // CraftBukkit - save player + + int i; + +@@ -63,6 +85,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.furnace.a(entityhuman); + } + diff --git a/paper-server/nms-patches/ContainerHopper.patch b/paper-server/nms-patches/ContainerHopper.patch new file mode 100644 index 0000000000..4654d33ad2 --- /dev/null +++ b/paper-server/nms-patches/ContainerHopper.patch @@ -0,0 +1,44 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerHopper.java 2014-11-27 08:59:46.613422234 +1100 ++++ src/main/java/net/minecraft/server/ContainerHopper.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,11 +1,33 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventory; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerHopper extends Container { + + private final IInventory hopper; ++ ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventory inventory = new CraftInventory(this.hopper); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + + public ContainerHopper(PlayerInventory playerinventory, IInventory iinventory, EntityHuman entityhuman) { + this.hopper = iinventory; ++ this.player = playerinventory; // CraftBukkit - save player + iinventory.startOpen(entityhuman); + byte b0 = 51; + +@@ -28,6 +50,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.hopper.a(entityhuman); + } + diff --git a/paper-server/nms-patches/ContainerHorse.patch b/paper-server/nms-patches/ContainerHorse.patch new file mode 100644 index 0000000000..9c9fa57aea --- /dev/null +++ b/paper-server/nms-patches/ContainerHorse.patch @@ -0,0 +1,36 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerHorse.java 2014-11-27 08:59:46.613422234 +1100 ++++ src/main/java/net/minecraft/server/ContainerHorse.java 2014-11-27 08:42:10.124850965 +1100 +@@ -1,11 +1,33 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventory; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++import org.bukkit.inventory.InventoryView; ++// CraftBukkit end ++ + public class ContainerHorse extends Container { + + private IInventory a; + private EntityHorse f; ++ ++ // CraftBukkit start ++ org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity; ++ PlayerInventory player; ++ ++ @Override ++ public InventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryHorse(this.a); ++ return bukkitEntity = new CraftInventoryView(player.player.getBukkitEntity(), inventory, this); ++ } + + public ContainerHorse(IInventory iinventory, IInventory iinventory1, EntityHorse entityhorse, EntityHuman entityhuman) { ++ player = (PlayerInventory) iinventory; ++ // CraftBukkit end + this.a = iinventory1; + this.f = entityhorse; + byte b0 = 3; diff --git a/paper-server/nms-patches/ContainerMerchant.patch b/paper-server/nms-patches/ContainerMerchant.patch new file mode 100644 index 0000000000..d62ffe9e1c --- /dev/null +++ b/paper-server/nms-patches/ContainerMerchant.patch @@ -0,0 +1,36 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerMerchant.java 2014-11-27 08:59:46.617422217 +1100 ++++ src/main/java/net/minecraft/server/ContainerMerchant.java 2014-11-27 08:42:10.136850942 +1100 +@@ -1,10 +1,25 @@ + package net.minecraft.server; + ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; // CraftBukkit ++ + public class ContainerMerchant extends Container { + + private IMerchant merchant; + private InventoryMerchant f; + private final World g; ++ ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity == null) { ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.inventory.CraftInventoryMerchant((InventoryMerchant) f), this); ++ } ++ return bukkitEntity; ++ } ++ // CraftBukkit end + + public ContainerMerchant(PlayerInventory playerinventory, IMerchant imerchant, World world) { + this.merchant = imerchant; +@@ -13,6 +28,7 @@ + this.a(new Slot(this.f, 0, 36, 53)); + this.a(new Slot(this.f, 1, 62, 53)); + this.a((Slot) (new SlotMerchantResult(playerinventory.player, imerchant, this.f, 2, 120, 53))); ++ this.player = playerinventory; // CraftBukkit - save player + + int i; + diff --git a/paper-server/nms-patches/ContainerPlayer.patch b/paper-server/nms-patches/ContainerPlayer.patch new file mode 100644 index 0000000000..8b2c347bd8 --- /dev/null +++ b/paper-server/nms-patches/ContainerPlayer.patch @@ -0,0 +1,74 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerPlayer.java 2014-11-27 08:59:46.621422199 +1100 ++++ src/main/java/net/minecraft/server/ContainerPlayer.java 2014-11-27 08:42:10.104851005 +1100 +@@ -1,15 +1,28 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerPlayer extends Container { + + public InventoryCrafting craftInventory = new InventoryCrafting(this, 2, 2); + public IInventory resultInventory = new InventoryCraftResult(); + public boolean g; + private final EntityHuman h; ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ // CraftBukkit end + + public ContainerPlayer(PlayerInventory playerinventory, boolean flag, EntityHuman entityhuman) { + this.g = flag; + this.h = entityhuman; ++ this.resultInventory = new InventoryCraftResult(); // CraftBukkit - moved to before InventoryCrafting construction ++ this.craftInventory = new InventoryCrafting(this, 2, 2, playerinventory.player); // CraftBukkit - pass player ++ this.craftInventory.resultInventory = this.resultInventory; // CraftBukkit - let InventoryCrafting know about its result slot ++ this.player = playerinventory; // CraftBukkit - save player + this.a((Slot) (new SlotResult(playerinventory.player, this.craftInventory, this.resultInventory, 0, 144, 36))); + + int i; +@@ -35,11 +48,22 @@ + this.a(new Slot(playerinventory, i, 8 + i * 18, 142)); + } + +- this.a((IInventory) this.craftInventory); ++ // this.a((IInventory) this.craftInventory); // CraftBukkit - unneeded since it just sets result slot to empty + } + + public void a(IInventory iinventory) { +- this.resultInventory.setItem(0, CraftingManager.getInstance().craft(this.craftInventory, this.h.world)); ++ // this.resultInventory.setItem(0, CraftingManager.getInstance().craft(this.craftInventory, this.h.world)); ++ // CraftBukkit start (Note: the following line would cause an error if called during construction) ++ CraftingManager.getInstance().lastCraftView = getBukkitView(); ++ ItemStack craftResult = CraftingManager.getInstance().craft(this.craftInventory, this.h.world); ++ this.resultInventory.setItem(0, craftResult); ++ if (super.listeners.size() < 1) { ++ return; ++ } ++ ++ EntityPlayer player = (EntityPlayer) super.listeners.get(0); // TODO: Is this _always_ correct? Seems like it. ++ player.playerConnection.sendPacket(new PacketPlayOutSetSlot(player.activeContainer.windowId, 0, craftResult)); ++ // CraftBukkit end + } + + public void b(EntityHuman entityhuman) { +@@ -119,4 +143,17 @@ + public boolean a(ItemStack itemstack, Slot slot) { + return slot.inventory != this.resultInventory && super.a(itemstack, slot); + } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftInventory, this.resultInventory); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ContainerWorkbench.patch b/paper-server/nms-patches/ContainerWorkbench.patch new file mode 100644 index 0000000000..045167c1b9 --- /dev/null +++ b/paper-server/nms-patches/ContainerWorkbench.patch @@ -0,0 +1,79 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ContainerWorkbench.java 2014-11-27 08:59:46.621422199 +1100 ++++ src/main/java/net/minecraft/server/ContainerWorkbench.java 2014-11-27 08:42:10.156850903 +1100 +@@ -1,13 +1,28 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++// CraftBukkit end ++ + public class ContainerWorkbench extends Container { + +- public InventoryCrafting craftInventory = new InventoryCrafting(this, 3, 3); +- public IInventory resultInventory = new InventoryCraftResult(); ++ public InventoryCrafting craftInventory; // CraftBukkit - move initialization into constructor ++ public IInventory resultInventory; // CraftBukkit - move initialization into constructor + private World g; + private BlockPosition h; ++ // CraftBukkit start ++ private CraftInventoryView bukkitEntity = null; ++ private PlayerInventory player; ++ // CraftBukkit end + + public ContainerWorkbench(PlayerInventory playerinventory, World world, BlockPosition blockposition) { ++ // CraftBukkit start - Switched order of IInventory construction and stored player ++ this.resultInventory = new InventoryCraftResult(); ++ this.craftInventory = new InventoryCrafting(this, 3, 3, playerinventory.player); // CraftBukkit - pass player ++ this.craftInventory.resultInventory = this.resultInventory; ++ this.player = playerinventory; ++ // CraftBukkit end + this.g = world; + this.h = blockposition; + this.a((Slot) (new SlotResult(playerinventory.player, this.craftInventory, this.resultInventory, 0, 124, 35))); +@@ -35,7 +50,18 @@ + } + + public void a(IInventory iinventory) { +- this.resultInventory.setItem(0, CraftingManager.getInstance().craft(this.craftInventory, this.g)); ++ // this.resultInventory.setItem(0, CraftingManager.getInstance().craft(this.craftInventory, this.g)); ++ // CraftBukkit start ++ CraftingManager.getInstance().lastCraftView = getBukkitView(); ++ ItemStack craftResult = CraftingManager.getInstance().craft(this.craftInventory, this.g); ++ this.resultInventory.setItem(0, craftResult); ++ if (super.listeners.size() < 1) { ++ return; ++ } ++ ++ EntityPlayer player = (EntityPlayer) super.listeners.get(0); // TODO: Is this _always_ correct? Seems like it. ++ player.playerConnection.sendPacket(new PacketPlayOutSetSlot(player.activeContainer.windowId, 0, craftResult)); ++ // CraftBukkit end + } + + public void b(EntityHuman entityhuman) { +@@ -53,6 +79,7 @@ + } + + public boolean a(EntityHuman entityhuman) { ++ if (!this.checkReachable) return true; // CraftBukkit + return this.g.getType(this.h).getBlock() != Blocks.CRAFTING_TABLE ? false : entityhuman.e((double) this.h.getX() + 0.5D, (double) this.h.getY() + 0.5D, (double) this.h.getZ() + 0.5D) <= 64.0D; + } + +@@ -101,4 +128,17 @@ + public boolean a(ItemStack itemstack, Slot slot) { + return slot.inventory != this.resultInventory && super.a(itemstack, slot); + } ++ ++ // CraftBukkit start ++ @Override ++ public CraftInventoryView getBukkitView() { ++ if (bukkitEntity != null) { ++ return bukkitEntity; ++ } ++ ++ CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftInventory, this.resultInventory); ++ bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this); ++ return bukkitEntity; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/ControllerLook.patch b/paper-server/nms-patches/ControllerLook.patch new file mode 100644 index 0000000000..212d063ea8 --- /dev/null +++ b/paper-server/nms-patches/ControllerLook.patch @@ -0,0 +1,23 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ControllerLook.java 2014-11-27 08:59:46.621422199 +1100 ++++ src/main/java/net/minecraft/server/ControllerLook.java 2014-11-27 08:42:10.172850872 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.craftbukkit.TrigMath; // CraftBukkit ++ + public class ControllerLook { + + private EntityInsentient a; +@@ -45,8 +47,10 @@ + double d1 = this.f - (this.a.locY + (double) this.a.getHeadHeight()); + double d2 = this.g - this.a.locZ; + double d3 = (double) MathHelper.sqrt(d0 * d0 + d2 * d2); +- float f = (float) (Math.atan2(d2, d0) * 180.0D / 3.1415927410125732D) - 90.0F; +- float f1 = (float) (-(Math.atan2(d1, d3) * 180.0D / 3.1415927410125732D)); ++ // CraftBukkit start - Math -> TrigMath ++ float f = (float) (TrigMath.atan2(d2, d0) * 180.0D / 3.1415927410125732D) - 90.0F; ++ float f1 = (float) (-(TrigMath.atan2(d1, d3) * 180.0D / 3.1415927410125732D)); ++ // CraftBukkit end + + this.a.pitch = this.a(this.a.pitch, f1, this.c); + this.a.aI = this.a(this.a.aI, f, this.b); diff --git a/paper-server/nms-patches/ControllerMove.patch b/paper-server/nms-patches/ControllerMove.patch new file mode 100644 index 0000000000..9963db77f5 --- /dev/null +++ b/paper-server/nms-patches/ControllerMove.patch @@ -0,0 +1,12 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ControllerMove.java 2014-11-27 08:59:46.625422182 +1100 ++++ src/main/java/net/minecraft/server/ControllerMove.java 2014-11-27 08:42:10.164850887 +1100 +@@ -43,7 +43,8 @@ + double d3 = d0 * d0 + d2 * d2 + d1 * d1; + + if (d3 >= 2.500000277905201E-7D) { +- float f = (float) (Math.atan2(d1, d0) * 180.0D / 3.1415927410125732D) - 90.0F; ++ // CraftBukkit - Math -> TrigMath ++ float f = (float) (org.bukkit.craftbukkit.TrigMath.atan2(d1, d0) * 180.0D / 3.1415927410125732D) - 90.0F; + + this.a.yaw = this.a(this.a.yaw, f, 30.0F); + this.a.j((float) (this.e * this.a.getAttributeInstance(GenericAttributes.d).getValue())); diff --git a/paper-server/nms-patches/CraftingManager.patch b/paper-server/nms-patches/CraftingManager.patch new file mode 100644 index 0000000000..8d0f4bde9d --- /dev/null +++ b/paper-server/nms-patches/CraftingManager.patch @@ -0,0 +1,57 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/CraftingManager.java 2014-11-27 08:59:46.625422182 +1100 ++++ src/main/java/net/minecraft/server/CraftingManager.java 2014-11-27 08:42:10.112850989 +1100 +@@ -8,10 +8,16 @@ + import java.util.Iterator; + import java.util.List; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class CraftingManager { + + private static final CraftingManager a = new CraftingManager(); + public List recipes = Lists.newArrayList(); ++ // CraftBukkit start ++ public IRecipe lastRecipe; ++ public org.bukkit.inventory.InventoryView lastCraftView; ++ // CraftBukkit end + + public static CraftingManager getInstance() { + return CraftingManager.a; +@@ -166,8 +172,15 @@ + this.registerShapedRecipe(new ItemStack(Blocks.DAYLIGHT_DETECTOR), new Object[] { "GGG", "QQQ", "WWW", Character.valueOf('G'), Blocks.GLASS, Character.valueOf('Q'), Items.QUARTZ, Character.valueOf('W'), Blocks.WOODEN_SLAB}); + this.registerShapedRecipe(new ItemStack(Blocks.HOPPER), new Object[] { "I I", "ICI", " I ", Character.valueOf('I'), Items.IRON_INGOT, Character.valueOf('C'), Blocks.CHEST}); + this.registerShapedRecipe(new ItemStack(Items.ARMOR_STAND, 1), new Object[] { "///", " / ", "/_/", Character.valueOf('/'), Items.STICK, Character.valueOf('_'), new ItemStack(Blocks.STONE_SLAB, 1, EnumStoneSlabVariant.STONE.a())}); ++ // Collections.sort(this.recipes, new RecipeSorter(this)); // CraftBukkit - moved below ++ sort(); ++ } ++ ++ // CraftBukkit start ++ public void sort() { + Collections.sort(this.recipes, new RecipeSorter(this)); + } ++ // CraftBukkit end + + public ShapedRecipes registerShapedRecipe(ItemStack itemstack, Object... aobject) { + String s = ""; +@@ -265,13 +278,18 @@ + + do { + if (!iterator.hasNext()) { ++ inventorycrafting.currentRecipe = null; // CraftBukkit - Clear recipe when no recipe is found + return null; + } + + irecipe = (IRecipe) iterator.next(); +- } while (!irecipe.a(inventorycrafting, world)); +- +- return irecipe.a(inventorycrafting); ++ } while (!irecipe.a(inventorycrafting, world)); ++ ++ // CraftBukkit start - INVENTORY_PRE_CRAFT event ++ inventorycrafting.currentRecipe = irecipe; ++ ItemStack result = irecipe.a(inventorycrafting); ++ return CraftEventFactory.callPreCraftEvent(inventorycrafting, result, lastCraftView, false); ++ // CraftBukkit end + } + + public ItemStack[] b(InventoryCrafting inventorycrafting, World world) { diff --git a/paper-server/nms-patches/CrashReport.patch b/paper-server/nms-patches/CrashReport.patch new file mode 100644 index 0000000000..3518bd3e81 --- /dev/null +++ b/paper-server/nms-patches/CrashReport.patch @@ -0,0 +1,10 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/CrashReport.java 2014-11-27 08:59:46.629422164 +1100 ++++ src/main/java/net/minecraft/server/CrashReport.java 2014-11-27 08:42:10.172850872 +1100 +@@ -40,6 +40,7 @@ + this.d.a("Memory", (Callable) (new CrashReportMemory(this))); + this.d.a("JVM Flags", (Callable) (new CrashReportJVMFlags(this))); + this.d.a("IntCache", (Callable) (new CrashReportIntCacheSize(this))); ++ this.d.a("CraftBukkit Information", (Callable) (new org.bukkit.craftbukkit.CraftCrashReport())); // CraftBukkit + } + + public String a() { diff --git a/paper-server/nms-patches/DedicatedServer.patch b/paper-server/nms-patches/DedicatedServer.patch new file mode 100644 index 0000000000..814b166b5c --- /dev/null +++ b/paper-server/nms-patches/DedicatedServer.patch @@ -0,0 +1,162 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DedicatedServer.java 2014-11-27 08:59:46.629422164 +1100 ++++ src/main/java/net/minecraft/server/DedicatedServer.java 2014-11-27 08:42:10.172850872 +1100 +@@ -13,6 +13,14 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.io.PrintStream; ++import org.apache.logging.log4j.Level; ++ ++import org.bukkit.craftbukkit.LoggerOutputStream; ++import org.bukkit.event.server.ServerCommandEvent; ++// CraftBukkit end ++ + public class DedicatedServer extends MinecraftServer implements IMinecraftServer { + + private static final Logger LOGGER = LogManager.getLogger(); +@@ -25,23 +33,48 @@ + private EnumGamemode q; + private boolean r; + +- public DedicatedServer(File file) { +- super(file, Proxy.NO_PROXY, DedicatedServer.a); ++ // CraftBukkit start - Signature changed ++ public DedicatedServer(joptsimple.OptionSet options) { ++ super(options, Proxy.NO_PROXY, a); ++ // super(file, Proxy.NO_PROXY, a); ++ // CraftBukkit end + new ThreadSleepForever(this, "Server Infinisleeper"); + } + +- protected boolean init() { ++ protected boolean init() throws java.net.UnknownHostException { // CraftBukkit - throws UnknownHostException + ThreadCommandReader threadcommandreader = new ThreadCommandReader(this, "Server console handler"); + + threadcommandreader.setDaemon(true); + threadcommandreader.start(); ++ ++ // CraftBukkit start - TODO: handle command-line logging arguments ++ java.util.logging.Logger global = java.util.logging.Logger.getLogger(""); ++ global.setUseParentHandlers(false); ++ for (java.util.logging.Handler handler : global.getHandlers()) { ++ global.removeHandler(handler); ++ } ++ global.addHandler(new org.bukkit.craftbukkit.util.ForwardLogHandler()); ++ ++ final org.apache.logging.log4j.core.Logger logger = ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()); ++ for (org.apache.logging.log4j.core.Appender appender : logger.getAppenders().values()) { ++ if (appender instanceof org.apache.logging.log4j.core.appender.ConsoleAppender) { ++ logger.removeAppender(appender); ++ } ++ } ++ ++ new Thread(new org.bukkit.craftbukkit.util.TerminalConsoleWriterThread(System.out, this.reader)).start(); ++ ++ System.setOut(new PrintStream(new LoggerOutputStream(logger, Level.INFO), true)); ++ System.setErr(new PrintStream(new LoggerOutputStream(logger, Level.WARN), true)); ++ // CraftBukkit end ++ + DedicatedServer.LOGGER.info("Starting minecraft server version 1.8"); + if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { + DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); + } + + DedicatedServer.LOGGER.info("Loading properties"); +- this.propertyManager = new PropertyManager(new File("server.properties")); ++ this.propertyManager = new PropertyManager(this.options); // CraftBukkit - CLI argument support + this.o = new EULA(new File("eula.txt")); + if (!this.o.a()) { + DedicatedServer.LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); +@@ -90,13 +123,15 @@ + + try { + this.ao().a(inetaddress, this.Q()); +- } catch (IOException ioexception) { ++ } catch (Throwable ioexception) { // CraftBukkit - IOException -> Throwable + DedicatedServer.LOGGER.warn("**** FAILED TO BIND TO PORT!"); + DedicatedServer.LOGGER.warn("The exception was: {}", new Object[] { ioexception.toString()}); + DedicatedServer.LOGGER.warn("Perhaps a server is already running on that port?"); + return false; + } + ++ this.a((PlayerList) (new DedicatedPlayerList(this))); // CraftBukkit ++ + if (!this.getOnlineMode()) { + DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); +@@ -111,7 +146,8 @@ + if (!NameReferencingFileConverter.a(this.propertyManager)) { + return false; + } else { +- this.a((PlayerList) (new DedicatedPlayerList(this))); ++ // this.a((PlayerList) (new DedicatedPlayerList(this))); // CraftBukkit - moved up ++ this.convertable = new WorldLoaderServer(server.getWorldContainer()); // CraftBukkit - moved from MinecraftServer constructor + long j = System.nanoTime(); + + if (this.T() == null) { +@@ -166,7 +202,18 @@ + DedicatedServer.LOGGER.info("Starting remote control listener"); + this.m = new RemoteControlListener(this); + this.m.a(); ++ this.remoteConsole = new org.bukkit.craftbukkit.command.CraftRemoteConsoleCommandSender(); // CraftBukkit ++ } ++ ++ // CraftBukkit start ++ if (this.server.getBukkitSpawnRadius() > -1) { ++ DedicatedServer.LOGGER.info("'settings.spawn-radius' in bukkit.yml has been moved to 'spawn-protection' in server.properties. I will move your config for you."); ++ this.propertyManager.properties.remove("spawn-protection"); ++ this.propertyManager.getInt("spawn-protection", this.server.getBukkitSpawnRadius()); ++ this.server.removeBukkitSpawnRadius(); ++ this.propertyManager.savePropertiesFile(); + } ++ // CraftBukkit end + + if (this.aQ() > 0L) { + Thread thread = new Thread(new ThreadWatchdog(this)); +@@ -181,6 +228,12 @@ + } + } + ++ // CraftBukkit start ++ public PropertyManager getPropertyManager() { ++ return this.propertyManager; ++ } ++ // CraftBukkit end ++ + public void setGamemode(EnumGamemode enumgamemode) { + super.setGamemode(enumgamemode); + this.q = enumgamemode; +@@ -203,6 +256,7 @@ + } + + protected void a(CrashReport crashreport) { ++ /* CraftBukkit start - not sure why you would want to continue running commands once the server crashed + while (this.isRunning()) { + this.aM(); + +@@ -212,7 +266,7 @@ + ; + } + } +- ++ // CraftBukkit end */ + } + + public CrashReport b(CrashReport crashreport) { +@@ -257,7 +311,14 @@ + while (!this.k.isEmpty()) { + ServerCommand servercommand = (ServerCommand) this.k.remove(0); + +- this.getCommandHandler().a(servercommand.source, servercommand.command); ++ // CraftBukkit start - ServerCommand for preprocessing ++ ServerCommandEvent event = new ServerCommandEvent(console, servercommand.command); ++ server.getPluginManager().callEvent(event); ++ servercommand = new ServerCommand(event.getCommand(), servercommand.source); ++ ++ // this.getCommandHandler().a(servercommand.source, servercommand.command); // Called in dispatchServerCommand ++ server.dispatchServerCommand(console, servercommand); ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/DispenseBehaviorArmor.patch b/paper-server/nms-patches/DispenseBehaviorArmor.patch new file mode 100644 index 0000000000..6c420e65e2 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorArmor.patch @@ -0,0 +1,59 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorArmor.java 2014-11-27 08:59:46.629422164 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorArmor.java 2014-11-27 08:42:10.144850927 +1100 +@@ -3,6 +3,11 @@ + import com.google.common.base.Predicates; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorArmor extends DispenseBehaviorItem { + + DispenseBehaviorArmor() {} +@@ -19,15 +24,42 @@ + EntityLiving entityliving = (EntityLiving) list.get(0); + int l = entityliving instanceof EntityHuman ? 1 : 0; + int i1 = EntityInsentient.c(itemstack); +- ItemStack itemstack1 = itemstack.cloneItemStack(); ++ ++ // CraftBukkit start ++ ItemStack itemstack1 = itemstack.a(1); ++ World world = isourceblock.i(); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } + ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ // CraftBukkit end ++ + itemstack1.count = 1; + entityliving.setEquipment(i1 - l, itemstack1); + if (entityliving instanceof EntityInsentient) { + ((EntityInsentient) entityliving).a(i1, 2.0F); + } + +- --itemstack.count; ++ // --itemstack.count; // CraftBukkit - handled above + return itemstack; + } else { + return super.b(isourceblock, itemstack); diff --git a/paper-server/nms-patches/DispenseBehaviorBoat.patch b/paper-server/nms-patches/DispenseBehaviorBoat.patch new file mode 100644 index 0000000000..19daf555a2 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorBoat.patch @@ -0,0 +1,54 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorBoat.java 2014-11-27 08:59:46.633422146 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorBoat.java 2014-11-27 08:42:10.164850887 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorBoat extends DispenseBehaviorItem { + + private final DispenseBehaviorItem b = new DispenseBehaviorItem(); +@@ -26,10 +31,38 @@ + d3 = 0.0D; + } + +- EntityBoat entityboat = new EntityBoat(world, d0, d1 + d3, d2); ++ // EntityBoat entityboat = new EntityBoat(world, d0, d1 + d3, d2); ++ // CraftBukkit start ++ ItemStack itemstack1 = itemstack.a(1); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ EntityBoat entityboat = new EntityBoat(world, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()); ++ // CraftBukkit end + + world.addEntity(entityboat); +- itemstack.a(1); ++ // itemstack.a(1); // CraftBukkit - handled during event processing + return itemstack; + } + diff --git a/paper-server/nms-patches/DispenseBehaviorBonemeal.patch b/paper-server/nms-patches/DispenseBehaviorBonemeal.patch new file mode 100644 index 0000000000..32cea5b74e --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorBonemeal.patch @@ -0,0 +1,44 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorBonemeal.java 2014-11-27 08:59:46.633422146 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorBonemeal.java 2014-11-27 08:42:10.120850973 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorBonemeal extends DispenseBehaviorItem { + + private boolean b = true; +@@ -10,6 +15,30 @@ + if (EnumColor.WHITE == EnumColor.fromInvColorIndex(itemstack.getData())) { + World world = isourceblock.i(); + BlockPosition blockposition = isourceblock.getBlockPosition().shift(BlockDispenser.b(isourceblock.f())); ++ ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asNewCraftStack(itemstack.getItem()); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ // CraftBukkit end + + if (ItemDye.a(itemstack, world, blockposition)) { + if (!world.isStatic) { diff --git a/paper-server/nms-patches/DispenseBehaviorEmptyBucket.patch b/paper-server/nms-patches/DispenseBehaviorEmptyBucket.patch new file mode 100644 index 0000000000..9727c367c8 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorEmptyBucket.patch @@ -0,0 +1,44 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorEmptyBucket.java 2014-11-27 08:59:46.633422146 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorEmptyBucket.java 2014-11-27 08:42:10.124850965 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorEmptyBucket extends DispenseBehaviorItem { + + private final DispenseBehaviorItem b = new DispenseBehaviorItem(); +@@ -23,6 +28,30 @@ + + item = Items.LAVA_BUCKET; + } ++ ++ // CraftBukkit start ++ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ // CraftBukkit end + + world.setAir(blockposition); + if (--itemstack.count == 0) { diff --git a/paper-server/nms-patches/DispenseBehaviorFilledBucket.patch b/paper-server/nms-patches/DispenseBehaviorFilledBucket.patch new file mode 100644 index 0000000000..e3bcc62e1a --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorFilledBucket.patch @@ -0,0 +1,65 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorFilledBucket.java 2014-11-27 08:59:46.637422129 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorFilledBucket.java 2014-11-27 08:42:10.088851036 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorFilledBucket extends DispenseBehaviorItem { + + private final DispenseBehaviorItem b = new DispenseBehaviorItem(); +@@ -9,10 +14,49 @@ + public ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) { + ItemBucket itembucket = (ItemBucket) itemstack.getItem(); + BlockPosition blockposition = isourceblock.getBlockPosition().shift(BlockDispenser.b(isourceblock.f())); ++ ++ // CraftBukkit start ++ World world = isourceblock.i(); ++ int x = blockposition.getX(); ++ int y = blockposition.getY(); ++ int z = blockposition.getZ(); ++ if (world.isEmpty(blockposition) || !world.getType(blockposition).getBlock().getMaterial().isBuildable()) { ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ itembucket = (ItemBucket) CraftItemStack.asNMSCopy(event.getItem()).getItem(); ++ } ++ // CraftBukkit end + + if (itembucket.a(isourceblock.i(), blockposition)) { +- itemstack.setItem(Items.BUCKET); +- itemstack.count = 1; ++ // CraftBukkit start - Handle stacked buckets ++ Item item = Items.BUCKET; ++ if (--itemstack.count == 0) { ++ itemstack.setItem(Items.BUCKET); ++ itemstack.count = 1; ++ } else if (((TileEntityDispenser) isourceblock.getTileEntity()).addItem(new ItemStack(item)) < 0) { ++ this.b.a(isourceblock, new ItemStack(item)); ++ } ++ // CraftBukkit end + return itemstack; + } else { + return this.b.a(isourceblock, itemstack); diff --git a/paper-server/nms-patches/DispenseBehaviorFireball.patch b/paper-server/nms-patches/DispenseBehaviorFireball.patch new file mode 100644 index 0000000000..1d21873fbb --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorFireball.patch @@ -0,0 +1,55 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorFireball.java 2014-11-27 08:59:46.637422129 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorFireball.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,11 @@ + + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorFireball extends DispenseBehaviorItem { + + DispenseBehaviorFireball() {} +@@ -18,8 +23,38 @@ + double d4 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentY(); + double d5 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentZ(); + +- world.addEntity(new EntitySmallFireball(world, d0, d1, d2, d3, d4, d5)); +- itemstack.a(1); ++ // CraftBukkit start ++ ItemStack itemstack1 = itemstack.a(1); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d3, d4, d5)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ EntitySmallFireball entitysmallfireball = new EntitySmallFireball(world, d0, d1, d2, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()); ++ entitysmallfireball.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((TileEntityDispenser) isourceblock.getTileEntity()); ++ ++ world.addEntity(entitysmallfireball); ++ // itemstack.a(1); // Handled during event processing ++ // CraftBukkit end + return itemstack; + } + diff --git a/paper-server/nms-patches/DispenseBehaviorFlintAndSteel.patch b/paper-server/nms-patches/DispenseBehaviorFlintAndSteel.patch new file mode 100644 index 0000000000..26ab2df077 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorFlintAndSteel.patch @@ -0,0 +1,57 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorFlintAndSteel.java 2014-11-27 08:59:46.641422111 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorFlintAndSteel.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorFlintAndSteel extends DispenseBehaviorItem { + + private boolean b = true; +@@ -10,11 +15,39 @@ + World world = isourceblock.i(); + BlockPosition blockposition = isourceblock.getBlockPosition().shift(BlockDispenser.b(isourceblock.f())); + +- if (world.isEmpty(blockposition)) { +- world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); +- if (itemstack.isDamaged(1, world.random)) { +- itemstack.count = 0; ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ // CraftBukkit end ++ ++ if (world.isEmpty(blockposition)) { ++ // CraftBukkit start - Ignition by dispensing flint and steel ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()).isCancelled()) { ++ world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ if (itemstack.isDamaged(1, world.random)) { ++ itemstack.count = 0; ++ } + } ++ // CraftBukkit end + } else if (world.getType(blockposition).getBlock() == Blocks.TNT) { + Blocks.TNT.postBreak(world, blockposition, Blocks.TNT.getBlockData().set(BlockTNT.EXPLODE, Boolean.valueOf(true))); + world.setAir(blockposition); diff --git a/paper-server/nms-patches/DispenseBehaviorItem.patch b/paper-server/nms-patches/DispenseBehaviorItem.patch new file mode 100644 index 0000000000..b902b835b1 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorItem.patch @@ -0,0 +1,76 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorItem.java 2014-11-27 08:59:46.641422111 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorItem.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + public class DispenseBehaviorItem implements IDispenseBehavior { + + public DispenseBehaviorItem() {} +@@ -17,11 +22,18 @@ + IPosition iposition = BlockDispenser.a(isourceblock); + ItemStack itemstack1 = itemstack.a(1); + +- a(isourceblock.i(), itemstack1, 6, enumdirection, iposition); ++ // CraftBukkit start ++ if (!a(isourceblock.i(), itemstack1, 6, enumdirection, isourceblock)) { ++ itemstack.count++; ++ } ++ // CraftBukkit end + return itemstack; + } + +- public static void a(World world, ItemStack itemstack, int i, EnumDirection enumdirection, IPosition iposition) { ++ // CraftBukkit start - void -> boolean return, IPosition -> ISourceBlock last argument ++ public static boolean a(World world, ItemStack itemstack, int i, EnumDirection enumdirection, ISourceBlock isourceblock) { ++ IPosition iposition = BlockDispenser.a(isourceblock); ++ // CraftBukkit end + double d0 = iposition.getX(); + double d1 = iposition.getY(); + double d2 = iposition.getZ(); +@@ -41,7 +53,41 @@ + entityitem.motX += world.random.nextGaussian() * 0.007499999832361937D * (double) i; + entityitem.motY += world.random.nextGaussian() * 0.007499999832361937D * (double) i; + entityitem.motZ += world.random.nextGaussian() * 0.007499999832361937D * (double) i; ++ ++ // CraftBukkit start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(entityitem.motX, entityitem.motY, entityitem.motZ)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ entityitem.setItemStack(CraftItemStack.asNMSCopy(event.getItem())); ++ entityitem.motX = event.getVelocity().getX(); ++ entityitem.motY = event.getVelocity().getY(); ++ entityitem.motZ = event.getVelocity().getZ(); ++ ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior.getClass() != DispenseBehaviorItem.class) { ++ idispensebehavior.a(isourceblock, eventStack); ++ } else { ++ world.addEntity(entityitem); ++ } ++ return false; ++ } ++ + world.addEntity(entityitem); ++ ++ return true; ++ // CraftBukkit end + } + + protected void a(ISourceBlock isourceblock) { diff --git a/paper-server/nms-patches/DispenseBehaviorMinecart.patch b/paper-server/nms-patches/DispenseBehaviorMinecart.patch new file mode 100644 index 0000000000..454c15b77c --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorMinecart.patch @@ -0,0 +1,58 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorMinecart.java 2014-11-27 08:59:46.641422111 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorMinecart.java 2014-11-27 08:42:10.084851043 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorMinecart extends DispenseBehaviorItem { + + private final DispenseBehaviorItem b = new DispenseBehaviorItem(); +@@ -38,14 +43,42 @@ + } + } + +- EntityMinecartAbstract entityminecartabstract = EntityMinecartAbstract.a(world, d0, d1 + d3, d2, ItemMinecart.a((ItemMinecart) itemstack.getItem())); ++ // CraftBukkit start ++ // EntityMinecartAbstract entityminecartabstract = EntityMinecartAbstract.a(world, d0, d1 + d3, d2, ItemMinecart.a((ItemMinecart) itemstack.getItem())); ++ ItemStack itemstack1 = itemstack.a(1); ++ org.bukkit.block.Block block2 = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ itemstack1 = CraftItemStack.asNMSCopy(event.getItem()); ++ EntityMinecartAbstract entityminecartabstract = EntityMinecartAbstract.a(world, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), ItemMinecart.a((ItemMinecart) itemstack1.getItem())); + + if (itemstack.hasName()) { + entityminecartabstract.setCustomName(itemstack.getName()); + } + + world.addEntity(entityminecartabstract); +- itemstack.a(1); ++ // itemstack.a(1); // CraftBukkit - handled during event processing + return itemstack; + } + diff --git a/paper-server/nms-patches/DispenseBehaviorMonsterEgg.patch b/paper-server/nms-patches/DispenseBehaviorMonsterEgg.patch new file mode 100644 index 0000000000..56a05a5401 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorMonsterEgg.patch @@ -0,0 +1,61 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorMonsterEgg.java 2014-11-27 08:59:46.645422093 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorMonsterEgg.java 2014-11-27 08:42:10.096851020 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorMonsterEgg extends DispenseBehaviorItem { + + DispenseBehaviorMonsterEgg() {} +@@ -9,13 +14,45 @@ + double d0 = isourceblock.getX() + (double) enumdirection.getAdjacentX(); + double d1 = (double) ((float) isourceblock.getBlockPosition().getY() + 0.2F); + double d2 = isourceblock.getZ() + (double) enumdirection.getAdjacentZ(); +- Entity entity = ItemMonsterEgg.a(isourceblock.i(), itemstack.getData(), d0, d1, d2); ++ // Entity entity = ItemMonsterEgg.a(isourceblock.i(), itemstack.getData(), d0, d1, d2); ++ ++ // CraftBukkit start ++ World world = isourceblock.i(); ++ ItemStack itemstack1 = itemstack.a(1); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1, d2)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ itemstack1 = CraftItemStack.asNMSCopy(event.getItem()); ++ ++ Entity entity = ItemMonsterEgg.spawnCreature(isourceblock.i(), itemstack.getData(), event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DISPENSE_EGG); + + if (entity instanceof EntityLiving && itemstack.hasName()) { + ((EntityInsentient) entity).setCustomName(itemstack.getName()); + } + +- itemstack.a(1); ++ // itemstack.a(1); // Handled during event processing ++ // CraftBukkit end + return itemstack; + } + } diff --git a/paper-server/nms-patches/DispenseBehaviorProjectile.patch b/paper-server/nms-patches/DispenseBehaviorProjectile.patch new file mode 100644 index 0000000000..b4e7083b0f --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorProjectile.patch @@ -0,0 +1,54 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorProjectile.java 2014-11-27 08:59:46.645422093 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java 2014-11-27 08:42:10.152850911 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + public abstract class DispenseBehaviorProjectile extends DispenseBehaviorItem { + + public DispenseBehaviorProjectile() {} +@@ -10,9 +15,38 @@ + EnumDirection enumdirection = BlockDispenser.b(isourceblock.f()); + IProjectile iprojectile = this.a(world, iposition); + +- iprojectile.shoot((double) enumdirection.getAdjacentX(), (double) ((float) enumdirection.getAdjacentY() + 0.1F), (double) enumdirection.getAdjacentZ(), this.b(), this.a()); ++ // iprojectile.shoot((double) enumdirection.getAdjacentX(), (double) ((float) enumdirection.getAdjacentY() + 0.1F), (double) enumdirection.getAdjacentZ(), this.b(), this.a()); ++ // CraftBukkit start ++ ItemStack itemstack1 = itemstack.a(1); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) enumdirection.getAdjacentX(), (double) ((float) enumdirection.getAdjacentY() + 0.1F), (double) enumdirection.getAdjacentZ())); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ iprojectile.shoot(event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.b(), this.a()); ++ ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((TileEntityDispenser) isourceblock.getTileEntity()); ++ // CraftBukkit end + world.addEntity((Entity) iprojectile); +- itemstack.a(1); ++ // itemstack.a(1); // CraftBukkit - Handled during event processing + return itemstack; + } + diff --git a/paper-server/nms-patches/DispenseBehaviorTNT.patch b/paper-server/nms-patches/DispenseBehaviorTNT.patch new file mode 100644 index 0000000000..1dd1d42c98 --- /dev/null +++ b/paper-server/nms-patches/DispenseBehaviorTNT.patch @@ -0,0 +1,56 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/DispenseBehaviorTNT.java 2014-11-27 08:59:46.645422093 +1100 ++++ src/main/java/net/minecraft/server/DispenseBehaviorTNT.java 2014-11-27 08:42:10.140850934 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.block.BlockDispenseEvent; ++// CraftBukkit end ++ + final class DispenseBehaviorTNT extends DispenseBehaviorItem { + + DispenseBehaviorTNT() {} +@@ -7,11 +12,40 @@ + protected ItemStack b(ISourceBlock isourceblock, ItemStack itemstack) { + World world = isourceblock.i(); + BlockPosition blockposition = isourceblock.getBlockPosition().shift(BlockDispenser.b(isourceblock.f())); +- EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, (EntityLiving) null); ++ // EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, (EntityLiving) null); ++ ++ // CraftBukkit start ++ ItemStack itemstack1 = itemstack.a(1); ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); ++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); ++ ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX() + 0.5, blockposition.getY() + 0.5, blockposition.getZ() + 0.5)); ++ if (!BlockDispenser.eventFired) { ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ itemstack.count++; ++ return itemstack; ++ } ++ ++ if (!event.getItem().equals(craftItem)) { ++ itemstack.count++; ++ // Chain to handler for new item ++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); ++ IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.M.get(eventStack.getItem()); ++ if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { ++ idispensebehavior.a(isourceblock, eventStack); ++ return itemstack; ++ } ++ } ++ ++ EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), (EntityLiving) null); ++ // CraftBukkit end + + world.addEntity(entitytntprimed); + world.makeSound(entitytntprimed, "game.tnt.primed", 1.0F, 1.0F); +- --itemstack.count; ++ // --itemstack.count; // CraftBukkit - handled above + return itemstack; + } + } diff --git a/paper-server/nms-patches/Enchantment.patch b/paper-server/nms-patches/Enchantment.patch new file mode 100644 index 0000000000..8b09c515e4 --- /dev/null +++ b/paper-server/nms-patches/Enchantment.patch @@ -0,0 +1,19 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Enchantment.java 2014-11-27 08:59:46.649422075 +1100 ++++ src/main/java/net/minecraft/server/Enchantment.java 2014-11-27 08:42:10.096851020 +1100 +@@ -8,6 +8,7 @@ + + public abstract class Enchantment { + ++ // CraftBukkit - update CraftEnchant.getName(i) if this changes + private static final Enchantment[] byId = new Enchantment[256]; + public static final Enchantment[] b; + private static final Map E = Maps.newHashMap(); +@@ -55,6 +56,8 @@ + Enchantment.byId[i] = this; + Enchantment.E.put(minecraftkey, this); + } ++ ++ org.bukkit.enchantments.Enchantment.registerEnchantment(new org.bukkit.craftbukkit.enchantments.CraftEnchantment(this)); // CraftBukkit + } + + public static Enchantment getByName(String s) { diff --git a/paper-server/nms-patches/Entity.patch b/paper-server/nms-patches/Entity.patch new file mode 100644 index 0000000000..95a7509b2e --- /dev/null +++ b/paper-server/nms-patches/Entity.patch @@ -0,0 +1,578 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Entity.java 2014-11-27 08:59:46.697421864 +1100 ++++ src/main/java/net/minecraft/server/Entity.java 2014-11-27 08:42:10.176850864 +1100 +@@ -6,8 +6,40 @@ + import java.util.UUID; + import java.util.concurrent.Callable; + ++// CraftBukkit start ++import org.bukkit.Bukkit; ++import org.bukkit.Location; ++import org.bukkit.Server; ++import org.bukkit.TravelAgent; ++import org.bukkit.block.BlockFace; ++import org.bukkit.entity.Hanging; ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.entity.Painting; ++import org.bukkit.entity.Vehicle; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.hanging.HangingBreakByEntityEvent; ++import org.bukkit.event.painting.PaintingBreakByEntityEvent; ++import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; ++import org.bukkit.event.vehicle.VehicleEnterEvent; ++import org.bukkit.event.vehicle.VehicleExitEvent; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.entity.CraftEntity; ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityCombustEvent; ++import org.bukkit.event.entity.EntityPortalEvent; ++import org.bukkit.plugin.PluginManager; ++// CraftBukkit end ++ + public abstract class Entity implements ICommandListener { + ++ // CraftBukkit start ++ private static final int CURRENT_LEVEL = 2; ++ static boolean isLevelAtLeast(NBTTagCompound tag, int level) { ++ return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level; ++ } ++ // CraftBukikt end ++ + private static final AxisAlignedBB a = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D); + private static int entityCount; + private int id; +@@ -77,6 +109,8 @@ + private boolean invulnerable; + public UUID uniqueID; + private final CommandObjectiveExecutor as; ++ public boolean valid; // CraftBukkit ++ public org.bukkit.projectiles.ProjectileSource projectileSource; // CraftBukkit - For projectiles only + + public int getId() { + return this.id; +@@ -150,6 +184,33 @@ + } + + protected void setYawPitch(float f, float f1) { ++ // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0 ++ if (Float.isNaN(f)) { ++ f = 0; ++ } ++ ++ if (f == Float.POSITIVE_INFINITY || f == Float.NEGATIVE_INFINITY) { ++ if (this instanceof EntityPlayer) { ++ this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid yaw"); ++ ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope"); ++ } ++ f = 0; ++ } ++ ++ // pitch was sometimes set to NaN, so we need to set it back to 0 ++ if (Float.isNaN(f1)) { ++ f1 = 0; ++ } ++ ++ if (f1 == Float.POSITIVE_INFINITY || f1 == Float.NEGATIVE_INFINITY) { ++ if (this instanceof EntityPlayer) { ++ this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid pitch"); ++ ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope"); ++ } ++ f1 = 0; ++ } ++ // CraftBukkit end ++ + this.yaw = f % 360.0F; + this.pitch = f1 % 360.0F; + } +@@ -186,7 +247,7 @@ + int i = this.L(); + + if (this.ak) { +- if (minecraftserver.getAllowNether()) { ++ if (true || minecraftserver.getAllowNether()) { // CraftBukkit + if (this.vehicle == null && this.al++ >= i) { + this.al = i; + this.portalCooldown = this.ar(); +@@ -263,6 +324,27 @@ + protected void burnFromLava() { + if (!this.fireProof) { + this.damageEntity(DamageSource.LAVA, 4.0F); ++ ++ // CraftBukkit start - Fallen in lava TODO: this event spams! ++ if (this instanceof EntityLiving) { ++ if (fireTicks <= 0) { ++ // not on fire yet ++ // TODO: shouldn't be sending null for the block ++ org.bukkit.block.Block damager = null; // ((WorldServer) this.l).getWorld().getBlockAt(i, j, k); ++ org.bukkit.entity.Entity damagee = this.getBukkitEntity(); ++ EntityCombustEvent combustEvent = new org.bukkit.event.entity.EntityCombustByBlockEvent(damager, damagee, 15); ++ this.world.getServer().getPluginManager().callEvent(combustEvent); ++ ++ if (!combustEvent.isCancelled()) { ++ this.setOnFire(combustEvent.getDuration()); ++ } ++ } else { ++ // This will be called every single tick the entity is in lava, so don't throw an event ++ this.setOnFire(15); ++ } ++ return; ++ } ++ // CraftBukkit end - we also don't throw an event unless the object in lava is living, to save on some event calls + this.setOnFire(15); + } + } +@@ -300,6 +382,22 @@ + this.a(this.getBoundingBox().c(d0, d1, d2)); + this.recalcPosition(); + } else { ++ // CraftBukkit start - Don't do anything if we aren't moving ++ // We need to do this regardless of whether or not we are moving thanks to portals ++ try { ++ this.checkBlockCollisions(); ++ } catch (Throwable throwable) { ++ CrashReport crashreport = CrashReport.a(throwable, "Checking entity block collision"); ++ CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being checked for collision"); ++ ++ this.appendEntityCrashDetails(crashreportsystemdetails); ++ throw new ReportedException(crashreport); ++ } ++ // Check if we're moving ++ if (d0 == 0 && d1 == 0 && d2 == 0 && this.vehicle == null && this.passenger == null) { ++ return; ++ } ++ // CraftBukkit end + this.world.methodProfiler.a("move"); + double d3 = this.locX; + double d4 = this.locY; +@@ -520,6 +618,28 @@ + block.a(this.world, this); + } + ++ // CraftBukkit start ++ if (positionChanged && getBukkitEntity() instanceof Vehicle) { ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ org.bukkit.block.Block bl = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), MathHelper.floor(this.locY - (double) this.getHeadHeight()), MathHelper.floor(this.locZ)); ++ ++ // PAIL: using local vars may break between updates, name them above? ++ ++ if (d6 > d0) { ++ bl = bl.getRelative(BlockFace.EAST); ++ } else if (d6 < d0) { ++ bl = bl.getRelative(BlockFace.WEST); ++ } else if (d8 > d2) { ++ bl = bl.getRelative(BlockFace.SOUTH); ++ } else if (d8 < d2) { ++ bl = bl.getRelative(BlockFace.NORTH); ++ } ++ ++ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl); ++ world.getServer().getPluginManager().callEvent(event); ++ } ++ // CraftBukkit end ++ + if (this.r_() && !flag && this.vehicle == null) { + double d21 = this.locX - d3; + double d22 = this.locY - d4; +@@ -530,7 +650,7 @@ + } + + if (block != null && this.onGround) { +- block.a(this.world, blockposition, this); ++ // block.a(this.world, blockposition, this); // CraftBukkit removed down + } + + this.M = (float) ((double) this.M + (double) MathHelper.sqrt(d21 * d21 + d23 * d23) * 0.6D); +@@ -548,9 +668,12 @@ + } + + this.a(blockposition, block); ++ block.a(this.world, blockposition, this); // CraftBukkit - moved from above + } + } + ++ // CraftBukkit start - Move to the top of the method ++ /* + try { + this.checkBlockCollisions(); + } catch (Throwable throwable) { +@@ -560,6 +683,8 @@ + this.appendEntityCrashDetails(crashreportsystemdetails); + throw new ReportedException(crashreport); + } ++ */ ++ // CraftBukkit end + + boolean flag2 = this.U(); + +@@ -567,7 +692,16 @@ + this.burn(1); + if (!flag2) { + ++this.fireTicks; +- if (this.fireTicks == 0) { ++ // CraftBukkit start - Not on fire yet ++ if (this.fireTicks <= 0) { // Only throw events on the first combust, otherwise it spams ++ EntityCombustEvent event = new EntityCombustEvent(getBukkitEntity(), 8); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ setOnFire(event.getDuration()); ++ } ++ } else { ++ // CraftBukkit end + this.setOnFire(8); + } + } +@@ -673,7 +807,7 @@ + return null; + } + +- protected void burn(int i) { ++ protected void burn(float i) { // CraftBukkit - int -> float + if (!this.fireProof) { + this.damageEntity(DamageSource.FIRE, (float) i); + } +@@ -823,6 +957,13 @@ + } + + public void spawnIn(World world) { ++ // CraftBukkit start ++ if (world == null) { ++ die(); ++ this.world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle(); ++ return; ++ } ++ // CraftBukkit end + this.world = world; + } + +@@ -1015,6 +1156,18 @@ + try { + nbttagcompound.set("Pos", this.a(new double[] { this.locX, this.locY, this.locZ})); + nbttagcompound.set("Motion", this.a(new double[] { this.motX, this.motY, this.motZ})); ++ ++ // CraftBukkit start - Checking for NaN pitch/yaw and resetting to zero ++ // TODO: make sure this is the best way to address this. ++ if (Float.isNaN(this.yaw)) { ++ this.yaw = 0; ++ } ++ ++ if (Float.isNaN(this.pitch)) { ++ this.pitch = 0; ++ } ++ // CraftBukkit end ++ + nbttagcompound.set("Rotation", this.a(new float[] { this.yaw, this.pitch})); + nbttagcompound.setFloat("FallDistance", this.fallDistance); + nbttagcompound.setShort("Fire", (short) this.fireTicks); +@@ -1025,6 +1178,11 @@ + nbttagcompound.setInt("PortalCooldown", this.portalCooldown); + nbttagcompound.setLong("UUIDMost", this.getUniqueID().getMostSignificantBits()); + nbttagcompound.setLong("UUIDLeast", this.getUniqueID().getLeastSignificantBits()); ++ // CraftBukkit start ++ nbttagcompound.setLong("WorldUUIDLeast", this.world.getDataManager().getUUID().getLeastSignificantBits()); ++ nbttagcompound.setLong("WorldUUIDMost", this.world.getDataManager().getUUID().getMostSignificantBits()); ++ nbttagcompound.setInt("Bukkit.updateLevel", CURRENT_LEVEL); ++ // CraftBukkit end + if (this.getCustomName() != null && this.getCustomName().length() > 0) { + nbttagcompound.setString("CustomName", this.getCustomName()); + nbttagcompound.setBoolean("CustomNameVisible", this.getCustomNameVisible()); +@@ -1062,6 +1220,7 @@ + this.motX = nbttaglist1.d(0); + this.motY = nbttaglist1.d(1); + this.motZ = nbttaglist1.d(2); ++ /* CraftBukkit start - Moved section down + if (Math.abs(this.motX) > 10.0D) { + this.motX = 0.0D; + } +@@ -1073,6 +1232,7 @@ + if (Math.abs(this.motZ) > 10.0D) { + this.motZ = 0.0D; + } ++ // CraftBukkit end */ + + this.lastX = this.P = this.locX = nbttaglist.d(0); + this.lastY = this.Q = this.locY = nbttaglist.d(1); +@@ -1105,7 +1265,57 @@ + if (this.af()) { + this.setPosition(this.locX, this.locY, this.locZ); + } ++ // CraftBukkit start ++ if (this instanceof EntityLiving) { ++ EntityLiving entity = (EntityLiving) this; ++ ++ // Reset the persistence for tamed animals ++ if (entity instanceof EntityTameableAnimal && !isLevelAtLeast(nbttagcompound, 2) && !nbttagcompound.getBoolean("PersistenceRequired")) { ++ EntityInsentient entityinsentient = (EntityInsentient) entity; ++ entityinsentient.persistent = !entityinsentient.isTypeNotPersistent(); ++ } ++ } ++ // CraftBukkit end ++ ++ // CraftBukkit start - Exempt Vehicles from notch's sanity check ++ if (!(getBukkitEntity() instanceof Vehicle)) { ++ if (Math.abs(this.motX) > 10.0D) { ++ this.motX = 0.0D; ++ } ++ ++ if (Math.abs(this.motY) > 10.0D) { ++ this.motY = 0.0D; ++ } ++ ++ if (Math.abs(this.motZ) > 10.0D) { ++ this.motZ = 0.0D; ++ } ++ } ++ // CraftBukkit end ++ ++ // CraftBukkit start - Reset world ++ if (this instanceof EntityPlayer) { ++ Server server = Bukkit.getServer(); ++ org.bukkit.World bworld = null; + ++ // TODO: Remove World related checks, replaced with WorldUID ++ String worldName = nbttagcompound.getString("world"); ++ ++ if (nbttagcompound.hasKey("WorldUUIDMost") && nbttagcompound.hasKey("WorldUUIDLeast")) { ++ UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast")); ++ bworld = server.getWorld(uid); ++ } else { ++ bworld = server.getWorld(worldName); ++ } ++ ++ if (bworld == null) { ++ EntityPlayer entityPlayer = (EntityPlayer) this; ++ bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(entityPlayer.dimension).getWorld(); ++ } ++ ++ spawnIn(bworld == null? null : ((CraftWorld) bworld).getHandle()); ++ } ++ // CraftBukkit end + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded"); +@@ -1167,6 +1377,12 @@ + + public EntityItem a(ItemStack itemstack, float f) { + if (itemstack.count != 0 && itemstack.getItem() != null) { ++ // CraftBukkit start - Capture drops for death event ++ if (this instanceof EntityLiving && ((EntityLiving) this).drops != null) { ++ ((EntityLiving) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); ++ return null; ++ } ++ // CraftBukkit end + EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY + (double) f, this.locZ, itemstack); + + entityitem.p(); +@@ -1276,16 +1492,76 @@ + } + + public void mount(Entity entity) { ++ // CraftBukkit start ++ setPassengerOf(entity); ++ } ++ ++ protected CraftEntity bukkitEntity; ++ ++ public CraftEntity getBukkitEntity() { ++ if (bukkitEntity == null) { ++ bukkitEntity = CraftEntity.getEntity(world.getServer(), this); ++ } ++ return bukkitEntity; ++ } ++ ++ public void setPassengerOf(Entity entity) { ++ // b(null) doesn't really fly for overloaded methods, ++ // so this method is needed ++ ++ Entity originalVehicle = this.vehicle; ++ Entity originalPassenger = this.vehicle == null ? null : this.vehicle.passenger; ++ PluginManager pluginManager = Bukkit.getPluginManager(); ++ getBukkitEntity(); // make sure bukkitEntity is initialised ++ // CraftBukkit end + this.ap = 0.0D; + this.aq = 0.0D; + if (entity == null) { + if (this.vehicle != null) { ++ // CraftBukkit start ++ if ((this.bukkitEntity instanceof LivingEntity) && (this.vehicle.getBukkitEntity() instanceof Vehicle)) { ++ VehicleExitEvent event = new VehicleExitEvent((Vehicle) this.vehicle.getBukkitEntity(), (LivingEntity) this.bukkitEntity); ++ pluginManager.callEvent(event); ++ ++ if (event.isCancelled() || vehicle != originalVehicle) { ++ return; ++ } ++ } ++ // CraftBukkit end + this.setPositionRotation(this.vehicle.locX, this.vehicle.getBoundingBox().b + (double) this.vehicle.length, this.vehicle.locZ, this.yaw, this.pitch); + this.vehicle.passenger = null; + } + + this.vehicle = null; + } else { ++ // CraftBukkit start ++ if ((this.bukkitEntity instanceof LivingEntity) && (entity.getBukkitEntity() instanceof Vehicle) && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, true)) { ++ // It's possible to move from one vehicle to another. We need to check if they're already in a vehicle, and fire an exit event if they are. ++ VehicleExitEvent exitEvent = null; ++ if (this.vehicle != null && this.vehicle.getBukkitEntity() instanceof Vehicle) { ++ exitEvent = new VehicleExitEvent((Vehicle) this.vehicle.getBukkitEntity(), (LivingEntity) this.bukkitEntity); ++ pluginManager.callEvent(exitEvent); ++ ++ if (exitEvent.isCancelled() || this.vehicle != originalVehicle || (this.vehicle != null && this.vehicle.passenger != originalPassenger)) { ++ return; ++ } ++ } ++ ++ VehicleEnterEvent event = new VehicleEnterEvent((Vehicle) entity.getBukkitEntity(), this.bukkitEntity); ++ pluginManager.callEvent(event); ++ ++ // If a plugin messes with the vehicle or the vehicle's passenger ++ if (event.isCancelled() || this.vehicle != originalVehicle || (this.vehicle != null && this.vehicle.passenger != originalPassenger)) { ++ // If we only cancelled the enterevent then we need to put the player in a decent position. ++ if (exitEvent != null && this.vehicle == originalVehicle && this.vehicle != null && this.vehicle.passenger == originalPassenger) { ++ this.setPositionRotation(this.vehicle.locX, this.vehicle.boundingBox.b + (double) this.vehicle.length, this.vehicle.locZ, this.yaw, this.pitch); ++ this.vehicle.passenger = null; ++ this.vehicle = null; ++ } ++ return; ++ } ++ } ++ // CraftBukkit end + if (this.vehicle != null) { + this.vehicle.passenger = null; + } +@@ -1406,10 +1682,50 @@ + } + + public void onLightningStrike(EntityLightning entitylightning) { +- this.damageEntity(DamageSource.LIGHTNING, 5.0F); ++ // CraftBukkit start ++ final org.bukkit.entity.Entity thisBukkitEntity = this.getBukkitEntity(); ++ final org.bukkit.entity.Entity stormBukkitEntity = entitylightning.getBukkitEntity(); ++ final PluginManager pluginManager = Bukkit.getPluginManager(); ++ ++ if (thisBukkitEntity instanceof Hanging) { ++ HangingBreakByEntityEvent hangingEvent = new HangingBreakByEntityEvent((Hanging) thisBukkitEntity, stormBukkitEntity); ++ PaintingBreakByEntityEvent paintingEvent = null; ++ ++ if (thisBukkitEntity instanceof Painting) { ++ paintingEvent = new PaintingBreakByEntityEvent((Painting) thisBukkitEntity, stormBukkitEntity); ++ } ++ ++ pluginManager.callEvent(hangingEvent); ++ ++ if (paintingEvent != null) { ++ paintingEvent.setCancelled(hangingEvent.isCancelled()); ++ pluginManager.callEvent(paintingEvent); ++ } ++ ++ if (hangingEvent.isCancelled() || (paintingEvent != null && paintingEvent.isCancelled())) { ++ return; ++ } ++ } ++ ++ if (this.fireProof) { ++ return; ++ } ++ CraftEventFactory.entityDamage = entitylightning; ++ if (!this.damageEntity(DamageSource.LIGHTNING, 5.0F)) { ++ CraftEventFactory.entityDamage = null; ++ return; ++ } ++ // CraftBukkit end + ++this.fireTicks; + if (this.fireTicks == 0) { + this.setOnFire(8); ++ // CraftBukkit start - Call a combust event when lightning strikes ++ EntityCombustByEntityEvent entityCombustEvent = new EntityCombustByEntityEvent(stormBukkitEntity, thisBukkitEntity, 8); ++ pluginManager.callEvent(entityCombustEvent); ++ if (!entityCombustEvent.isCancelled()) { ++ this.setOnFire(entityCombustEvent.getDuration()); ++ } ++ // CraftBukkit end + } + + } +@@ -1546,32 +1862,78 @@ + if (!this.world.isStatic && !this.dead) { + this.world.methodProfiler.a("changeDimension"); + MinecraftServer minecraftserver = MinecraftServer.getServer(); +- int j = this.dimension; +- WorldServer worldserver = minecraftserver.getWorldServer(j); +- WorldServer worldserver1 = minecraftserver.getWorldServer(i); ++ // CraftBukkit start - Move logic into new function "teleportToLocation" ++ // int j = this.dimension; ++ // WorldServer worldserver = minecraftserver.getWorldServer(j); ++ // WorldServer worldserver1 = minecraftserver.getWorldServer(i); ++ WorldServer exitWorld = null; ++ if (this.dimension < CraftWorld.CUSTOM_DIMENSION_OFFSET) { // Plugins must specify exit from custom Bukkit worlds ++ // Only target existing worlds (compensate for allow-nether/allow-end as false) ++ for (WorldServer world : minecraftserver.worlds) { ++ if (world.dimension == i) { ++ exitWorld = world; ++ } ++ } ++ } ++ ++ Location enter = this.getBukkitEntity().getLocation(); ++ Location exit = exitWorld != null ? minecraftserver.getPlayerList().calculateTarget(enter, minecraftserver.getWorldServer(i)) : null; ++ boolean useTravelAgent = exitWorld != null && !(this.dimension == 1 && exitWorld.dimension == 1); // don't use agent for custom worlds or return from THE_END ++ ++ TravelAgent agent = exit != null ? (TravelAgent) ((CraftWorld) exit.getWorld()).getHandle().getTravelAgent() : org.bukkit.craftbukkit.CraftTravelAgent.DEFAULT; // return arbitrary TA to compensate for implementation dependent plugins ++ EntityPortalEvent event = new EntityPortalEvent(this.getBukkitEntity(), enter, exit, agent); ++ event.useTravelAgent(useTravelAgent); ++ event.getEntity().getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null || !this.isAlive()) { ++ return; ++ } ++ exit = event.useTravelAgent() ? event.getPortalTravelAgent().findOrCreate(event.getTo()) : event.getTo(); ++ this.teleportTo(exit, true); ++ } ++ } ++ ++ public void teleportTo(Location exit, boolean portal) { ++ if (true) { ++ WorldServer worldserver = ((CraftWorld) getBukkitEntity().getLocation().getWorld()).getHandle(); ++ WorldServer worldserver1 = ((CraftWorld) exit.getWorld()).getHandle(); ++ int i = worldserver1.dimension; ++ // CraftBukkit end + + this.dimension = i; ++ /* CraftBukkit start - TODO: Check if we need this + if (j == 1 && i == 1) { + worldserver1 = minecraftserver.getWorldServer(0); + this.dimension = 0; + } ++ // CraftBukkit end */ + + this.world.kill(this); + this.dead = false; + this.world.methodProfiler.a("reposition"); +- minecraftserver.getPlayerList().changeWorld(this, j, worldserver, worldserver1); ++ // CraftBukkit start - Ensure chunks are loaded in case TravelAgent is not used which would initially cause chunks to load during find/create ++ // minecraftserver.getPlayerList().changeWorld(this, j, worldserver, worldserver1); ++ boolean before = worldserver1.chunkProviderServer.forceChunkLoad; ++ worldserver1.chunkProviderServer.forceChunkLoad = true; ++ worldserver1.getMinecraftServer().getPlayerList().repositionEntity(this, exit, portal); ++ worldserver1.chunkProviderServer.forceChunkLoad = before; ++ // CraftBukkit end + this.world.methodProfiler.c("reloading"); + Entity entity = EntityTypes.createEntityByName(EntityTypes.b(this), worldserver1); + + if (entity != null) { + entity.n(this); ++ /* CraftBukkit start - We need to do this... + if (j == 1 && i == 1) { + BlockPosition blockposition = this.world.r(worldserver1.getSpawn()); + + entity.setPositionRotation(blockposition, entity.yaw, entity.pitch); + } +- ++ // CraftBukkit end */ + worldserver1.addEntity(entity); ++ // CraftBukkit start - Forward the CraftEntity to the new entity ++ this.getBukkitEntity().setHandle(entity); ++ entity.bukkitEntity = this.getBukkitEntity(); ++ // CraftBukkit end + } + + this.dead = true; diff --git a/paper-server/nms-patches/EntityAgeable.patch b/paper-server/nms-patches/EntityAgeable.patch new file mode 100644 index 0000000000..f1fe109bca --- /dev/null +++ b/paper-server/nms-patches/EntityAgeable.patch @@ -0,0 +1,48 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityAgeable.java 2014-11-27 08:59:46.649422075 +1100 ++++ src/main/java/net/minecraft/server/EntityAgeable.java 2014-11-27 08:42:10.144850927 +1100 +@@ -7,6 +7,7 @@ + protected int c; + private float bk = -1.0F; + private float bl; ++ public boolean ageLocked = false; // CraftBukkit + + public EntityAgeable(World world) { + super(world); +@@ -27,14 +28,14 @@ + if (entityageable != null) { + entityageable.setAgeRaw(-24000); + entityageable.setPositionRotation(this.locX, this.locY, this.locZ, 0.0F, 0.0F); +- this.world.addEntity(entityageable); ++ this.world.addEntity(entityageable, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit + if (itemstack.hasName()) { + entityageable.setCustomName(itemstack.getName()); + } + + if (!entityhuman.abilities.canInstantlyBuild) { + --itemstack.count; +- if (itemstack.count <= 0) { ++ if (itemstack.count == 0) { // CraftBukkit - allow less than 0 stacks as "infinite" + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, (ItemStack) null); + } + } +@@ -99,17 +100,19 @@ + super.b(nbttagcompound); + nbttagcompound.setInt("Age", this.getAge()); + nbttagcompound.setInt("ForcedAge", this.b); ++ nbttagcompound.setBoolean("AgeLocked", this.ageLocked); // CraftBukkit + } + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.setAgeRaw(nbttagcompound.getInt("Age")); + this.b = nbttagcompound.getInt("ForcedAge"); ++ this.ageLocked = nbttagcompound.getBoolean("AgeLocked"); // CraftBukkit + } + + public void m() { + super.m(); +- if (this.world.isStatic) { ++ if (this.world.isStatic || ageLocked) { // CraftBukkit + if (this.c > 0) { + if (this.c % 4 == 0) { + this.world.addParticle(EnumParticle.VILLAGER_HAPPY, this.locX + (double) (this.random.nextFloat() * this.width * 2.0F) - (double) this.width, this.locY + 0.5D + (double) (this.random.nextFloat() * this.length), this.locZ + (double) (this.random.nextFloat() * this.width * 2.0F) - (double) this.width, 0.0D, 0.0D, 0.0D, new int[0]); diff --git a/paper-server/nms-patches/EntityArrow.patch b/paper-server/nms-patches/EntityArrow.patch new file mode 100644 index 0000000000..2912f97b01 --- /dev/null +++ b/paper-server/nms-patches/EntityArrow.patch @@ -0,0 +1,106 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityArrow.java 2014-11-27 08:59:46.653422058 +1100 ++++ src/main/java/net/minecraft/server/EntityArrow.java 2014-11-27 08:42:10.100851012 +1100 +@@ -2,6 +2,12 @@ + + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.entity.LivingEntity; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.player.PlayerPickupItemEvent; ++// CraftBukkit end ++ + public class EntityArrow extends Entity implements IProjectile { + + private int d = -1; +@@ -35,6 +41,7 @@ + super(world); + this.j = 10.0D; + this.shooter = entityliving; ++ this.projectileSource = (LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit + if (entityliving instanceof EntityHuman) { + this.fromPlayer = 1; + } +@@ -62,6 +69,7 @@ + super(world); + this.j = 10.0D; + this.shooter = entityliving; ++ this.projectileSource = (LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit + if (entityliving instanceof EntityHuman) { + this.fromPlayer = 1; + } +@@ -175,7 +183,7 @@ + MovingObjectPosition movingobjectposition1 = axisalignedbb1.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { +- double d1 = vec3d.f(movingobjectposition1.pos); ++ double d1 = vec3d.distanceSquared(movingobjectposition1.pos); // CraftBukkit + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; +@@ -202,6 +210,8 @@ + float f4; + + if (movingobjectposition != null) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this); // CraftBukkit - Call event ++ + if (movingobjectposition.entity != null) { + f2 = MathHelper.sqrt(this.motX * this.motX + this.motY * this.motY + this.motZ * this.motZ); + int k = MathHelper.f((double) f2 * this.damage); +@@ -217,12 +227,20 @@ + } else { + damagesource = DamageSource.arrow(this, this.shooter); + } ++ ++ // CraftBukkit start - Moved damage call ++ if (movingobjectposition.entity.damageEntity(damagesource, (float) k)) { ++ if (this.isBurning() && !(movingobjectposition.entity instanceof EntityEnderman) && (!(movingobjectposition.entity instanceof EntityPlayer) || !(this.shooter instanceof EntityPlayer) || this.world.pvpMode)) { // CraftBukkit - abide by pvp setting if destination is a player ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); + +- if (this.isBurning() && !(movingobjectposition.entity instanceof EntityEnderman)) { +- movingobjectposition.entity.setOnFire(5); ++ if (!combustEvent.isCancelled()) { ++ movingobjectposition.entity.setOnFire(combustEvent.getDuration()); ++ } ++ // CraftBukkit end + } + +- if (movingobjectposition.entity.damageEntity(damagesource, (float) k)) { ++ // if (movingobjectposition.entity.damageEntity(damagesource, (float) k)) { // CraftBukkit - moved up + if (movingobjectposition.entity instanceof EntityLiving) { + EntityLiving entityliving = (EntityLiving) movingobjectposition.entity; + +@@ -382,6 +400,21 @@ + + public void d(EntityHuman entityhuman) { + if (!this.world.isStatic && this.inGround && this.shake <= 0) { ++ // CraftBukkit start ++ ItemStack itemstack = new ItemStack(Items.ARROW); ++ if (this.fromPlayer == 1 && entityhuman.inventory.canHold(itemstack) > 0) { ++ EntityItem item = new EntityItem(this.world, this.locX, this.locY, this.locZ, itemstack); ++ ++ PlayerPickupItemEvent event = new PlayerPickupItemEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), new org.bukkit.craftbukkit.entity.CraftItem(this.world.getServer(), this, item), 0); ++ // event.setCancelled(!entityhuman.canPickUpLoot); TODO ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end ++ + boolean flag = this.fromPlayer == 1 || this.fromPlayer == 2 && entityhuman.abilities.canInstantlyBuild; + + if (this.fromPlayer == 1 && !entityhuman.inventory.pickup(new ItemStack(Items.ARROW, 1))) { +@@ -433,4 +466,10 @@ + + return (b0 & 1) != 0; + } ++ ++ // CraftBukkit start ++ public boolean isInGround() { ++ return inGround; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/EntityBoat.patch b/paper-server/nms-patches/EntityBoat.patch new file mode 100644 index 0000000000..6ab202bf16 --- /dev/null +++ b/paper-server/nms-patches/EntityBoat.patch @@ -0,0 +1,249 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityBoat.java 2014-11-27 08:59:46.653422058 +1100 ++++ src/main/java/net/minecraft/server/EntityBoat.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,16 @@ + + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.entity.Vehicle; ++import org.bukkit.event.vehicle.VehicleDamageEvent; ++import org.bukkit.event.vehicle.VehicleDestroyEvent; ++import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; ++import org.bukkit.event.vehicle.VehicleMoveEvent; ++// CraftBukkit end ++ + public class EntityBoat extends Entity { + + private boolean a; +@@ -12,6 +22,27 @@ + private double f; + private double g; + private double h; ++ ++ // CraftBukkit start ++ public double maxSpeed = 0.4D; ++ public double occupiedDeceleration = 0.2D; ++ public double unoccupiedDeceleration = -1; ++ public boolean landBoats = false; ++ ++ @Override ++ public void collide(Entity entity) { ++ org.bukkit.entity.Entity hitEntity = (entity == null) ? null : entity.getBukkitEntity(); ++ ++ VehicleEntityCollisionEvent event = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), hitEntity); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ super.collide(entity); ++ } ++ // CraftBukkit end + + public EntityBoat(World world) { + super(world); +@@ -52,6 +83,8 @@ + this.lastX = d0; + this.lastY = d1; + this.lastZ = d2; ++ ++ this.world.getServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleCreateEvent((Vehicle) this.getBukkitEntity())); // CraftBukkit + } + + public double an() { +@@ -65,6 +98,19 @@ + if (this.passenger != null && this.passenger == damagesource.getEntity() && damagesource instanceof EntityDamageSourceIndirect) { + return false; + } else { ++ // CraftBukkit start ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ org.bukkit.entity.Entity attacker = (damagesource.getEntity() == null) ? null : damagesource.getEntity().getBukkitEntity(); ++ ++ VehicleDamageEvent event = new VehicleDamageEvent(vehicle, attacker, (double) f); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return true; ++ } ++ // f = event.getDamage(); // TODO Why don't we do this? ++ // CraftBukkit end ++ + this.b(-this.m()); + this.a(10); + this.setDamage(this.j() + f * 10.0F); +@@ -72,6 +118,15 @@ + boolean flag = damagesource.getEntity() instanceof EntityHuman && ((EntityHuman) damagesource.getEntity()).abilities.canInstantlyBuild; + + if (flag || this.j() > 40.0F) { ++ // CraftBukkit start ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, attacker); ++ this.world.getServer().getPluginManager().callEvent(destroyEvent); ++ ++ if (destroyEvent.isCancelled()) { ++ this.setDamage(40F); // Maximize damage so this doesn't get triggered again right away ++ return true; ++ } ++ // CraftBukkit end + if (this.passenger != null) { + this.passenger.mount(this); + } +@@ -95,6 +150,13 @@ + } + + public void s_() { ++ // CraftBukkit start ++ double prevX = this.locX; ++ double prevY = this.locY; ++ double prevZ = this.locZ; ++ float prevYaw = this.yaw; ++ float prevPitch = this.pitch; ++ // CraftBukkit end + super.s_(); + if (this.l() > 0) { + this.a(this.l() - 1); +@@ -196,6 +258,19 @@ + this.motX += -Math.sin((double) (f * 3.1415927F / 180.0F)) * this.b * (double) entityliving.aY * 0.05000000074505806D; + this.motZ += Math.cos((double) (f * 3.1415927F / 180.0F)) * this.b * (double) entityliving.aY * 0.05000000074505806D; + } ++ // CraftBukkit start - Support unoccupied deceleration ++ else if (unoccupiedDeceleration >= 0) { ++ this.motX *= unoccupiedDeceleration; ++ this.motZ *= unoccupiedDeceleration; ++ // Kill lingering speed ++ if (motX <= 0.00001) { ++ motX = 0; ++ } ++ if (motZ <= 0.00001) { ++ motZ = 0; ++ } ++ } ++ // CraftBukkit end + + d4 = Math.sqrt(this.motX * this.motX + this.motZ * this.motZ); + if (d4 > 0.35D) { +@@ -230,16 +305,26 @@ + Block block = this.world.getType(blockposition).getBlock(); + + if (block == Blocks.SNOW_LAYER) { ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, l, j1, j, Blocks.AIR, 0).isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end + this.world.setAir(blockposition); + this.positionChanged = false; + } else if (block == Blocks.WATERLILY) { ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, l, j1, j, Blocks.AIR, 0).isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end + this.world.setAir(blockposition, true); + this.positionChanged = false; + } + } + } + +- if (this.onGround) { ++ if (this.onGround && !this.landBoats) { // CraftBukkit + this.motX *= 0.5D; + this.motY *= 0.5D; + this.motZ *= 0.5D; +@@ -247,16 +332,23 @@ + + this.move(this.motX, this.motY, this.motZ); + if (this.positionChanged && d3 > 0.2D) { +- if (!this.world.isStatic && !this.dead) { +- this.die(); ++ if (!this.world.isStatic && !this.dead) { ++ // CraftBukkit start ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, null); ++ this.world.getServer().getPluginManager().callEvent(destroyEvent); ++ if (!destroyEvent.isCancelled()) { ++ this.die(); + +- for (k = 0; k < 3; ++k) { +- this.a(Item.getItemOf(Blocks.PLANKS), 1, 0.0F); +- } ++ for (k = 0; k < 3; ++k) { ++ this.a(Item.getItemOf(Blocks.PLANKS), 1, 0.0F); ++ } + +- for (k = 0; k < 2; ++k) { +- this.a(Items.STICK, 1, 0.0F); ++ for (k = 0; k < 2; ++k) { ++ this.a(Items.STICK, 1, 0.0F); ++ } + } ++ // CraftBukkit end + } + } else { + this.motX *= 0.9900000095367432D; +@@ -284,6 +376,23 @@ + + this.yaw = (float) ((double) this.yaw + d12); + this.setYawPitch(this.yaw, this.pitch); ++ ++ // CraftBukkit start ++ org.bukkit.Server server = this.world.getServer(); ++ org.bukkit.World bworld = this.world.getWorld(); ++ ++ Location from = new Location(bworld, prevX, prevY, prevZ, prevYaw, prevPitch); ++ Location to = new Location(bworld, this.locX, this.locY, this.locZ, this.yaw, this.pitch); ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ ++ server.getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle)); ++ ++ if (!from.equals(to)) { ++ VehicleMoveEvent event = new VehicleMoveEvent(vehicle, from, to); ++ server.getPluginManager().callEvent(event); ++ } ++ // CraftBukkit end ++ + if (!this.world.isStatic) { + List list = this.world.getEntities(this, this.getBoundingBox().grow(0.20000000298023224D, 0.0D, 0.20000000298023224D)); + +@@ -298,6 +407,7 @@ + } + + if (this.passenger != null && this.passenger.dead) { ++ this.passenger.vehicle = null; // CraftBukkit + this.passenger = null; + } + +@@ -335,17 +445,24 @@ + if (this.fallDistance > 3.0F) { + this.e(this.fallDistance, 1.0F); + if (!this.world.isStatic && !this.dead) { +- this.die(); ++ // CraftBukkit start ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, null); ++ this.world.getServer().getPluginManager().callEvent(destroyEvent); ++ if (!destroyEvent.isCancelled()) { ++ this.die(); + +- int i; ++ int i; + +- for (i = 0; i < 3; ++i) { +- this.a(Item.getItemOf(Blocks.PLANKS), 1, 0.0F); +- } ++ for (i = 0; i < 3; ++i) { ++ this.a(Item.getItemOf(Blocks.PLANKS), 1, 0.0F); ++ } + +- for (i = 0; i < 2; ++i) { +- this.a(Items.STICK, 1, 0.0F); ++ for (i = 0; i < 2; ++i) { ++ this.a(Items.STICK, 1, 0.0F); ++ } + } ++ // CraftBukkit end + } + + this.fallDistance = 0.0F; diff --git a/paper-server/nms-patches/EntityChicken.patch b/paper-server/nms-patches/EntityChicken.patch new file mode 100644 index 0000000000..07602829a1 --- /dev/null +++ b/paper-server/nms-patches/EntityChicken.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityChicken.java 2014-11-27 08:59:46.657422040 +1100 ++++ src/main/java/net/minecraft/server/EntityChicken.java 2014-11-27 08:42:10.104851005 +1100 +@@ -35,6 +35,11 @@ + } + + public void m() { ++ // CraftBukkit start ++ if (this.isChickenJockey()) { ++ this.persistent = !this.isTypeNotPersistent(); ++ } ++ // CraftBukkit end + super.m(); + this.bo = this.bk; + this.bn = this.bm; diff --git a/paper-server/nms-patches/EntityCow.patch b/paper-server/nms-patches/EntityCow.patch new file mode 100644 index 0000000000..c8aafbcc62 --- /dev/null +++ b/paper-server/nms-patches/EntityCow.patch @@ -0,0 +1,42 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityCow.java 2014-11-27 08:59:46.657422040 +1100 ++++ src/main/java/net/minecraft/server/EntityCow.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++// CraftBukkit end ++ + public class EntityCow extends EntityAnimal { + + public EntityCow(World world) { +@@ -69,13 +74,23 @@ + + public boolean a(EntityHuman entityhuman) { + ItemStack itemstack = entityhuman.inventory.getItemInHand(); +- ++ + if (itemstack != null && itemstack.getItem() == Items.BUCKET && !entityhuman.abilities.canInstantlyBuild) { +- if (itemstack.count-- == 1) { +- entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, new ItemStack(Items.MILK_BUCKET)); +- } else if (!entityhuman.inventory.pickup(new ItemStack(Items.MILK_BUCKET))) { +- entityhuman.drop(new ItemStack(Items.MILK_BUCKET, 1, 0), false); ++ // CraftBukkit start - Got milk? ++ org.bukkit.Location loc = this.getBukkitEntity().getLocation(); ++ org.bukkit.event.player.PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), null, itemstack, Items.MILK_BUCKET); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ ItemStack result = CraftItemStack.asNMSCopy(event.getItemStack()); ++ if (--itemstack.count <= 0) { ++ entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, result); ++ } else if (!entityhuman.inventory.pickup(result)) { ++ entityhuman.drop(result, false); + } ++ // CraftBukkit end + + return true; + } else { diff --git a/paper-server/nms-patches/EntityCreature.patch b/paper-server/nms-patches/EntityCreature.patch new file mode 100644 index 0000000000..f9d70d5e81 --- /dev/null +++ b/paper-server/nms-patches/EntityCreature.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityCreature.java 2014-11-27 08:59:46.657422040 +1100 ++++ src/main/java/net/minecraft/server/EntityCreature.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,12 @@ + + import java.util.UUID; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftEntity; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.event.entity.EntityUnleashEvent; ++// CraftBukkit end ++ + public abstract class EntityCreature extends EntityInsentient { + + public static final UUID bi = UUID.fromString("E199AD21-BA8A-4C53-8D13-6182D5C69D3A"); +@@ -69,6 +75,7 @@ + + if (this instanceof EntityTameableAnimal && ((EntityTameableAnimal) this).isSitting()) { + if (f > 10.0F) { ++ this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); // CraftBukkit + this.unleash(true, true); + } + +@@ -100,6 +107,7 @@ + } + + if (f > 10.0F) { ++ this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); // CraftBukkit + this.unleash(true, true); + } + } else if (!this.cb() && this.bk) { diff --git a/paper-server/nms-patches/EntityCreeper.patch b/paper-server/nms-patches/EntityCreeper.patch new file mode 100644 index 0000000000..47e72258c9 --- /dev/null +++ b/paper-server/nms-patches/EntityCreeper.patch @@ -0,0 +1,104 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityCreeper.java 2014-11-27 08:59:46.661422023 +1100 ++++ src/main/java/net/minecraft/server/EntityCreeper.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.ExplosionPrimeEvent; ++// CraftBukkit end ++ + public class EntityCreeper extends EntityMonster { + + private int b; +@@ -7,6 +12,7 @@ + private int maxFuseTicks = 30; + private int explosionRadius = 3; + private int bm = 0; ++ private int record = -1; // CraftBukkit + + public EntityCreeper(World world) { + super(world); +@@ -111,19 +117,36 @@ + } + + public void die(DamageSource damagesource) { +- super.die(damagesource); ++ // super.die(damagesource); // CraftBukkit - Moved to end + if (damagesource.getEntity() instanceof EntitySkeleton) { + int i = Item.getId(Items.RECORD_13); + int j = Item.getId(Items.RECORD_WAIT); + int k = i + this.random.nextInt(j - i + 1); + +- this.a(Item.getById(k), 1); ++ // CraftBukkit start - Store record for now, drop in dropDeathLoot ++ // this.a(Item.getById(k), 1); ++ this.record = k; ++ // CraftBukkit end + } else if (damagesource.getEntity() instanceof EntityCreeper && damagesource.getEntity() != this && ((EntityCreeper) damagesource.getEntity()).isPowered() && ((EntityCreeper) damagesource.getEntity()).cn()) { + ((EntityCreeper) damagesource.getEntity()).co(); + this.a(new ItemStack(Items.SKULL, 1, 4), 0.0F); + } +- ++ ++ super.die(damagesource); // CraftBukkit - Moved from above ++ } ++ ++ // CraftBukkit start - Whole method ++ @Override ++ protected void dropDeathLoot(boolean flag, int i) { ++ super.dropDeathLoot(flag, i); ++ ++ // Drop a music disc? ++ if (this.record != -1) { ++ this.a(Item.getById(this.record), 1); ++ this.record = -1; ++ } + } ++ // CraftBukkit end + + public boolean r(Entity entity) { + return true; +@@ -147,7 +170,21 @@ + + public void onLightningStrike(EntityLightning entitylightning) { + super.onLightningStrike(entitylightning); +- this.datawatcher.watch(17, Byte.valueOf((byte) 1)); ++ // CraftBukkit start ++ if (CraftEventFactory.callCreeperPowerEvent(this, entitylightning, org.bukkit.event.entity.CreeperPowerEvent.PowerCause.LIGHTNING).isCancelled()) { ++ return; ++ } ++ ++ this.setPowered(true); ++ } ++ ++ public void setPowered(boolean powered) { ++ if (!powered) { ++ this.datawatcher.watch(17, Byte.valueOf((byte) 0)); ++ } else { ++ this.datawatcher.watch(17, Byte.valueOf((byte) 1)); ++ } ++ // CraftBukkit end + } + + protected boolean a(EntityHuman entityhuman) { +@@ -170,9 +207,16 @@ + if (!this.world.isStatic) { + boolean flag = this.world.getGameRules().getBoolean("mobGriefing"); + float f = this.isPowered() ? 2.0F : 1.0F; +- +- this.world.explode(this, this.locX, this.locY, this.locZ, (float) this.explosionRadius * f, flag); +- this.die(); ++ ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), this.explosionRadius * f, false); ++ this.world.getServer().getPluginManager().callEvent(event); ++ if (!event.isCancelled()) { ++ this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire(), flag); ++ this.die(); ++ } else { ++ fuseTicks = 0; ++ } ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/EntityDamageSourceIndirect.patch b/paper-server/nms-patches/EntityDamageSourceIndirect.patch new file mode 100644 index 0000000000..efcfd591f6 --- /dev/null +++ b/paper-server/nms-patches/EntityDamageSourceIndirect.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityDamageSourceIndirect.java 2014-11-27 08:59:46.661422023 +1100 ++++ src/main/java/net/minecraft/server/EntityDamageSourceIndirect.java 2014-11-27 08:42:10.164850887 +1100 +@@ -24,5 +24,11 @@ + String s1 = s + ".item"; + + return itemstack != null && itemstack.hasName() && LocaleI18n.c(s1) ? new ChatMessage(s1, new Object[] { entityliving.getScoreboardDisplayName(), ichatbasecomponent, itemstack.C()}) : new ChatMessage(s, new Object[] { entityliving.getScoreboardDisplayName(), ichatbasecomponent}); ++ } ++ ++ // CraftBukkit start ++ public Entity getProximateDamageSource() { ++ return super.getEntity(); + } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/EntityEgg.patch b/paper-server/nms-patches/EntityEgg.patch new file mode 100644 index 0000000000..9b51e76638 --- /dev/null +++ b/paper-server/nms-patches/EntityEgg.patch @@ -0,0 +1,65 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityEgg.java 2014-11-27 08:59:46.665422005 +1100 ++++ src/main/java/net/minecraft/server/EntityEgg.java 2014-11-27 08:42:10.112850989 +1100 +@@ -1,5 +1,12 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.entity.Ageable; ++import org.bukkit.entity.EntityType; ++import org.bukkit.entity.Player; ++import org.bukkit.event.player.PlayerEggThrowEvent; ++// CraftBukkit end ++ + public class EntityEgg extends EntityProjectile { + + public EntityEgg(World world) { +@@ -19,21 +26,36 @@ + movingobjectposition.entity.damageEntity(DamageSource.projectile(this, this.getShooter()), 0.0F); + } + +- if (!this.world.isStatic && this.random.nextInt(8) == 0) { +- byte b0 = 1; ++ // CraftBukkit start - Fire PlayerEggThrowEvent ++ boolean hatching = !this.world.isStatic && this.random.nextInt(8) == 0; ++ int numHatching = (this.random.nextInt(32) == 0) ? 4 : 1; ++ if (!hatching) { ++ numHatching = 0; ++ } ++ ++ EntityType hatchingType = EntityType.CHICKEN; + +- if (this.random.nextInt(32) == 0) { +- b0 = 4; +- } +- +- for (int i = 0; i < b0; ++i) { +- EntityChicken entitychicken = new EntityChicken(this.world); +- +- entitychicken.setAgeRaw(-24000); +- entitychicken.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F); +- this.world.addEntity(entitychicken); +- } ++ Entity shooter = this.getShooter(); ++ if (shooter instanceof EntityPlayer) { ++ Player player = (shooter == null) ? null : (Player) shooter.getBukkitEntity(); ++ ++ PlayerEggThrowEvent event = new PlayerEggThrowEvent(player, (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, (byte) numHatching, hatchingType); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ hatching = event.isHatching(); ++ numHatching = event.getNumHatches(); ++ hatchingType = event.getHatchingType(); ++ } ++ ++ if (hatching) { ++ for (int k = 0; k < numHatching; k++) { ++ org.bukkit.entity.Entity entity = world.getWorld().spawn(new org.bukkit.Location(world.getWorld(), this.locX, this.locY, this.locZ, this.yaw, 0.0F), hatchingType.getEntityClass(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); ++ if (entity instanceof Ageable) { ++ ((Ageable) entity).setBaby(); ++ } ++ } + } ++ // CraftBukkit end + + double d0 = 0.08D; + diff --git a/paper-server/nms-patches/EntityEnderCrystal.patch b/paper-server/nms-patches/EntityEnderCrystal.patch new file mode 100644 index 0000000000..0bf41baa2f --- /dev/null +++ b/paper-server/nms-patches/EntityEnderCrystal.patch @@ -0,0 +1,43 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityEnderCrystal.java 2014-11-27 08:59:46.665422005 +1100 ++++ src/main/java/net/minecraft/server/EntityEnderCrystal.java 2014-11-27 08:42:10.172850872 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.ExplosionPrimeEvent; ++// CraftBukkit end ++ + public class EntityEnderCrystal extends Entity { + + public int a; +@@ -32,7 +37,11 @@ + int k = MathHelper.floor(this.locZ); + + if (this.world.worldProvider instanceof WorldProviderTheEnd && this.world.getType(new BlockPosition(i, j, k)).getBlock() != Blocks.FIRE) { +- this.world.setTypeUpdate(new BlockPosition(i, j, k), Blocks.FIRE.getBlockData()); ++ // CraftBukkit start ++ if (!CraftEventFactory.callBlockIgniteEvent(this.world, i, j, k, this).isCancelled()) { ++ this.world.setTypeUpdate(new BlockPosition(i, j, k), Blocks.FIRE.getBlockData()); ++ } ++ // CraftBukkit end + } + + } +@@ -54,7 +63,15 @@ + if (this.b <= 0) { + this.die(); + if (!this.world.isStatic) { +- this.world.explode((Entity) null, this.locX, this.locY, this.locZ, 6.0F, true); ++ // CraftBukkit start ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 6.0F, false); ++ this.world.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ this.dead = false; ++ return false; ++ } ++ this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire(), true); ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/EntityEnderDragon.patch b/paper-server/nms-patches/EntityEnderDragon.patch new file mode 100644 index 0000000000..a58d2f8fc7 --- /dev/null +++ b/paper-server/nms-patches/EntityEnderDragon.patch @@ -0,0 +1,330 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityEnderDragon.java 2014-11-27 08:59:46.665422005 +1100 ++++ src/main/java/net/minecraft/server/EntityEnderDragon.java 2014-11-27 08:42:10.116850981 +1100 +@@ -5,6 +5,17 @@ + import java.util.Iterator; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.block.BlockState; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.util.BlockStateListPopulator; ++import org.bukkit.event.entity.EntityCreatePortalEvent; ++import org.bukkit.event.entity.EntityExplodeEvent; ++import org.bukkit.event.entity.EntityRegainHealthEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.Bukkit; ++// CraftBukkit end ++ + public class EntityEnderDragon extends EntityInsentient implements IComplex, IMonster { + + public double a; +@@ -27,6 +38,7 @@ + private Entity by; + public int bw; + public EntityEnderCrystal bx; ++ private Explosion explosionSource = new Explosion(null, this, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, true); // CraftBukkit - reusable source for CraftTNTPrimed.getSource() + + public EntityEnderDragon(World world) { + super(world); +@@ -120,21 +132,21 @@ + + if (this.world.isStatic) { + if (this.ba > 0) { +- d3 = this.locX + (this.bb - this.locX) / (double) this.ba; +- d0 = this.locY + (this.bc - this.locY) / (double) this.ba; +- d1 = this.locZ + (this.bd - this.locZ) / (double) this.ba; +- d2 = MathHelper.g(this.be - (double) this.yaw); +- this.yaw = (float) ((double) this.yaw + d2 / (double) this.ba); ++ d0 = this.locX + (this.bb - this.locX) / (double) this.ba; ++ d1 = this.locY + (this.bc - this.locY) / (double) this.ba; ++ d2 = this.locZ + (this.bd - this.locZ) / (double) this.ba; ++ d3 = MathHelper.g(this.be - (double) this.yaw); ++ this.yaw = (float) ((double) this.yaw + d3 / (double) this.ba); + this.pitch = (float) ((double) this.pitch + (this.bf - (double) this.pitch) / (double) this.ba); + --this.ba; +- this.setPosition(d3, d0, d1); ++ this.setPosition(d0, d1, d2); + this.setYawPitch(this.yaw, this.pitch); + } + } else { +- d3 = this.a - this.locX; +- d0 = this.b - this.locY; +- d1 = this.c - this.locZ; +- d2 = d3 * d3 + d0 * d0 + d1 * d1; ++ d0 = this.a - this.locX; ++ d1 = this.b - this.locY; ++ d2 = this.c - this.locZ; ++ d3 = d0 * d0 + d1 * d1 + d2 * d2; + double d4; + + if (this.by != null) { +@@ -155,16 +167,16 @@ + this.c += this.random.nextGaussian() * 2.0D; + } + +- if (this.bu || d2 < 100.0D || d2 > 22500.0D || this.positionChanged || this.E) { ++ if (this.bu || d3 < 100.0D || d3 > 22500.0D || this.positionChanged || this.E) { + this.cd(); + } + +- d0 /= (double) MathHelper.sqrt(d3 * d3 + d1 * d1); ++ d1 /= (double) MathHelper.sqrt(d0 * d0 + d2 * d2); + f3 = 0.6F; +- d0 = MathHelper.a(d0, (double) (-f3), (double) f3); +- this.motY += d0 * 0.10000000149011612D; ++ d1 = MathHelper.a(d1, (double) (-f3), (double) f3); ++ this.motY += d1 * 0.10000000149011612D; + this.yaw = MathHelper.g(this.yaw); +- double d8 = 180.0D - Math.atan2(d3, d1) * 180.0D / 3.1415927410125732D; ++ double d8 = 180.0D - Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D; + double d9 = MathHelper.g(d8 - (double) this.yaw); + + if (d9 > 50.0D) { +@@ -290,12 +302,21 @@ + if (this.bx != null) { + if (this.bx.dead) { + if (!this.world.isStatic) { ++ CraftEventFactory.entityDamage = this.bx; // CraftBukkit + this.a(this.bl, DamageSource.explosion((Explosion) null), 10.0F); ++ CraftEventFactory.entityDamage = null; // CraftBukkit + } + + this.bx = null; + } else if (this.ticksLived % 10 == 0 && this.getHealth() < this.getMaxHealth()) { +- this.setHealth(this.getHealth() + 1.0F); ++ // CraftBukkit start ++ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), 1.0D, EntityRegainHealthEvent.RegainReason.ENDER_CRYSTAL); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.setHealth((float) (this.getHealth() + event.getAmount())); ++ } ++ // CraftBukkit end + } + } + +@@ -364,7 +385,19 @@ + } + + if (this.random.nextInt(2) == 0 && !arraylist.isEmpty()) { +- this.by = (Entity) arraylist.get(this.random.nextInt(arraylist.size())); ++ // CraftBukkit start ++ Entity target = (Entity) this.world.players.get(this.random.nextInt(this.world.players.size())); ++ EntityTargetEvent event = new EntityTargetEvent(this.getBukkitEntity(), target.getBukkitEntity(), EntityTargetEvent.TargetReason.RANDOM_TARGET); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ if (event.getTarget() == null) { ++ this.by = null; ++ } else { ++ this.by = ((org.bukkit.craftbukkit.entity.CraftEntity) event.getTarget()).getHandle(); ++ } ++ } ++ // CraftBukkit end + } else { + boolean flag; + +@@ -399,6 +432,11 @@ + int j1 = MathHelper.floor(axisalignedbb.f); + boolean flag = false; + boolean flag1 = false; ++ ++ // CraftBukkit start - Create a list to hold all the destroyed blocks ++ List destroyedBlocks = new java.util.ArrayList(); ++ org.bukkit.craftbukkit.CraftWorld craftWorld = this.world.getWorld(); ++ // CraftBukkit end + + for (int k1 = i; k1 <= l; ++k1) { + for (int l1 = j; l1 <= i1; ++l1) { +@@ -407,7 +445,11 @@ + + if (block.getMaterial() != Material.AIR) { + if (block != Blocks.BARRIER && block != Blocks.OBSIDIAN && block != Blocks.END_STONE && block != Blocks.BEDROCK && block != Blocks.COMMAND_BLOCK && this.world.getGameRules().getBoolean("mobGriefing")) { +- flag1 = this.world.setAir(new BlockPosition(k1, l1, i2)) || flag1; ++ // CraftBukkit start - Add blocks to list rather than destroying them ++ // flag1 = this.world.setAir(new BlockPosition(k1, l1, i2)) || flag1; ++ flag1 = true; ++ destroyedBlocks.add(craftWorld.getBlockAt(k1, l1, i2)); ++ // CraftBukkit end + } else { + flag = true; + } +@@ -417,6 +459,40 @@ + } + + if (flag1) { ++ // CraftBukkit start - Set off an EntityExplodeEvent for the dragon exploding all these blocks ++ org.bukkit.entity.Entity bukkitEntity = this.getBukkitEntity(); ++ EntityExplodeEvent event = new EntityExplodeEvent(bukkitEntity, bukkitEntity.getLocation(), destroyedBlocks, 0F); ++ Bukkit.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ // This flag literally means 'Dragon hit something hard' (Obsidian, White Stone or Bedrock) and will cause the dragon to slow down. ++ // We should consider adding an event extension for it, or perhaps returning true if the event is cancelled. ++ return flag; ++ } else if (event.getYield() == 0F) { ++ // Yield zero ==> no drops ++ for (org.bukkit.block.Block block : event.blockList()) { ++ this.world.setAir(new BlockPosition(block.getX(), block.getY(), block.getZ())); ++ } ++ } else { ++ for (org.bukkit.block.Block block : event.blockList()) { ++ org.bukkit.Material blockId = block.getType(); ++ if (blockId == org.bukkit.Material.AIR) { ++ continue; ++ } ++ ++ int blockX = block.getX(); ++ int blockY = block.getY(); ++ int blockZ = block.getZ(); ++ ++ Block nmsBlock = org.bukkit.craftbukkit.util.CraftMagicNumbers.getBlock(blockId); ++ if (nmsBlock.a(explosionSource)) { ++ nmsBlock.dropNaturally(this.world, new BlockPosition(blockX, blockY, blockZ), nmsBlock.fromLegacyData(block.getData()), event.getYield(), 0); ++ } ++ nmsBlock.wasExploded(world, new BlockPosition(blockX, blockY, blockZ), explosionSource); ++ ++ this.world.setAir(new BlockPosition(blockX, blockY, blockZ)); ++ } ++ } ++ // CraftBukkit end + double d0 = axisalignedbb.a + (axisalignedbb.d - axisalignedbb.a) * (double) this.random.nextFloat(); + double d1 = axisalignedbb.b + (axisalignedbb.e - axisalignedbb.b) * (double) this.random.nextFloat(); + double d2 = axisalignedbb.c + (axisalignedbb.f - axisalignedbb.c) * (double) this.random.nextFloat(); +@@ -464,6 +540,7 @@ + } + + protected void aY() { ++ if (this.dead) return; // CraftBukkit - can't kill what's already dead + ++this.bw; + if (this.bw >= 180 && this.bw <= 200) { + float f = (this.random.nextFloat() - 0.5F) * 8.0F; +@@ -478,7 +555,7 @@ + + if (!this.world.isStatic) { + if (this.bw > 150 && this.bw % 5 == 0 && this.world.getGameRules().getBoolean("doMobLoot")) { +- i = 1000; ++ i = this.expToDrop / 12; // CraftBukkit - drop experience as dragon falls from sky. use experience drop from death event. This is now set in getExpReward() + + while (i > 0) { + j = EntityExperienceOrb.getOrbValue(i); +@@ -488,14 +565,30 @@ + } + + if (this.bw == 1) { +- this.world.a(1018, new BlockPosition(this), 0); ++ // CraftBukkit start - Use relative location for far away sounds ++ // this.world.a(1018, new BlockPosition(this), 0); ++ int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16; ++ for (EntityPlayer player : (List) this.world.players) { ++ double deltaX = this.locX - player.locX; ++ double deltaZ = this.locZ - player.locZ; ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.locX + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.locZ + (deltaZ / deltaLength) * viewDistance; ++ player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1018, new BlockPosition((int) relativeX, (int) this.locY, (int) relativeZ), 0, true)); ++ } else { ++ player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1018, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0, true)); ++ } ++ } ++ // CraftBukkit end + } + } + + this.move(0.0D, 0.10000000149011612D, 0.0D); + this.aG = this.yaw += 20.0F; + if (this.bw == 200 && !this.world.isStatic) { +- i = 2000; ++ i = this.expToDrop - (10 * this.expToDrop / 12); // CraftBukkit - drop the remaining experience + + while (i > 0) { + j = EntityExperienceOrb.getOrbValue(i); +@@ -513,6 +606,9 @@ + boolean flag = true; + double d0 = 12.25D; + double d1 = 6.25D; ++ ++ // CraftBukkit start - Replace any "this.world" in the following with just "world"! ++ BlockStateListPopulator world = new BlockStateListPopulator(this.world.getWorld()); + + for (int i = -1; i <= 32; ++i) { + for (int j = -4; j <= 4; ++j) { +@@ -524,31 +620,51 @@ + + if (i < 0) { + if (d2 <= 6.25D) { +- this.world.setTypeUpdate(blockposition1, Blocks.BEDROCK.getBlockData()); ++ world.setTypeUpdate(blockposition1, Blocks.BEDROCK.getBlockData()); + } + } else if (i > 0) { +- this.world.setTypeUpdate(blockposition1, Blocks.AIR.getBlockData()); ++ world.setTypeUpdate(blockposition1, Blocks.AIR.getBlockData()); + } else if (d2 > 6.25D) { +- this.world.setTypeUpdate(blockposition1, Blocks.BEDROCK.getBlockData()); ++ world.setTypeUpdate(blockposition1, Blocks.BEDROCK.getBlockData()); + } else { +- this.world.setTypeUpdate(blockposition1, Blocks.END_PORTAL.getBlockData()); ++ world.setTypeUpdate(blockposition1, Blocks.END_PORTAL.getBlockData()); + } + } + } + } + } + +- this.world.setTypeUpdate(blockposition, Blocks.BEDROCK.getBlockData()); +- this.world.setTypeUpdate(blockposition.up(), Blocks.BEDROCK.getBlockData()); ++ world.setTypeUpdate(blockposition, Blocks.BEDROCK.getBlockData()); ++ world.setTypeUpdate(blockposition.up(), Blocks.BEDROCK.getBlockData()); + BlockPosition blockposition2 = blockposition.up(2); + +- this.world.setTypeUpdate(blockposition2, Blocks.BEDROCK.getBlockData()); +- this.world.setTypeUpdate(blockposition2.west(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.EAST)); +- this.world.setTypeUpdate(blockposition2.east(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.WEST)); +- this.world.setTypeUpdate(blockposition2.north(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.SOUTH)); +- this.world.setTypeUpdate(blockposition2.south(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.NORTH)); +- this.world.setTypeUpdate(blockposition.up(3), Blocks.BEDROCK.getBlockData()); +- this.world.setTypeUpdate(blockposition.up(4), Blocks.DRAGON_EGG.getBlockData()); ++ world.setTypeUpdate(blockposition2, Blocks.BEDROCK.getBlockData()); ++ world.setTypeUpdate(blockposition2.west(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.EAST)); ++ world.setTypeUpdate(blockposition2.east(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.WEST)); ++ world.setTypeUpdate(blockposition2.north(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.SOUTH)); ++ world.setTypeUpdate(blockposition2.south(), Blocks.TORCH.getBlockData().set(BlockTorch.FACING, EnumDirection.NORTH)); ++ world.setTypeUpdate(blockposition.up(3), Blocks.BEDROCK.getBlockData()); ++ world.setTypeUpdate(blockposition.up(4), Blocks.DRAGON_EGG.getBlockData()); ++ ++ EntityCreatePortalEvent event = new EntityCreatePortalEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), java.util.Collections.unmodifiableList(world.getList()), org.bukkit.PortalType.ENDER); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ for (BlockState state : event.getBlocks()) { ++ state.update(true); ++ } ++ } else { ++ for (BlockState state : event.getBlocks()) { ++ PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(this.world, new BlockPosition(state.getX(), state.getY(), state.getZ())); ++ for (Iterator it = this.world.players.iterator(); it.hasNext();) { ++ EntityHuman entity = (EntityHuman) it.next(); ++ if (entity instanceof EntityPlayer) { ++ ((EntityPlayer) entity).playerConnection.sendPacket(packet); ++ } ++ } ++ } ++ } ++ // CraftBukkit end + } + + protected void D() {} +@@ -576,4 +692,12 @@ + protected float bA() { + return 5.0F; + } ++ ++ // CraftBukkit start ++ public int getExpReward() { ++ // This value is equal to the amount of experience dropped while falling from the sky (10 * 1000) ++ // plus what is dropped when the dragon hits the ground (2000) ++ return 12000; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/EntityEnderPearl.patch b/paper-server/nms-patches/EntityEnderPearl.patch new file mode 100644 index 0000000000..de13eefd67 --- /dev/null +++ b/paper-server/nms-patches/EntityEnderPearl.patch @@ -0,0 +1,50 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityEnderPearl.java 2014-11-27 08:59:46.669421987 +1100 ++++ src/main/java/net/minecraft/server/EntityEnderPearl.java 2014-11-27 08:42:10.124850965 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.player.PlayerTeleportEvent; ++// CraftBukkit end ++ + public class EntityEnderPearl extends EntityProjectile { + + public EntityEnderPearl(World world, EntityLiving entityliving) { +@@ -29,14 +35,28 @@ + entityendermite.setPositionRotation(entityliving.locX, entityliving.locY, entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.world.addEntity(entityendermite); + } +- +- if (entityliving.av()) { +- entityliving.mount((Entity) null); ++ ++ // CraftBukkit start - Fire PlayerTeleportEvent ++ org.bukkit.craftbukkit.entity.CraftPlayer player = entityplayer.getBukkitEntity(); ++ org.bukkit.Location location = getBukkitEntity().getLocation(); ++ location.setPitch(player.getLocation().getPitch()); ++ location.setYaw(player.getLocation().getYaw()); ++ ++ PlayerTeleportEvent teleEvent = new PlayerTeleportEvent(player, player.getLocation(), location, PlayerTeleportEvent.TeleportCause.ENDER_PEARL); ++ Bukkit.getPluginManager().callEvent(teleEvent); ++ ++ if (!teleEvent.isCancelled() && !entityplayer.playerConnection.isDisconnected()) { ++ if (entityliving.av()) { ++ entityliving.mount((Entity) null); ++ } ++ ++ entityplayer.playerConnection.teleport(teleEvent.getTo()); ++ entityliving.fallDistance = 0.0F; ++ CraftEventFactory.entityDamage = this; ++ entityliving.damageEntity(DamageSource.FALL, 5.0F); ++ CraftEventFactory.entityDamage = null; + } +- +- entityliving.enderTeleportTo(this.locX, this.locY, this.locZ); +- entityliving.fallDistance = 0.0F; +- entityliving.damageEntity(DamageSource.FALL, 5.0F); ++ // CraftBukkit end + } + } + diff --git a/paper-server/nms-patches/EntityEnderman.patch b/paper-server/nms-patches/EntityEnderman.patch new file mode 100644 index 0000000000..1fb9b6069d --- /dev/null +++ b/paper-server/nms-patches/EntityEnderman.patch @@ -0,0 +1,34 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityEnderman.java 2014-11-27 08:59:46.669421987 +1100 ++++ src/main/java/net/minecraft/server/EntityEnderman.java 2014-11-27 08:42:10.140850934 +1100 +@@ -4,6 +4,12 @@ + import java.util.Set; + import java.util.UUID; + ++// CraftBukkit start ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTeleportEvent; ++// CraftBukkit end ++ + public class EntityEnderman extends EntityMonster { + + private static final UUID b = UUID.fromString("020E0DFB-87AE-4653-9556-831010E291A0"); +@@ -165,7 +171,17 @@ + } + + if (flag1) { +- super.enderTeleportTo(this.locX, this.locY, this.locZ); ++ // CraftBukkit start - Teleport event ++ // super.enderTeleportTo(this.locX, this.locY, this.locZ); ++ EntityTeleportEvent teleport = new EntityTeleportEvent(this.getBukkitEntity(), new Location(this.world.getWorld(), d3, d4, d5), new Location(this.world.getWorld(), this.locX, this.locY, this.locZ)); ++ this.world.getServer().getPluginManager().callEvent(teleport); ++ if (teleport.isCancelled()) { ++ return false; ++ } ++ ++ Location to = teleport.getTo(); ++ this.enderTeleportTo(to.getX(), to.getY(), to.getZ()); ++ // CraftBukkit end + if (this.world.getCubes(this, this.getBoundingBox()).isEmpty() && !this.world.containsLiquid(this.getBoundingBox())) { + flag = true; + } diff --git a/paper-server/nms-patches/EntityExperienceOrb.patch b/paper-server/nms-patches/EntityExperienceOrb.patch new file mode 100644 index 0000000000..0f389895b8 --- /dev/null +++ b/paper-server/nms-patches/EntityExperienceOrb.patch @@ -0,0 +1,82 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityExperienceOrb.java 2014-11-27 08:59:46.673421970 +1100 ++++ src/main/java/net/minecraft/server/EntityExperienceOrb.java 2014-11-27 08:42:10.100851012 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTargetLivingEntityEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++// CraftBukkit end ++ + public class EntityExperienceOrb extends Entity { + + public int a; +@@ -34,6 +40,7 @@ + + public void s_() { + super.s_(); ++ EntityHuman prevTarget = this.targetPlayer;// CraftBukkit - store old target + if (this.c > 0) { + --this.c; + } +@@ -65,6 +72,16 @@ + } + + if (this.targetPlayer != null) { ++ // CraftBukkit start ++ boolean cancelled = false; ++ if (this.targetPlayer != prevTarget) { ++ EntityTargetLivingEntityEvent event = CraftEventFactory.callEntityTargetLivingEvent(this, targetPlayer, EntityTargetEvent.TargetReason.CLOSEST_PLAYER); ++ EntityLiving target = event.getTarget() == null ? null : ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); ++ targetPlayer = target instanceof EntityHuman ? (EntityHuman) target : null; ++ cancelled = event.isCancelled(); ++ } ++ ++ if (!cancelled && targetPlayer != null) { + double d1 = (this.targetPlayer.locX - this.locX) / d0; + double d2 = (this.targetPlayer.locY + (double) this.targetPlayer.getHeadHeight() - this.locY) / d0; + double d3 = (this.targetPlayer.locZ - this.locZ) / d0; +@@ -77,6 +94,8 @@ + this.motY += d2 / d4 * d5 * 0.1D; + this.motZ += d3 / d4 * d5 * 0.1D; + } ++ } ++ // CraftBukkit end + } + + this.move(this.motX, this.motY, this.motZ); +@@ -141,7 +160,7 @@ + entityhuman.bn = 2; + this.world.makeSound(entityhuman, "random.orb", 0.1F, 0.5F * ((this.random.nextFloat() - this.random.nextFloat()) * 0.7F + 1.8F)); + entityhuman.receive(this, 1); +- entityhuman.giveExp(this.value); ++ entityhuman.giveExp(CraftEventFactory.callPlayerExpChangeEvent(entityhuman, this.value).getAmount()); // CraftBukkit - this.value -> event.getAmount() + this.die(); + } + +@@ -153,6 +172,24 @@ + } + + public static int getOrbValue(int i) { ++ // CraftBukkit start ++ if (i > 162670129) return i - 100000; ++ if (i > 81335063) return 81335063; ++ if (i > 40667527) return 40667527; ++ if (i > 20333759) return 20333759; ++ if (i > 10166857) return 10166857; ++ if (i > 5083423) return 5083423; ++ if (i > 2541701) return 2541701; ++ if (i > 1270849) return 1270849; ++ if (i > 635413) return 635413; ++ if (i > 317701) return 317701; ++ if (i > 158849) return 158849; ++ if (i > 79423) return 79423; ++ if (i > 39709) return 39709; ++ if (i > 19853) return 19853; ++ if (i > 9923) return 9923; ++ if (i > 4957) return 4957; ++ // CraftBukkit end + return i >= 2477 ? 2477 : (i >= 1237 ? 1237 : (i >= 617 ? 617 : (i >= 307 ? 307 : (i >= 149 ? 149 : (i >= 73 ? 73 : (i >= 37 ? 37 : (i >= 17 ? 17 : (i >= 7 ? 7 : (i >= 3 ? 3 : 1))))))))); + } + diff --git a/paper-server/nms-patches/EntityFallingBlock.patch b/paper-server/nms-patches/EntityFallingBlock.patch new file mode 100644 index 0000000000..2b53c264e8 --- /dev/null +++ b/paper-server/nms-patches/EntityFallingBlock.patch @@ -0,0 +1,44 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityFallingBlock.java 2014-11-27 08:59:46.673421970 +1100 ++++ src/main/java/net/minecraft/server/EntityFallingBlock.java 2014-11-27 08:42:10.132850949 +1100 +@@ -4,6 +4,8 @@ + import java.util.ArrayList; + import java.util.Iterator; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class EntityFallingBlock extends Entity { + + public IBlockData block; +@@ -56,7 +58,7 @@ + + if (this.ticksLived++ == 0) { + blockposition = new BlockPosition(this); +- if (this.world.getType(blockposition).getBlock() == block) { ++ if (this.world.getType(blockposition).getBlock() == block && !CraftEventFactory.callEntityChangeBlockEvent(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), Blocks.AIR, 0).isCancelled()) { + this.world.setAir(blockposition); + } else if (!this.world.isStatic) { + this.die(); +@@ -77,7 +79,12 @@ + this.motY *= -0.5D; + if (this.world.getType(blockposition).getBlock() != Blocks.PISTON_EXTENSION) { + this.die(); +- if (!this.e && this.world.a(block, blockposition, true, EnumDirection.UP, (Entity) null, (ItemStack) null) && !BlockFalling.canFall(this.world, blockposition.down()) && this.world.setTypeAndData(blockposition, this.block, 3)) { ++ if (!this.e && this.world.a(block, blockposition, true, EnumDirection.UP, (Entity) null, (ItemStack) null) && !BlockFalling.canFall(this.world, blockposition.down()) /* mimic the false conditions of setTypeIdAndData */ && blockposition.getX() >= -30000000 && blockposition.getZ() >= -30000000 && blockposition.getX() < 30000000 && blockposition.getZ() < 30000000 && blockposition.getY() >= 0 && blockposition.getY() < 256 && this.world.getType(blockposition) != this.block) { ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.block.getBlock(), this.block.getBlock().toLegacyData(this.block)).isCancelled()) { ++ return; ++ } ++ this.world.setTypeAndData(blockposition, this.block, 3); ++ // CraftBukkit end + if (block instanceof BlockFalling) { + ((BlockFalling) block).a_(this.world, blockposition); + } +@@ -135,7 +142,9 @@ + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); + ++ CraftEventFactory.entityDamage = this; // CraftBukkit + entity.damageEntity(damagesource, (float) Math.min(MathHelper.d((float) i * this.fallHurtAmount), this.fallHurtMax)); ++ CraftEventFactory.entityDamage = null; // CraftBukkit + } + + if (flag && (double) this.random.nextFloat() < 0.05000000074505806D + (double) i * 0.05D) { diff --git a/paper-server/nms-patches/EntityFireball.patch b/paper-server/nms-patches/EntityFireball.patch new file mode 100644 index 0000000000..67022e164b --- /dev/null +++ b/paper-server/nms-patches/EntityFireball.patch @@ -0,0 +1,111 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityFireball.java 2014-11-27 08:59:46.677421952 +1100 ++++ src/main/java/net/minecraft/server/EntityFireball.java 2014-11-27 08:42:10.144850927 +1100 +@@ -2,6 +2,8 @@ + + import java.util.List; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public abstract class EntityFireball extends Entity { + + private int e = -1; +@@ -15,6 +17,8 @@ + public double dirX; + public double dirY; + public double dirZ; ++ public float bukkitYield = 1; // CraftBukkit ++ public boolean isIncendiary = true; // CraftBukkit + + public EntityFireball(World world) { + super(world); +@@ -38,10 +42,17 @@ + public EntityFireball(World world, EntityLiving entityliving, double d0, double d1, double d2) { + super(world); + this.shooter = entityliving; ++ this.projectileSource = (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit + this.a(1.0F, 1.0F); + this.setPositionRotation(entityliving.locX, entityliving.locY, entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.setPosition(this.locX, this.locY, this.locZ); + this.motX = this.motY = this.motZ = 0.0D; ++ // CraftBukkit start - Added setDirection method ++ this.setDirection(d0, d1, d2); ++ } ++ ++ public void setDirection(double d0, double d1, double d2) { ++ // CraftBukkit end + d0 += this.random.nextGaussian() * 0.4D; + d1 += this.random.nextGaussian() * 0.4D; + d2 += this.random.nextGaussian() * 0.4D; +@@ -101,7 +112,7 @@ + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { +- double d1 = vec3d.f(movingobjectposition1.pos); ++ double d1 = vec3d.distanceSquared(movingobjectposition1.pos); // CraftBukkit - distance efficiency + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; +@@ -117,6 +128,12 @@ + + if (movingobjectposition != null) { + this.a(movingobjectposition); ++ ++ // CraftBukkit start - Fire ProjectileHitEvent ++ if (this.dead) { ++ CraftEventFactory.callProjectileHitEvent(this); ++ } ++ // CraftBukkit end + } + + this.locX += this.motX; +@@ -181,7 +198,8 @@ + + nbttagcompound.setString("inTile", minecraftkey == null ? "" : minecraftkey.toString()); + nbttagcompound.setByte("inGround", (byte) (this.i ? 1 : 0)); +- nbttagcompound.set("direction", this.a(new double[] { this.motX, this.motY, this.motZ})); ++ // CraftBukkit - Fix direction being mismapped to invalid variables ++ nbttagcompound.set("power", this.a(new double[] { this.dirX, this.dirY, this.dirZ})); + } + + public void a(NBTTagCompound nbttagcompound) { +@@ -195,12 +213,14 @@ + } + + this.i = nbttagcompound.getByte("inGround") == 1; +- if (nbttagcompound.hasKeyOfType("direction", 9)) { +- NBTTagList nbttaglist = nbttagcompound.getList("direction", 6); +- +- this.motX = nbttaglist.d(0); +- this.motY = nbttaglist.d(1); +- this.motZ = nbttaglist.d(2); ++ // CraftBukkit start - direction -> power ++ if (nbttagcompound.hasKeyOfType("power", 9)) { ++ NBTTagList nbttaglist = nbttagcompound.getList("power", 6); ++ ++ this.dirX = nbttaglist.d(0); ++ this.dirY = nbttaglist.d(1); ++ this.dirZ = nbttaglist.d(2); ++ // CraftBukkit end + } else { + this.die(); + } +@@ -221,6 +241,11 @@ + } else { + this.ac(); + if (damagesource.getEntity() != null) { ++ // CraftBukkit start ++ if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, damagesource, f)) { ++ return false; ++ } ++ // CraftBukkit end + Vec3D vec3d = damagesource.getEntity().ap(); + + if (vec3d != null) { +@@ -234,6 +259,7 @@ + + if (damagesource.getEntity() instanceof EntityLiving) { + this.shooter = (EntityLiving) damagesource.getEntity(); ++ this.projectileSource = (org.bukkit.projectiles.ProjectileSource) this.shooter.getBukkitEntity(); + } + + return true; diff --git a/paper-server/nms-patches/EntityFishingHook.patch b/paper-server/nms-patches/EntityFishingHook.patch new file mode 100644 index 0000000000..b2a015b838 --- /dev/null +++ b/paper-server/nms-patches/EntityFishingHook.patch @@ -0,0 +1,159 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityFishingHook.java 2014-11-27 08:59:46.677421952 +1100 ++++ src/main/java/net/minecraft/server/EntityFishingHook.java 2014-11-27 08:42:10.104851005 +1100 +@@ -3,6 +3,12 @@ + import java.util.Arrays; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.entity.Player; ++import org.bukkit.entity.Fish; ++import org.bukkit.event.player.PlayerFishEvent; ++// CraftBukkit end ++ + public class EntityFishingHook extends Entity { + + private static final List d = Arrays.asList(new PossibleFishingResult[] { (new PossibleFishingResult(new ItemStack(Items.LEATHER_BOOTS), 10)).a(0.9F), new PossibleFishingResult(new ItemStack(Items.LEATHER), 10), new PossibleFishingResult(new ItemStack(Items.BONE), 10), new PossibleFishingResult(new ItemStack(Items.POTION), 10), new PossibleFishingResult(new ItemStack(Items.STRING), 5), (new PossibleFishingResult(new ItemStack(Items.FISHING_ROD), 2)).a(0.9F), new PossibleFishingResult(new ItemStack(Items.BOWL), 10), new PossibleFishingResult(new ItemStack(Items.STICK), 5), new PossibleFishingResult(new ItemStack(Items.DYE, 10, EnumColor.BLACK.getInvColorIndex()), 1), new PossibleFishingResult(new ItemStack(Blocks.TRIPWIRE_HOOK), 10), new PossibleFishingResult(new ItemStack(Items.ROTTEN_FLESH), 10)}); +@@ -168,7 +174,7 @@ + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { +- d6 = vec3d.f(movingobjectposition1.pos); ++ d6 = vec3d.distanceSquared(movingobjectposition1.pos); // CraftBukkit - distance efficiency + if (d6 < d5 || d5 == 0.0D) { + entity = entity1; + d5 = d6; +@@ -182,6 +188,7 @@ + } + + if (movingobjectposition != null) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this); // Craftbukkit - Call event + if (movingobjectposition.entity != null) { + if (movingobjectposition.entity.damageEntity(DamageSource.projectile(this, this.owner), 0.0F)) { + this.hooked = movingobjectposition.entity; +@@ -261,8 +268,8 @@ + } else { + float f3; + float f4; +- double d11; + float f5; ++ double d11; + double d12; + + if (this.av > 0) { +@@ -277,20 +284,20 @@ + } else { + this.aw = (float) ((double) this.aw + this.random.nextGaussian() * 4.0D); + f3 = this.aw * 0.017453292F; +- f5 = MathHelper.sin(f3); +- f4 = MathHelper.cos(f3); +- d8 = this.locX + (double) (f5 * (float) this.av * 0.1F); +- d12 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F); +- d11 = this.locZ + (double) (f4 * (float) this.av * 0.1F); ++ f4 = MathHelper.sin(f3); ++ f5 = MathHelper.cos(f3); ++ d8 = this.locX + (double) (f4 * (float) this.av * 0.1F); ++ d11 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F); ++ d12 = this.locZ + (double) (f5 * (float) this.av * 0.1F); + if (this.random.nextFloat() < 0.15F) { +- worldserver.a(EnumParticle.WATER_BUBBLE, d8, d12 - 0.10000000149011612D, d11, 1, (double) f5, 0.1D, (double) f4, 0.0D, new int[0]); ++ worldserver.a(EnumParticle.WATER_BUBBLE, d8, d11 - 0.10000000149011612D, d12, 1, (double) f4, 0.1D, (double) f5, 0.0D, new int[0]); + } + +- float f6 = f5 * 0.04F; +- float f7 = f4 * 0.04F; ++ float f6 = f4 * 0.04F; ++ float f7 = f5 * 0.04F; + +- worldserver.a(EnumParticle.WATER_WAKE, d8, d12, d11, 0, (double) f7, 0.01D, (double) (-f6), 1.0D, new int[0]); +- worldserver.a(EnumParticle.WATER_WAKE, d8, d12, d11, 0, (double) (-f7), 0.01D, (double) f6, 1.0D, new int[0]); ++ worldserver.a(EnumParticle.WATER_WAKE, d8, d11, d12, 0, (double) f7, 0.01D, (double) (-f6), 1.0D, new int[0]); ++ worldserver.a(EnumParticle.WATER_WAKE, d8, d11, d12, 0, (double) (-f7), 0.01D, (double) f6, 1.0D, new int[0]); + } + } else if (this.au > 0) { + this.au -= k; +@@ -304,12 +311,12 @@ + } + + if (this.random.nextFloat() < f3) { +- f5 = MathHelper.a(this.random, 0.0F, 360.0F) * 0.017453292F; +- f4 = MathHelper.a(this.random, 25.0F, 60.0F); +- d8 = this.locX + (double) (MathHelper.sin(f5) * f4 * 0.1F); +- d12 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F); +- d11 = this.locZ + (double) (MathHelper.cos(f5) * f4 * 0.1F); +- worldserver.a(EnumParticle.WATER_SPLASH, d8, d12, d11, 2 + this.random.nextInt(2), 0.10000000149011612D, 0.0D, 0.10000000149011612D, 0.0D, new int[0]); ++ f4 = MathHelper.a(this.random, 0.0F, 360.0F) * 0.017453292F; ++ f5 = MathHelper.a(this.random, 25.0F, 60.0F); ++ d8 = this.locX + (double) (MathHelper.sin(f4) * f5 * 0.1F); ++ d11 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F); ++ d12 = this.locZ + (double) (MathHelper.cos(f4) * f5 * 0.1F); ++ worldserver.a(EnumParticle.WATER_SPLASH, d8, d11, d12, 2 + this.random.nextInt(2), 0.10000000149011612D, 0.0D, 0.10000000149011612D, 0.0D, new int[0]); + } + + if (this.au <= 0) { +@@ -374,6 +381,15 @@ + byte b0 = 0; + + if (this.hooked != null) { ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), this.hooked.getBukkitEntity(), (Fish) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY); ++ this.world.getServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end ++ + double d0 = this.owner.locX - this.locX; + double d1 = this.owner.locY - this.locY; + double d2 = this.owner.locZ - this.locZ; +@@ -386,6 +402,16 @@ + b0 = 3; + } else if (this.at > 0) { + EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY, this.locZ, this.m()); ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), entityitem.getBukkitEntity(), (Fish) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); ++ playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); ++ this.world.getServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end ++ + double d5 = this.owner.locX - this.locX; + double d6 = this.owner.locY - this.locY; + double d7 = this.owner.locZ - this.locZ; +@@ -396,13 +422,32 @@ + entityitem.motY = d6 * d9 + (double) MathHelper.sqrt(d8) * 0.08D; + entityitem.motZ = d7 * d9; + this.world.addEntity(entityitem); +- this.owner.world.addEntity(new EntityExperienceOrb(this.owner.world, this.owner.locX, this.owner.locY + 0.5D, this.owner.locZ + 0.5D, this.random.nextInt(6) + 1)); ++ // CraftBukkit - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() ++ this.owner.world.addEntity(new EntityExperienceOrb(this.owner.world, this.owner.locX, this.owner.locY + 0.5D, this.owner.locZ + 0.5D, playerFishEvent.getExpToDrop())); + b0 = 1; + } + + if (this.aq) { ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.IN_GROUND); ++ this.world.getServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end + b0 = 2; + } ++ ++ // CraftBukkit start ++ if (b0 == 0) { ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT); ++ this.world.getServer().getPluginManager().callEvent(playerFishEvent); ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ } ++ // CraftBukkit end + + this.die(); + this.owner.hookedFish = null; diff --git a/paper-server/nms-patches/EntityHanging.patch b/paper-server/nms-patches/EntityHanging.patch new file mode 100644 index 0000000000..d65c6dd9bc --- /dev/null +++ b/paper-server/nms-patches/EntityHanging.patch @@ -0,0 +1,111 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityHanging.java 2014-11-27 08:59:46.681421935 +1100 ++++ src/main/java/net/minecraft/server/EntityHanging.java 2014-11-27 08:42:10.168850880 +1100 +@@ -4,6 +4,13 @@ + import java.util.List; + import org.apache.commons.lang3.Validate; + ++// CraftBukkit start ++import org.bukkit.entity.Hanging; ++import org.bukkit.entity.Painting; ++import org.bukkit.event.hanging.HangingBreakEvent; ++import org.bukkit.event.painting.PaintingBreakEvent; ++// CraftBukkit end ++ + public abstract class EntityHanging extends Entity { + + private int c; +@@ -77,6 +84,33 @@ + if (this.c++ == 100 && !this.world.isStatic) { + this.c = 0; + if (!this.dead && !this.survives()) { ++ // CraftBukkit start - fire break events ++ Material material = this.world.getType(new BlockPosition(this)).getBlock().getMaterial(); ++ HangingBreakEvent.RemoveCause cause; ++ ++ if (!material.equals(Material.AIR)) { ++ // TODO: This feels insufficient to catch 100% of suffocation cases ++ cause = HangingBreakEvent.RemoveCause.OBSTRUCTION; ++ } else { ++ cause = HangingBreakEvent.RemoveCause.PHYSICS; ++ } ++ ++ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), cause); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ PaintingBreakEvent paintingEvent = null; ++ if (this instanceof EntityPainting) { ++ // Fire old painting event until it can be removed ++ paintingEvent = new PaintingBreakEvent((Painting) this.getBukkitEntity(), PaintingBreakEvent.RemoveCause.valueOf(cause.name())); ++ paintingEvent.setCancelled(event.isCancelled()); ++ this.world.getServer().getPluginManager().callEvent(paintingEvent); ++ } ++ ++ if (dead || event.isCancelled() || (paintingEvent != null && paintingEvent.isCancelled())) { ++ return; ++ } ++ // CraftBukkit end ++ + this.die(); + this.b((Entity) null); + } +@@ -138,6 +172,32 @@ + return false; + } else { + if (!this.dead && !this.world.isStatic) { ++ // CraftBukkit start - fire break events ++ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), HangingBreakEvent.RemoveCause.DEFAULT); ++ PaintingBreakEvent paintingEvent = null; ++ if (damagesource.getEntity() != null) { ++ event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damagesource.getEntity() == null ? null : damagesource.getEntity().getBukkitEntity()); ++ ++ if (this instanceof EntityPainting) { ++ // Fire old painting event until it can be removed ++ paintingEvent = new org.bukkit.event.painting.PaintingBreakByEntityEvent((Painting) this.getBukkitEntity(), damagesource.getEntity() == null ? null : damagesource.getEntity().getBukkitEntity()); ++ } ++ } else if (damagesource.isExplosion()) { ++ event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), HangingBreakEvent.RemoveCause.EXPLOSION); ++ } ++ ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (paintingEvent != null) { ++ paintingEvent.setCancelled(event.isCancelled()); ++ this.world.getServer().getPluginManager().callEvent(paintingEvent); ++ } ++ ++ if (this.dead || event.isCancelled() || (paintingEvent != null && paintingEvent.isCancelled())) { ++ return true; ++ } ++ // CraftBukkit end ++ + this.die(); + this.ac(); + this.b(damagesource.getEntity()); +@@ -149,6 +209,18 @@ + + public void move(double d0, double d1, double d2) { + if (!this.world.isStatic && !this.dead && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { ++ if (this.dead) return; // CraftBukkit ++ ++ // CraftBukkit start - fire break events ++ // TODO - Does this need its own cause? Seems to only be triggered by pistons ++ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), HangingBreakEvent.RemoveCause.PHYSICS); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (this.dead || event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ + this.die(); + this.b((Entity) null); + } +@@ -156,7 +228,7 @@ + } + + public void g(double d0, double d1, double d2) { +- if (!this.world.isStatic && !this.dead && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { ++ if (false && !this.world.isStatic && !this.dead && d0 * d0 + d1 * d1 + d2 * d2 > 0.0D) { // CraftBukkit - not needed + this.die(); + this.b((Entity) null); + } diff --git a/paper-server/nms-patches/EntityHorse.patch b/paper-server/nms-patches/EntityHorse.patch new file mode 100644 index 0000000000..f4ff42d080 --- /dev/null +++ b/paper-server/nms-patches/EntityHorse.patch @@ -0,0 +1,140 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityHorse.java 2014-11-27 08:59:46.681421935 +1100 ++++ src/main/java/net/minecraft/server/EntityHorse.java 2014-11-27 08:42:10.148850918 +1100 +@@ -4,6 +4,8 @@ + import java.util.Iterator; + import java.util.List; + ++import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; // CraftBukkit ++ + public class EntityHorse extends EntityAnimal implements IInventoryListener { + + private static final Predicate bq = new EntitySelectorHorse(); +@@ -36,6 +38,7 @@ + private String bM; + private String[] bN = new String[3]; + private boolean bO = false; ++ public int maxDomestication = 100; // CraftBukkit - store max domestication value + + public EntityHorse(World world) { + super(world); +@@ -314,13 +317,13 @@ + private int cX() { + int i = this.getType(); + +- return this.hasChest() && (i == 1 || i == 2) ? 17 : 2; ++ return this.hasChest() /* && (i == 1 || i == 2) */ ? 17 : 2; // CraftBukkit - Remove type check + } + + public void loadChest() { + InventoryHorseChest inventoryhorsechest = this.inventoryChest; + +- this.inventoryChest = new InventoryHorseChest("HorseChest", this.cX()); ++ this.inventoryChest = new InventoryHorseChest("HorseChest", this.cX(), this); // CraftBukkit - add this horse + this.inventoryChest.a(this.getName()); + if (inventoryhorsechest != null) { + inventoryhorsechest.b(this); +@@ -485,7 +488,7 @@ + } + + public int getMaxDomestication() { +- return 100; ++ return this.maxDomestication; // CraftBukkit - return stored max domestication instead of 100 + } + + protected float bA() { +@@ -585,7 +588,7 @@ + } + + if (this.getHealth() < this.getMaxHealth() && f > 0.0F) { +- this.heal(f); ++ this.heal(f, RegainReason.EATING); // CraftBukkit + flag = true; + } + +@@ -692,11 +695,24 @@ + + public void die(DamageSource damagesource) { + super.die(damagesource); ++ /* CraftBukkit start - Handle chest dropping in dropDeathLoot below + if (!this.world.isStatic) { + this.dropChest(); + } ++ // CraftBukkit end */ ++ } + ++ // CraftBukkit start - Add method ++ @Override ++ protected void dropDeathLoot(boolean flag, int i) { ++ super.dropDeathLoot(flag, i); ++ ++ // Moved from die method above ++ if (!this.world.isStatic) { ++ this.dropChest(); ++ } + } ++ // CraftBukkit end + + public void m() { + if (this.random.nextInt(200) == 0) { +@@ -706,7 +722,7 @@ + super.m(); + if (!this.world.isStatic) { + if (this.random.nextInt(900) == 0 && this.deathTicks == 0) { +- this.heal(1.0F); ++ this.heal(1.0F, RegainReason.REGEN); // CraftBukkit + } + + if (!this.cw() && this.passenger == null && this.random.nextInt(300) == 0 && this.world.getType(new BlockPosition(MathHelper.floor(this.locX), MathHelper.floor(this.locY) - 1, MathHelper.floor(this.locZ))).getBlock() == Blocks.GRASS) { +@@ -949,6 +965,7 @@ + nbttagcompound.setInt("Temper", this.getTemper()); + nbttagcompound.setBoolean("Tame", this.isTame()); + nbttagcompound.setString("OwnerUUID", this.getOwnerUUID()); ++ nbttagcompound.setInt("Bukkit.MaxDomestication", this.maxDomestication); // CraftBukkit + if (this.hasChest()) { + NBTTagList nbttaglist = new NBTTagList(); + +@@ -1001,6 +1018,12 @@ + this.setOwnerUUID(s); + } + ++ // CraftBukkit start ++ if (nbttagcompound.hasKey("Bukkit.MaxDomestication")) { ++ this.maxDomestication = nbttagcompound.getInt("Bukkit.MaxDomestication"); ++ } ++ // CraftBukkit end ++ + AttributeInstance attributeinstance = this.getAttributeMap().a("Speed"); + + if (attributeinstance != null) { +@@ -1166,18 +1189,25 @@ + + public void v(int i) { + if (this.cE()) { ++ // CraftBukkit start - fire HorseJumpEvent, use event power + if (i < 0) { + i = 0; +- } else { +- this.bE = true; +- this.df(); + } +- ++ ++ float power; + if (i >= 90) { +- this.bp = 1.0F; ++ power = 1.0F; + } else { +- this.bp = 0.4F + 0.4F * (float) i / 90.0F; ++ power = 0.4F + 0.4F * (float) i / 90.0F; ++ } ++ ++ org.bukkit.event.entity.HorseJumpEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callHorseJumpEvent(this, power); ++ if (!event.isCancelled()) { ++ this.bE = true; ++ this.df(); ++ this.bp = power; + } ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/EntityHuman.patch b/paper-server/nms-patches/EntityHuman.patch new file mode 100644 index 0000000000..185b52b4bf --- /dev/null +++ b/paper-server/nms-patches/EntityHuman.patch @@ -0,0 +1,383 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityHuman.java 2014-11-27 08:59:46.685421917 +1100 ++++ src/main/java/net/minecraft/server/EntityHuman.java 2014-11-27 08:42:10.120850973 +1100 +@@ -8,13 +8,25 @@ + import java.util.List; + import java.util.UUID; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.craftbukkit.entity.CraftItem; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.entity.Player; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.player.PlayerBedEnterEvent; ++import org.bukkit.event.player.PlayerBedLeaveEvent; ++import org.bukkit.event.player.PlayerDropItemEvent; ++import org.bukkit.event.player.PlayerItemConsumeEvent; ++// CraftBukkit end ++ + public abstract class EntityHuman extends EntityLiving { + + public PlayerInventory inventory = new PlayerInventory(this); + private InventoryEnderChest enderChest = new InventoryEnderChest(); + public Container defaultContainer; + public Container activeContainer; +- protected FoodMetaData foodData = new FoodMetaData(); ++ protected FoodMetaData foodData = new FoodMetaData(this); // CraftBukkit - add "this" to constructor + protected int bk; + public float bl; + public float bm; +@@ -34,6 +46,7 @@ + private boolean d; + private BlockPosition e; + public PlayerAbilities abilities = new PlayerAbilities(); ++ public int oldLevel = -1; // CraftBukkit - add field + public int expLevel; + public int expTotal; + public float exp; +@@ -46,6 +59,16 @@ + private final GameProfile bF; + private boolean bG = false; + public EntityFishingHook hookedFish; ++ ++ // CraftBukkit start ++ public boolean fauxSleeping; ++ public String spawnWorld = ""; ++ ++ @Override ++ public CraftHumanEntity getBukkitEntity() { ++ return (CraftHumanEntity) super.getBukkitEntity(); ++ } ++ // CraftBukkit end + + public EntityHuman(World world, GameProfile gameprofile) { + super(world); +@@ -265,6 +288,32 @@ + if (this.g != null) { + this.b(this.g, 16); + int i = this.g.count; ++ ++ // CraftBukkit start - fire PlayerItemConsumeEvent ++ org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.g); ++ PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ // Update client ++ if (this instanceof EntityPlayer) { ++ ((EntityPlayer) this).playerConnection.sendPacket(new PacketPlayOutSetSlot((byte) 0, activeContainer.getSlot((IInventory) this.inventory, this.inventory.itemInHandIndex).index, this.g)); ++ } ++ return; ++ } ++ ++ // Plugin modified the item, process it but don't remove it ++ if (!craftItem.equals(event.getItem())) { ++ CraftItemStack.asNMSCopy(event.getItem()).b(this.world, this); ++ ++ // Update client ++ if (this instanceof EntityPlayer) { ++ ((EntityPlayer) this).playerConnection.sendPacket(new PacketPlayOutSetSlot((byte) 0, activeContainer.getSlot((IInventory) this.inventory, this.inventory.itemInHandIndex).index, this.g)); ++ } ++ return; ++ } ++ // CraftBukkit end ++ + ItemStack itemstack = this.g.b(this.world, this); + + if (itemstack != this.g || itemstack != null && itemstack.count != i) { +@@ -324,7 +373,8 @@ + + if (this.world.getDifficulty() == EnumDifficulty.PEACEFUL && this.world.getGameRules().getBoolean("naturalRegeneration")) { + if (this.getHealth() < this.getMaxHealth() && this.ticksLived % 20 == 0) { +- this.heal(1.0F); ++ // CraftBukkit - added regain reason of "REGEN" for filtering purposes. ++ this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); + } + + if (this.foodData.c() && this.ticksLived % 10 == 0) { +@@ -348,7 +398,7 @@ + + this.j((float) attributeinstance.getValue()); + float f = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ); +- float f1 = (float) (Math.atan(-this.motY * 0.20000000298023224D) * 15.0D); ++ float f1 = (float) ( org.bukkit.craftbukkit.TrigMath.atan(-this.motY * 0.20000000298023224D) * 15.0D); // CraftBukkit + + if (f > 0.1F) { + f = 0.1F; +@@ -438,11 +488,14 @@ + + public void b(Entity entity, int i) { + this.addScore(i); +- Collection collection = this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.f); ++ // CraftBukkit - Get our scores instead ++ Collection collection = this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.e, this.getName(), new java.util.ArrayList()); ++ + + if (entity instanceof EntityHuman) { + this.b(StatisticList.B); +- collection.addAll(this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.e)); ++ // CraftBukkit - Get our scores instead ++ this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.d, this.getName(), collection); + collection.addAll(this.e(entity)); + } else { + this.b(StatisticList.z); +@@ -451,8 +504,7 @@ + Iterator iterator = collection.iterator(); + + while (iterator.hasNext()) { +- ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next(); +- ScoreboardScore scoreboardscore = this.getScoreboard().getPlayerScoreForObjective(this.getName(), scoreboardobjective); ++ ScoreboardScore scoreboardscore = (ScoreboardScore) iterator.next(); // CraftBukkit - Use our scores instead + + scoreboardscore.incrementScore(); + } +@@ -491,6 +543,7 @@ + } + + public EntityItem a(boolean flag) { ++ // Called only when dropped by Q or CTRL-Q + return this.a(this.inventory.splitStack(this.inventory.itemInHandIndex, flag && this.inventory.getItemInHand() != null ? this.inventory.getItemInHand().count : 1), false, true); + } + +@@ -532,6 +585,30 @@ + entityitem.motY += (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F); + entityitem.motZ += Math.sin((double) f1) * (double) f; + } ++ ++ // CraftBukkit start - fire PlayerDropItemEvent ++ Player player = (Player) this.getBukkitEntity(); ++ CraftItem drop = new CraftItem(this.world.getServer(), entityitem); ++ ++ PlayerDropItemEvent event = new PlayerDropItemEvent(player, drop); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ org.bukkit.inventory.ItemStack cur = player.getInventory().getItemInHand(); ++ if (flag1 && (cur == null || cur.getAmount() == 0)) { ++ // The complete stack was dropped ++ player.getInventory().setItemInHand(drop.getItemStack()); ++ } else if (flag1 && cur.isSimilar(drop.getItemStack()) && drop.getItemStack().getAmount() == 1) { ++ // Only one item is dropped ++ cur.setAmount(cur.getAmount() + 1); ++ player.getInventory().setItemInHand(cur); ++ } else { ++ // Fallback ++ player.getInventory().addItem(drop.getItemStack()); ++ } ++ return null; ++ } ++ // CraftBukkit end + + this.a(entityitem); + if (flag1) { +@@ -623,10 +700,18 @@ + this.bv = new BlockPosition(this); + this.a(true, true, false); + } ++ ++ // CraftBukkit start ++ this.spawnWorld = nbttagcompound.getString("SpawnWorld"); ++ if ("".equals(spawnWorld)) { ++ this.spawnWorld = this.world.getServer().getWorlds().get(0).getName(); ++ } ++ // CraftBukkit end + + if (nbttagcompound.hasKeyOfType("SpawnX", 99) && nbttagcompound.hasKeyOfType("SpawnY", 99) && nbttagcompound.hasKeyOfType("SpawnZ", 99)) { + this.c = new BlockPosition(nbttagcompound.getInt("SpawnX"), nbttagcompound.getInt("SpawnY"), nbttagcompound.getInt("SpawnZ")); + this.d = nbttagcompound.getBoolean("SpawnForced"); ++ nbttagcompound.setString("SpawnWorld", spawnWorld); // CraftBukkit - fixes bed spawns for multiworld worlds + } + + this.foodData.a(nbttagcompound); +@@ -684,7 +769,7 @@ + + if (damagesource.r()) { + if (this.world.getDifficulty() == EnumDifficulty.PEACEFUL) { +- f = 0.0F; ++ return false; // CraftBukkit - f = 0.0f -> return false + } + + if (this.world.getDifficulty() == EnumDifficulty.EASY) { +@@ -696,7 +781,7 @@ + } + } + +- if (f == 0.0F) { ++ if (false && f == 0.0F) { // CraftBukkit - Don't filter out 0 damage + return false; + } else { + Entity entity = damagesource.getEntity(); +@@ -712,10 +797,29 @@ + } + + public boolean a(EntityHuman entityhuman) { +- ScoreboardTeamBase scoreboardteambase = this.getScoreboardTeam(); +- ScoreboardTeamBase scoreboardteambase1 = entityhuman.getScoreboardTeam(); ++ // CraftBukkit start - Change to check OTHER player's scoreboard team according to API ++ // To summarize this method's logic, it's "Can parameter hurt this" ++ org.bukkit.scoreboard.Team team; ++ if (entityhuman instanceof EntityPlayer) { ++ EntityPlayer thatPlayer = (EntityPlayer) entityhuman; ++ team = thatPlayer.getBukkitEntity().getScoreboard().getPlayerTeam(thatPlayer.getBukkitEntity()); ++ if (team == null || team.allowFriendlyFire()) { ++ return true; ++ } ++ } else { ++ // This should never be called, but is implemented anyway ++ org.bukkit.OfflinePlayer thisPlayer = entityhuman.world.getServer().getOfflinePlayer(entityhuman.getName()); ++ team = entityhuman.world.getServer().getScoreboardManager().getMainScoreboard().getPlayerTeam(thisPlayer); ++ if (team == null || team.allowFriendlyFire()) { ++ return true; ++ } ++ } + +- return scoreboardteambase == null ? true : (!scoreboardteambase.isAlly(scoreboardteambase1) ? true : scoreboardteambase.allowFriendlyFire()); ++ if (this instanceof EntityPlayer) { ++ return !team.hasPlayer(((EntityPlayer) this).getBukkitEntity()); ++ } ++ return !team.hasPlayer(this.world.getServer().getOfflinePlayer(this.getName())); ++ // CraftBukkit end + } + + protected void damageArmor(float f) { +@@ -742,7 +846,12 @@ + return (float) i / (float) this.inventory.armor.length; + } + +- protected void d(DamageSource damagesource, float f) { ++ // CraftBukkit start ++ protected boolean d(DamageSource damagesource, float f) { // void -> boolean ++ if (true) { ++ return super.d(damagesource, f); ++ } ++ // CraftBukkit end + if (!this.isInvulnerable(damagesource)) { + if (!damagesource.ignoresArmor() && this.isBlocking() && f > 0.0F) { + f = (1.0F + f) * 0.5F; +@@ -766,6 +875,7 @@ + + } + } ++ return false; // CraftBukkit + } + + public void openSign(TileEntitySign tileentitysign) {} +@@ -800,7 +910,8 @@ + } + + if (itemstack.a(this, (EntityLiving) entity)) { +- if (itemstack.count <= 0 && !this.abilities.canInstantlyBuild) { ++ // CraftBukkit - bypass infinite items; <= 0 -> == 0 ++ if (itemstack.count == 0 && !this.abilities.canInstantlyBuild) { + this.bZ(); + } + +@@ -866,8 +977,15 @@ + int j = EnchantmentManager.getFireAspectEnchantmentLevel(this); + + if (entity instanceof EntityLiving && j > 0 && !entity.isBurning()) { +- flag1 = true; +- entity.setOnFire(1); ++ // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 1); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ ++ if (!combustEvent.isCancelled()) { ++ flag1 = true; ++ entity.setOnFire(combustEvent.getDuration()); ++ } ++ // CraftBukkit end + } + + double d0 = entity.motX; +@@ -922,7 +1040,8 @@ + + if (itemstack != null && object instanceof EntityLiving) { + itemstack.a((EntityLiving) object, this); +- if (itemstack.count <= 0) { ++ // CraftBukkit - bypass infinite items; <= 0 -> == 0 ++ if (itemstack.count == 0) { + this.bZ(); + } + } +@@ -930,7 +1049,14 @@ + if (entity instanceof EntityLiving) { + this.a(StatisticList.w, Math.round(f * 10.0F)); + if (j > 0) { +- entity.setOnFire(j * 4); ++ // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), j * 4); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ ++ if (!combustEvent.isCancelled()) { ++ entity.setOnFire(combustEvent.getDuration()); ++ } ++ // CraftBukkit end + } + } + +@@ -995,6 +1121,20 @@ + if (this.av()) { + this.mount((Entity) null); + } ++ ++ // CraftBukkit start - fire PlayerBedEnterEvent ++ if (this.getBukkitEntity() instanceof Player) { ++ Player player = (Player) this.getBukkitEntity(); ++ org.bukkit.block.Block bed = this.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ PlayerBedEnterEvent event = new PlayerBedEnterEvent(player, bed); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return EnumBedResult.OTHER_PROBLEM; ++ } ++ } ++ // CraftBukkit end + + this.a(0.2F, 0.2F); + if (this.world.isLoaded(blockposition)) { +@@ -1077,6 +1217,23 @@ + if (!this.world.isStatic && flag1) { + this.world.everyoneSleeping(); + } ++ ++ // CraftBukkit start - fire PlayerBedLeaveEvent ++ if (this.getBukkitEntity() instanceof Player) { ++ Player player = (Player) this.getBukkitEntity(); ++ ++ org.bukkit.block.Block bed; ++ BlockPosition blockposition = this.bv; ++ if (blockposition != null) { ++ bed = this.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ } else { ++ bed = this.world.getWorld().getBlockAt(player.getLocation()); ++ } ++ ++ PlayerBedLeaveEvent event = new PlayerBedLeaveEvent(player, bed); ++ this.world.getServer().getPluginManager().callEvent(event); ++ } ++ // CraftBukkit end + + this.sleepTicks = flag ? 0 : 100; + if (flag2) { +@@ -1128,9 +1285,11 @@ + if (blockposition != null) { + this.c = blockposition; + this.d = flag; ++ this.spawnWorld = this.world.worldData.getName(); // CraftBukkit + } else { + this.c = null; + this.d = false; ++ this.spawnWorld = ""; // CraftBukkit + } + + } +@@ -1477,6 +1636,7 @@ + } + + public IChatBaseComponent getScoreboardDisplayName() { ++ // CraftBukkit - todo: fun + ChatComponentText chatcomponenttext = new ChatComponentText(ScoreboardTeam.getPlayerDisplayName(this.getScoreboardTeam(), this.getName())); + + chatcomponenttext.getChatModifier().setChatClickable(new ChatClickable(EnumClickAction.SUGGEST_COMMAND, "/msg " + this.getName() + " ")); diff --git a/paper-server/nms-patches/EntityInsentient.patch b/paper-server/nms-patches/EntityInsentient.patch new file mode 100644 index 0000000000..17867b8da3 --- /dev/null +++ b/paper-server/nms-patches/EntityInsentient.patch @@ -0,0 +1,164 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityInsentient.java 2014-11-27 08:59:46.689421900 +1100 ++++ src/main/java/net/minecraft/server/EntityInsentient.java 2014-11-27 08:42:10.156850903 +1100 +@@ -4,6 +4,15 @@ + import java.util.List; + import java.util.UUID; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.entity.CraftLivingEntity; ++import org.bukkit.event.entity.EntityTargetLivingEntityEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.event.entity.EntityUnleashEvent; ++import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason; ++// CraftBukkit end ++ + public abstract class EntityInsentient extends EntityLiving { + + public int a_; +@@ -39,7 +48,9 @@ + for (int i = 0; i < this.dropChances.length; ++i) { + this.dropChances[i] = 0.085F; + } +- ++ // CraftBukkit start - default persistance to type's persistance value ++ this.persistent = !isTypeNotPersistent(); ++ // CraftBukkit end + } + + protected void aW() { +@@ -76,7 +87,37 @@ + } + + public void setGoalTarget(EntityLiving entityliving) { ++ // CraftBukkit start - fire event ++ setGoalTarget(entityliving, EntityTargetEvent.TargetReason.UNKNOWN, true); ++ } ++ ++ public void setGoalTarget(EntityLiving entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) { ++ if (getGoalTarget() == entityliving) return; ++ if (fireEvent) { ++ if (reason == EntityTargetEvent.TargetReason.UNKNOWN && getGoalTarget() != null && entityliving == null) { ++ reason = getGoalTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED; ++ } ++ if (reason == EntityTargetEvent.TargetReason.UNKNOWN) { ++ world.getServer().getLogger().log(java.util.logging.Level.WARNING, "Unknown target reason, please report on the issue tracker", new Exception()); ++ } ++ CraftLivingEntity ctarget = null; ++ if (entityliving != null) { ++ ctarget = (CraftLivingEntity) entityliving.getBukkitEntity(); ++ } ++ EntityTargetLivingEntityEvent event = new EntityTargetLivingEntityEvent(this.getBukkitEntity(), ctarget, reason); ++ world.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ if (event.getTarget() != null) { ++ entityliving = ((CraftLivingEntity) event.getTarget()).getHandle(); ++ } else { ++ entityliving = null; ++ } ++ } + this.goalTarget = entityliving; ++ // CraftBukkit end + } + + public boolean a(Class oclass) { +@@ -235,11 +276,21 @@ + + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); ++ ++ // CraftBukkit start - If looting or persistence is false only use it if it was set after we started using it + if (nbttagcompound.hasKeyOfType("CanPickUpLoot", 1)) { +- this.j(nbttagcompound.getBoolean("CanPickUpLoot")); ++ boolean data = nbttagcompound.getBoolean("CanPickUpLoot"); ++ if (isLevelAtLeast(nbttagcompound, 1) || data) { ++ this.j(data); ++ } + } + +- this.persistent = nbttagcompound.getBoolean("PersistenceRequired"); ++ boolean data = nbttagcompound.getBoolean("PersistenceRequired"); ++ if (isLevelAtLeast(nbttagcompound, 1) || data) { ++ this.persistent = data; ++ } ++ // CraftBukkit end ++ + NBTTagList nbttaglist; + int i; + +@@ -380,11 +431,11 @@ + double d2 = entityhuman.locZ - this.locZ; + double d3 = d0 * d0 + d1 * d1 + d2 * d2; + +- if (this.isTypeNotPersistent() && d3 > 16384.0D) { ++ if (d3 > 16384.0D) { // CraftBukkit - remove isTypeNotPersistent() check + this.die(); + } + +- if (this.aO > 600 && this.random.nextInt(800) == 0 && d3 > 1024.0D && this.isTypeNotPersistent()) { ++ if (this.aO > 600 && this.random.nextInt(800) == 0 && d3 > 1024.0D) { // CraftBukkit - remove isTypeNotPersistent() check + this.die(); + } else if (d3 < 1024.0D) { + this.aO = 0; +@@ -707,6 +758,12 @@ + + public final boolean e(EntityHuman entityhuman) { + if (this.cb() && this.getLeashHolder() == entityhuman) { ++ // CraftBukkit start - fire PlayerUnleashEntityEvent ++ if (CraftEventFactory.callPlayerUnleashEntityEvent(this, entityhuman).isCancelled()) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutAttachEntity(1, this, this.getLeashHolder())); ++ return false; ++ } ++ // CraftBukkit end + this.unleash(true, !entityhuman.abilities.canInstantlyBuild); + return true; + } else { +@@ -714,12 +771,24 @@ + + if (itemstack != null && itemstack.getItem() == Items.LEAD && this.ca()) { + if (!(this instanceof EntityTameableAnimal) || !((EntityTameableAnimal) this).isTamed()) { ++ // CraftBukkit start - fire PlayerLeashEntityEvent ++ if (CraftEventFactory.callPlayerLeashEntityEvent(this, entityhuman, entityhuman).isCancelled()) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutAttachEntity(1, this, this.getLeashHolder())); ++ return false; ++ } ++ // CraftBukkit end + this.setLeashHolder(entityhuman, true); + --itemstack.count; + return true; + } + + if (((EntityTameableAnimal) this).e((EntityLiving) entityhuman)) { ++ // CraftBukkit start - fire PlayerLeashEntityEvent ++ if (CraftEventFactory.callPlayerLeashEntityEvent(this, entityhuman, entityhuman).isCancelled()) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutAttachEntity(1, this, this.getLeashHolder())); ++ return false; ++ } ++ // CraftBukkit end + this.setLeashHolder(entityhuman, true); + --itemstack.count; + return true; +@@ -741,10 +810,12 @@ + + if (this.bm) { + if (!this.isAlive()) { ++ this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.PLAYER_UNLEASH)); // CraftBukkit + this.unleash(true, true); + } + + if (this.bn == null || this.bn.dead) { ++ this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.HOLDER_GONE)); // CraftBukkit + this.unleash(true, true); + } + } +@@ -811,6 +882,7 @@ + + this.bn = entityleash; + } else { ++ this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit + this.unleash(false, true); + } + } diff --git a/paper-server/nms-patches/EntityIronGolem.patch b/paper-server/nms-patches/EntityIronGolem.patch new file mode 100644 index 0000000000..e71334e17f --- /dev/null +++ b/paper-server/nms-patches/EntityIronGolem.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityIronGolem.java 2014-11-27 08:59:46.689421900 +1100 ++++ src/main/java/net/minecraft/server/EntityIronGolem.java 2014-11-27 08:42:10.100851012 +1100 +@@ -57,7 +57,7 @@ + + protected void s(Entity entity) { + if (entity instanceof IMonster && this.bb().nextInt(20) == 0) { +- this.setGoalTarget((EntityLiving) entity); ++ this.setGoalTarget((EntityLiving) entity, org.bukkit.event.entity.EntityTargetLivingEntityEvent.TargetReason.COLLISION, true); // CraftBukkit - set reason + } + + super.s(entity); diff --git a/paper-server/nms-patches/EntityItem.patch b/paper-server/nms-patches/EntityItem.patch new file mode 100644 index 0000000000..0873e363cb --- /dev/null +++ b/paper-server/nms-patches/EntityItem.patch @@ -0,0 +1,115 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityItem.java 2014-11-27 08:59:46.693421882 +1100 ++++ src/main/java/net/minecraft/server/EntityItem.java 2014-11-27 08:42:10.104851005 +1100 +@@ -4,6 +4,8 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++import org.bukkit.event.player.PlayerPickupItemEvent; // CraftBukkit ++ + public class EntityItem extends Entity { + + private static final Logger b = LogManager.getLogger(); +@@ -13,6 +15,7 @@ + private String f; + private String g; + public float a; ++ private int lastTick = MinecraftServer.currentTick; // CraftBukkit + + public EntityItem(World world, double d0, double d1, double d2) { + super(world); +@@ -28,6 +31,11 @@ + + public EntityItem(World world, double d0, double d1, double d2, ItemStack itemstack) { + this(world, d0, d1, d2); ++ // CraftBukkit start - Can't set null items in the datawatcher ++ if (itemstack == null || itemstack.getItem() == null) { ++ return; ++ } ++ // CraftBukkit end + this.setItemStack(itemstack); + } + +@@ -52,9 +60,12 @@ + this.die(); + } else { + super.s_(); +- if (this.pickupDelay > 0 && this.pickupDelay != 32767) { +- --this.pickupDelay; +- } ++ // CraftBukkit start - Use wall time for pickup and despawn timers ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ this.pickupDelay -= elapsedTicks; ++ this.age += elapsedTicks; ++ this.lastTick = MinecraftServer.currentTick; ++ // CraftBukkit end + + this.lastX = this.locX; + this.lastY = this.locY; +@@ -90,12 +101,20 @@ + this.motY *= -0.5D; + } + ++ /* Craftbukkit start - moved up + if (this.age != -32768) { + ++this.age; + } ++ // Craftbukkit end */ + + this.W(); + if (!this.world.isStatic && this.age >= 6000) { ++ // CraftBukkit start - fire ItemDespawnEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callItemDespawnEvent(this).isCancelled()) { ++ this.age = 0; ++ return; ++ } ++ // CraftBukkit end + this.die(); + } + +@@ -228,7 +247,18 @@ + + NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Item"); + +- this.setItemStack(ItemStack.createStack(nbttagcompound1)); ++ // CraftBukkit start - Handle missing "Item" compounds ++ if (nbttagcompound1 != null) { ++ ItemStack itemstack = ItemStack.createStack(nbttagcompound1); ++ if (itemstack != null) { ++ this.setItemStack(itemstack); ++ } else { ++ this.die(); ++ } ++ } else { ++ this.die(); ++ } ++ // CraftBukkit end + if (this.getItemStack() == null) { + this.die(); + } +@@ -239,6 +269,26 @@ + if (!this.world.isStatic) { + ItemStack itemstack = this.getItemStack(); + int i = itemstack.count; ++ ++ // CraftBukkit start - fire PlayerPickupItemEvent ++ int canHold = entityhuman.inventory.canHold(itemstack); ++ int remaining = itemstack.count - canHold; ++ ++ if (this.pickupDelay <= 0 && canHold > 0) { ++ itemstack.count = canHold; ++ PlayerPickupItemEvent event = new PlayerPickupItemEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); ++ // event.setCancelled(!entityhuman.canPickUpLoot); TODO ++ this.world.getServer().getPluginManager().callEvent(event); ++ itemstack.count = canHold + remaining; ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ // Possibly < 0; fix here so we do not have to modify code below ++ this.pickupDelay = 0; ++ } ++ // CraftBukkit end + + if (this.pickupDelay == 0 && (this.g == null || 6000 - this.age <= 200 || this.g.equals(entityhuman.getName())) && entityhuman.inventory.pickup(itemstack)) { + if (itemstack.getItem() == Item.getItemOf(Blocks.LOG)) { diff --git a/paper-server/nms-patches/EntityItemFrame.patch b/paper-server/nms-patches/EntityItemFrame.patch new file mode 100644 index 0000000000..1ae52fd27a --- /dev/null +++ b/paper-server/nms-patches/EntityItemFrame.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityItemFrame.java 2014-11-27 08:59:46.693421882 +1100 ++++ src/main/java/net/minecraft/server/EntityItemFrame.java 2014-11-27 08:42:10.176850864 +1100 +@@ -27,6 +27,12 @@ + return false; + } else if (!damagesource.isExplosion() && this.getItem() != null) { + if (!this.world.isStatic) { ++ // CraftBukkit start - fire EntityDamageEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damagesource, f, false) || this.dead) { ++ return true; ++ } ++ // CraftBukkit end ++ + this.a(damagesource.getEntity(), false); + this.setItem((ItemStack) null); + } diff --git a/paper-server/nms-patches/EntityLargeFireball.patch b/paper-server/nms-patches/EntityLargeFireball.patch new file mode 100644 index 0000000000..2e14fc4d4e --- /dev/null +++ b/paper-server/nms-patches/EntityLargeFireball.patch @@ -0,0 +1,38 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityLargeFireball.java 2014-11-27 08:59:46.697421864 +1100 ++++ src/main/java/net/minecraft/server/EntityLargeFireball.java 2014-11-27 08:42:10.152850911 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.ExplosionPrimeEvent; // CraftBukkit ++ + public class EntityLargeFireball extends EntityFireball { + + public int yield = 1; +@@ -21,7 +23,16 @@ + + boolean flag = this.world.getGameRules().getBoolean("mobGriefing"); + +- this.world.createExplosion((Entity) null, this.locX, this.locY, this.locZ, (float) this.yield, flag, flag); ++ // CraftBukkit start - fire ExplosionPrimeEvent ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) org.bukkit.craftbukkit.entity.CraftEntity.getEntity(this.world.getServer(), this)); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ // give 'this' instead of (Entity) null so we know what causes the damage ++ this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire(), flag); ++ } ++ // CraftBukkit end ++ + this.die(); + } + +@@ -35,7 +46,8 @@ + public void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + if (nbttagcompound.hasKeyOfType("ExplosionPower", 99)) { +- this.yield = nbttagcompound.getInt("ExplosionPower"); ++ // CraftBukkit - set bukkitYield when setting explosionpower ++ bukkitYield = this.yield = nbttagcompound.getInt("ExplosionPower"); + } + + } diff --git a/paper-server/nms-patches/EntityLeash.patch b/paper-server/nms-patches/EntityLeash.patch new file mode 100644 index 0000000000..65d979ac56 --- /dev/null +++ b/paper-server/nms-patches/EntityLeash.patch @@ -0,0 +1,61 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityLeash.java 2014-11-27 08:59:46.701421847 +1100 ++++ src/main/java/net/minecraft/server/EntityLeash.java 2014-11-27 08:42:10.136850942 +1100 +@@ -3,6 +3,8 @@ + import java.util.Iterator; + import java.util.List; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class EntityLeash extends EntityHanging { + + public EntityLeash(World world) { +@@ -63,6 +65,12 @@ + while (iterator.hasNext()) { + entityinsentient = (EntityInsentient) iterator.next(); + if (entityinsentient.cb() && entityinsentient.getLeashHolder() == entityhuman) { ++ // CraftBukkit start ++ if (CraftEventFactory.callPlayerLeashEntityEvent(entityinsentient, this, entityhuman).isCancelled()) { ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutAttachEntity(1, entityinsentient, entityinsentient.getLeashHolder())); ++ continue; ++ } ++ // CraftBukkit end + entityinsentient.setLeashHolder(this, true); + flag = true; + } +@@ -70,8 +78,11 @@ + } + + if (!this.world.isStatic && !flag) { +- this.die(); +- if (entityhuman.abilities.canInstantlyBuild) { ++ // CraftBukkit start - Move below ++ // this.die(); ++ boolean die = true; ++ // CraftBukkit end ++ if (true || entityhuman.abilities.canInstantlyBuild) { // CraftBukkit - Process for non-creative as well + d0 = 7.0D; + list = this.world.a(EntityInsentient.class, new AxisAlignedBB(this.locX - d0, this.locY - d0, this.locZ - d0, this.locX + d0, this.locY + d0, this.locZ + d0)); + iterator = list.iterator(); +@@ -79,10 +90,21 @@ + while (iterator.hasNext()) { + entityinsentient = (EntityInsentient) iterator.next(); + if (entityinsentient.cb() && entityinsentient.getLeashHolder() == this) { +- entityinsentient.unleash(true, false); ++ // CraftBukkit start ++ if (CraftEventFactory.callPlayerUnleashEntityEvent(entityinsentient, entityhuman).isCancelled()) { ++ die = false; ++ continue; ++ } ++ entityinsentient.unleash(true, !entityhuman.abilities.canInstantlyBuild); // false -> survival mode boolean ++ // CraftBukkit end + } + } + } ++ // CraftBukkit start ++ if (die) { ++ this.die(); ++ } ++ // CraftBukkit end + } + + return true; diff --git a/paper-server/nms-patches/EntityLightning.patch b/paper-server/nms-patches/EntityLightning.patch new file mode 100644 index 0000000000..7e8633d295 --- /dev/null +++ b/paper-server/nms-patches/EntityLightning.patch @@ -0,0 +1,111 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityLightning.java 2014-11-27 08:59:46.701421847 +1100 ++++ src/main/java/net/minecraft/server/EntityLightning.java 2014-11-27 08:42:10.116850981 +1100 +@@ -2,30 +2,54 @@ + + import java.util.List; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class EntityLightning extends EntityWeather { + + private int lifeTicks; + public long a; + private int c; ++ ++ // CraftBukkit start ++ public boolean isEffect = false; + + public EntityLightning(World world, double d0, double d1, double d2) { ++ this(world, d0, d1, d2, false); ++ } ++ ++ public EntityLightning(World world, double d0, double d1, double d2, boolean isEffect) { ++ // CraftBukkit end ++ + super(world); ++ ++ // CraftBukkit - Set isEffect ++ this.isEffect = isEffect; ++ + this.setPositionRotation(d0, d1, d2, 0.0F, 0.0F); + this.lifeTicks = 2; + this.a = this.random.nextLong(); + this.c = this.random.nextInt(3) + 1; +- if (!world.isStatic && world.getGameRules().getBoolean("doFireTick") && (world.getDifficulty() == EnumDifficulty.NORMAL || world.getDifficulty() == EnumDifficulty.HARD) && world.areChunksLoaded(new BlockPosition(this), 10)) { ++ // CraftBukkit - add "!isEffect" ++ if (!isEffect && !world.isStatic && world.getGameRules().getBoolean("doFireTick") && (world.getDifficulty() == EnumDifficulty.NORMAL || world.getDifficulty() == EnumDifficulty.HARD) && world.areChunksLoaded(new BlockPosition(this), 10)) { + BlockPosition blockposition = new BlockPosition(this); + +- if (world.getType(blockposition).getBlock().getMaterial() == Material.AIR && Blocks.FIRE.canPlace(world, blockposition)) { +- world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ if (world.getType(blockposition).getBlock().getMaterial() == Material.AIR && Blocks.FIRE.canPlace(world, blockposition)) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this).isCancelled()) { ++ world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ } ++ // CraftBukkit end + } + + for (int i = 0; i < 4; ++i) { + BlockPosition blockposition1 = blockposition.a(this.random.nextInt(3) - 1, this.random.nextInt(3) - 1, this.random.nextInt(3) - 1); + +- if (world.getType(blockposition1).getBlock().getMaterial() == Material.AIR && Blocks.FIRE.canPlace(world, blockposition1)) { +- world.setTypeUpdate(blockposition1, Blocks.FIRE.getBlockData()); ++ if (world.getType(blockposition1).getBlock().getMaterial() == Material.AIR && Blocks.FIRE.canPlace(world, blockposition1)) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callBlockIgniteEvent(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), this).isCancelled()) { ++ world.setTypeUpdate(blockposition1, Blocks.FIRE.getBlockData()); ++ } ++ // CraftBukkit end + } + } + } +@@ -35,7 +59,24 @@ + public void s_() { + super.s_(); + if (this.lifeTicks == 2) { +- this.world.makeSound(this.locX, this.locY, this.locZ, "ambient.weather.thunder", 10000.0F, 0.8F + this.random.nextFloat() * 0.2F); ++ // CraftBukkit start - Use relative location for far away sounds ++ //this.world.makeSound(this.locX, this.locY, this.locZ, "ambient.weather.thunder", 10000.0F, 0.8F + this.random.nextFloat() * 0.2F); ++ float pitch = 0.8F + this.random.nextFloat() * 0.2F; ++ int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16; ++ for (EntityPlayer player : (List) this.world.players) { ++ double deltaX = this.locX - player.locX; ++ double deltaZ = this.locZ - player.locZ; ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.locX + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.locZ + (deltaZ / deltaLength) * viewDistance; ++ player.playerConnection.sendPacket(new PacketPlayOutNamedSoundEffect("ambient.weather.thunder", relativeX, this.locY, relativeZ, 10000.0F, pitch)); ++ } else { ++ player.playerConnection.sendPacket(new PacketPlayOutNamedSoundEffect("ambient.weather.thunder", this.locX, this.locY, this.locZ, 10000.0F, pitch)); ++ } ++ } ++ // CraftBukkit end + this.world.makeSound(this.locX, this.locY, this.locZ, "random.explode", 2.0F, 0.5F + this.random.nextFloat() * 0.2F); + } + +@@ -48,14 +89,18 @@ + this.lifeTicks = 1; + this.a = this.random.nextLong(); + BlockPosition blockposition = new BlockPosition(this); +- +- if (!this.world.isStatic && this.world.getGameRules().getBoolean("doFireTick") && this.world.areChunksLoaded(blockposition, 10) && this.world.getType(blockposition).getBlock().getMaterial() == Material.AIR && Blocks.FIRE.canPlace(this.world, blockposition)) { +- this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ // CraftBukkit - add "!isEffect" ++ if (!isEffect && !this.world.isStatic && this.world.getGameRules().getBoolean("doFireTick") && this.world.areChunksLoaded(blockposition, 10) && this.world.getType(blockposition).getBlock().getMaterial() == Material.AIR && Blocks.FIRE.canPlace(this.world, blockposition)) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this).isCancelled()) { ++ this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ } ++ // CraftBukkit end + } + } + } + +- if (this.lifeTicks >= 0) { ++ if (this.lifeTicks >= 0 && !this.isEffect) { // CraftBukkit - add !this.isEffect + if (this.world.isStatic) { + this.world.c(2); + } else { diff --git a/paper-server/nms-patches/EntityLiving.patch b/paper-server/nms-patches/EntityLiving.patch new file mode 100644 index 0000000000..880a5b3296 --- /dev/null +++ b/paper-server/nms-patches/EntityLiving.patch @@ -0,0 +1,440 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityLiving.java 2014-11-27 08:59:46.705421829 +1100 ++++ src/main/java/net/minecraft/server/EntityLiving.java 2014-11-27 08:42:10.160850895 +1100 +@@ -8,6 +8,15 @@ + import java.util.Random; + import java.util.UUID; + ++// CraftBukkit start ++import java.util.ArrayList; ++import com.google.common.base.Function; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityDamageEvent; ++import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; ++import org.bukkit.event.entity.EntityRegainHealthEvent; ++// CraftBukkit end ++ + public abstract class EntityLiving extends Entity { + + private static final UUID a = UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D"); +@@ -67,6 +76,11 @@ + private float bk; + private int bl; + private float bm; ++ // CraftBukkit start ++ public int expToDrop; ++ public int maxAirTicks = 300; ++ ArrayList drops = null; ++ // CraftBukkit end + + public void G() { + this.damageEntity(DamageSource.OUT_OF_WORLD, Float.MAX_VALUE); +@@ -75,7 +89,8 @@ + public EntityLiving(World world) { + super(world); + this.aW(); +- this.setHealth(this.getMaxHealth()); ++ // CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor ++ this.datawatcher.watch(6, (float) this.getAttributeInstance(GenericAttributes.maxHealth).getValue()); + this.k = true; + this.aF = (float) ((Math.random() + 1.0D) * 0.009999999776482582D); + this.setPosition(this.locX, this.locY, this.locZ); +@@ -116,8 +131,14 @@ + } + + int i = (int) (150.0D * d1); +- +- ((WorldServer) this.world).a(EnumParticle.BLOCK_DUST, this.locX, this.locY, this.locZ, i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D, new int[] { Block.getCombinedId(iblockdata)}); ++ ++ // CraftBukkit start - visiblity api ++ if (this instanceof EntityPlayer) { ++ ((WorldServer) this.world).sendParticles((EntityPlayer) this, EnumParticle.BLOCK_DUST, false, this.locX, this.locY, this.locZ, i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D, new int[] { Block.getCombinedId(iblockdata)}); ++ } else { ++ ((WorldServer) this.world).a(EnumParticle.BLOCK_DUST, this.locX, this.locY, this.locZ, i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D, new int[] { Block.getCombinedId(iblockdata)}); ++ } ++ // CraftBukkit end + } + } + +@@ -174,7 +195,11 @@ + this.mount((Entity) null); + } + } else { +- this.setAirTicks(300); ++ // CraftBukkit start - Only set if needed to work around a DataWatcher inefficiency ++ if (this.getAirTicks() != 300) { ++ this.setAirTicks(maxAirTicks); ++ } ++ // CraftBukkit end + } + + if (this.isAlive() && this.U()) { +@@ -220,6 +245,18 @@ + this.lastPitch = this.pitch; + this.world.methodProfiler.b(); + } ++ ++ // CraftBukkit start ++ public int getExpReward() { ++ int exp = this.getExpValue(this.killer); ++ ++ if (!this.world.isStatic && (this.lastDamageByPlayerTime > 0 || this.alwaysGivesExp()) && this.aZ() && this.world.getGameRules().getBoolean("doMobLoot")) { ++ return exp; ++ } else { ++ return 0; ++ } ++ } ++ // CraftBukkit end + + public boolean isBaby() { + return false; +@@ -227,19 +264,18 @@ + + protected void aY() { + ++this.deathTicks; +- if (this.deathTicks == 20) { ++ if (this.deathTicks >= 20 && !this.dead) { // CraftBukkit - (this.deathTicks == 20) -> (this.deathTicks >= 20 && !this.dead) + int i; + +- if (!this.world.isStatic && (this.lastDamageByPlayerTime > 0 || this.alwaysGivesExp()) && this.aZ() && this.world.getGameRules().getBoolean("doMobLoot")) { +- i = this.getExpValue(this.killer); +- +- while (i > 0) { +- int j = EntityExperienceOrb.getOrbValue(i); +- +- i -= j; +- this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j)); +- } ++ // CraftBukkit start - Update getExpReward() above if the removed if() changes! ++ i = this.expToDrop; ++ while (i > 0) { ++ int j = EntityExperienceOrb.getOrbValue(i); ++ i -= j; ++ this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j)); + } ++ this.expToDrop = 0; ++ // CraftBukkit end + + this.die(); + +@@ -375,6 +411,17 @@ + } + } + } ++ ++ // CraftBukkit start ++ if (nbttagcompound.hasKey("Bukkit.MaxHealth")) { ++ NBTBase nbtbase = nbttagcompound.get("Bukkit.MaxHealth"); ++ if (nbtbase.getTypeId() == 5) { ++ this.getAttributeInstance(GenericAttributes.maxHealth).setValue((double) ((NBTTagFloat) nbtbase).c()); ++ } else if (nbtbase.getTypeId() == 3) { ++ this.getAttributeInstance(GenericAttributes.maxHealth).setValue((double) ((NBTTagInt) nbtbase).d()); ++ } ++ } ++ // CraftBukkit end + + if (nbttagcompound.hasKeyOfType("HealF", 99)) { + this.setHealth(nbttagcompound.getFloat("HealF")); +@@ -486,7 +533,8 @@ + } + + public boolean hasEffect(int i) { +- return this.effects.containsKey(Integer.valueOf(i)); ++ // CraftBukkit - Add size check for efficiency ++ return this.effects.size() != 0 && this.effects.containsKey(Integer.valueOf(i)); + } + + public boolean hasEffect(MobEffectList mobeffectlist) { +@@ -560,20 +608,52 @@ + + } + ++ // CraftBukkit start - Delegate so we can handle providing a reason for health being regained + public void heal(float f) { ++ heal(f, EntityRegainHealthEvent.RegainReason.CUSTOM); ++ } ++ ++ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) { + float f1 = this.getHealth(); + + if (f1 > 0.0F) { +- this.setHealth(f1 + f); ++ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.setHealth((float) (this.getHealth() + event.getAmount())); ++ } ++ // CraftBukkit end + } + + } + + public final float getHealth() { ++ // CraftBukkit start - Use unscaled health ++ if (this instanceof EntityPlayer) { ++ return (float) ((EntityPlayer) this).getBukkitEntity().getHealth(); ++ } ++ // CraftBukkit end + return this.datawatcher.getFloat(6); + } + + public void setHealth(float f) { ++ // CraftBukkit start - Handle scaled health ++ if (this instanceof EntityPlayer) { ++ org.bukkit.craftbukkit.entity.CraftPlayer player = ((EntityPlayer) this).getBukkitEntity(); ++ // Squeeze ++ if (f < 0.0F) { ++ player.setRealHealth(0.0D); ++ } else if (f > player.getMaxHealth()) { ++ player.setRealHealth(player.getMaxHealth()); ++ } else { ++ player.setRealHealth(f); ++ } ++ ++ this.datawatcher.watch(6, Float.valueOf(player.getScaledHealth())); ++ return; ++ } ++ // CraftBukkit end + this.datawatcher.watch(6, Float.valueOf(MathHelper.a(f, 0.0F, this.getMaxHealth()))); + } + +@@ -589,7 +669,8 @@ + } else if (damagesource.o() && this.hasEffect(MobEffectList.FIRE_RESISTANCE)) { + return false; + } else { +- if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && this.getEquipment(4) != null) { ++ // CraftBukkit - Moved into d(DamageSource, float) ++ if (false && (damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && this.getEquipment(4) != null) { + this.getEquipment(4).damage((int) (f * 4.0F + this.random.nextFloat() * f * 2.0F), this); + f *= 0.75F; + } +@@ -602,13 +683,22 @@ + return false; + } + +- this.d(damagesource, f - this.lastDamage); ++ // CraftBukkit start ++ if (!this.d(damagesource, f - this.lastDamage)) { ++ return false; ++ } ++ // CraftBukkit end + this.lastDamage = f; + flag = false; + } else { ++ // CraftBukkit start ++ float previousHealth = this.getHealth(); ++ if (!this.d(damagesource, f)) { ++ return false; ++ } + this.lastDamage = f; + this.noDamageTicks = this.maxNoDamageTicks; +- this.d(damagesource, f); ++ // CraftBukkit end + this.hurtTicks = this.at = 10; + } + +@@ -717,11 +807,19 @@ + } + + if (this.aZ() && this.world.getGameRules().getBoolean("doMobLoot")) { ++ this.drops = new ArrayList(); // CraftBukkit - Setup drop capture ++ + this.dropDeathLoot(this.lastDamageByPlayerTime > 0, i); + this.dropEquipment(this.lastDamageByPlayerTime > 0, i); + if (this.lastDamageByPlayerTime > 0 && this.random.nextFloat() < 0.025F + (float) i * 0.01F) { + this.getRareDrop(); +- } ++ } ++ // CraftBukkit start - Call death event ++ CraftEventFactory.callEntityDeathEvent(this, this.drops); ++ this.drops = null; ++ } else { ++ CraftEventFactory.callEntityDeathEvent(this); ++ // CraftBukkit end + } + } + +@@ -781,8 +879,13 @@ + int i = MathHelper.f((f - 3.0F - f2) * f1); + + if (i > 0) { ++ // CraftBukkit start ++ if (!this.damageEntity(DamageSource.FALL, (float) i)) { ++ return; ++ } ++ // CraftBukkit end + this.makeSound(this.n(i), 1.0F, 1.0F); +- this.damageEntity(DamageSource.FALL, (float) i); ++ // this.damageEntity(DamageSource.FALL, (float) i); // CraftBukkit - moved up + int j = MathHelper.floor(this.locX); + int k = MathHelper.floor(this.locY - 0.20000000298023224D); + int l = MathHelper.floor(this.locZ); +@@ -826,7 +929,7 @@ + int i = 25 - this.bq(); + float f1 = f * (float) i; + +- this.damageArmor(f); ++ // this.damageArmor(f); // CraftBukkit - Moved into d(DamageSource, float) + f = f1 / 25.0F; + } + +@@ -840,8 +943,9 @@ + int i; + int j; + float f1; +- +- if (this.hasEffect(MobEffectList.RESISTANCE) && damagesource != DamageSource.OUT_OF_WORLD) { ++ ++ // CraftBukkit - Moved to d(DamageSource, float) ++ if (false && this.hasEffect(MobEffectList.RESISTANCE) && damagesource != DamageSource.OUT_OF_WORLD) { + i = (this.getEffect(MobEffectList.RESISTANCE).getAmplifier() + 1) * 5; + j = 25 - i; + f1 = f * (float) j; +@@ -867,22 +971,117 @@ + } + } + +- protected void d(DamageSource damagesource, float f) { ++ // CraftBukkit start ++ protected boolean d(final DamageSource damagesource, float f) { // void -> boolean, add final + if (!this.isInvulnerable(damagesource)) { +- f = this.applyArmorModifier(damagesource, f); +- f = this.applyMagicModifier(damagesource, f); +- float f1 = f; ++ final boolean human = this instanceof EntityHuman; ++ float originalDamage = f; ++ Function hardHat = new Function() { ++ @Override ++ public Double apply(Double f) { ++ if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && EntityLiving.this.getEquipment(4) != null) { ++ return -(f - (f * 0.75F)); ++ } ++ return -0.0; ++ } ++ }; ++ float hardHatModifier = hardHat.apply((double) f).floatValue(); ++ f += hardHatModifier; ++ ++ Function blocking = new Function() { ++ @Override ++ public Double apply(Double f) { ++ if (human) { ++ if (!damagesource.ignoresArmor() && ((EntityHuman) EntityLiving.this).isBlocking() && f > 0.0F) { ++ return -(f - ((1.0F + f) * 0.5F)); ++ } ++ } ++ return -0.0; ++ } ++ }; ++ float blockingModifier = blocking.apply((double) f).floatValue(); ++ f += blockingModifier; ++ ++ Function armor = new Function() { ++ @Override ++ public Double apply(Double f) { ++ return -(f - EntityLiving.this.applyArmorModifier(damagesource, f.floatValue())); ++ } ++ }; ++ float armorModifier = armor.apply((double) f).floatValue(); ++ f += armorModifier; ++ ++ Function resistance = new Function() { ++ @Override ++ public Double apply(Double f) { ++ if (!damagesource.isStarvation() && EntityLiving.this.hasEffect(MobEffectList.RESISTANCE) && damagesource != DamageSource.OUT_OF_WORLD) { ++ int i = (EntityLiving.this.getEffect(MobEffectList.RESISTANCE).getAmplifier() + 1) * 5; ++ int j = 25 - i; ++ float f1 = f.floatValue() * (float) j; ++ return -(f - (f1 / 25.0F)); ++ } ++ return -0.0; ++ } ++ }; ++ float resistanceModifier = resistance.apply((double) f).floatValue(); ++ f += resistanceModifier; ++ ++ Function magic = new Function() { ++ @Override ++ public Double apply(Double f) { ++ return -(f - EntityLiving.this.applyMagicModifier(damagesource, f.floatValue())); ++ } ++ }; ++ float magicModifier = magic.apply((double) f).floatValue(); ++ f += magicModifier; ++ ++ Function absorption = new Function() { ++ @Override ++ public Double apply(Double f) { ++ return -(Math.max(f - Math.max(f - EntityLiving.this.getAbsorptionHearts(), 0.0F), 0.0F)); ++ } ++ }; ++ float absorptionModifier = absorption.apply((double) f).floatValue(); ++ ++ EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption); ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ f = (float) event.getFinalDamage(); + +- f = Math.max(f - this.getAbsorptionHearts(), 0.0F); +- this.setAbsorptionHearts(this.getAbsorptionHearts() - (f1 - f)); ++ // Apply damage to helmet ++ if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && this.getEquipment(4) != null) { ++ this.getEquipment(4).damage((int) (event.getDamage() * 4.0F + this.random.nextFloat() * event.getDamage() * 2.0F), this); ++ } ++ ++ // Apply damage to armor ++ if (!damagesource.ignoresArmor()) { ++ float armorDamage = (float) (event.getDamage() + event.getDamage(DamageModifier.BLOCKING) + event.getDamage(DamageModifier.HARD_HAT)); ++ this.damageArmor(armorDamage); ++ } ++ ++ absorptionModifier = (float) -event.getDamage(DamageModifier.ABSORPTION); ++ this.setAbsorptionHearts(Math.max(this.getAbsorptionHearts() - absorptionModifier, 0.0F)); + if (f != 0.0F) { ++ if (human) { ++ ((EntityHuman) this).applyExhaustion(damagesource.getExhaustionCost()); ++ } ++ // CraftBukkit end + float f2 = this.getHealth(); + + this.setHealth(f2 - f); + this.br().a(damagesource, f2, f); ++ // CraftBukkit start ++ if (human) { ++ return true; ++ } ++ // CraftBukkit end + this.setAbsorptionHearts(this.getAbsorptionHearts() - f); + } ++ return true; // CraftBukkit + } ++ return false; // CraftBukkit + } + + public CombatTracker br() { +@@ -1236,7 +1435,8 @@ + if (f > 0.0025000002F) { + f3 = 1.0F; + f2 = (float) Math.sqrt((double) f) * 3.0F; +- f1 = (float) Math.atan2(d1, d0) * 180.0F / 3.1415927F - 90.0F; ++ // CraftBukkit - Math -> TrigMath ++ f1 = (float) org.bukkit.craftbukkit.TrigMath.atan2(d1, d0) * 180.0F / 3.1415927F - 90.0F; + } + + if (this.ax > 0.0F) { +@@ -1400,6 +1600,13 @@ + if (list != null && !list.isEmpty()) { + for (int i = 0; i < list.size(); ++i) { + Entity entity = (Entity) list.get(i); ++ ++ // TODO better check now? ++ // CraftBukkit start - Only handle mob (non-player) collisions every other tick ++ if (entity instanceof EntityLiving && !(this instanceof EntityPlayer) && this.ticksLived % 2 == 0) { ++ continue; ++ } ++ // CraftBukkit end + + if (entity.ae()) { + this.s(entity); diff --git a/paper-server/nms-patches/EntityMinecartAbstract.patch b/paper-server/nms-patches/EntityMinecartAbstract.patch new file mode 100644 index 0000000000..c8ed3d563a --- /dev/null +++ b/paper-server/nms-patches/EntityMinecartAbstract.patch @@ -0,0 +1,231 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityMinecartAbstract.java 2014-11-27 08:59:46.705421829 +1100 ++++ src/main/java/net/minecraft/server/EntityMinecartAbstract.java 2014-11-27 08:42:10.136850942 +1100 +@@ -2,6 +2,15 @@ + + import java.util.Iterator; + ++// CraftBukkit start ++import org.bukkit.Location; ++import org.bukkit.entity.Vehicle; ++import org.bukkit.event.vehicle.VehicleDamageEvent; ++import org.bukkit.event.vehicle.VehicleDestroyEvent; ++import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; ++import org.bukkit.util.Vector; ++// CraftBukkit end ++ + public abstract class EntityMinecartAbstract extends Entity implements INamableTileEntity { + + private boolean a; +@@ -13,6 +22,17 @@ + private double g; + private double h; + private double i; ++ ++ // CraftBukkit start ++ public boolean slowWhenEmpty = true; ++ private double derailedX = 0.5; ++ private double derailedY = 0.5; ++ private double derailedZ = 0.5; ++ private double flyingX = 0.95; ++ private double flyingY = 0.95; ++ private double flyingZ = 0.95; ++ public double maxSpeed = 0.4D; ++ // CraftBukkit end + + public EntityMinecartAbstract(World world) { + super(world); +@@ -79,6 +99,8 @@ + this.lastX = d0; + this.lastY = d1; + this.lastZ = d2; ++ ++ this.world.getServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleCreateEvent((Vehicle) this.getBukkitEntity())); // CraftBukkit + } + + public double an() { +@@ -90,16 +112,39 @@ + if (this.isInvulnerable(damagesource)) { + return false; + } else { ++ // CraftBukkit start - fire VehicleDamageEvent ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ org.bukkit.entity.Entity passenger = (damagesource.getEntity() == null) ? null : damagesource.getEntity().getBukkitEntity(); ++ ++ VehicleDamageEvent event = new VehicleDamageEvent(vehicle, passenger, f); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return true; ++ } ++ ++ f = (float) event.getDamage(); ++ // CraftBukkit end ++ + this.k(-this.r()); + this.j(10); + this.ac(); + this.setDamage(this.getDamage() + f * 10.0F); + boolean flag = damagesource.getEntity() instanceof EntityHuman && ((EntityHuman) damagesource.getEntity()).abilities.canInstantlyBuild; + +- if (flag || this.getDamage() > 40.0F) { ++ if (flag || this.getDamage() > 40.0F) { // CraftBukkit - multi-world should still allow teleport even if default vanilla nether disabled + if (this.passenger != null) { + this.passenger.mount((Entity) null); + } ++ // CraftBukkit start ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, passenger); ++ this.world.getServer().getPluginManager().callEvent(destroyEvent); ++ ++ if (destroyEvent.isCancelled()) { ++ this.setDamage(40); // Maximize damage so this doesn't get triggered again right away ++ return true; ++ } ++ // CraftBukkit end + + if (flag && !this.hasCustomName()) { + this.die(); +@@ -135,6 +180,14 @@ + } + + public void s_() { ++ // CraftBukkit start ++ double prevX = this.locX; ++ double prevY = this.locY; ++ double prevZ = this.locZ; ++ float prevYaw = this.yaw; ++ float prevPitch = this.pitch; ++ // CraftBukkit end ++ + if (this.getType() > 0) { + this.j(this.getType() - 1); + } +@@ -155,7 +208,7 @@ + + i = this.L(); + if (this.ak) { +- if (minecraftserver.getAllowNether()) { ++ if (true || minecraftserver.getAllowNether()) { + if (this.vehicle == null && this.al++ >= i) { + this.al = i; + this.portalCooldown = this.ar(); +@@ -252,6 +305,20 @@ + } + + this.setYawPitch(this.yaw, this.pitch); ++ ++ // CraftBukkit start ++ org.bukkit.World bworld = this.world.getWorld(); ++ Location from = new Location(bworld, prevX, prevY, prevZ, prevYaw, prevPitch); ++ Location to = new Location(bworld, this.locX, this.locY, this.locZ, this.yaw, this.pitch); ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ ++ this.world.getServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle)); ++ ++ if (!from.equals(to)) { ++ this.world.getServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleMoveEvent(vehicle, from, to)); ++ } ++ // CraftBukkit end ++ + Iterator iterator = this.world.getEntities(this, this.getBoundingBox().grow(0.20000000298023224D, 0.0D, 0.20000000298023224D)).iterator(); + + while (iterator.hasNext()) { +@@ -275,7 +342,7 @@ + } + + protected double m() { +- return 0.4D; ++ return this.maxSpeed; // CraftBukkit + } + + public void a(int i, int j, int k, boolean flag) {} +@@ -286,16 +353,20 @@ + this.motX = MathHelper.a(this.motX, -d0, d0); + this.motZ = MathHelper.a(this.motZ, -d0, d0); + if (this.onGround) { +- this.motX *= 0.5D; +- this.motY *= 0.5D; +- this.motZ *= 0.5D; ++ // CraftBukkit start - replace magic numbers with our variables ++ this.motX *= this.derailedX; ++ this.motY *= this.derailedY; ++ this.motZ *= this.derailedZ; ++ // CraftBukkit end + } + + this.move(this.motX, this.motY, this.motZ); + if (!this.onGround) { +- this.motX *= 0.949999988079071D; +- this.motY *= 0.949999988079071D; +- this.motZ *= 0.949999988079071D; ++ // CraftBukkit start - replace magic numbers with our variables ++ this.motX *= this.flyingX; ++ this.motY *= this.flyingY; ++ this.motZ *= this.flyingZ; ++ // CraftBukkit end + } + + } +@@ -483,7 +554,7 @@ + } + + protected void o() { +- if (this.passenger != null) { ++ if (this.passenger != null || !this.slowWhenEmpty) { // CraftBukkit - add !this.slowWhenEmpty + this.motX *= 0.996999979019165D; + this.motY *= 0.0D; + this.motZ *= 0.996999979019165D; +@@ -611,6 +682,17 @@ + if (!this.world.isStatic) { + if (!entity.T && !this.T) { + if (entity != this.passenger) { ++ // CraftBukkit start ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ org.bukkit.entity.Entity hitEntity = (entity == null) ? null : entity.getBukkitEntity(); ++ ++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, hitEntity); ++ this.world.getServer().getPluginManager().callEvent(collisionEvent); ++ ++ if (collisionEvent.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + if (entity instanceof EntityLiving && !(entity instanceof EntityHuman) && !(entity instanceof EntityIronGolem) && this.s() == EnumMinecartType.RIDEABLE && this.motX * this.motX + this.motZ * this.motZ > 0.01D && this.passenger == null && entity.vehicle == null) { + entity.mount(this); + } +@@ -619,7 +701,8 @@ + double d1 = entity.locZ - this.locZ; + double d2 = d0 * d0 + d1 * d1; + +- if (d2 >= 9.999999747378752E-5D) { ++ // CraftBukkit - collision ++ if (d2 >= 9.999999747378752E-5D && !collisionEvent.isCollisionCancelled()) { + d2 = (double) MathHelper.sqrt(d2); + d0 /= d2; + d1 /= d2; +@@ -775,4 +858,26 @@ + return chatmessage; + } + } ++ ++ // CraftBukkit start - Methods for getting and setting flying and derailed velocity modifiers ++ public Vector getFlyingVelocityMod() { ++ return new Vector(flyingX, flyingY, flyingZ); ++ } ++ ++ public void setFlyingVelocityMod(Vector flying) { ++ flyingX = flying.getX(); ++ flyingY = flying.getY(); ++ flyingZ = flying.getZ(); ++ } ++ ++ public Vector getDerailedVelocityMod() { ++ return new Vector(derailedX, derailedY, derailedZ); ++ } ++ ++ public void setDerailedVelocityMod(Vector derailed) { ++ derailedX = derailed.getX(); ++ derailedY = derailed.getY(); ++ derailedZ = derailed.getZ(); ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/EntityMinecartCommandBlockListener.patch b/paper-server/nms-patches/EntityMinecartCommandBlockListener.patch new file mode 100644 index 0000000000..ccfa4973c9 --- /dev/null +++ b/paper-server/nms-patches/EntityMinecartCommandBlockListener.patch @@ -0,0 +1,10 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityMinecartCommandBlockListener.java 2014-11-27 08:59:46.709421812 +1100 ++++ src/main/java/net/minecraft/server/EntityMinecartCommandBlockListener.java 2014-11-27 08:42:10.088851036 +1100 +@@ -6,6 +6,7 @@ + + EntityMinecartCommandBlockListener(EntityMinecartCommandBlock entityminecartcommandblock) { + this.a = entityminecartcommandblock; ++ this.sender = (org.bukkit.craftbukkit.entity.CraftMinecartCommand) entityminecartcommandblock.getBukkitEntity(); // CraftBukkit - Set the sender + } + + public void h() { diff --git a/paper-server/nms-patches/EntityMinecartContainer.patch b/paper-server/nms-patches/EntityMinecartContainer.patch new file mode 100644 index 0000000000..3a7c0c58f4 --- /dev/null +++ b/paper-server/nms-patches/EntityMinecartContainer.patch @@ -0,0 +1,61 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityMinecartContainer.java 2014-11-27 08:59:46.709421812 +1100 ++++ src/main/java/net/minecraft/server/EntityMinecartContainer.java 2014-11-27 08:42:10.120850973 +1100 +@@ -1,9 +1,48 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.inventory.InventoryHolder; ++// CraftBukkit end ++ + public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory { + +- private ItemStack[] items = new ItemStack[36]; ++ private ItemStack[] items = new ItemStack[27]; // CraftBukkit - 36 -> 27 + private boolean b = true; ++ ++ // CraftBukkit start ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public InventoryHolder getOwner() { ++ org.bukkit.entity.Entity cart = getBukkitEntity(); ++ if(cart instanceof InventoryHolder) return (InventoryHolder) cart; ++ return null; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public EntityMinecartContainer(World world) { + super(world); +@@ -81,7 +120,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public void c(int i) { diff --git a/paper-server/nms-patches/EntityMonster.patch b/paper-server/nms-patches/EntityMonster.patch new file mode 100644 index 0000000000..f5500facb8 --- /dev/null +++ b/paper-server/nms-patches/EntityMonster.patch @@ -0,0 +1,26 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityMonster.java 2014-11-27 08:59:46.709421812 +1100 ++++ src/main/java/net/minecraft/server/EntityMonster.java 2014-11-27 08:42:10.164850887 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.EntityCombustByEntityEvent; // CraftBukkit ++ + public abstract class EntityMonster extends EntityCreature implements IMonster { + + protected final PathfinderGoal a = new PathfinderGoalAvoidTarget(this, new EntitySelectorExplodingCreeper(this), 4.0F, 1.0D, 2.0D); +@@ -81,7 +83,14 @@ + int j = EnchantmentManager.getFireAspectEnchantmentLevel(this); + + if (j > 0) { +- entity.setOnFire(j * 4); ++ // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), j * 4); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ ++ if (!combustEvent.isCancelled()) { ++ entity.setOnFire(combustEvent.getDuration()); ++ } ++ // CraftBukkit end + } + + this.a((EntityLiving) this, entity); diff --git a/paper-server/nms-patches/EntityMushroomCow.patch b/paper-server/nms-patches/EntityMushroomCow.patch new file mode 100644 index 0000000000..2d2507ed62 --- /dev/null +++ b/paper-server/nms-patches/EntityMushroomCow.patch @@ -0,0 +1,26 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityMushroomCow.java 2014-11-27 08:59:46.713421793 +1100 ++++ src/main/java/net/minecraft/server/EntityMushroomCow.java 2014-11-27 08:42:10.084851043 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.player.PlayerShearEntityEvent; // CraftBukkit ++ + public class EntityMushroomCow extends EntityCow { + + public EntityMushroomCow(World world) { +@@ -24,6 +26,15 @@ + } + + if (itemstack != null && itemstack.getItem() == Items.SHEARS && this.getAge() >= 0) { ++ // CraftBukkit start ++ PlayerShearEntityEvent event = new PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity()); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end ++ + this.die(); + this.world.addParticle(EnumParticle.EXPLOSION_LARGE, this.locX, this.locY + (double) (this.length / 2.0F), this.locZ, 0.0D, 0.0D, 0.0D, new int[0]); + if (!this.world.isStatic) { diff --git a/paper-server/nms-patches/EntityOcelot.patch b/paper-server/nms-patches/EntityOcelot.patch new file mode 100644 index 0000000000..1abf343c8e --- /dev/null +++ b/paper-server/nms-patches/EntityOcelot.patch @@ -0,0 +1,30 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityOcelot.java 2014-11-27 08:59:46.713421793 +1100 ++++ src/main/java/net/minecraft/server/EntityOcelot.java 2014-11-27 08:42:10.160850895 +1100 +@@ -51,7 +51,7 @@ + } + + protected boolean isTypeNotPersistent() { +- return !this.isTamed() && this.ticksLived > 2400; ++ return !this.isTamed() /*&& this.ticksLived > 2400*/; // CraftBukkit + } + + protected void aW() { +@@ -124,7 +124,8 @@ + } + + if (!this.world.isStatic) { +- if (this.random.nextInt(3) == 0) { ++ // CraftBukkit - added event call and isCancelled check ++ if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { + this.setTamed(true); + this.setCatType(1 + this.world.random.nextInt(3)); + this.setOwnerUUID(entityhuman.getUniqueID().toString()); +@@ -231,7 +232,7 @@ + + entityocelot.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F); + entityocelot.setAgeRaw(-24000); +- this.world.addEntity(entityocelot); ++ this.world.addEntity(entityocelot, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OCELOT_BABY); // CraftBukkit - add SpawnReason + } + } + diff --git a/paper-server/nms-patches/EntityPainting.patch b/paper-server/nms-patches/EntityPainting.patch new file mode 100644 index 0000000000..7c698b4f44 --- /dev/null +++ b/paper-server/nms-patches/EntityPainting.patch @@ -0,0 +1,10 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityPainting.java 2014-11-27 08:59:46.717421776 +1100 ++++ src/main/java/net/minecraft/server/EntityPainting.java 2014-11-27 08:42:10.132850949 +1100 +@@ -9,6 +9,7 @@ + + public EntityPainting(World world) { + super(world); ++ this.art = EnumArt.values()[this.random.nextInt(EnumArt.values().length)]; // CraftBukkit - generate a non-null painting + } + + public EntityPainting(World world, BlockPosition blockposition, EnumDirection enumdirection) { diff --git a/paper-server/nms-patches/EntityPig.patch b/paper-server/nms-patches/EntityPig.patch new file mode 100644 index 0000000000..064655a70a --- /dev/null +++ b/paper-server/nms-patches/EntityPig.patch @@ -0,0 +1,29 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityPig.java 2014-11-27 08:59:46.717421776 +1100 ++++ src/main/java/net/minecraft/server/EntityPig.java 2014-11-27 08:42:10.140850934 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit ++ + public class EntityPig extends EntityAnimal { + + private final PathfinderGoalPassengerCarrotStick bk; +@@ -111,10 +113,17 @@ + public void onLightningStrike(EntityLightning entitylightning) { + if (!this.world.isStatic) { + EntityPigZombie entitypigzombie = new EntityPigZombie(this.world); ++ ++ // CraftBukkit start ++ if (CraftEventFactory.callPigZapEvent(this, entitylightning, entitypigzombie).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + + entitypigzombie.setEquipment(0, new ItemStack(Items.GOLDEN_SWORD)); + entitypigzombie.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, this.pitch); +- this.world.addEntity(entitypigzombie); ++ // CraftBukkit - added a reason for spawning this creature ++ this.world.addEntity(entitypigzombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); + this.die(); + } + } diff --git a/paper-server/nms-patches/EntityPlayer.patch b/paper-server/nms-patches/EntityPlayer.patch new file mode 100644 index 0000000000..e63348a005 --- /dev/null +++ b/paper-server/nms-patches/EntityPlayer.patch @@ -0,0 +1,542 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityPlayer.java 2014-11-27 08:59:46.721421758 +1100 ++++ src/main/java/net/minecraft/server/EntityPlayer.java 2014-11-27 08:42:10.164850887 +1100 +@@ -13,6 +13,17 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import org.bukkit.Bukkit; ++import org.bukkit.WeatherType; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.inventory.InventoryType; ++import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; ++// CraftBukkit end ++ + public class EntityPlayer extends EntityHuman implements ICrafting { + + private static final Logger bF = LogManager.getLogger(); +@@ -39,6 +50,18 @@ + public boolean g; + public int ping; + public boolean viewingCredits; ++ ++ // CraftBukkit start ++ public String displayName; ++ public IChatBaseComponent listName; ++ public org.bukkit.Location compassTarget; ++ public int newExp = 0; ++ public int newLevel = 0; ++ public int newTotalExp = 0; ++ public boolean keepLevel = false; ++ public double maxHealthCache; ++ public boolean joining = true; ++ // CraftBukkit end + + public EntityPlayer(MinecraftServer minecraftserver, WorldServer worldserver, GameProfile gameprofile, PlayerInteractManager playerinteractmanager) { + super(worldserver, gameprofile); +@@ -69,7 +92,11 @@ + while (!worldserver.getCubes(this, this.getBoundingBox()).isEmpty() && this.locY < 255.0D) { + this.setPosition(this.locX, this.locY + 1.0D, this.locZ); + } +- ++ // CraftBukkit start ++ this.displayName = this.getName(); ++ // this.canPickUpLoot = true; TODO ++ this.maxHealthCache = this.getMaxHealth(); ++ // CraftBukkit end + } + + public void a(NBTTagCompound nbttagcompound) { +@@ -81,13 +108,39 @@ + this.playerInteractManager.setGameMode(EnumGamemode.getById(nbttagcompound.getInt("playerGameType"))); + } + } +- ++ this.getBukkitEntity().readExtraData(nbttagcompound); // CraftBukkit + } + + public void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); + nbttagcompound.setInt("playerGameType", this.playerInteractManager.getGameMode().getId()); ++ this.getBukkitEntity().setExtraData(nbttagcompound); // CraftBukkit ++ } ++ ++ // CraftBukkit start - World fallback code, either respawn location or global spawn ++ public void spawnIn(World world) { ++ super.spawnIn(world); ++ if (world == null) { ++ this.dead = false; ++ BlockPosition position = null; ++ if (this.spawnWorld != null && !this.spawnWorld.equals("")) { ++ CraftWorld cworld = (CraftWorld) Bukkit.getServer().getWorld(this.spawnWorld); ++ if (cworld != null && this.getBed() != null) { ++ world = cworld.getHandle(); ++ position = EntityHuman.getBed(cworld.getHandle(), this.getBed(), false); ++ } ++ } ++ if (world == null || position == null) { ++ world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle(); ++ position = world.getSpawn(); ++ } ++ this.world = world; ++ this.setPosition(position.getX() + 0.5, position.getY(), position.getZ() + 0.5); ++ } ++ this.dimension = ((WorldServer) this.world).dimension; ++ this.playerInteractManager.a((WorldServer) world); + } ++ // CraftBukkit end + + public void levelDown(int i) { + super.levelDown(i); +@@ -114,6 +167,11 @@ + } + + public void s_() { ++ // CraftBukkit start ++ if (this.joining) { ++ this.joining = false; ++ } ++ // CraftBukkit end + this.playerInteractManager.a(); + --this.invulnerableTicks; + if (this.noDamageTicks > 0) { +@@ -155,7 +213,7 @@ + chunk = this.world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z); + if (chunk.isReady()) { + arraylist.add(chunk); +- arraylist1.addAll(((WorldServer) this.world).getTileEntities(chunkcoordintpair.x * 16, 0, chunkcoordintpair.z * 16, chunkcoordintpair.x * 16 + 16, 256, chunkcoordintpair.z * 16 + 16)); ++ arraylist1.addAll(chunk.tileEntities.values()); // CraftBukkit - Get tile entities directly from the chunk instead of the world + iterator1.remove(); + } + } +@@ -220,8 +278,9 @@ + } + } + ++ // CraftBukkit - Optionally scale health + if (this.getHealth() != this.bK || this.bL != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.bM) { +- this.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(this.getHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel())); ++ this.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(this.getBukkitEntity().getScaledHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel())); + this.bK = this.getHealth(); + this.bL = this.foodData.getFoodLevel(); + this.bM = this.foodData.getSaturationLevel() == 0.0F; +@@ -229,15 +288,14 @@ + + if (this.getHealth() + this.getAbsorptionHearts() != this.bJ) { + this.bJ = this.getHealth() + this.getAbsorptionHearts(); +- Collection collection = this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.g); +- Iterator iterator = collection.iterator(); +- +- while (iterator.hasNext()) { +- ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next(); +- +- this.getScoreboard().getPlayerScoreForObjective(this.getName(), scoreboardobjective).updateForList(Arrays.asList(new EntityHuman[] { this})); +- } ++ // CraftBukkit - Update ALL the scores! ++ this.world.getServer().getScoreboardManager().updateAllScoresForList(IScoreboardCriteria.f, this.getName(), com.google.common.collect.ImmutableList.of(this)); ++ } ++ // CraftBukkit start - Force max health updates ++ if (this.maxHealthCache != this.getMaxHealth()) { ++ this.getBukkitEntity().updateScaledHealth(); + } ++ // CraftBukkit end + + if (this.expTotal != this.lastSentExp) { + this.lastSentExp = this.expTotal; +@@ -247,7 +305,17 @@ + if (this.ticksLived % 20 * 5 == 0 && !this.getStatisticManager().hasAchievement(AchievementList.L)) { + this.h_(); + } ++ ++ // CraftBukkit start - initialize oldLevel and fire PlayerLevelChangeEvent ++ if (this.oldLevel == -1) { ++ this.oldLevel = this.expLevel; ++ } + ++ if (this.oldLevel != this.expLevel) { ++ CraftEventFactory.callPlayerLevelChangeEvent(this.world.getServer().getPlayer((EntityPlayer) this), this.oldLevel, this.expLevel); ++ this.oldLevel = this.expLevel; ++ } ++ // CraftBukkit end + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.a(throwable, "Ticking player"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Player being ticked"); +@@ -296,30 +364,64 @@ + } + + public void die(DamageSource damagesource) { +- if (this.world.getGameRules().getBoolean("showDeathMessages")) { +- ScoreboardTeamBase scoreboardteambase = this.getScoreboardTeam(); ++ // CraftBukkit start - fire PlayerDeathEvent ++ if (this.dead) { ++ return; ++ } ++ ++ java.util.List loot = new java.util.ArrayList(); ++ boolean keepInventory = this.world.getGameRules().getBoolean("keepInventory"); ++ ++ if (!keepInventory) { ++ for (int i = 0; i < this.inventory.items.length; ++i) { ++ if (this.inventory.items[i] != null) { ++ loot.add(CraftItemStack.asCraftMirror(this.inventory.items[i])); ++ } ++ } + +- if (scoreboardteambase != null && scoreboardteambase.j() != EnumNameTagVisibility.ALWAYS) { +- if (scoreboardteambase.j() == EnumNameTagVisibility.HIDE_FOR_OTHER_TEAMS) { +- this.server.getPlayerList().a((EntityHuman) this, this.br().b()); +- } else if (scoreboardteambase.j() == EnumNameTagVisibility.HIDE_FOR_OWN_TEAM) { +- this.server.getPlayerList().b((EntityHuman) this, this.br().b()); ++ for (int i = 0; i < this.inventory.armor.length; ++i) { ++ if (this.inventory.armor[i] != null) { ++ loot.add(CraftItemStack.asCraftMirror(this.inventory.armor[i])); + } ++ } ++ } ++ ++ IChatBaseComponent chatmessage = this.br().b(); ++ ++ String deathmessage = chatmessage.c(); ++ org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory); ++ ++ String deathMessage = event.getDeathMessage(); ++ ++ if (deathMessage != null && deathMessage.length() > 0 && this.world.getGameRules().getBoolean("showDeathMessages")) { // TODO: allow plugins to override? ++ if (deathMessage.equals(deathmessage)) { ++ this.server.getPlayerList().sendMessage(chatmessage); + } else { +- this.server.getPlayerList().sendMessage(this.br().b()); ++ this.server.getPlayerList().sendMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(deathMessage)); + } + } ++ ++ // we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory. ++ if (!event.getKeepInventory()) { ++ for (int i = 0; i < this.inventory.items.length; ++i) { ++ this.inventory.items[i] = null; ++ } + +- if (!this.world.getGameRules().getBoolean("keepInventory")) { +- this.inventory.n(); ++ for (int i = 0; i < this.inventory.armor.length; ++i) { ++ this.inventory.armor[i] = null; ++ } + } + +- Collection collection = this.world.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.d); ++ this.closeInventory(); ++ this.e((Entity) this); // Remove spectated target ++ // CraftBukkit end ++ ++ // CraftBukkit - Get our scores instead ++ Collection collection = this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.c, this.getName(), new java.util.ArrayList()); + Iterator iterator = collection.iterator(); + + while (iterator.hasNext()) { +- ScoreboardObjective scoreboardobjective = (ScoreboardObjective) iterator.next(); +- ScoreboardScore scoreboardscore = this.getScoreboard().getPlayerScoreForObjective(this.getName(), scoreboardobjective); ++ ScoreboardScore scoreboardscore = (ScoreboardScore) iterator.next(); // CraftBukkit - Use our scores instead + + scoreboardscore.incrementScore(); + } +@@ -376,7 +478,8 @@ + } + + private boolean cq() { +- return this.server.getPVP(); ++ // CraftBukkit - this.server.getPvP() -> this.world.pvpMode ++ return this.world.pvpMode; + } + + public void c(int i) { +@@ -388,6 +491,8 @@ + } else { + if (this.dimension == 0 && i == 1) { + this.b((Statistic) AchievementList.C); ++ // CraftBukkit start - Rely on custom portal management ++ /* + BlockPosition blockposition = this.server.getWorldServer(i).getDimensionSpawn(); + + if (blockposition != null) { +@@ -395,11 +500,16 @@ + } + + i = 1; ++ */ ++ // CraftBukkit end + } else { + this.b((Statistic) AchievementList.y); + } + +- this.server.getPlayerList().changeDimension(this, i); ++ // CraftBukkit start ++ TeleportCause cause = (this.dimension == 1 || i == 1) ? TeleportCause.END_PORTAL : TeleportCause.NETHER_PORTAL; ++ this.server.getPlayerList().changeDimension(this, i, cause); ++ // CraftBukkit end + this.lastSentExp = -1; + this.bK = -1.0F; + this.bL = -1; +@@ -442,6 +552,8 @@ + } + + public void a(boolean flag, boolean flag1, boolean flag2) { ++ if (!this.sleeping) return; // CraftBukkit - Can't leave bed if not in one! ++ + if (this.isSleeping()) { + this.u().getTracker().sendPacketToEntity(this, new PacketPlayOutAnimation(this, 2)); + } +@@ -454,14 +566,23 @@ + } + + public void mount(Entity entity) { +- Entity entity1 = this.vehicle; ++ // CraftBukkit start ++ this.setPassengerOf(entity); ++ } ++ ++ public void setPassengerOf(Entity entity) { ++ // mount(null) doesn't really fly for overloaded methods, ++ // so this method is needed ++ Entity currentVehicle = this.vehicle; ++ ++ super.setPassengerOf(entity); + +- super.mount(entity); +- if (entity != entity1) { ++ // Check if the vehicle actually changed. ++ if (currentVehicle != this.vehicle) { + this.playerConnection.sendPacket(new PacketPlayOutAttachEntity(0, this, this.vehicle)); + this.playerConnection.a(this.locX, this.locY, this.locZ, this.yaw, this.pitch); + } +- ++ // CraftBukkit end + } + + protected void a(double d0, boolean flag, Block block, BlockPosition blockposition) {} +@@ -490,19 +611,38 @@ + this.playerConnection.sendPacket(new PacketPlayOutOpenSignEditor(tileentitysign.getPosition())); + } + +- public void nextContainerCounter() { ++ public int nextContainerCounter() { // CraftBukkit - private void -> public int + this.containerCounter = this.containerCounter % 100 + 1; ++ return containerCounter; // CraftBukkit + } + + public void openTileEntity(ITileEntityContainer itileentitycontainer) { ++ // CraftBukkit start - Inventory open hook ++ Container container = CraftEventFactory.callInventoryOpenEvent(this, itileentitycontainer.createContainer(this.inventory, this)); ++ if (container == null) { ++ return; ++ } ++ // CraftBukkit end + this.nextContainerCounter(); + this.playerConnection.sendPacket(new PacketPlayOutOpenWindow(this.containerCounter, itileentitycontainer.getContainerName(), itileentitycontainer.getScoreboardDisplayName())); +- this.activeContainer = itileentitycontainer.createContainer(this.inventory, this); ++ this.activeContainer = container; // CraftBukkit + this.activeContainer.windowId = this.containerCounter; + this.activeContainer.addSlotListener(this); + } + + public void openContainer(IInventory iinventory) { ++ // CraftBukkit start - Inventory open hook ++ Container container; ++ if (iinventory instanceof ITileEntityContainer) { ++ container = ((ITileEntityContainer)iinventory).createContainer(this.inventory, this); ++ } else { ++ container = new ContainerChest(this.inventory, iinventory, this); ++ } ++ container = CraftEventFactory.callInventoryOpenEvent(this, container); ++ if (container == null) { ++ return; ++ } ++ // CraftBukkit end + if (this.activeContainer != this.defaultContainer) { + this.closeInventory(); + } +@@ -520,10 +660,10 @@ + this.nextContainerCounter(); + if (iinventory instanceof ITileEntityContainer) { + this.playerConnection.sendPacket(new PacketPlayOutOpenWindow(this.containerCounter, ((ITileEntityContainer) iinventory).getContainerName(), iinventory.getScoreboardDisplayName(), iinventory.getSize())); +- this.activeContainer = ((ITileEntityContainer) iinventory).createContainer(this.inventory, this); ++ this.activeContainer = container; // CraftBukkit + } else { + this.playerConnection.sendPacket(new PacketPlayOutOpenWindow(this.containerCounter, "minecraft:container", iinventory.getScoreboardDisplayName(), iinventory.getSize())); +- this.activeContainer = new ContainerChest(this.inventory, iinventory, this); ++ this.activeContainer = container; // CraftBukkit + } + + this.activeContainer.windowId = this.containerCounter; +@@ -531,8 +671,14 @@ + } + + public void openTrade(IMerchant imerchant) { ++ // CraftBukkit start - Inventory open hook ++ Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerMerchant(this.inventory, imerchant, this.world)); ++ if (container == null) { ++ return; ++ } ++ // CraftBukkit end + this.nextContainerCounter(); +- this.activeContainer = new ContainerMerchant(this.inventory, imerchant, this.world); ++ this.activeContainer = container; // CraftBukkit + this.activeContainer.windowId = this.containerCounter; + this.activeContainer.addSlotListener(this); + InventoryMerchant inventorymerchant = ((ContainerMerchant) this.activeContainer).e(); +@@ -552,13 +698,20 @@ + } + + public void openHorseInventory(EntityHorse entityhorse, IInventory iinventory) { ++ // CraftBukkit start - Inventory open hook ++ Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerHorse(this.inventory, iinventory, entityhorse, this)); ++ if (container == null) { ++ iinventory.closeContainer(this); ++ return; ++ } ++ // CraftBukkit end + if (this.activeContainer != this.defaultContainer) { + this.closeInventory(); + } + + this.nextContainerCounter(); + this.playerConnection.sendPacket(new PacketPlayOutOpenWindow(this.containerCounter, "EntityHorse", iinventory.getScoreboardDisplayName(), iinventory.getSize(), entityhorse.getId())); +- this.activeContainer = new ContainerHorse(this.inventory, iinventory, entityhorse, this); ++ this.activeContainer = container; + this.activeContainer.windowId = this.containerCounter; + this.activeContainer.addSlotListener(this); + } +@@ -587,6 +740,11 @@ + public void a(Container container, List list) { + this.playerConnection.sendPacket(new PacketPlayOutWindowItems(container.windowId, list)); + this.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, this.inventory.getCarried())); ++ // CraftBukkit start - Send a Set Slot to update the crafting result slot ++ if (java.util.EnumSet.of(InventoryType.CRAFTING,InventoryType.WORKBENCH).contains(container.getBukkitView().getType())) { ++ this.playerConnection.sendPacket(new PacketPlayOutSetSlot(container.windowId, 0, container.getSlot(0).getItem())); ++ } ++ // CraftBukkit end + } + + public void setContainerData(Container container, int i, int j) { +@@ -601,6 +759,7 @@ + } + + public void closeInventory() { ++ CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit + this.playerConnection.sendPacket(new PacketPlayOutCloseWindow(this.activeContainer.windowId)); + this.p(); + } +@@ -681,7 +840,16 @@ + + public void triggerHealthUpdate() { + this.bK = -1.0E8F; ++ this.lastSentExp = -1; // CraftBukkit - Added to reset ++ } ++ ++ // CraftBukkit start - Support multi-line messages ++ public void sendMessage(IChatBaseComponent[] ichatbasecomponent) { ++ for (IChatBaseComponent component : ichatbasecomponent) { ++ this.sendMessage(component); ++ } + } ++ // CraftBukkit end + + public void b(IChatBaseComponent ichatbasecomponent) { + this.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent)); +@@ -867,6 +1035,93 @@ + } + + public IChatBaseComponent getPlayerListName() { +- return null; ++ return listName; // CraftBukkit ++ } ++ ++ // CraftBukkit start - Add per-player time and weather. ++ public long timeOffset = 0; ++ public boolean relativeTime = true; ++ ++ public long getPlayerTime() { ++ if (this.relativeTime) { ++ // Adds timeOffset to the current server time. ++ return this.world.getDayTime() + this.timeOffset; ++ } else { ++ // Adds timeOffset to the beginning of this day. ++ return this.world.getDayTime() - (this.world.getDayTime() % 24000) + this.timeOffset; ++ } ++ } ++ ++ public WeatherType weather = null; ++ ++ public WeatherType getPlayerWeather() { ++ return this.weather; ++ } ++ ++ public void setPlayerWeather(WeatherType type, boolean plugin) { ++ if (!plugin && this.weather != null) { ++ return; ++ } ++ ++ if (plugin) { ++ this.weather = type; ++ } ++ ++ if (type == WeatherType.DOWNFALL) { ++ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(2, 0)); ++ // this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(7, this.world.j(1.0F))); ++ // this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(8, this.world.h(1.0F))); ++ } else { ++ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(1, 0)); ++ } ++ } ++ ++ public void resetPlayerWeather() { ++ this.weather = null; ++ this.setPlayerWeather(this.world.getWorldData().hasStorm() ? WeatherType.DOWNFALL : WeatherType.CLEAR, false); ++ } ++ ++ @Override ++ public String toString() { ++ return super.toString() + "(" + this.getName() + " at " + this.locX + "," + this.locY + "," + this.locZ + ")"; ++ } ++ ++ public void reset() { ++ float exp = 0; ++ boolean keepInventory = this.world.getGameRules().getBoolean("keepInventory"); ++ ++ if (this.keepLevel || keepInventory) { ++ exp = this.exp; ++ this.newTotalExp = this.expTotal; ++ this.newLevel = this.expLevel; ++ } ++ ++ this.setHealth(this.getMaxHealth()); ++ this.fireTicks = 0; ++ this.fallDistance = 0; ++ this.foodData = new FoodMetaData(this); ++ this.expLevel = this.newLevel; ++ this.expTotal = this.newTotalExp; ++ this.exp = 0; ++ this.deathTicks = 0; ++ this.removeAllEffects(); ++ this.updateEffects = true; ++ this.activeContainer = this.defaultContainer; ++ this.killer = null; ++ this.lastDamager = null; ++ this.combatTracker = new CombatTracker(this); ++ this.lastSentExp = -1; ++ if (this.keepLevel || keepInventory) { ++ this.exp = exp; ++ } else { ++ this.giveExp(this.newExp); ++ } ++ this.keepLevel = false; ++ } ++ ++ @Override ++ public CraftPlayer getBukkitEntity() { ++ return (CraftPlayer) super.getBukkitEntity(); + } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/EntityPotion.patch b/paper-server/nms-patches/EntityPotion.patch new file mode 100644 index 0000000000..fd9e7d337b --- /dev/null +++ b/paper-server/nms-patches/EntityPotion.patch @@ -0,0 +1,70 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityPotion.java 2014-11-27 08:59:46.721421758 +1100 ++++ src/main/java/net/minecraft/server/EntityPotion.java 2014-11-27 08:42:10.112850989 +1100 +@@ -3,6 +3,13 @@ + import java.util.Iterator; + import java.util.List; + ++// CraftBukkit start ++import java.util.HashMap; ++ ++import org.bukkit.craftbukkit.entity.CraftLivingEntity; ++import org.bukkit.entity.LivingEntity; ++// CraftBukkit end ++ + public class EntityPotion extends EntityProjectile { + + public ItemStack item; +@@ -57,12 +64,15 @@ + if (!this.world.isStatic) { + List list = Items.POTION.h(this.item); + +- if (list != null && !list.isEmpty()) { ++ if (true || list != null && !list.isEmpty()) { // CraftBukkit - Call event even if no effects to apply + AxisAlignedBB axisalignedbb = this.getBoundingBox().grow(4.0D, 2.0D, 4.0D); + List list1 = this.world.a(EntityLiving.class, axisalignedbb); + +- if (!list1.isEmpty()) { ++ if (true || !list1.isEmpty()) { // CraftBukkit - Run code even if there are no entities around + Iterator iterator = list1.iterator(); ++ ++ // CraftBukkit ++ HashMap affected = new HashMap(); + + while (iterator.hasNext()) { + EntityLiving entityliving = (EntityLiving) iterator.next(); +@@ -74,12 +84,35 @@ + if (entityliving == movingobjectposition.entity) { + d1 = 1.0D; + } ++ ++ // CraftBukkit start ++ affected.put((LivingEntity) entityliving.getBukkitEntity(), d1); ++ } ++ } ++ ++ org.bukkit.event.entity.PotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPotionSplashEvent(this, affected); ++ if (!event.isCancelled() && list != null && !list.isEmpty()) { // do not process effects if there are no effects to process ++ for (LivingEntity victim : event.getAffectedEntities()) { ++ if (!(victim instanceof CraftLivingEntity)) { ++ continue; ++ } ++ ++ EntityLiving entityliving = ((CraftLivingEntity) victim).getHandle(); ++ double d1 = event.getIntensity(victim); ++ // CraftBukkit end + + Iterator iterator1 = list.iterator(); + + while (iterator1.hasNext()) { + MobEffect mobeffect = (MobEffect) iterator1.next(); + int i = mobeffect.getEffectId(); ++ ++ // CraftBukkit start - Abide by PVP settings - for players only! ++ if (!this.world.pvpMode && this.getShooter() instanceof EntityPlayer && entityliving instanceof EntityPlayer && entityliving != this.getShooter()) { ++ // Block SLOWER_MOVEMENT, SLOWER_DIG, HARM, BLINDNESS, HUNGER, WEAKNESS and POISON potions ++ if (i == 2 || i == 4 || i == 7 || i == 15 || i == 17 || i == 18 || i == 19) continue; ++ } ++ // CraftBukkit end + + if (MobEffectList.byId[i].isInstant()) { + MobEffectList.byId[i].applyInstantEffect(this, this.getShooter(), entityliving, mobeffect.getAmplifier(), d1); diff --git a/paper-server/nms-patches/EntityProjectile.patch b/paper-server/nms-patches/EntityProjectile.patch new file mode 100644 index 0000000000..bd4789e618 --- /dev/null +++ b/paper-server/nms-patches/EntityProjectile.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityProjectile.java 2014-11-27 08:59:46.725421741 +1100 ++++ src/main/java/net/minecraft/server/EntityProjectile.java 2014-11-27 08:42:10.140850934 +1100 +@@ -25,6 +25,7 @@ + public EntityProjectile(World world, EntityLiving entityliving) { + super(world); + this.shooter = entityliving; ++ this.projectileSource = (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit + this.a(0.25F, 0.25F); + this.setPositionRotation(entityliving.locX, entityliving.locY + (double) entityliving.getHeadHeight(), entityliving.locZ, entityliving.yaw, entityliving.pitch); + this.locX -= (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * 0.16F); +@@ -130,7 +131,7 @@ + MovingObjectPosition movingobjectposition1 = axisalignedbb.a(vec3d, vec3d1); + + if (movingobjectposition1 != null) { +- double d1 = vec3d.f(movingobjectposition1.pos); ++ double d1 = vec3d.distanceSquared(movingobjectposition1.pos); // CraftBukkit - distance efficiency + + if (d1 < d0 || d0 == 0.0D) { + entity = entity1; +@@ -150,6 +151,11 @@ + this.aq(); + } else { + this.a(movingobjectposition); ++ // CraftBukkit start ++ if (this.dead) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this); ++ } ++ // CraftBukkit end + } + } + diff --git a/paper-server/nms-patches/EntitySheep.patch b/paper-server/nms-patches/EntitySheep.patch new file mode 100644 index 0000000000..b173759251 --- /dev/null +++ b/paper-server/nms-patches/EntitySheep.patch @@ -0,0 +1,54 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySheep.java 2014-11-27 08:59:46.725421741 +1100 ++++ src/main/java/net/minecraft/server/EntitySheep.java 2014-11-27 08:42:10.124850965 +1100 +@@ -4,6 +4,11 @@ + import java.util.Map; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.event.entity.SheepRegrowWoolEvent; ++import org.bukkit.event.player.PlayerShearEntityEvent; ++// CraftBukkit end ++ + public class EntitySheep extends EntityAnimal { + + private final InventoryCrafting bk = new InventoryCrafting(new ContainerSheepBreed(this), 2, 1); +@@ -30,6 +35,7 @@ + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); + this.bk.setItem(0, new ItemStack(Items.DYE, 1, 0)); + this.bk.setItem(1, new ItemStack(Items.DYE, 1, 0)); ++ this.bk.resultInventory = new InventoryCraftResult(); // CraftBukkit - add result slot for event + } + + protected void E() { +@@ -82,6 +88,15 @@ + + if (itemstack != null && itemstack.getItem() == Items.SHEARS && !this.isSheared() && !this.isBaby()) { + if (!this.world.isStatic) { ++ // CraftBukkit start ++ PlayerShearEntityEvent event = new PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity()); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end ++ + this.setSheared(true); + int i = 1 + this.random.nextInt(3); + +@@ -169,7 +184,14 @@ + } + + public void v() { +- this.setSheared(false); ++ // CraftBukkit start ++ SheepRegrowWoolEvent event = new SheepRegrowWoolEvent((org.bukkit.entity.Sheep) this.getBukkitEntity()); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.setSheared(false); ++ } ++ // CraftBukkit end + if (this.isBaby()) { + this.setAge(60); + } diff --git a/paper-server/nms-patches/EntitySkeleton.patch b/paper-server/nms-patches/EntitySkeleton.patch new file mode 100644 index 0000000000..fe60351841 --- /dev/null +++ b/paper-server/nms-patches/EntitySkeleton.patch @@ -0,0 +1,60 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySkeleton.java 2014-11-27 08:59:46.725421741 +1100 ++++ src/main/java/net/minecraft/server/EntitySkeleton.java 2014-11-27 08:42:10.136850942 +1100 +@@ -2,6 +2,8 @@ + + import java.util.Calendar; + ++import org.bukkit.event.entity.EntityCombustEvent; // CraftBukkit ++ + public class EntitySkeleton extends EntityMonster implements IRangedEntity { + + private PathfinderGoalArrowAttack b = new PathfinderGoalArrowAttack(this, 1.0D, 20, 60, 15.0F); +@@ -90,7 +92,14 @@ + } + + if (flag) { +- this.setOnFire(8); ++ // CraftBukkit start ++ EntityCombustEvent event = new EntityCombustEvent(this.getBukkitEntity(), 8); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.setOnFire(event.getDuration()); ++ } ++ // CraftBukkit end + } + } + } +@@ -225,11 +234,30 @@ + } + + if (EnchantmentManager.getEnchantmentLevel(Enchantment.ARROW_FIRE.id, this.bz()) > 0 || this.getSkeletonType() == 1) { +- entityarrow.setOnFire(100); ++ // CraftBukkit start - call EntityCombustEvent ++ EntityCombustEvent event = new EntityCombustEvent(entityarrow.getBukkitEntity(), 100); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ entityarrow.setOnFire(event.getDuration()); ++ } ++ // CraftBukkit end ++ } ++ ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.bz(), entityarrow, 0.8F); ++ if (event.isCancelled()) { ++ event.getProjectile().remove(); ++ return; ++ } ++ ++ if (event.getProjectile() == entityarrow.getBukkitEntity()) { ++ world.addEntity(entityarrow); + } ++ // CraftBukkit end + + this.makeSound("random.bow", 1.0F, 1.0F / (this.bb().nextFloat() * 0.4F + 0.8F)); +- this.world.addEntity(entityarrow); ++ // this.world.addEntity(entityarrow); // CraftBukkit - moved up + } + + public int getSkeletonType() { diff --git a/paper-server/nms-patches/EntitySlime.patch b/paper-server/nms-patches/EntitySlime.patch new file mode 100644 index 0000000000..02d48970d8 --- /dev/null +++ b/paper-server/nms-patches/EntitySlime.patch @@ -0,0 +1,40 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySlime.java 2014-11-27 08:59:46.729421723 +1100 ++++ src/main/java/net/minecraft/server/EntitySlime.java 2014-11-27 08:42:10.100851012 +1100 +@@ -1,5 +1,9 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.event.entity.SlimeSplitEvent; ++// CraftBukkit end ++ + public class EntitySlime extends EntityInsentient implements IMonster { + + public float a; +@@ -132,6 +136,18 @@ + + if (!this.world.isStatic && i > 1 && this.getHealth() <= 0.0F) { + int j = 2 + this.random.nextInt(3); ++ ++ // CraftBukkit start ++ SlimeSplitEvent event = new SlimeSplitEvent((org.bukkit.entity.Slime) this.getBukkitEntity(), j); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled() && event.getCount() > 0) { ++ j = event.getCount(); ++ } else { ++ super.die(); ++ return; ++ } ++ // CraftBukkit end + + for (int k = 0; k < j; ++k) { + float f = ((float) (k % 2) - 0.5F) * (float) i / 4.0F; +@@ -148,7 +164,7 @@ + + entityslime.setSize(i / 2); + entityslime.setPositionRotation(this.locX + (double) f, this.locY + 0.5D, this.locZ + (double) f1, this.random.nextFloat() * 360.0F, 0.0F); +- this.world.addEntity(entityslime); ++ this.world.addEntity(entityslime, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SLIME_SPLIT); // CraftBukkit - SpawnReason + } + } + diff --git a/paper-server/nms-patches/EntitySmallFireball.patch b/paper-server/nms-patches/EntitySmallFireball.patch new file mode 100644 index 0000000000..7d2e7589f1 --- /dev/null +++ b/paper-server/nms-patches/EntitySmallFireball.patch @@ -0,0 +1,39 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySmallFireball.java 2014-11-27 08:59:46.729421723 +1100 ++++ src/main/java/net/minecraft/server/EntitySmallFireball.java 2014-11-27 08:42:10.152850911 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.EntityCombustByEntityEvent; // CraftBukkit ++ + public class EntitySmallFireball extends EntityFireball { + + public EntitySmallFireball(World world) { +@@ -26,7 +28,14 @@ + if (flag) { + this.a(this.shooter, movingobjectposition.entity); + if (!movingobjectposition.entity.isFireProof()) { +- movingobjectposition.entity.setOnFire(5); ++ // CraftBukkit start - Entity damage by entity event + combust event ++ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent((org.bukkit.entity.Projectile) this.getBukkitEntity(), movingobjectposition.entity.getBukkitEntity(), 5); ++ movingobjectposition.entity.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ movingobjectposition.entity.setOnFire(event.getDuration()); ++ } ++ // CraftBukkit end + } + } + } else { +@@ -39,7 +48,11 @@ + BlockPosition blockposition = movingobjectposition.a().shift(movingobjectposition.direction); + + if (this.world.isEmpty(blockposition)) { +- this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this).isCancelled()) { ++ this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ } ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/EntitySnowman.patch b/paper-server/nms-patches/EntitySnowman.patch new file mode 100644 index 0000000000..67e4371ff3 --- /dev/null +++ b/paper-server/nms-patches/EntitySnowman.patch @@ -0,0 +1,42 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySnowman.java 2014-11-27 08:59:46.733421706 +1100 ++++ src/main/java/net/minecraft/server/EntitySnowman.java 2014-11-27 08:42:10.144850927 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.event.block.EntityBlockFormEvent; ++// CraftBukkit end ++ + public class EntitySnowman extends EntityGolem implements IRangedEntity { + + public EntitySnowman(World world) { +@@ -31,7 +37,7 @@ + } + + if (this.world.getBiome(new BlockPosition(i, 0, k)).a(new BlockPosition(i, j, k)) > 1.0F) { +- this.damageEntity(DamageSource.BURN, 1.0F); ++ this.damageEntity(CraftEventFactory.MELTING, 1.0F); // CraftBukkit - DamageSource.BURN -> CraftEventFactory.MELTING + } + + for (int l = 0; l < 4; ++l) { +@@ -39,7 +45,17 @@ + j = MathHelper.floor(this.locY); + k = MathHelper.floor(this.locZ + (double) ((float) (l / 2 % 2 * 2 - 1) * 0.25F)); + if (this.world.getType(new BlockPosition(i, j, k)).getBlock().getMaterial() == Material.AIR && this.world.getBiome(new BlockPosition(i, 0, k)).a(new BlockPosition(i, j, k)) < 0.8F && Blocks.SNOW_LAYER.canPlace(this.world, new BlockPosition(i, j, k))) { +- this.world.setTypeUpdate(new BlockPosition(i, j, k), Blocks.SNOW_LAYER.getBlockData()); ++ // CraftBukkit start ++ org.bukkit.block.BlockState blockState = this.world.getWorld().getBlockAt(i, j, k).getState(); ++ blockState.setType(CraftMagicNumbers.getMaterial(Blocks.SNOW_LAYER)); ++ ++ EntityBlockFormEvent event = new EntityBlockFormEvent(this.getBukkitEntity(), blockState.getBlock(), blockState); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if(!event.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/EntitySpider.patch b/paper-server/nms-patches/EntitySpider.patch new file mode 100644 index 0000000000..c9c70dc844 --- /dev/null +++ b/paper-server/nms-patches/EntitySpider.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySpider.java 2014-11-27 08:59:46.733421706 +1100 ++++ src/main/java/net/minecraft/server/EntitySpider.java 2014-11-27 08:42:10.096851020 +1100 +@@ -107,7 +107,7 @@ + + entityskeleton.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F); + entityskeleton.prepare(difficultydamagescaler, (GroupDataEntity) null); +- this.world.addEntity(entityskeleton); ++ this.world.addEntity(entityskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.JOCKEY); // CraftBukkit - add SpawnReason + entityskeleton.mount(this); + } + diff --git a/paper-server/nms-patches/EntitySquid.patch b/paper-server/nms-patches/EntitySquid.patch new file mode 100644 index 0000000000..83d481ae78 --- /dev/null +++ b/paper-server/nms-patches/EntitySquid.patch @@ -0,0 +1,37 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntitySquid.java 2014-11-27 08:59:46.733421706 +1100 ++++ src/main/java/net/minecraft/server/EntitySquid.java 2014-11-27 08:42:10.156850903 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.craftbukkit.TrigMath; // CraftBukkit ++ + public class EntitySquid extends EntityWaterAnimal { + + public float a; +@@ -67,9 +69,11 @@ + + } + ++ /* CraftBukkit start - Delegate to Entity to use existing inWater value + public boolean V() { + return this.world.a(this.getBoundingBox().grow(0.0D, -0.6000000238418579D, 0.0D), Material.WATER, (Entity) this); + } ++ // CraftBukkit end */ + + public void m() { + super.m(); +@@ -116,10 +120,12 @@ + } + + f = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ); +- this.aG += (-((float) Math.atan2(this.motX, this.motZ)) * 180.0F / 3.1415927F - this.aG) * 0.1F; ++ // CraftBukkit - Math -> TrigMath ++ this.aG += (-((float) TrigMath.atan2(this.motX, this.motZ)) * 180.0F / 3.1415927F - this.aG) * 0.1F; + this.yaw = this.aG; + this.c = (float) ((double) this.c + 3.141592653589793D * (double) this.bp * 1.5D); +- this.a += (-((float) Math.atan2((double) f, this.motY)) * 180.0F / 3.1415927F - this.a) * 0.1F; ++ // CraftBukkit - Math -> TrigMath ++ this.a += (-((float) TrigMath.atan2((double) f, this.motY)) * 180.0F / 3.1415927F - this.a) * 0.1F; + } else { + this.bl = MathHelper.e(MathHelper.sin(this.bj)) * 3.1415927F * 0.25F; + if (!this.world.isStatic) { diff --git a/paper-server/nms-patches/EntityTNTPrimed.patch b/paper-server/nms-patches/EntityTNTPrimed.patch new file mode 100644 index 0000000000..96c3399a89 --- /dev/null +++ b/paper-server/nms-patches/EntityTNTPrimed.patch @@ -0,0 +1,52 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityTNTPrimed.java 2014-11-27 08:59:46.737421688 +1100 ++++ src/main/java/net/minecraft/server/EntityTNTPrimed.java 2014-11-27 08:42:10.120850973 +1100 +@@ -1,9 +1,13 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.ExplosionPrimeEvent; // CraftBukkit ++ + public class EntityTNTPrimed extends Entity { + + public int fuseTicks; + private EntityLiving source; ++ public float yield = 4; // CraftBukkit - add field ++ public boolean isIncendiary = false; // CraftBukkit - add field + + public EntityTNTPrimed(World world) { + super(world); +@@ -52,10 +56,13 @@ + } + + if (this.fuseTicks-- <= 0) { +- this.die(); ++ // CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event ++ // this.die(); + if (!this.world.isStatic) { + this.explode(); + } ++ this.die(); ++ // CraftBukkit end + } else { + this.W(); + this.world.addParticle(EnumParticle.SMOKE_NORMAL, this.locX, this.locY + 0.5D, this.locZ, 0.0D, 0.0D, 0.0D, new int[0]); +@@ -64,9 +71,18 @@ + } + + private void explode() { +- float f = 4.0F; ++ // CraftBukkit start ++ // float f = 4.0F; + +- this.world.explode(this, this.locX, this.locY + (double) (this.length / 2.0F), this.locZ, f, true); ++ org.bukkit.craftbukkit.CraftServer server = this.world.getServer(); ++ ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) org.bukkit.craftbukkit.entity.CraftEntity.getEntity(server, this)); ++ server.getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.world.createExplosion(this, this.locX, this.locY + (double) (this.length / 2.0F), this.locZ, event.getRadius(), event.getFire(), true); ++ } ++ // CraftBukkit end + } + + protected void b(NBTTagCompound nbttagcompound) { diff --git a/paper-server/nms-patches/EntityThrownExpBottle.patch b/paper-server/nms-patches/EntityThrownExpBottle.patch new file mode 100644 index 0000000000..c6b40039e2 --- /dev/null +++ b/paper-server/nms-patches/EntityThrownExpBottle.patch @@ -0,0 +1,22 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityThrownExpBottle.java 2014-11-27 08:59:46.737421688 +1100 ++++ src/main/java/net/minecraft/server/EntityThrownExpBottle.java 2014-11-27 08:42:10.112850989 +1100 +@@ -28,8 +28,17 @@ + + protected void a(MovingObjectPosition movingobjectposition) { + if (!this.world.isStatic) { +- this.world.triggerEffect(2002, new BlockPosition(this), 0); +- int i = 3 + this.world.random.nextInt(5) + this.world.random.nextInt(5); ++ // CraftBukkit - moved to after event ++ // this.world.triggerEffect(2002, new BlockPosition(this), 0); ++ int i = 3 + this.world.random.nextInt(5) + this.world.random.nextInt(5); ++ ++ // CraftBukkit start ++ org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, i); ++ i = event.getExperience(); ++ if (event.getShowEffect()) { ++ this.world.triggerEffect(2002, new BlockPosition(this), 0); ++ } ++ // CraftBukkit end + + while (i > 0) { + int j = EntityExperienceOrb.getOrbValue(i); diff --git a/paper-server/nms-patches/EntityTrackerEntry.patch b/paper-server/nms-patches/EntityTrackerEntry.patch new file mode 100644 index 0000000000..9d0f38de61 --- /dev/null +++ b/paper-server/nms-patches/EntityTrackerEntry.patch @@ -0,0 +1,176 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityTrackerEntry.java 2014-11-27 08:59:46.741421670 +1100 ++++ src/main/java/net/minecraft/server/EntityTrackerEntry.java 2014-11-27 08:42:10.136850942 +1100 +@@ -8,6 +8,11 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import org.bukkit.entity.Player; ++import org.bukkit.event.player.PlayerVelocityEvent; ++// CraftBukkit end ++ + public class EntityTrackerEntry { + + private static final Logger p = LogManager.getLogger(); +@@ -74,13 +79,13 @@ + this.broadcast(new PacketPlayOutAttachEntity(0, this.tracker, this.tracker.vehicle)); + } + +- if (this.tracker instanceof EntityItemFrame && this.m % 10 == 0) { ++ if (this.tracker instanceof EntityItemFrame /*&& this.m % 10 == 0*/) { // CraftBukkit - Moved below, should always enter this block + EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker; + ItemStack itemstack = entityitemframe.getItem(); + +- if (itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { ++ if (this.m % 10 == 0 && itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // CraftBukkit - Moved this.m % 10 logic here so item frames do not enter the other blocks + WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.tracker.world); +- Iterator iterator = list.iterator(); ++ Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit + + while (iterator.hasNext()) { + EntityHuman entityhuman = (EntityHuman) iterator.next(); +@@ -115,6 +120,19 @@ + Object object = null; + boolean flag = Math.abs(j1) >= 4 || Math.abs(k1) >= 4 || Math.abs(l1) >= 4 || this.m % 60 == 0; + boolean flag1 = Math.abs(l - this.yRot) >= 4 || Math.abs(i1 - this.xRot) >= 4; ++ ++ // CraftBukkit start - Code moved from below ++ if (flag) { ++ this.xLoc = i; ++ this.yLoc = j; ++ this.zLoc = k; ++ } ++ ++ if (flag1) { ++ this.yRot = l; ++ this.xRot = i1; ++ } ++ // CraftBukkit end + + if (this.m > 0 || this.tracker instanceof EntityArrow) { + if (j1 >= -128 && j1 < 128 && k1 >= -128 && k1 < 128 && l1 >= -128 && l1 < 128 && this.v <= 400 && !this.x && this.y == this.tracker.onGround) { +@@ -128,6 +146,11 @@ + } else { + this.y = this.tracker.onGround; + this.v = 0; ++ // CraftBukkit start - Refresh list of who can see a player before sending teleport packet ++ if (this.tracker instanceof EntityPlayer) { ++ this.scanPlayers(new java.util.ArrayList(this.trackedPlayers)); ++ } ++ // CraftBukkit end + object = new PacketPlayOutEntityTeleport(this.tracker.getId(), i, j, k, (byte) l, (byte) i1, this.tracker.onGround); + } + } +@@ -152,6 +175,7 @@ + } + + this.b(); ++ /* CraftBukkit start - Code moved up + if (flag) { + this.xLoc = i; + this.yLoc = j; +@@ -162,6 +186,7 @@ + this.yRot = l; + this.xRot = i1; + } ++ // CraftBukkit end */ + + this.x = false; + } else { +@@ -193,7 +218,27 @@ + + ++this.m; + if (this.tracker.velocityChanged) { +- this.broadcastIncludingSelf(new PacketPlayOutEntityVelocity(this.tracker)); ++ // CraftBukkit start - Create PlayerVelocity event ++ boolean cancelled = false; ++ ++ if (this.tracker instanceof EntityPlayer) { ++ Player player = (Player) this.tracker.getBukkitEntity(); ++ org.bukkit.util.Vector velocity = player.getVelocity(); ++ ++ PlayerVelocityEvent event = new PlayerVelocityEvent(player, velocity); ++ this.tracker.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ cancelled = true; ++ } else if (!velocity.equals(event.getVelocity())) { ++ player.setVelocity(velocity); ++ } ++ } ++ ++ if (!cancelled) { ++ this.broadcastIncludingSelf(new PacketPlayOutEntityVelocity(this.tracker)); ++ } ++ // CraftBukkit end + this.tracker.velocityChanged = false; + } + +@@ -211,6 +256,11 @@ + Set set = attributemapserver.getAttributes(); + + if (!set.isEmpty()) { ++ // CraftBukkit start - Send scaled max health ++ if (this.tracker instanceof EntityPlayer) { ++ ((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(set, false); ++ } ++ // CraftBukkit end + this.broadcastIncludingSelf(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set)); + } + +@@ -260,7 +310,17 @@ + public void updatePlayer(EntityPlayer entityplayer) { + if (entityplayer != this.tracker) { + if (this.c(entityplayer)) { +- if (!this.trackedPlayers.contains(entityplayer) && (this.e(entityplayer) || this.tracker.attachedToPlayer)) { ++ if (!this.trackedPlayers.contains(entityplayer) && (this.e(entityplayer) || this.tracker.attachedToPlayer)) { ++ // CraftBukkit start - respect vanish API ++ if (this.tracker instanceof EntityPlayer) { ++ Player player = ((EntityPlayer) this.tracker).getBukkitEntity(); ++ if (!entityplayer.getBukkitEntity().canSee(player)) { ++ return; ++ } ++ } ++ ++ entityplayer.removeQueue.remove(Integer.valueOf(this.tracker.getId())); ++ // CraftBukkit end + this.trackedPlayers.add(entityplayer); + Packet packet = this.c(); + +@@ -278,6 +338,12 @@ + if (this.tracker instanceof EntityLiving) { + AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap(); + Collection collection = attributemapserver.c(); ++ ++ // CraftBukkit start - If sending own attributes send scaled health instead of current maximum health ++ if (this.tracker.getId() == entityplayer.getId()) { ++ ((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(collection, false); ++ } ++ // CraftBukkit end + + if (!collection.isEmpty()) { + entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(this.tracker.getId(), collection)); +@@ -316,6 +382,11 @@ + entityplayer.playerConnection.sendPacket(new PacketPlayOutBed(entityhuman, new BlockPosition(this.tracker))); + } + } ++ ++ // CraftBukkit start - Fix for nonsensical head yaw ++ this.i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F); ++ this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i)); ++ // CraftBukkit end + + if (this.tracker instanceof EntityLiving) { + EntityLiving entityliving = (EntityLiving) this.tracker; +@@ -356,7 +427,10 @@ + + private Packet c() { + if (this.tracker.dead) { +- EntityTrackerEntry.p.warn("Fetching addPacket for removed entity"); ++ // CraftBukkit start - Remove useless error spam, just return ++ // EntityTrackerEntry.p.warn("Fetching addPacket for removed entity"); ++ return null; ++ // CraftBukkit end + } + + if (this.tracker instanceof EntityItem) { diff --git a/paper-server/nms-patches/EntityVillager.patch b/paper-server/nms-patches/EntityVillager.patch new file mode 100644 index 0000000000..e2b327aebd --- /dev/null +++ b/paper-server/nms-patches/EntityVillager.patch @@ -0,0 +1,19 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityVillager.java 2014-11-27 08:59:46.741421670 +1100 ++++ src/main/java/net/minecraft/server/EntityVillager.java 2014-11-27 08:42:10.144850927 +1100 +@@ -1,6 +1,7 @@ + package net.minecraft.server; + + import java.util.Iterator; ++import org.bukkit.craftbukkit.entity.CraftVillager; + + public class EntityVillager extends EntityAgeable implements NPC, IMerchant { + +@@ -28,7 +29,7 @@ + + public EntityVillager(World world, int i) { + super(world); +- this.inventory = new InventorySubcontainer("Items", false, 8); ++ this.inventory = new InventorySubcontainer("Items", false, 8, (CraftVillager) this.getBukkitEntity()); // CraftBukkit add argument + this.setProfession(i); + this.a(0.6F, 1.8F); + ((Navigation) this.getNavigation()).b(true); diff --git a/paper-server/nms-patches/EntityWither.patch b/paper-server/nms-patches/EntityWither.patch new file mode 100644 index 0000000000..7caa58e9cc --- /dev/null +++ b/paper-server/nms-patches/EntityWither.patch @@ -0,0 +1,78 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityWither.java 2014-11-27 08:59:46.745421653 +1100 ++++ src/main/java/net/minecraft/server/EntityWither.java 2014-11-27 08:42:10.156850903 +1100 +@@ -5,6 +5,12 @@ + import java.util.Iterator; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityRegainHealthEvent; ++import org.bukkit.event.entity.ExplosionPrimeEvent; ++// CraftBukkit end ++ + public class EntityWither extends EntityMonster implements IRangedEntity { + + private float[] b = new float[2]; +@@ -160,13 +166,38 @@ + if (this.cj() > 0) { + i = this.cj() - 1; + if (i <= 0) { +- this.world.createExplosion(this, this.locX, this.locY + (double) this.getHeadHeight(), this.locZ, 7.0F, false, this.world.getGameRules().getBoolean("mobGriefing")); +- this.world.a(1013, new BlockPosition(this), 0); ++ // CraftBukkit start ++ // this.world.createExplosion(this, this.locX, this.locY + (double) this.getHeadHeight(), this.locZ, 7.0F, false, this.world.getGameRules().getBoolean("mobGriefing")); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.world.createExplosion(this, this.locX, this.locY + (double) this.getHeadHeight(), this.locZ, event.getRadius(), event.getFire(), this.world.getGameRules().getBoolean("mobGriefing")); ++ } ++ // CraftBukkit end ++ ++ // CraftBukkit start - Use relative location for far away sounds ++ // this.world.a(1013, new BlockPosition(this), 0); ++ int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16; ++ for (EntityPlayer player : (List) this.world.players) { ++ double deltaX = this.locX - player.locX; ++ double deltaZ = this.locZ - player.locZ; ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.locX + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.locZ + (deltaZ / deltaLength) * viewDistance; ++ player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1013, new BlockPosition((int) relativeX, (int) this.locY, (int) relativeZ), 0, true)); ++ } else { ++ player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1013, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0, true)); ++ } ++ } ++ // CraftBukkit end + } + + this.r(i); + if (this.ticksLived % 10 == 0) { +- this.heal(10.0F); ++ this.heal(10.0F, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit + } + + } else { +@@ -251,6 +282,11 @@ + Block block = this.world.getType(new BlockPosition(j2, k2, l2)).getBlock(); + + if (block.getMaterial() != Material.AIR && block != Blocks.BEDROCK && block != Blocks.END_PORTAL && block != Blocks.END_PORTAL_FRAME && block != Blocks.COMMAND_BLOCK && block != Blocks.BARRIER) { ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, j2, k2, l2, Blocks.AIR, 0).isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end + flag = this.world.setAir(new BlockPosition(j2, k2, l2), true) || flag; + } + } +@@ -264,7 +300,7 @@ + } + + if (this.ticksLived % 20 == 0) { +- this.heal(1.0F); ++ this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit + } + + } diff --git a/paper-server/nms-patches/EntityWitherSkull.patch b/paper-server/nms-patches/EntityWitherSkull.patch new file mode 100644 index 0000000000..1428bf512e --- /dev/null +++ b/paper-server/nms-patches/EntityWitherSkull.patch @@ -0,0 +1,36 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityWitherSkull.java 2014-11-27 08:59:46.745421653 +1100 ++++ src/main/java/net/minecraft/server/EntityWitherSkull.java 2014-11-27 08:42:10.120850973 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.ExplosionPrimeEvent; // CraftBukkit ++ + public class EntityWitherSkull extends EntityFireball { + + public EntityWitherSkull(World world) { +@@ -36,7 +38,7 @@ + if (this.shooter != null) { + if (movingobjectposition.entity.damageEntity(DamageSource.mobAttack(this.shooter), 8.0F)) { + if (!movingobjectposition.entity.isAlive()) { +- this.shooter.heal(5.0F); ++ this.shooter.heal(5.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER); // CraftBukkit + } else { + this.a(this.shooter, movingobjectposition.entity); + } +@@ -60,7 +62,15 @@ + } + } + +- this.world.createExplosion(this, this.locX, this.locY, this.locZ, 1.0F, false, this.world.getGameRules().getBoolean("mobGriefing")); ++ // CraftBukkit start ++ // this.world.createExplosion(this, this.locX, this.locY, this.locZ, 1.0F, false, this.world.getGameRules().getBoolean("mobGriefing")); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire(), this.world.getGameRules().getBoolean("mobGriefing")); ++ } ++ // CraftBukkit end + this.die(); + } + diff --git a/paper-server/nms-patches/EntityWolf.patch b/paper-server/nms-patches/EntityWolf.patch new file mode 100644 index 0000000000..1621a4842c --- /dev/null +++ b/paper-server/nms-patches/EntityWolf.patch @@ -0,0 +1,87 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityWolf.java 2014-11-27 08:59:46.749421635 +1100 ++++ src/main/java/net/minecraft/server/EntityWolf.java 2014-11-27 08:42:10.160850895 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTargetEvent.TargetReason; ++// CraftBukkit end ++ + public class EntityWolf extends EntityTameableAnimal { + + private float bm; +@@ -51,8 +56,19 @@ + } else if (!this.isTamed()) { + this.setAngry(true); + } ++ } + ++ // CraftBukkit - add overriden version ++ @Override ++ public void setGoalTarget(EntityLiving entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fire) { ++ super.setGoalTarget(entityliving, reason, fire); ++ if (entityliving == null) { ++ this.setAngry(false); ++ } else if (!this.isTamed()) { ++ this.setAngry(true); ++ } + } ++ // CraftBukkit end + + protected void E() { + this.datawatcher.watch(18, Float.valueOf(this.getHealth())); +@@ -85,7 +101,8 @@ + } + + protected String z() { +- return this.isAngry() ? "mob.wolf.growl" : (this.random.nextInt(3) == 0 ? (this.isTamed() && this.datawatcher.getFloat(18) < 10.0F ? "mob.wolf.whine" : "mob.wolf.panting") : "mob.wolf.bark"); ++ // CraftBukkit - (getFloat(18) < 10) -> (getFloat(18) < this.getMaxHealth() / 2) ++ return this.isAngry() ? "mob.wolf.growl" : (this.random.nextInt(3) == 0 ? (this.isTamed() && this.datawatcher.getFloat(18) < this.getMaxHealth() / 2 ? "mob.wolf.whine" : "mob.wolf.panting") : "mob.wolf.bark"); + } + + protected String bn() { +@@ -219,7 +236,7 @@ + --itemstack.count; + } + +- this.heal((float) itemfood.getNutrition(itemstack)); ++ this.heal((float) itemfood.getNutrition(itemstack), org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit + if (itemstack.count <= 0) { + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, (ItemStack) null); + } +@@ -244,7 +261,7 @@ + this.bk.setSitting(!this.isSitting()); + this.aW = false; + this.navigation.n(); +- this.setGoalTarget((EntityLiving) null); ++ this.setGoalTarget((EntityLiving) null, TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason + } + } else if (itemstack != null && itemstack.getItem() == Items.BONE && !this.isAngry()) { + if (!entityhuman.abilities.canInstantlyBuild) { +@@ -256,12 +273,13 @@ + } + + if (!this.world.isStatic) { +- if (this.random.nextInt(3) == 0) { ++ // CraftBukkit - added event call and isCancelled check. ++ if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { + this.setTamed(true); + this.navigation.n(); +- this.setGoalTarget((EntityLiving) null); ++ this.setGoalTarget((EntityLiving) null, TargetReason.FORGOT_TARGET, true); + this.bk.setSitting(true); +- this.setHealth(20.0F); ++ this.setHealth(this.getMaxHealth()); // CraftBukkit - 20.0 -> getMaxHealth() + this.setOwnerUUID(entityhuman.getUniqueID().toString()); + this.l(true); + this.world.broadcastEntityEffect(this, (byte) 7); +@@ -348,7 +366,7 @@ + } + + protected boolean isTypeNotPersistent() { +- return !this.isTamed() && this.ticksLived > 2400; ++ return !this.isTamed() /*&& this.ticksLived > 2400*/; // CraftBukkit + } + + public boolean a(EntityLiving entityliving, EntityLiving entityliving1) { diff --git a/paper-server/nms-patches/EntityZombie.patch b/paper-server/nms-patches/EntityZombie.patch new file mode 100644 index 0000000000..634ca93999 --- /dev/null +++ b/paper-server/nms-patches/EntityZombie.patch @@ -0,0 +1,108 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/EntityZombie.java 2014-11-27 08:59:46.749421635 +1100 ++++ src/main/java/net/minecraft/server/EntityZombie.java 2014-11-27 08:42:10.144850927 +1100 +@@ -4,6 +4,14 @@ + import java.util.List; + import java.util.UUID; + ++//CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftLivingEntity; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.entity.EntityCombustEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++//CraftBukkit end ++ + public class EntityZombie extends EntityMonster { + + protected static final IAttribute b = (new AttributeRanged((IAttribute) null, "zombie.spawnReinforcements", 0.0D, 0.0D, 1.0D)).a("Spawn Reinforcements Chance"); +@@ -14,6 +22,7 @@ + private boolean bn = false; + private float bo = -1.0F; + private float bp; ++ private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field + + public EntityZombie(World world) { + super(world); +@@ -136,7 +145,14 @@ + } + + if (flag) { +- this.setOnFire(8); ++ // CraftBukkit start ++ EntityCombustEvent event = new EntityCombustEvent(this.getBukkitEntity(), 8); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.setOnFire(event.getDuration()); ++ } ++ // CraftBukkit end + } + } + } +@@ -170,8 +186,8 @@ + if (World.a((IBlockAccess) this.world, new BlockPosition(i1, j1 - 1, k1)) && this.world.getLightLevel(new BlockPosition(i1, j1, k1)) < 10) { + entityzombie.setPosition((double) i1, (double) j1, (double) k1); + if (!this.world.isPlayerNearby((double) i1, (double) j1, (double) k1, 7.0D) && this.world.a(entityzombie.getBoundingBox(), (Entity) entityzombie) && this.world.getCubes(entityzombie, entityzombie.getBoundingBox()).isEmpty() && !this.world.containsLiquid(entityzombie.getBoundingBox())) { +- this.world.addEntity(entityzombie); +- entityzombie.setGoalTarget(entityliving); ++ this.world.addEntity(entityzombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit ++ entityzombie.setGoalTarget(entityliving, EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET, true); + entityzombie.prepare(this.world.E(new BlockPosition(entityzombie)), (GroupDataEntity) null); + this.getAttributeInstance(EntityZombie.b).b(new AttributeModifier("Zombie reinforcement caller charge", -0.05000000074505806D, 0)); + entityzombie.getAttributeInstance(EntityZombie.b).b(new AttributeModifier("Zombie reinforcement callee charge", -0.05000000074505806D, 0)); +@@ -190,6 +206,12 @@ + public void s_() { + if (!this.world.isStatic && this.cn()) { + int i = this.cp(); ++ ++ // CraftBukkit start - Use wall time instead of ticks for villager conversion ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ this.lastTick = MinecraftServer.currentTick; ++ i *= elapsedTicks; ++ // CraftBukkit end + + this.bm -= i; + if (this.bm <= 0) { +@@ -207,7 +229,14 @@ + int i = this.world.getDifficulty().a(); + + if (this.bz() == null && this.isBurning() && this.random.nextFloat() < (float) i * 0.3F) { +- entity.setOnFire(2 * i); ++ // CraftBukkit start ++ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 2 * i); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ entity.setOnFire(event.getDuration()); ++ } ++ // CraftBukkit end + } + } + +@@ -316,7 +345,7 @@ + entityzombie.setBaby(true); + } + +- this.world.addEntity(entityzombie); ++ this.world.addEntity(entityzombie, CreatureSpawnEvent.SpawnReason.INFECTION); // CraftBukkit - add SpawnReason + this.world.a((EntityHuman) null, 1016, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0); + } + +@@ -369,7 +398,7 @@ + entitychicken1.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F); + entitychicken1.prepare(difficultydamagescaler, (GroupDataEntity) null); + entitychicken1.l(true); +- this.world.addEntity(entitychicken1); ++ this.world.addEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); + this.mount(entitychicken1); + } + } +@@ -452,7 +481,7 @@ + } + + this.world.kill(this); +- this.world.addEntity(entityvillager); ++ this.world.addEntity(entityvillager, CreatureSpawnEvent.SpawnReason.CURED); // CraftBukkit - add SpawnReason + entityvillager.addEffect(new MobEffect(MobEffectList.CONFUSION.id, 200, 0)); + this.world.a((EntityHuman) null, 1017, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0); + } diff --git a/paper-server/nms-patches/ExpirableListEntry.patch b/paper-server/nms-patches/ExpirableListEntry.patch new file mode 100644 index 0000000000..6bb3d3918f --- /dev/null +++ b/paper-server/nms-patches/ExpirableListEntry.patch @@ -0,0 +1,42 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ExpirableListEntry.java 2014-11-27 08:59:46.749421635 +1100 ++++ src/main/java/net/minecraft/server/ExpirableListEntry.java 2014-11-27 08:42:10.096851020 +1100 +@@ -22,7 +22,7 @@ + } + + protected ExpirableListEntry(Object object, JsonObject jsonobject) { +- super(object, jsonobject); ++ super(checkExpiry(object, jsonobject), jsonobject); + + Date date; + +@@ -65,4 +65,30 @@ + jsonobject.addProperty("expires", this.d == null ? "forever" : ExpirableListEntry.a.format(this.d)); + jsonobject.addProperty("reason", this.e); + } ++ ++ // CraftBukkit start ++ public String getSource() { ++ return this.c; ++ } ++ ++ public Date getCreated() { ++ return this.b; ++ } ++ ++ private static Object checkExpiry(Object object, JsonObject jsonobject) { ++ Date expires = null; ++ ++ try { ++ expires = jsonobject.has("expires") ? a.parse(jsonobject.get("expires").getAsString()) : null; ++ } catch (ParseException ex) { ++ // Guess we don't have a date ++ } ++ ++ if (expires == null || expires.after(new Date())) { ++ return object; ++ } else { ++ return null; ++ } ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/Explosion.patch b/paper-server/nms-patches/Explosion.patch new file mode 100644 index 0000000000..3d0b5b84c2 --- /dev/null +++ b/paper-server/nms-patches/Explosion.patch @@ -0,0 +1,127 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Explosion.java 2014-11-27 08:59:46.753421618 +1100 ++++ src/main/java/net/minecraft/server/Explosion.java 2014-11-27 08:42:10.160850895 +1100 +@@ -8,6 +8,12 @@ + import java.util.List; + import java.util.Map; + import java.util.Random; ++ ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityExplodeEvent; ++import org.bukkit.Location; ++// CraftBukkit end + + public class Explosion { + +@@ -22,11 +28,12 @@ + private final float size; + private final List blocks = Lists.newArrayList(); + private final Map k = Maps.newHashMap(); ++ public boolean wasCanceled = false; // CraftBukkit - add field + + public Explosion(World world, Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) { + this.world = world; + this.source = entity; +- this.size = f; ++ this.size = (float) Math.max(f, 0.0); // CraftBukkit - clamp bad values + this.posX = d0; + this.posY = d1; + this.posZ = d2; +@@ -35,6 +42,12 @@ + } + + public void a() { ++ // CraftBukkit start ++ if (this.size < 0.1F) { ++ return; ++ } ++ // CraftBukkit end ++ + HashSet hashset = Sets.newHashSet(); + boolean flag = true; + +@@ -68,7 +81,7 @@ + f -= (f2 + 0.3F) * 0.3F; + } + +- if (f > 0.0F && (this.source == null || this.source.a(this, this.world, blockposition, iblockdata, f))) { ++ if (f > 0.0F && (this.source == null || this.source.a(this, this.world, blockposition, iblockdata, f)) && blockposition.getY() < 256 && blockposition.getY() >= 0) { // CraftBukkit - don't wrap explosions + hashset.add(blockposition); + } + +@@ -112,7 +125,14 @@ + double d12 = (double) this.world.a(vec3d, entity.getBoundingBox()); + double d13 = (1.0D - d7) * d12; + ++ // entity.damageEntity(DamageSource.explosion(this), (float) ((int) ((d13 * d13 + d13) / 2.0D * 8.0D * (double) f3 + 1.0D))); ++ ++ // CraftBukkit start ++ CraftEventFactory.entityDamage = source; + entity.damageEntity(DamageSource.explosion(this), (float) ((int) ((d13 * d13 + d13) / 2.0D * 8.0D * (double) f3 + 1.0D))); ++ CraftEventFactory.entityDamage = null; ++ // CraftBukkit end ++ + double d14 = EnchantmentProtection.a(entity, d13); + + entity.motX += d8 * d14; +@@ -140,6 +160,35 @@ + BlockPosition blockposition; + + if (this.b) { ++ // CraftBukkit start ++ org.bukkit.World bworld = this.world.getWorld(); ++ org.bukkit.entity.Entity explode = this.source == null ? null : this.source.getBukkitEntity(); ++ Location location = new Location(bworld, this.posX, this.posY, this.posZ); ++ ++ List blockList = Lists.newArrayList(); ++ for (int i1 = this.blocks.size() - 1; i1 >= 0; i1--) { ++ BlockPosition cpos = (BlockPosition) this.blocks.get(i1); ++ org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ()); ++ if (bblock.getType() != org.bukkit.Material.AIR) { ++ blockList.add(bblock); ++ } ++ } ++ ++ EntityExplodeEvent event = new EntityExplodeEvent(explode, location, blockList, 0.3F); ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ this.blocks.clear(); ++ ++ for (org.bukkit.block.Block bblock : event.blockList()) { ++ BlockPosition coords = new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ()); ++ blocks.add(coords); ++ } ++ ++ if (event.isCancelled()) { ++ this.wasCanceled = true; ++ return; ++ } ++ // CraftBukkit end + iterator = this.blocks.iterator(); + + while (iterator.hasNext()) { +@@ -170,7 +219,8 @@ + + if (block.getMaterial() != Material.AIR) { + if (block.a(this)) { +- block.dropNaturally(this.world, blockposition, this.world.getType(blockposition), 1.0F / this.size, 0); ++ // CraftBukkit - add yield ++ block.dropNaturally(this.world, blockposition, this.world.getType(blockposition), event.getYield(), 0); + } + + this.world.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 3); +@@ -184,8 +234,12 @@ + + while (iterator.hasNext()) { + blockposition = (BlockPosition) iterator.next(); +- if (this.world.getType(blockposition).getBlock().getMaterial() == Material.AIR && this.world.getType(blockposition.down()).getBlock().m() && this.c.nextInt(3) == 0) { +- this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ if (this.world.getType(blockposition).getBlock().getMaterial() == Material.AIR && this.world.getType(blockposition.down()).getBlock().m() && this.c.nextInt(3) == 0) { ++ // CraftBukkit start - Ignition by explosion ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this).isCancelled()) { ++ this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ } ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/FoodMetaData.patch b/paper-server/nms-patches/FoodMetaData.patch new file mode 100644 index 0000000000..bfd974b35a --- /dev/null +++ b/paper-server/nms-patches/FoodMetaData.patch @@ -0,0 +1,66 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/FoodMetaData.java 2014-11-27 08:59:46.753421618 +1100 ++++ src/main/java/net/minecraft/server/FoodMetaData.java 2014-11-27 08:42:10.104851005 +1100 +@@ -6,9 +6,17 @@ + public float saturationLevel = 5.0F; + public float exhaustionLevel; + public int foodTickTimer; ++ private EntityHuman entityhuman; // CraftBukkit + private int e = 20; + +- public FoodMetaData() {} ++ public FoodMetaData() { throw new AssertionError("Whoopsie, we missed the bukkit."); } // CraftBukkit start - throw an error ++ ++ // CraftBukkit start - added EntityHuman constructor ++ public FoodMetaData(EntityHuman entityhuman) { ++ org.apache.commons.lang.Validate.notNull(entityhuman); ++ this.entityhuman = entityhuman; ++ } ++ // CraftBukkit end + + public void eat(int i, float f) { + this.foodLevel = Math.min(i + this.foodLevel, 20); +@@ -16,7 +24,17 @@ + } + + public void a(ItemFood itemfood, ItemStack itemstack) { +- this.eat(itemfood.getNutrition(itemstack), itemfood.getSaturationModifier(itemstack)); ++ // CraftBukkit start ++ int oldFoodLevel = foodLevel; ++ ++ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(entityhuman, itemfood.getNutrition(itemstack) + oldFoodLevel); ++ ++ if (!event.isCancelled()) { ++ this.eat(event.getFoodLevel() - oldFoodLevel, itemfood.getSaturationModifier(itemstack)); ++ } ++ ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutUpdateHealth(((EntityPlayer) entityhuman).getBukkitEntity().getScaledHealth(), entityhuman.getFoodData().foodLevel, entityhuman.getFoodData().saturationLevel)); ++ // CraftBukkit end + } + + public void a(EntityHuman entityhuman) { +@@ -28,14 +46,23 @@ + if (this.saturationLevel > 0.0F) { + this.saturationLevel = Math.max(this.saturationLevel - 1.0F, 0.0F); + } else if (enumdifficulty != EnumDifficulty.PEACEFUL) { +- this.foodLevel = Math.max(this.foodLevel - 1, 0); ++ // CraftBukkit start ++ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(entityhuman, Math.max(this.foodLevel - 1, 0)); ++ ++ if (!event.isCancelled()) { ++ this.foodLevel = event.getFoodLevel(); ++ } ++ ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutUpdateHealth(((EntityPlayer) entityhuman).getBukkitEntity().getScaledHealth(), this.foodLevel, this.saturationLevel)); ++ // CraftBukkit end + } + } + + if (entityhuman.world.getGameRules().getBoolean("naturalRegeneration") && this.foodLevel >= 18 && entityhuman.cl()) { + ++this.foodTickTimer; + if (this.foodTickTimer >= 80) { +- entityhuman.heal(1.0F); ++ // CraftBukkit - added RegainReason ++ entityhuman.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); + this.a(3.0F); + this.foodTickTimer = 0; + } diff --git a/paper-server/nms-patches/HandshakeListener.patch b/paper-server/nms-patches/HandshakeListener.patch new file mode 100644 index 0000000000..651b7fee09 --- /dev/null +++ b/paper-server/nms-patches/HandshakeListener.patch @@ -0,0 +1,69 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/HandshakeListener.java 2014-11-27 08:59:46.757421600 +1100 ++++ src/main/java/net/minecraft/server/HandshakeListener.java 2014-11-27 08:42:10.100851012 +1100 +@@ -1,6 +1,16 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.net.InetAddress; ++import java.util.HashMap; ++// CraftBukkit end ++ + public class HandshakeListener implements PacketHandshakingInListener { ++ ++ // CraftBukkit start - add fields ++ private static final HashMap throttleTracker = new HashMap(); ++ private static int throttleCounter = 0; ++ // CraftBukkit end + + private final MinecraftServer a; + private final NetworkManager b; +@@ -15,6 +25,41 @@ + case 1: + this.b.a(EnumProtocol.LOGIN); + ChatComponentText chatcomponenttext; ++ ++ // CraftBukkit start - Connection throttle ++ try { ++ long currentTime = System.currentTimeMillis(); ++ long connectionThrottle = MinecraftServer.getServer().server.getConnectionThrottle(); ++ InetAddress address = ((java.net.InetSocketAddress) this.b.getSocketAddress()).getAddress(); ++ ++ synchronized (throttleTracker) { ++ if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) { ++ throttleTracker.put(address, currentTime); ++ chatcomponenttext = new ChatComponentText("Connection throttled! Please wait before reconnecting."); ++ this.b.handle(new PacketLoginOutDisconnect(chatcomponenttext)); ++ this.b.close(chatcomponenttext); ++ return; ++ } ++ ++ throttleTracker.put(address, currentTime); ++ throttleCounter++; ++ if (throttleCounter > 200) { ++ throttleCounter = 0; ++ ++ // Cleanup stale entries ++ java.util.Iterator iter = throttleTracker.entrySet().iterator(); ++ while (iter.hasNext()) { ++ java.util.Map.Entry entry = (java.util.Map.Entry) iter.next(); ++ if (entry.getValue() > connectionThrottle) { ++ iter.remove(); ++ } ++ } ++ } ++ } ++ } catch (Throwable t) { ++ org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t); ++ } ++ // CraftBukkit end + + if (packethandshakinginsetprotocol.b() > 47) { + chatcomponenttext = new ChatComponentText("Outdated server! I\'m still on 1.8"); +@@ -26,6 +71,7 @@ + this.b.close(chatcomponenttext); + } else { + this.b.a((PacketListener) (new LoginListener(this.a, this.b))); ++ ((LoginListener) this.b.getPacketListener()).hostname = packethandshakinginsetprotocol.b + ":" + packethandshakinginsetprotocol.c; // CraftBukkit - set hostname + } + break; + diff --git a/paper-server/nms-patches/IDataManager.patch b/paper-server/nms-patches/IDataManager.patch new file mode 100644 index 0000000000..0c8a372309 --- /dev/null +++ b/paper-server/nms-patches/IDataManager.patch @@ -0,0 +1,18 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/IDataManager.java 2014-11-27 08:59:46.757421600 +1100 ++++ src/main/java/net/minecraft/server/IDataManager.java 2014-11-27 08:42:10.104851005 +1100 +@@ -6,7 +6,7 @@ + + WorldData getWorldData(); + +- void checkSession(); ++ void checkSession() throws ExceptionWorldConflict; // CraftBukkit - throws ExceptionWorldConflict + + IChunkLoader createChunkLoader(WorldProvider worldprovider); + +@@ -23,4 +23,6 @@ + File getDataFile(String s); + + String g(); ++ ++ java.util.UUID getUUID(); // CraftBukkit + } diff --git a/paper-server/nms-patches/IInventory.patch b/paper-server/nms-patches/IInventory.patch new file mode 100644 index 0000000000..d65dcde87f --- /dev/null +++ b/paper-server/nms-patches/IInventory.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/IInventory.java 2014-11-27 08:59:46.757421600 +1100 ++++ src/main/java/net/minecraft/server/IInventory.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; // CraftBukkit ++ + public interface IInventory extends INamableTileEntity { + + int getSize(); +@@ -31,4 +33,20 @@ + int g(); + + void l(); ++ ++ // CraftBukkit start ++ ItemStack[] getContents(); ++ ++ void onOpen(CraftHumanEntity who); ++ ++ void onClose(CraftHumanEntity who); ++ ++ java.util.List getViewers(); ++ ++ org.bukkit.inventory.InventoryHolder getOwner(); ++ ++ void setMaxStackSize(int size); ++ ++ int MAX_STACK = 64; ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/IRecipe.patch b/paper-server/nms-patches/IRecipe.patch new file mode 100644 index 0000000000..cdc6680143 --- /dev/null +++ b/paper-server/nms-patches/IRecipe.patch @@ -0,0 +1,9 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/IRecipe.java 2014-11-27 08:59:46.769421547 +1100 ++++ src/main/java/net/minecraft/server/IRecipe.java 2014-11-27 08:42:10.168850880 +1100 +@@ -11,4 +11,6 @@ + ItemStack b(); + + ItemStack[] b(InventoryCrafting inventorycrafting); ++ ++ org.bukkit.inventory.Recipe toBukkitRecipe(); // CraftBukkit + } diff --git a/paper-server/nms-patches/InventoryCraftResult.patch b/paper-server/nms-patches/InventoryCraftResult.patch new file mode 100644 index 0000000000..af51f97f94 --- /dev/null +++ b/paper-server/nms-patches/InventoryCraftResult.patch @@ -0,0 +1,48 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventoryCraftResult.java 2014-11-27 08:59:46.761421583 +1100 ++++ src/main/java/net/minecraft/server/InventoryCraftResult.java 2014-11-27 08:42:10.140850934 +1100 +@@ -1,8 +1,36 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class InventoryCraftResult implements IInventory { + + private ItemStack[] items = new ItemStack[1]; ++ ++ // CraftBukkit start ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return null; // Result slots don't get an owner ++ } ++ ++ // Don't need a transaction; the InventoryCrafting keeps track of it for us ++ public void onOpen(CraftHumanEntity who) {} ++ public void onClose(CraftHumanEntity who) {} ++ public java.util.List getViewers() { ++ return new java.util.ArrayList(); ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public InventoryCraftResult() {} + +@@ -53,7 +81,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public void update() {} diff --git a/paper-server/nms-patches/InventoryCrafting.patch b/paper-server/nms-patches/InventoryCrafting.patch new file mode 100644 index 0000000000..84e27a9940 --- /dev/null +++ b/paper-server/nms-patches/InventoryCrafting.patch @@ -0,0 +1,64 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventoryCrafting.java 2014-11-27 08:59:46.761421583 +1100 ++++ src/main/java/net/minecraft/server/InventoryCrafting.java 2014-11-27 08:42:10.152850911 +1100 +@@ -1,11 +1,61 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.event.inventory.InventoryType; ++// CraftBukkit end ++ + public class InventoryCrafting implements IInventory { + + private final ItemStack[] items; + private final int b; + private final int c; + private final Container d; ++ ++ // CraftBukkit start - add fields ++ public List transaction = new java.util.ArrayList(); ++ public IRecipe currentRecipe; ++ public IInventory resultInventory; ++ private EntityHuman owner; ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public InventoryType getInvType() { ++ return items.length == 4 ? InventoryType.CRAFTING : InventoryType.WORKBENCH; ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return owner.getBukkitEntity(); ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ resultInventory.setMaxStackSize(size); ++ } ++ ++ public InventoryCrafting(Container container, int i, int j, EntityHuman player) { ++ this(container, i, j); ++ this.owner = player; ++ } ++ // CraftBukkit end + + public InventoryCrafting(Container container, int i, int j) { + int k = i * j; diff --git a/paper-server/nms-patches/InventoryEnderChest.patch b/paper-server/nms-patches/InventoryEnderChest.patch new file mode 100644 index 0000000000..ee181fb3a0 --- /dev/null +++ b/paper-server/nms-patches/InventoryEnderChest.patch @@ -0,0 +1,51 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventoryEnderChest.java 2014-11-27 08:59:46.761421583 +1100 ++++ src/main/java/net/minecraft/server/InventoryEnderChest.java 2014-11-27 08:42:10.096851020 +1100 +@@ -1,8 +1,48 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class InventoryEnderChest extends InventorySubcontainer { + + private TileEntityEnderChest a; ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ public org.bukkit.entity.Player player; ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return this.player; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ ++ public int getMaxStackSize() { ++ return maxStack; ++ } ++ // CraftBukkit end + + public InventoryEnderChest() { + super("container.enderchest", false, 27); diff --git a/paper-server/nms-patches/InventoryHorseChest.patch b/paper-server/nms-patches/InventoryHorseChest.patch new file mode 100644 index 0000000000..4146987edc --- /dev/null +++ b/paper-server/nms-patches/InventoryHorseChest.patch @@ -0,0 +1,63 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventoryHorseChest.java 2014-11-27 08:59:46.765421565 +1100 ++++ src/main/java/net/minecraft/server/InventoryHorseChest.java 2014-11-27 08:42:10.172850872 +1100 +@@ -1,8 +1,60 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class InventoryHorseChest extends InventorySubcontainer { + + public InventoryHorseChest(String s, int i) { + super(s, false, i); + } ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private EntityHorse horse; ++ private int maxStack = MAX_STACK; ++ ++ public InventoryHorseChest(String s, int i, EntityHorse horse) { ++ super(s, false, i, (org.bukkit.craftbukkit.entity.CraftHorse) horse.getBukkitEntity()); ++ this.horse = horse; ++ } ++ ++ @Override ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ @Override ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ @Override ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ @Override ++ public List getViewers() { ++ return transaction; ++ } ++ ++ @Override ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return (org.bukkit.entity.Horse) this.horse.getBukkitEntity(); ++ } ++ ++ @Override ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return maxStack; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/InventoryLargeChest.patch b/paper-server/nms-patches/InventoryLargeChest.patch new file mode 100644 index 0000000000..2e1b2eaad7 --- /dev/null +++ b/paper-server/nms-patches/InventoryLargeChest.patch @@ -0,0 +1,66 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventoryLargeChest.java 2014-11-27 08:59:46.765421565 +1100 ++++ src/main/java/net/minecraft/server/InventoryLargeChest.java 2014-11-27 08:42:10.164850887 +1100 +@@ -1,10 +1,54 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class InventoryLargeChest implements ITileInventory { + + private String a; + public ITileInventory left; + public ITileInventory right; ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ ++ public ItemStack[] getContents() { ++ ItemStack[] result = new ItemStack[this.getSize()]; ++ for (int i = 0; i < result.length; i++) { ++ result[i] = this.getItem(i); ++ } ++ return result; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ this.left.onOpen(who); ++ this.right.onOpen(who); ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ this.left.onClose(who); ++ this.right.onClose(who); ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return null; // This method won't be called since CraftInventoryDoubleChest doesn't defer to here ++ } ++ ++ public void setMaxStackSize(int size) { ++ this.left.setMaxStackSize(size); ++ this.right.setMaxStackSize(size); ++ } ++ // CraftBukkit end + + public InventoryLargeChest(String s, ITileInventory itileinventory, ITileInventory itileinventory1) { + this.a = s; +@@ -68,7 +112,7 @@ + } + + public int getMaxStackSize() { +- return this.left.getMaxStackSize(); ++ return Math.min(this.left.getMaxStackSize(), this.right.getMaxStackSize()); // CraftBukkit - check both sides + } + + public void update() { diff --git a/paper-server/nms-patches/InventoryMerchant.patch b/paper-server/nms-patches/InventoryMerchant.patch new file mode 100644 index 0000000000..bc24b3dc6d --- /dev/null +++ b/paper-server/nms-patches/InventoryMerchant.patch @@ -0,0 +1,59 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventoryMerchant.java 2014-11-27 08:59:46.769421547 +1100 ++++ src/main/java/net/minecraft/server/InventoryMerchant.java 2014-11-27 08:42:10.136850942 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class InventoryMerchant implements IInventory { + + private final IMerchant merchant; +@@ -8,6 +14,35 @@ + private MerchantRecipe recipe; + private int e; + ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.itemsInSlots; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int i) { ++ maxStack = i; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return player.getBukkitEntity(); ++ } ++ // CraftBukkit end ++ + public InventoryMerchant(EntityHuman entityhuman, IMerchant imerchant) { + this.player = entityhuman; + this.merchant = imerchant; +@@ -94,7 +129,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public boolean a(EntityHuman entityhuman) { diff --git a/paper-server/nms-patches/InventorySubcontainer.patch b/paper-server/nms-patches/InventorySubcontainer.patch new file mode 100644 index 0000000000..ddacf613b4 --- /dev/null +++ b/paper-server/nms-patches/InventorySubcontainer.patch @@ -0,0 +1,59 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/InventorySubcontainer.java 2014-11-27 08:59:46.769421547 +1100 ++++ src/main/java/net/minecraft/server/InventorySubcontainer.java 2014-11-27 08:42:10.088851036 +1100 +@@ -3,6 +3,12 @@ + import com.google.common.collect.Lists; + import java.util.List; + ++// CraftBukkit start ++import java.util.List; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class InventorySubcontainer implements IInventory { + + private String a; +@@ -10,8 +16,43 @@ + public ItemStack[] items; + private List d; + private boolean e; ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ protected org.bukkit.inventory.InventoryHolder bukkitOwner; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } + ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int i) { ++ maxStack = i; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return bukkitOwner; ++ } ++ + public InventorySubcontainer(String s, boolean flag, int i) { ++ this(s, flag, i, null); ++ } ++ ++ public InventorySubcontainer(String s, boolean flag, int i, org.bukkit.inventory.InventoryHolder owner) { // Added argument ++ this.bukkitOwner = owner; ++ // CraftBukkit end + this.a = s; + this.e = flag; + this.b = i; diff --git a/paper-server/nms-patches/ItemBoat.patch b/paper-server/nms-patches/ItemBoat.patch new file mode 100644 index 0000000000..29142514bc --- /dev/null +++ b/paper-server/nms-patches/ItemBoat.patch @@ -0,0 +1,17 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemBoat.java 2014-11-27 08:59:46.773421530 +1100 ++++ src/main/java/net/minecraft/server/ItemBoat.java 2014-11-27 08:42:10.156850903 +1100 +@@ -53,6 +53,14 @@ + } else { + if (movingobjectposition.type == EnumMovingObjectType.BLOCK) { + BlockPosition blockposition = movingobjectposition.a(); ++ ++ // CraftBukkit start - Boat placement ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(entityhuman, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, blockposition, movingobjectposition.direction, itemstack); ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ // CraftBukkit end + + if (world.getType(blockposition).getBlock() == Blocks.SNOW_LAYER) { + blockposition = blockposition.down(); diff --git a/paper-server/nms-patches/ItemBow.patch b/paper-server/nms-patches/ItemBow.patch new file mode 100644 index 0000000000..9f8c9f513f --- /dev/null +++ b/paper-server/nms-patches/ItemBow.patch @@ -0,0 +1,49 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemBow.java 2014-11-27 08:59:46.773421530 +1100 ++++ src/main/java/net/minecraft/server/ItemBow.java 2014-11-27 08:42:10.140850934 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.EntityCombustEvent; // CraftBukkit ++ + public class ItemBow extends Item { + + public static final String[] a = new String[] { "pulling_0", "pulling_1", "pulling_2"}; +@@ -45,9 +47,28 @@ + } + + if (EnchantmentManager.getEnchantmentLevel(Enchantment.ARROW_FIRE.id, itemstack) > 0) { +- entityarrow.setOnFire(100); ++ // CraftBukkit start - call EntityCombustEvent ++ EntityCombustEvent event = new EntityCombustEvent(entityarrow.getBukkitEntity(), 100); ++ entityarrow.world.getServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ entityarrow.setOnFire(event.getDuration()); ++ } ++ // CraftBukkit end ++ } ++ ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(entityhuman, itemstack, entityarrow, f); ++ if (event.isCancelled()) { ++ event.getProjectile().remove(); ++ return; + } + ++ if (event.getProjectile() == entityarrow.getBukkitEntity()) { ++ world.addEntity(entityarrow); ++ } ++ // CraftBukkit end ++ + itemstack.damage(1, entityhuman); + world.makeSound(entityhuman, "random.bow", 1.0F, 1.0F / (ItemBow.g.nextFloat() * 0.4F + 1.2F) + f * 0.5F); + if (flag) { +@@ -58,7 +79,7 @@ + + entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this)]); + if (!world.isStatic) { +- world.addEntity(entityarrow); ++ // world.addEntity(entityarrow); // CraftBukkit - moved up + } + } + diff --git a/paper-server/nms-patches/ItemBucket.patch b/paper-server/nms-patches/ItemBucket.patch new file mode 100644 index 0000000000..d037c57b4b --- /dev/null +++ b/paper-server/nms-patches/ItemBucket.patch @@ -0,0 +1,102 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemBucket.java 2014-11-27 08:59:46.777421512 +1100 ++++ src/main/java/net/minecraft/server/ItemBucket.java 2014-11-27 08:42:10.156850903 +1100 +@@ -1,5 +1,12 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.player.PlayerBucketEmptyEvent; ++import org.bukkit.event.player.PlayerBucketFillEvent; ++// CraftBukkit end ++ + public class ItemBucket extends Item { + + private Block a; +@@ -33,19 +40,41 @@ + Material material = iblockdata.getBlock().getMaterial(); + + if (material == Material.WATER && ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue() == 0) { ++ // CraftBukkit start ++ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), null, itemstack, Items.WATER_BUCKET); ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ // CraftBukkit end + world.setAir(blockposition); + entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this)]); +- return this.a(itemstack, entityhuman, Items.WATER_BUCKET); ++ return this.a(itemstack, entityhuman, Items.WATER_BUCKET, event.getItemStack()); // CraftBukkit - added Event stack + } + + if (material == Material.LAVA && ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue() == 0) { ++ // CraftBukkit start ++ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), null, itemstack, Items.LAVA_BUCKET); ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ // CraftBukkit end + world.setAir(blockposition); + entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this)]); +- return this.a(itemstack, entityhuman, Items.LAVA_BUCKET); ++ return this.a(itemstack, entityhuman, Items.LAVA_BUCKET, event.getItemStack()); // CraftBukkit - added Event stack + } + } else { + if (this.a == Blocks.AIR) { +- return new ItemStack(Items.BUCKET); ++ // CraftBukkit start ++ PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), movingobjectposition.direction, itemstack); ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ ++ return CraftItemStack.asNMSCopy(event.getItemStack()); ++ // CraftBukkit end + } + + BlockPosition blockposition1 = blockposition.shift(movingobjectposition.direction); +@@ -53,10 +82,18 @@ + if (!entityhuman.a(blockposition1, movingobjectposition.direction, itemstack)) { + return itemstack; + } ++ ++ // CraftBukkit start ++ PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), movingobjectposition.direction, itemstack); ++ ++ if (event.isCancelled()) { ++ return itemstack; ++ } ++ // CraftBukkit end + + if (this.a(world, blockposition1) && !entityhuman.abilities.canInstantlyBuild) { + entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this)]); +- return new ItemStack(Items.BUCKET); ++ return CraftItemStack.asNMSCopy(event.getItemStack()); // CraftBukkit + } + } + } +@@ -64,15 +101,16 @@ + return itemstack; + } + } +- +- private ItemStack a(ItemStack itemstack, EntityHuman entityhuman, Item item) { ++ ++ // CraftBukkit - added ob.ItemStack result - TODO: Is this... the right way to handle this? ++ private ItemStack a(ItemStack itemstack, EntityHuman entityhuman, Item item, org.bukkit.inventory.ItemStack result) { + if (entityhuman.abilities.canInstantlyBuild) { + return itemstack; + } else if (--itemstack.count <= 0) { +- return new ItemStack(item); ++ return CraftItemStack.asNMSCopy(result); // CraftBukkit + } else { +- if (!entityhuman.inventory.pickup(new ItemStack(item))) { +- entityhuman.drop(new ItemStack(item, 1, 0), false); ++ if (!entityhuman.inventory.pickup(CraftItemStack.asNMSCopy(result))) { ++ entityhuman.drop(CraftItemStack.asNMSCopy(result), false); + } + + return itemstack; diff --git a/paper-server/nms-patches/ItemDye.patch b/paper-server/nms-patches/ItemDye.patch new file mode 100644 index 0000000000..8586e78611 --- /dev/null +++ b/paper-server/nms-patches/ItemDye.patch @@ -0,0 +1,28 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemDye.java 2014-11-27 08:59:46.777421512 +1100 ++++ src/main/java/net/minecraft/server/ItemDye.java 2014-11-27 08:42:10.160850895 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.entity.SheepDyeWoolEvent; // CraftBukkit ++ + public class ItemDye extends Item { + + public static final int[] a = new int[] { 1973019, 11743532, 3887386, 5320730, 2437522, 8073150, 2651799, 11250603, 4408131, 14188952, 4312372, 14602026, 6719955, 12801229, 15435844, 15790320}; +@@ -89,6 +91,17 @@ + EnumColor enumcolor = EnumColor.fromInvColorIndex(itemstack.getData()); + + if (!entitysheep.isSheared() && entitysheep.getColor() != enumcolor) { ++ // CraftBukkit start ++ byte bColor = (byte) enumcolor.getColorIndex(); ++ SheepDyeWoolEvent event = new SheepDyeWoolEvent((org.bukkit.entity.Sheep) entitysheep.getBukkitEntity(), org.bukkit.DyeColor.getByData(bColor)); ++ entitysheep.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ enumcolor = EnumColor.fromColorIndex((byte) event.getColor().getWoolData()); ++ // CraftBukkit end + entitysheep.setColor(enumcolor); + --itemstack.count; + } diff --git a/paper-server/nms-patches/ItemFireball.patch b/paper-server/nms-patches/ItemFireball.patch new file mode 100644 index 0000000000..6a754928cd --- /dev/null +++ b/paper-server/nms-patches/ItemFireball.patch @@ -0,0 +1,19 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemFireball.java 2014-11-27 08:59:46.777421512 +1100 ++++ src/main/java/net/minecraft/server/ItemFireball.java 2014-11-27 08:42:10.124850965 +1100 +@@ -15,7 +15,15 @@ + return false; + } else { + if (world.getType(blockposition).getBlock().getMaterial() == Material.AIR) { +- world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "item.fireCharge.use", 1.0F, (ItemFireball.g.nextFloat() - ItemFireball.g.nextFloat()) * 0.2F + 1.0F); ++ // CraftBukkit start - fire BlockIgniteEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, entityhuman).isCancelled()) { ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ --itemstack.count; ++ } ++ return false; ++ } ++ // CraftBukkit end ++ world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "item.fireCharge.use", 1.0F, (g.nextFloat() - g.nextFloat()) * 0.2F + 1.0F); + world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); + } + diff --git a/paper-server/nms-patches/ItemFishingRod.patch b/paper-server/nms-patches/ItemFishingRod.patch new file mode 100644 index 0000000000..564c24b47a --- /dev/null +++ b/paper-server/nms-patches/ItemFishingRod.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemFishingRod.java 2014-11-27 08:59:46.781421494 +1100 ++++ src/main/java/net/minecraft/server/ItemFishingRod.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.player.PlayerFishEvent; // CraftBukkit ++ + public class ItemFishingRod extends Item { + + public ItemFishingRod() { +@@ -15,9 +17,18 @@ + itemstack.damage(i, entityhuman); + entityhuman.bv(); + } else { +- world.makeSound(entityhuman, "random.bow", 0.5F, 0.4F / (ItemFishingRod.g.nextFloat() * 0.4F + 0.8F)); ++ // CraftBukkit start ++ EntityFishingHook hook = new EntityFishingHook(world, entityhuman); ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), null, (org.bukkit.entity.Fish) hook.getBukkitEntity(), PlayerFishEvent.State.FISHING); ++ world.getServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return itemstack; ++ } ++ // CraftBukkit end ++ world.makeSound(entityhuman, "random.bow", 0.5F, 0.4F / (g.nextFloat() * 0.4F + 0.8F)); + if (!world.isStatic) { +- world.addEntity(new EntityFishingHook(world, entityhuman)); ++ world.addEntity(hook); // CraftBukkit - moved creation up + } + + entityhuman.bv(); diff --git a/paper-server/nms-patches/ItemFlintAndSteel.patch b/paper-server/nms-patches/ItemFlintAndSteel.patch new file mode 100644 index 0000000000..a27cc0b6ac --- /dev/null +++ b/paper-server/nms-patches/ItemFlintAndSteel.patch @@ -0,0 +1,47 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemFlintAndSteel.java 2014-11-27 08:59:46.781421494 +1100 ++++ src/main/java/net/minecraft/server/ItemFlintAndSteel.java 2014-11-27 08:42:10.152850911 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.block.CraftBlockState; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++// CraftBukkit end ++ + public class ItemFlintAndSteel extends Item { + + public ItemFlintAndSteel() { +@@ -9,13 +14,32 @@ + } + + public boolean interactWith(ItemStack itemstack, EntityHuman entityhuman, World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2) { ++ BlockPosition clicked = blockposition; // CraftBukkit + blockposition = blockposition.shift(enumdirection); + if (!entityhuman.a(blockposition, enumdirection, itemstack)) { + return false; + } else { + if (world.getType(blockposition).getBlock().getMaterial() == Material.AIR) { +- world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "fire.ignite", 1.0F, ItemFlintAndSteel.g.nextFloat() * 0.4F + 0.8F); ++ // CraftBukkit start - Store the clicked block ++ if (CraftEventFactory.callBlockIgniteEvent(world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, entityhuman).isCancelled()) { ++ itemstack.damage(1, entityhuman); ++ return false; ++ } ++ ++ CraftBlockState blockState = CraftBlockState.getBlockState(world, blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ // CraftBukkit end ++ ++ world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "fire.ignite", 1.0F, g.nextFloat() * 0.4F + 0.8F); + world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData()); ++ ++ // CraftBukkit start ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockState, clicked.getX(), clicked.getY(), clicked.getZ()); ++ ++ if (placeEvent.isCancelled() || !placeEvent.canBuild()) { ++ placeEvent.getBlockPlaced().setTypeIdAndData(0, (byte) 0, false); ++ return false; ++ } ++ // CraftBukkit end + } + + itemstack.damage(1, entityhuman); diff --git a/paper-server/nms-patches/ItemHanging.patch b/paper-server/nms-patches/ItemHanging.patch new file mode 100644 index 0000000000..0a312a806a --- /dev/null +++ b/paper-server/nms-patches/ItemHanging.patch @@ -0,0 +1,41 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemHanging.java 2014-11-27 08:59:46.785421476 +1100 ++++ src/main/java/net/minecraft/server/ItemHanging.java 2014-11-27 08:42:10.144850927 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.entity.Player; ++import org.bukkit.event.hanging.HangingPlaceEvent; ++import org.bukkit.event.painting.PaintingPlaceEvent; ++// CraftBukkit end ++ + public class ItemHanging extends Item { + + private final Class a; +@@ -24,6 +30,26 @@ + + if (entityhanging != null && entityhanging.survives()) { + if (!world.isStatic) { ++ // CraftBukkit start - fire HangingPlaceEvent ++ Player who = (entityhuman == null) ? null : (Player) entityhuman.getBukkitEntity(); ++ org.bukkit.block.Block blockClicked = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection); ++ ++ HangingPlaceEvent event = new HangingPlaceEvent((org.bukkit.entity.Hanging) entityhanging.getBukkitEntity(), who, blockClicked, blockFace); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ PaintingPlaceEvent paintingEvent = null; ++ if (entityhanging instanceof EntityPainting) { ++ // Fire old painting event until it can be removed ++ paintingEvent = new PaintingPlaceEvent((org.bukkit.entity.Painting) entityhanging.getBukkitEntity(), who, blockClicked, blockFace); ++ paintingEvent.setCancelled(event.isCancelled()); ++ world.getServer().getPluginManager().callEvent(paintingEvent); ++ } ++ ++ if (event.isCancelled() || (paintingEvent != null && paintingEvent.isCancelled())) { ++ return false; ++ } ++ // CraftBukkit end + world.addEntity(entityhanging); + } + diff --git a/paper-server/nms-patches/ItemLeash.patch b/paper-server/nms-patches/ItemLeash.patch new file mode 100644 index 0000000000..2836ac93b4 --- /dev/null +++ b/paper-server/nms-patches/ItemLeash.patch @@ -0,0 +1,35 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemLeash.java 2014-11-27 08:59:46.785421476 +1100 ++++ src/main/java/net/minecraft/server/ItemLeash.java 2014-11-27 08:42:10.084851043 +1100 +@@ -3,6 +3,8 @@ + import java.util.Iterator; + import java.util.List; + ++import org.bukkit.event.hanging.HangingPlaceEvent; // CraftBukkit ++ + public class ItemLeash extends Item { + + public ItemLeash() { +@@ -40,7 +42,23 @@ + if (entityinsentient.cb() && entityinsentient.getLeashHolder() == entityhuman) { + if (entityleash == null) { + entityleash = EntityLeash.a(world, blockposition); ++ ++ // CraftBukkit start - fire HangingPlaceEvent ++ HangingPlaceEvent event = new HangingPlaceEvent((org.bukkit.entity.Hanging) entityleash.getBukkitEntity(), entityhuman != null ? (org.bukkit.entity.Player) entityhuman.getBukkitEntity() : null, world.getWorld().getBlockAt(i, j, k), org.bukkit.block.BlockFace.SELF); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ entityleash.die(); ++ return false; ++ } ++ // CraftBukkit end ++ } ++ ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(entityinsentient, entityleash, entityhuman).isCancelled()) { ++ continue; + } ++ // CraftBukkit end + + entityinsentient.setLeashHolder(entityleash, true); + flag = true; diff --git a/paper-server/nms-patches/ItemMapEmpty.patch b/paper-server/nms-patches/ItemMapEmpty.patch new file mode 100644 index 0000000000..9159a10675 --- /dev/null +++ b/paper-server/nms-patches/ItemMapEmpty.patch @@ -0,0 +1,24 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemMapEmpty.java 2014-11-27 08:59:46.785421476 +1100 ++++ src/main/java/net/minecraft/server/ItemMapEmpty.java 2014-11-27 08:42:10.164850887 +1100 +@@ -7,15 +7,19 @@ + } + + public ItemStack a(ItemStack itemstack, World world, EntityHuman entityhuman) { +- ItemStack itemstack1 = new ItemStack(Items.FILLED_MAP, 1, world.b("map")); ++ World worldMain = world.getServer().getServer().worlds.get(0); // CraftBukkit - store reference to primary world ++ ItemStack itemstack1 = new ItemStack(Items.FILLED_MAP, 1, worldMain.b("map")); // CraftBukkit - use primary world for maps + String s = "map_" + itemstack1.getData(); + WorldMap worldmap = new WorldMap(s); + + world.a(s, (PersistentBase) worldmap); + worldmap.scale = 0; + worldmap.a(entityhuman.locX, entityhuman.locZ, worldmap.scale); +- worldmap.map = (byte) world.worldProvider.getDimension(); ++ worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit - use bukkit dimension + worldmap.c(); ++ ++ org.bukkit.craftbukkit.event.CraftEventFactory.callEvent(new org.bukkit.event.server.MapInitializeEvent(worldmap.mapView)); // CraftBukkit ++ + --itemstack.count; + if (itemstack.count <= 0) { + return itemstack1; diff --git a/paper-server/nms-patches/ItemMinecart.patch b/paper-server/nms-patches/ItemMinecart.patch new file mode 100644 index 0000000000..5cff838fdd --- /dev/null +++ b/paper-server/nms-patches/ItemMinecart.patch @@ -0,0 +1,16 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemMinecart.java 2014-11-27 08:59:46.789421459 +1100 ++++ src/main/java/net/minecraft/server/ItemMinecart.java 2014-11-27 08:42:10.168850880 +1100 +@@ -23,6 +23,13 @@ + if (enumtrackposition.c()) { + d0 = 0.5D; + } ++ // CraftBukkit start - Minecarts ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(entityhuman, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, blockposition, enumdirection, itemstack); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end + + EntityMinecartAbstract entityminecartabstract = EntityMinecartAbstract.a(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.0625D + d0, (double) blockposition.getZ() + 0.5D, this.b); + diff --git a/paper-server/nms-patches/ItemMonsterEgg.patch b/paper-server/nms-patches/ItemMonsterEgg.patch new file mode 100644 index 0000000000..3a5fbee62e --- /dev/null +++ b/paper-server/nms-patches/ItemMonsterEgg.patch @@ -0,0 +1,25 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemMonsterEgg.java 2014-11-27 08:59:46.789421459 +1100 ++++ src/main/java/net/minecraft/server/ItemMonsterEgg.java 2014-11-27 08:42:10.172850872 +1100 +@@ -19,7 +19,8 @@ + } + + public boolean interactWith(ItemStack itemstack, EntityHuman entityhuman, World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2) { +- if (world.isStatic) { ++ // CraftBukkit - check ItemStack data ++ if (world.isStatic || itemstack.getData() == 48 || itemstack.getData() == 49 || itemstack.getData() == 63 || itemstack.getData() == 64) { + return true; + } else if (!entityhuman.a(blockposition.shift(enumdirection), enumdirection, itemstack)) { + return false; +@@ -109,6 +110,12 @@ + } + + public static Entity a(World world, int i, double d0, double d1, double d2) { ++ // CraftBukkit start - delegate to spawnCreature ++ return spawnCreature(world, i, d0, d1, d2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); ++ } ++ ++ public static Entity spawnCreature(World world, int i, double d0, double d1, double d2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { ++ // CraftBukkit end + if (!EntityTypes.eggInfo.containsKey(Integer.valueOf(i))) { + return null; + } else { diff --git a/paper-server/nms-patches/ItemStack.patch b/paper-server/nms-patches/ItemStack.patch new file mode 100644 index 0000000000..da50d5cfdb --- /dev/null +++ b/paper-server/nms-patches/ItemStack.patch @@ -0,0 +1,219 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemStack.java 2014-11-27 08:59:46.789421459 +1100 ++++ src/main/java/net/minecraft/server/ItemStack.java 2014-11-27 08:42:10.156850903 +1100 +@@ -5,6 +5,18 @@ + import java.text.DecimalFormat; + import java.util.Random; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.Location; ++import org.bukkit.TreeType; ++import org.bukkit.block.BlockState; ++import org.bukkit.craftbukkit.block.CraftBlockState; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.entity.Player; ++import org.bukkit.event.world.StructureGrowEvent; ++// CraftBukkit end ++ + public final class ItemStack { + + public static final DecimalFormat a = new DecimalFormat("#.###"); +@@ -46,11 +58,13 @@ + this.k = false; + this.item = item; + this.count = i; +- this.damage = j; +- if (this.damage < 0) { +- this.damage = 0; +- } +- ++ // CraftBukkit start - Pass to setData to do filtering ++ this.setData(j); ++ //this.damage = j; ++ //if (this.damage < 0) { ++ // this.damage = 0; ++ //} ++ // CraftBukkit end + } + + public static ItemStack createStack(NBTTagCompound nbttagcompound) { +@@ -83,11 +97,96 @@ + } + + public boolean placeItem(EntityHuman entityhuman, World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2) { ++ // CraftBukkit start - handle all block place event logic here ++ int data = this.getData(); ++ int count = this.count; ++ ++ if (!(this.getItem() instanceof ItemBucket)) { // if not bucket ++ world.captureBlockStates = true; ++ // special case bonemeal ++ if (this.getItem() instanceof ItemDye && this.getData() == 15) { ++ Block block = world.getType(blockposition).getBlock(); ++ if (block == Blocks.SAPLING || block instanceof BlockMushroom) { ++ world.captureTreeGeneration = true; ++ } ++ } ++ } + boolean flag = this.getItem().interactWith(this, entityhuman, world, blockposition, enumdirection, f, f1, f2); ++ int newData = this.getData(); ++ int newCount = this.count; ++ this.count = count; ++ this.setData(data); ++ world.captureBlockStates = false; ++ if (flag && world.captureTreeGeneration && world.capturedBlockStates.size() > 0) { ++ world.captureTreeGeneration = false; ++ Location location = new Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ TreeType treeType = BlockSapling.treeType; ++ BlockSapling.treeType = null; ++ List blocks = (List) world.capturedBlockStates.clone(); ++ world.capturedBlockStates.clear(); ++ StructureGrowEvent event = null; ++ if (treeType != null) { ++ event = new StructureGrowEvent(location, treeType, false, (Player) entityhuman.getBukkitEntity(), blocks); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ } ++ if (event == null || !event.isCancelled()) { ++ // Change the stack to its new contents if it hasn't been tampered with. ++ if (this.count == count && this.getData() == data) { ++ this.setData(newData); ++ this.count = newCount; ++ } ++ for (BlockState blockstate : blocks) { ++ blockstate.update(true); ++ } ++ } ++ ++ return flag; ++ } ++ world.captureTreeGeneration = false; + + if (flag) { +- entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this.item)]); ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = null; ++ List blocks = (List) world.capturedBlockStates.clone(); ++ world.capturedBlockStates.clear(); ++ if (blocks.size() > 1) { ++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ } else if (blocks.size() == 1) { ++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ } ++ ++ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { ++ flag = false; // cancel placement ++ // revert back all captured blocks ++ for (BlockState blockstate : blocks) { ++ blockstate.update(true, false); ++ } ++ } else { ++ // Change the stack to its new contents if it hasn't been tampered with. ++ if (this.count == count && this.getData() == data) { ++ this.setData(newData); ++ this.count = newCount; ++ } ++ for (BlockState blockstate : blocks) { ++ int x = blockstate.getX(); ++ int y = blockstate.getY(); ++ int z = blockstate.getZ(); ++ int updateFlag = ((CraftBlockState) blockstate).getFlag(); ++ org.bukkit.Material mat = blockstate.getType(); ++ Block oldBlock = CraftMagicNumbers.getBlock(mat); ++ BlockPosition newblockposition = new BlockPosition(x, y, z); ++ IBlockData block = world.getType(newblockposition); ++ ++ if (!(block instanceof BlockContainer)) { // Containers get placed automatically ++ block.getBlock().onPlace(world, newblockposition, block); ++ } ++ ++ world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block.getBlock(), updateFlag); // send null chunk as chunk.k() returns false by this point ++ } ++ entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this.item)]); ++ } + } ++ world.capturedBlockStates.clear(); ++ // CraftBukkit end + + return flag; + } +@@ -111,7 +210,7 @@ + nbttagcompound.setByte("Count", (byte) this.count); + nbttagcompound.setShort("Damage", (short) this.damage); + if (this.tag != null) { +- nbttagcompound.set("tag", this.tag); ++ nbttagcompound.set("tag", this.tag.clone()); // CraftBukkit - make defensive copy, data is going to another thread + } + + return nbttagcompound; +@@ -125,13 +224,18 @@ + } + + this.count = nbttagcompound.getByte("Count"); ++ /* CraftBukkit start - Route through setData for filtering + this.damage = nbttagcompound.getShort("Damage"); + if (this.damage < 0) { + this.damage = 0; + } ++ */ ++ this.setData(nbttagcompound.getShort("Damage")); ++ // CraftBukkit end + + if (nbttagcompound.hasKeyOfType("tag", 10)) { +- this.tag = nbttagcompound.getCompound("tag"); ++ // CraftBukkit - make defensive copy as this data may be coming from the save thread ++ this.tag = (NBTTagCompound) nbttagcompound.getCompound("tag").clone(); + if (this.item != null) { + this.item.a(this.tag); + } +@@ -168,8 +272,29 @@ + } + + public void setData(int i) { ++ // CraftBukkit start - Filter out data for items that shouldn't have it ++ // The crafting system uses this value for a special purpose so we have to allow it ++ if (i == 32767) { ++ this.damage = i; ++ return; ++ } ++ ++ // Is this a block? ++ if (CraftMagicNumbers.getBlock(CraftMagicNumbers.getId(this.getItem())) != Blocks.AIR) { ++ // If vanilla doesn't use data on it don't allow any ++ if (!(this.usesData() || this.getItem().usesDurability())) { ++ i = 0; ++ } ++ } ++ ++ // Filter invalid plant data ++ if (CraftMagicNumbers.getBlock(CraftMagicNumbers.getId(this.getItem())) == Blocks.DOUBLE_PLANT && (i > 5 || i < 0)) { ++ i = 0; ++ } ++ // CraftBukkit end ++ + this.damage = i; +- if (this.damage < 0) { ++ if (this.damage < -1) { // CraftBukkit + this.damage = 0; + } + +@@ -222,6 +347,12 @@ + if (this.count < 0) { + this.count = 0; + } ++ ++ // CraftBukkit start - Check for item breaking ++ if (this.count == 0 && entityliving instanceof EntityHuman) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((EntityHuman) entityliving, this); ++ } ++ // CraftBukkit end + + this.damage = 0; + } +@@ -489,6 +620,7 @@ + + public void setItem(Item item) { + this.item = item; ++ this.setData(this.getData()); // CraftBukkit - Set data again to ensure it is filtered properly + } + + public IChatBaseComponent C() { diff --git a/paper-server/nms-patches/ItemWaterLily.patch b/paper-server/nms-patches/ItemWaterLily.patch new file mode 100644 index 0000000000..2158f6428b --- /dev/null +++ b/paper-server/nms-patches/ItemWaterLily.patch @@ -0,0 +1,18 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemWaterLily.java 2014-11-27 08:59:46.793421441 +1100 ++++ src/main/java/net/minecraft/server/ItemWaterLily.java 2014-11-27 08:42:10.152850911 +1100 +@@ -27,7 +27,15 @@ + IBlockData iblockdata = world.getType(blockposition); + + if (iblockdata.getBlock().getMaterial() == Material.WATER && ((Integer) iblockdata.get(BlockFluids.LEVEL)).intValue() == 0 && world.isEmpty(blockposition1)) { ++ // CraftBukkit start - special case for handling block placement with water lilies ++ org.bukkit.block.BlockState blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()); + world.setTypeUpdate(blockposition1, Blocks.WATERLILY.getBlockData()); ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, blockstate, blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { ++ blockstate.update(true, false); ++ return itemstack; ++ } ++ // CraftBukkit end + if (!entityhuman.abilities.canInstantlyBuild) { + --itemstack.count; + } diff --git a/paper-server/nms-patches/ItemWorldMap.patch b/paper-server/nms-patches/ItemWorldMap.patch new file mode 100644 index 0000000000..f85596fdc0 --- /dev/null +++ b/paper-server/nms-patches/ItemWorldMap.patch @@ -0,0 +1,75 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ItemWorldMap.java 2014-11-27 08:59:46.793421441 +1100 ++++ src/main/java/net/minecraft/server/ItemWorldMap.java 2014-11-27 08:42:10.144850927 +1100 +@@ -4,6 +4,11 @@ + import com.google.common.collect.Iterables; + import com.google.common.collect.Multisets; + ++// CraftBukkit start ++import org.bukkit.Bukkit; ++import org.bukkit.event.server.MapInitializeEvent; ++// CraftBukkit end ++ + public class ItemWorldMap extends ItemWorldMapBase { + + protected ItemWorldMap() { +@@ -11,25 +16,32 @@ + } + + public WorldMap getSavedMap(ItemStack itemstack, World world) { ++ World worldMain = world.getServer().getServer().worlds.get(0); // CraftBukkit - store reference to primary world + String s = "map_" + itemstack.getData(); +- WorldMap worldmap = (WorldMap) world.a(WorldMap.class, s); ++ WorldMap worldmap = (WorldMap) worldMain.a(WorldMap.class, s); // CraftBukkit - use primary world for maps + + if (worldmap == null && !world.isStatic) { +- itemstack.setData(world.b("map")); ++ itemstack.setData(worldMain.b("map")); // CraftBukkit - use primary world for maps + s = "map_" + itemstack.getData(); + worldmap = new WorldMap(s); + worldmap.scale = 3; + worldmap.a((double) world.getWorldData().c(), (double) world.getWorldData().e(), worldmap.scale); +- worldmap.map = (byte) world.worldProvider.getDimension(); ++ worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit - fixes Bukkit multiworld maps + worldmap.c(); +- world.a(s, (PersistentBase) worldmap); ++ worldMain.a(s, (PersistentBase) worldmap); // CraftBukkit - use primary world for maps ++ ++ // CraftBukkit start ++ MapInitializeEvent event = new MapInitializeEvent(worldmap.mapView); ++ Bukkit.getServer().getPluginManager().callEvent(event); ++ // CraftBukkit end + } + + return worldmap; + } + + public void a(World world, Entity entity, WorldMap worldmap) { +- if (world.worldProvider.getDimension() == worldmap.map && entity instanceof EntityHuman) { ++ // CraftBukkit - world.worldProvider -> ((WorldServer) world) ++ if (((WorldServer) world).dimension == worldmap.map && entity instanceof EntityHuman) { + int i = 1 << worldmap.scale; + int j = worldmap.centerX; + int k = worldmap.centerZ; +@@ -179,6 +191,8 @@ + if (itemstack.hasTag() && itemstack.getTag().getBoolean("map_is_scaling")) { + WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world); + ++ world = world.getServer().getServer().worlds.get(0); // CraftBukkit - use primary world for maps ++ + itemstack.setData(world.b("map")); + WorldMap worldmap1 = new WorldMap("map_" + itemstack.getData()); + +@@ -190,7 +204,12 @@ + worldmap1.a((double) worldmap.centerX, (double) worldmap.centerZ, worldmap1.scale); + worldmap1.map = worldmap.map; + worldmap1.c(); +- world.a("map_" + itemstack.getData(), (PersistentBase) worldmap1); ++ world.a("map_" + itemstack.getData(), (PersistentBase) worldmap1); ++ ++ // CraftBukkit start ++ MapInitializeEvent event = new MapInitializeEvent(worldmap1.mapView); ++ Bukkit.getServer().getPluginManager().callEvent(event); ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/JsonList.patch b/paper-server/nms-patches/JsonList.patch new file mode 100644 index 0000000000..0dcf03529a --- /dev/null +++ b/paper-server/nms-patches/JsonList.patch @@ -0,0 +1,33 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/JsonList.java 2014-11-27 08:59:46.797421424 +1100 ++++ src/main/java/net/minecraft/server/JsonList.java 2014-11-27 08:42:10.168850880 +1100 +@@ -79,6 +79,12 @@ + public String[] getEntries() { + return (String[]) this.d.keySet().toArray(new String[this.d.size()]); + } ++ ++ // CraftBukkit start ++ public Collection getValues() { ++ return this.d.values(); ++ } ++ // CraftBukkit end + + public boolean isEmpty() { + return this.d.size() < 1; +@@ -122,7 +128,7 @@ + return this.d; + } + +- public void save() { ++ public void save() throws IOException { // CraftBukkit - Added throws + Collection collection = this.d.values(); + String s = this.b.toJson(collection); + BufferedWriter bufferedwriter = null; +@@ -136,7 +142,7 @@ + + } + +- public void load() { ++ public void load() throws IOException { // CraftBukkit - Added throws + Collection collection = null; + BufferedReader bufferedreader = null; + diff --git a/paper-server/nms-patches/LoginListener.patch b/paper-server/nms-patches/LoginListener.patch new file mode 100644 index 0000000000..b80cdad040 --- /dev/null +++ b/paper-server/nms-patches/LoginListener.patch @@ -0,0 +1,35 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/LoginListener.java 2014-11-27 08:59:46.797421424 +1100 ++++ src/main/java/net/minecraft/server/LoginListener.java 2014-11-27 08:42:10.172850872 +1100 +@@ -26,6 +26,7 @@ + private GameProfile i; + private String j; + private SecretKey loginKey; ++ public String hostname = ""; // CraftBukkit - add field + + public LoginListener(MinecraftServer minecraftserver, NetworkManager networkmanager) { + this.g = EnumProtocolState.HELLO; +@@ -64,10 +65,12 @@ + this.i = this.a(this.i); + } + +- String s = this.server.getPlayerList().attemptLogin(this.networkManager.getSocketAddress(), this.i); ++ // CraftBukkit start - fire PlayerLoginEvent ++ EntityPlayer s = this.server.getPlayerList().attemptLogin(this, this.i, hostname); + +- if (s != null) { +- this.disconnect(s); ++ if (s == null) { ++ // this.disconnect(s); ++ // CraftBukkit end + } else { + this.g = EnumProtocolState.ACCEPTED; + if (this.server.aI() >= 0 && !this.networkManager.c()) { +@@ -75,7 +78,7 @@ + } + + this.networkManager.handle(new PacketLoginOutSuccess(this.i)); +- this.server.getPlayerList().a(this.networkManager, this.server.getPlayerList().processLogin(this.i)); ++ this.server.getPlayerList().a(this.networkManager, this.server.getPlayerList().processLogin(this.i, s)); // CraftBukkit - add player reference + } + + } diff --git a/paper-server/nms-patches/MethodProfiler.patch b/paper-server/nms-patches/MethodProfiler.patch new file mode 100644 index 0000000000..624249838e --- /dev/null +++ b/paper-server/nms-patches/MethodProfiler.patch @@ -0,0 +1,135 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/MethodProfiler.java 2014-11-27 08:59:46.797421424 +1100 ++++ src/main/java/net/minecraft/server/MethodProfiler.java 2014-11-27 08:42:10.132850949 +1100 +@@ -10,129 +10,29 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start - Strip down to empty methods, performance cost + public class MethodProfiler { +- +- private static final Logger b = LogManager.getLogger(); +- private final List c = Lists.newArrayList(); +- private final List d = Lists.newArrayList(); + public boolean a; +- private String e = ""; +- private final Map f = Maps.newHashMap(); + + public MethodProfiler() {} + + public void a() { +- this.f.clear(); +- this.e = ""; +- this.c.clear(); + } + + public void a(String s) { +- if (this.a) { +- if (this.e.length() > 0) { +- this.e = this.e + "."; +- } +- +- this.e = this.e + s; +- this.c.add(this.e); +- this.d.add(Long.valueOf(System.nanoTime())); +- } + } + + public void b() { +- if (this.a) { +- long i = System.nanoTime(); +- long j = ((Long) this.d.remove(this.d.size() - 1)).longValue(); +- +- this.c.remove(this.c.size() - 1); +- long k = i - j; +- +- if (this.f.containsKey(this.e)) { +- this.f.put(this.e, Long.valueOf(((Long) this.f.get(this.e)).longValue() + k)); +- } else { +- this.f.put(this.e, Long.valueOf(k)); +- } +- +- if (k > 100000000L) { +- MethodProfiler.b.warn("Something\'s taking too long! \'" + this.e + "\' took aprox " + (double) k / 1000000.0D + " ms"); +- } +- +- this.e = !this.c.isEmpty() ? (String) this.c.get(this.c.size() - 1) : ""; +- } + } + + public List b(String s) { +- if (!this.a) { +- return null; +- } else { +- long i = this.f.containsKey("root") ? ((Long) this.f.get("root")).longValue() : 0L; +- long j = this.f.containsKey(s) ? ((Long) this.f.get(s)).longValue() : -1L; +- ArrayList arraylist = Lists.newArrayList(); +- +- if (s.length() > 0) { +- s = s + "."; +- } +- +- long k = 0L; +- Iterator iterator = this.f.keySet().iterator(); +- +- while (iterator.hasNext()) { +- String s1 = (String) iterator.next(); +- +- if (s1.length() > s.length() && s1.startsWith(s) && s1.indexOf(".", s.length() + 1) < 0) { +- k += ((Long) this.f.get(s1)).longValue(); +- } +- } +- +- float f = (float) k; +- +- if (k < j) { +- k = j; +- } +- +- if (i < k) { +- i = k; +- } +- +- Iterator iterator1 = this.f.keySet().iterator(); +- +- String s2; +- +- while (iterator1.hasNext()) { +- s2 = (String) iterator1.next(); +- if (s2.length() > s.length() && s2.startsWith(s) && s2.indexOf(".", s.length() + 1) < 0) { +- long l = ((Long) this.f.get(s2)).longValue(); +- double d0 = (double) l * 100.0D / (double) k; +- double d1 = (double) l * 100.0D / (double) i; +- String s3 = s2.substring(s.length()); +- +- arraylist.add(new ProfilerInfo(s3, d0, d1)); +- } +- } +- +- iterator1 = this.f.keySet().iterator(); +- +- while (iterator1.hasNext()) { +- s2 = (String) iterator1.next(); +- this.f.put(s2, Long.valueOf(((Long) this.f.get(s2)).longValue() * 999L / 1000L)); +- } +- +- if ((float) k > f) { +- arraylist.add(new ProfilerInfo("unspecified", (double) ((float) k - f) * 100.0D / (double) k, (double) ((float) k - f) * 100.0D / (double) i)); +- } +- +- Collections.sort(arraylist); +- arraylist.add(0, new ProfilerInfo(s, 100.0D, (double) k * 100.0D / (double) i)); +- return arraylist; +- } ++ return null; + } + + public void c(String s) { +- this.b(); +- this.a(s); + } + + public String c() { +- return this.c.size() == 0 ? "[UNKNOWN]" : (String) this.c.get(this.c.size() - 1); ++ return null; + } + } diff --git a/paper-server/nms-patches/MinecraftServer.patch b/paper-server/nms-patches/MinecraftServer.patch new file mode 100644 index 0000000000..22d7748fda --- /dev/null +++ b/paper-server/nms-patches/MinecraftServer.patch @@ -0,0 +1,726 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/MinecraftServer.java 2014-11-27 08:59:46.801421406 +1100 ++++ src/main/java/net/minecraft/server/MinecraftServer.java 2014-11-27 08:42:10.092851027 +1100 +@@ -37,6 +37,18 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.io.IOException; ++ ++import jline.console.ConsoleReader; ++import joptsimple.OptionSet; ++ ++import org.bukkit.craftbukkit.Main; ++import org.bukkit.World.Environment; ++import org.bukkit.craftbukkit.util.Waitable; ++import org.bukkit.event.server.RemoteServerCommandEvent; ++import org.bukkit.event.world.WorldSaveEvent; ++// CraftBukkit end + public abstract class MinecraftServer implements ICommandListener, Runnable, IAsyncTaskHandler, IMojangStatistics { + + private static final Logger LOGGER = LogManager.getLogger(); +@@ -93,24 +105,66 @@ + private Thread serverThread; + private long ab = ax(); + +- public MinecraftServer(File file, Proxy proxy, File file1) { ++ // CraftBukkit start ++ public List worlds = new ArrayList(); ++ public org.bukkit.craftbukkit.CraftServer server; ++ public OptionSet options; ++ public org.bukkit.command.ConsoleCommandSender console; ++ public org.bukkit.command.RemoteConsoleCommandSender remoteConsole; ++ public ConsoleReader reader; ++ public static int currentTick = (int) (System.currentTimeMillis() / 50); ++ public final Thread primaryThread; ++ public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); ++ public int autosavePeriod; ++ // CraftBukkit end ++ ++ public MinecraftServer(OptionSet options, Proxy proxy, File file1) { + this.d = proxy; + MinecraftServer.k = this; +- this.universe = file; ++ // this.universe = file; // CraftBukkit + this.q = new ServerConnection(this); + this.Z = new UserCache(this, file1); + this.p = this.h(); +- this.convertable = new WorldLoaderServer(file); ++ // this.convertable = new WorldLoaderServer(file); // CraftBukkit - moved to DedicatedServer.init + this.V = new YggdrasilAuthenticationService(proxy, UUID.randomUUID().toString()); + this.W = this.V.createMinecraftSessionService(); + this.Y = this.V.createProfileRepository(); ++ // CraftBukkit start ++ this.options = options; ++ // Try to see if we're actually running in a terminal, disable jline if not ++ if (System.console() == null) { ++ System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); ++ Main.useJline = false; ++ } ++ ++ try { ++ reader = new ConsoleReader(System.in, System.out); ++ reader.setExpandEvents(false); // Avoid parsing exceptions for uncommonly used event designators ++ } catch (Throwable e) { ++ try { ++ // Try again with jline disabled for Windows users without C++ 2008 Redistributable ++ System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); ++ System.setProperty("user.language", "en"); ++ Main.useJline = false; ++ reader = new ConsoleReader(System.in, System.out); ++ reader.setExpandEvents(false); ++ } catch (IOException ex) { ++ LOGGER.warn((String) null, ex); ++ } ++ } ++ Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this)); ++ ++ this.serverThread = primaryThread = new Thread(this, "Server thread"); // Moved from main + } + ++ public abstract PropertyManager getPropertyManager(); ++ // CraftBukkit end ++ + protected CommandDispatcher h() { + return new CommandDispatcher(); + } + +- protected abstract boolean init(); ++ protected abstract boolean init() throws java.net.UnknownHostException; // CraftBukkit - throws UnknownHostException + + protected void a(String s) { + if (this.getConvertable().isConvertable(s)) { +@@ -129,6 +183,7 @@ + this.a(s); + this.b("menu.loadingLevel"); + this.worldServer = new WorldServer[3]; ++ /* CraftBukkit start - Remove ticktime arrays and worldsettings + this.h = new long[this.worldServer.length][100]; + IDataManager idatamanager = this.convertable.a(s, true); + +@@ -152,37 +207,110 @@ + worlddata.a(s1); + worldsettings = new WorldSettings(worlddata); + } ++ */ ++ int worldCount = 3; + +- for (int j = 0; j < this.worldServer.length; ++j) { +- byte b0 = 0; ++ for (int j = 0; j < worldCount; ++j) { ++ WorldServer world; ++ byte dimension = 0; + + if (j == 1) { +- b0 = -1; ++ if (getAllowNether()) { ++ dimension = -1; ++ } else { ++ continue; ++ } + } + + if (j == 2) { +- b0 = 1; ++ if (server.getAllowEnd()) { ++ dimension = 1; ++ } else { ++ continue; ++ } + } + ++ String worldType = org.bukkit.World.Environment.getEnvironment(dimension).toString().toLowerCase(); ++ String name = (dimension == 0) ? s : s + "_" + worldType; ++ ++ org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name); ++ WorldSettings worldsettings = new WorldSettings(i, this.getGamemode(), this.getGenerateStructures(), this.isHardcore(), worldtype); ++ worldsettings.setGeneratorSettings(s2); ++ + if (j == 0) { ++ IDataManager idatamanager = new ServerNBTManager(server.getWorldContainer(), s1, true); ++ WorldData worlddata = idatamanager.getWorldData(); ++ if (worlddata == null) { ++ worlddata = new WorldData(worldsettings, s1); ++ } + if (this.W()) { +- this.worldServer[j] = (WorldServer) (new DemoWorldServer(this, idatamanager, worlddata, b0, this.methodProfiler)).b(); ++ world = (WorldServer) (new DemoWorldServer(this, idatamanager, worlddata, dimension, this.methodProfiler)).b(); + } else { +- this.worldServer[j] = (WorldServer) (new WorldServer(this, idatamanager, worlddata, b0, this.methodProfiler)).b(); ++ world = (WorldServer) (new WorldServer(this, idatamanager, worlddata, dimension, this.methodProfiler, org.bukkit.World.Environment.getEnvironment(dimension), gen)).b(); + } + +- this.worldServer[j].a(worldsettings); ++ world.a(worldsettings); ++ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard()); + } else { +- this.worldServer[j] = (WorldServer) (new SecondaryWorldServer(this, idatamanager, b0, this.worldServer[0], this.methodProfiler)).b(); ++ String dim = "DIM" + dimension; ++ ++ File newWorld = new File(new File(name), dim); ++ File oldWorld = new File(new File(s), dim); ++ ++ if ((!newWorld.isDirectory()) && (oldWorld.isDirectory())) { ++ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder required ----"); ++ MinecraftServer.LOGGER.info("Unfortunately due to the way that Minecraft implemented multiworld support in 1.6, Bukkit requires that you move your " + worldType + " folder to a new location in order to operate correctly."); ++ MinecraftServer.LOGGER.info("We will move this folder for you, but it will mean that you need to move it back should you wish to stop using Bukkit in the future."); ++ MinecraftServer.LOGGER.info("Attempting to move " + oldWorld + " to " + newWorld + "..."); ++ ++ if (newWorld.exists()) { ++ MinecraftServer.LOGGER.warn("A file or folder already exists at " + newWorld + "!"); ++ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----"); ++ } else if (newWorld.getParentFile().mkdirs()) { ++ if (oldWorld.renameTo(newWorld)) { ++ MinecraftServer.LOGGER.info("Success! To restore " + worldType + " in the future, simply move " + newWorld + " to " + oldWorld); ++ // Migrate world data too. ++ try { ++ com.google.common.io.Files.copy(new File(new File(s), "level.dat"), new File(new File(name), "level.dat")); ++ } catch (IOException exception) { ++ MinecraftServer.LOGGER.warn("Unable to migrate world data."); ++ } ++ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder complete ----"); ++ } else { ++ MinecraftServer.LOGGER.warn("Could not move folder " + oldWorld + " to " + newWorld + "!"); ++ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----"); ++ } ++ } else { ++ MinecraftServer.LOGGER.warn("Could not create path for " + newWorld + "!"); ++ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----"); ++ } ++ } ++ ++ IDataManager idatamanager = new ServerNBTManager(server.getWorldContainer(), name, true); ++ // world =, b0 to dimension, s1 to name, added Environment and gen ++ WorldData worlddata = idatamanager.getWorldData(); ++ if (worlddata == null) { ++ worlddata = new WorldData(worldsettings, name); ++ } ++ world = (WorldServer) new SecondaryWorldServer(this, idatamanager, dimension, this.worlds.get(0), this.methodProfiler, worlddata, org.bukkit.World.Environment.getEnvironment(dimension), gen).b(); + } + +- this.worldServer[j].addIWorldAccess(new WorldManager(this, this.worldServer[j])); ++ if (gen != null) { ++ world.getWorld().getPopulators().addAll(gen.getDefaultPopulators(world.getWorld())); ++ } ++ ++ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(world.getWorld())); ++ ++ world.addIWorldAccess(new WorldManager(this, world)); + if (!this.S()) { +- this.worldServer[j].getWorldData().setGameType(this.getGamemode()); ++ world.getWorldData().setGameType(this.getGamemode()); + } ++ ++ worlds.add(world); ++ getPlayerList().setPlayerFileData(worlds.toArray(new WorldServer[worlds.size()])); + } + +- this.v.setPlayerFileData(this.worldServer); ++ // CraftBukkit end + this.a(this.getDifficulty()); + this.k(); + } +@@ -197,25 +325,38 @@ + this.b("menu.generatingTerrain"); + byte b0 = 0; + +- MinecraftServer.LOGGER.info("Preparing start region for level " + b0); +- WorldServer worldserver = this.worldServer[b0]; +- BlockPosition blockposition = worldserver.getSpawn(); +- long j = ax(); +- +- for (int k = -192; k <= 192 && this.isRunning(); k += 16) { +- for (int l = -192; l <= 192 && this.isRunning(); l += 16) { +- long i1 = ax(); +- +- if (i1 - j > 1000L) { +- this.a_("Preparing spawn area", i * 100 / 625); +- j = i1; +- } ++ // CraftBukkit start - fire WorldLoadEvent and handle whether or not to keep the spawn in memory ++ for (int m = 0; m < worlds.size(); m++) { ++ WorldServer worldserver = this.worlds.get(m); ++ LOGGER.info("Preparing start region for level " + m + " (Seed: " + worldserver.getSeed() + ")"); ++ ++ if (!worldserver.getWorld().getKeepSpawnInMemory()) { ++ continue; ++ } ++ ++ BlockPosition blockposition = worldserver.getSpawn(); ++ long j = ax(); ++ i = 0; ++ ++ for (int k = -192; k <= 192 && this.isRunning(); k += 16) { ++ for (int l = -192; l <= 192 && this.isRunning(); l += 16) { ++ long i1 = ax(); ++ ++ if (i1 - j > 1000L) { ++ this.a_("Preparing spawn area", i * 100 / 625); ++ j = i1; ++ } + +- ++i; +- worldserver.chunkProviderServer.getChunkAt(blockposition.getX() + k >> 4, blockposition.getZ() + l >> 4); ++ ++i; ++ worldserver.chunkProviderServer.getChunkAt(blockposition.getX() + k >> 4, blockposition.getZ() + l >> 4); ++ } + } + } + ++ for (WorldServer world : this.worlds) { ++ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(world.getWorld())); ++ } ++ // CraftBukkit end + this.q(); + } + +@@ -247,35 +388,42 @@ + protected void q() { + this.e = null; + this.f = 0; ++ ++ this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD); // CraftBukkit + } + +- protected void saveChunks(boolean flag) { ++ protected void saveChunks(boolean flag) throws ExceptionWorldConflict { // CraftBukkit - added throws + if (!this.N) { +- WorldServer[] aworldserver = this.worldServer; +- int i = aworldserver.length; +- +- for (int j = 0; j < i; ++j) { +- WorldServer worldserver = aworldserver[j]; + ++ // CraftBukkit start ++ for (int j = 0; j < worlds.size(); ++j) { ++ WorldServer worldserver = worlds.get(j); ++ // CraftBukkit end + if (worldserver != null) { + if (!flag) { + MinecraftServer.LOGGER.info("Saving chunks for level \'" + worldserver.getWorldData().getName() + "\'/" + worldserver.worldProvider.getName()); + } + +- try { +- worldserver.save(true, (IProgressUpdate) null); +- } catch (ExceptionWorldConflict exceptionworldconflict) { +- MinecraftServer.LOGGER.warn(exceptionworldconflict.getMessage()); +- } ++ worldserver.save(true, (IProgressUpdate) null); ++ worldserver.saveLevel(); ++ ++ WorldSaveEvent event = new WorldSaveEvent(worldserver.getWorld()); ++ this.server.getPluginManager().callEvent(event); ++ // CraftBukkit end + } + } + + } + } + +- public void stop() { ++ public void stop() throws ExceptionWorldConflict { // CraftBukkit - added throws + if (!this.N) { + MinecraftServer.LOGGER.info("Stopping server"); ++ // CraftBukkit start ++ if (this.server != null) { ++ this.server.disablePlugins(); ++ } ++ // CraftBukkit end + if (this.ao() != null) { + this.ao().b(); + } +@@ -290,11 +438,13 @@ + MinecraftServer.LOGGER.info("Saving worlds"); + this.saveChunks(false); + ++ /* CraftBukkit start - Handled in saveChunks + for (int i = 0; i < this.worldServer.length; ++i) { + WorldServer worldserver = this.worldServer[i]; + + worldserver.saveLevel(); + } ++ // CraftBukkit end */ + } + + if (this.m.d()) { +@@ -335,6 +485,7 @@ + long k = j - this.ab; + + if (k > 2000L && this.ab - this.R >= 15000L) { ++ if (server.getWarnOnOverload()) // CraftBukkit + MinecraftServer.LOGGER.warn("Can\'t keep up! Did the system time change, or is the server overloaded? Running {}ms behind, skipping {} tick(s)", new Object[] { Long.valueOf(k), Long.valueOf(k / 50L)}); + k = 2000L; + this.R = this.ab; +@@ -347,11 +498,12 @@ + + i += k; + this.ab = j; +- if (this.worldServer[0].everyoneDeeplySleeping()) { ++ if (this.worlds.get(0).everyoneDeeplySleeping()) { // CraftBukkit + this.y(); + i = 0L; + } else { + while (i > 50L) { ++ MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit + i -= 50L; + this.y(); + } +@@ -389,6 +541,12 @@ + } catch (Throwable throwable1) { + MinecraftServer.LOGGER.error("Exception stopping the server", throwable1); + } finally { ++ // CraftBukkit start - Restore terminal to original settings ++ try { ++ reader.getTerminal().restore(); ++ } catch (Exception ignored) { ++ } ++ // CraftBukkit end + this.x(); + } + +@@ -428,7 +586,7 @@ + + protected void x() {} + +- protected void y() { ++ protected void y() throws ExceptionWorldConflict { // CraftBukkit - added throws + long i = System.nanoTime(); + + ++this.ticks; +@@ -454,7 +612,7 @@ + this.r.b().a(agameprofile); + } + +- if (this.ticks % 900 == 0) { ++ if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit + this.methodProfiler.a("save"); + this.v.savePlayers(); + this.saveChunks(true); +@@ -493,20 +651,40 @@ + + this.methodProfiler.c("levels"); + ++ // CraftBukkit start ++ this.server.getScheduler().mainThreadHeartbeat(this.ticks); ++ ++ // Run tasks that are waiting on processing ++ while (!processQueue.isEmpty()) { ++ processQueue.remove().run(); ++ } ++ ++ org.bukkit.craftbukkit.chunkio.ChunkIOExecutor.tick(); ++ ++ // Send time updates to everyone, it will get the right time from the world the player is in. ++ if (this.ticks % 20 == 0) { ++ for (int i = 0; i < this.getPlayerList().players.size(); ++i) { ++ EntityPlayer entityplayer = (EntityPlayer) this.getPlayerList().players.get(i); ++ entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateTime(entityplayer.world.getTime(), entityplayer.getPlayerTime(), entityplayer.world.getGameRules().getBoolean("doDaylightCycle"))); // Add support for per player time ++ } ++ } ++ + int i; + +- for (i = 0; i < this.worldServer.length; ++i) { ++ for (i = 0; i < this.worlds.size(); ++i) { + long j = System.nanoTime(); + +- if (i == 0 || this.getAllowNether()) { +- WorldServer worldserver = this.worldServer[i]; ++ // if (i == 0 || this.getAllowNether()) { ++ WorldServer worldserver = this.worlds.get(i); + + this.methodProfiler.a(worldserver.getWorldData().getName()); ++ /* Drop global time updates + if (this.ticks % 20 == 0) { + this.methodProfiler.a("timeSync"); + this.v.a(new PacketPlayOutUpdateTime(worldserver.getTime(), worldserver.getDayTime(), worldserver.getGameRules().getBoolean("doDaylightCycle")), worldserver.worldProvider.getDimension()); + this.methodProfiler.b(); + } ++ // CraftBukkit end */ + + this.methodProfiler.a("tick"); + +@@ -533,9 +711,9 @@ + worldserver.getTracker().updatePlayers(); + this.methodProfiler.b(); + this.methodProfiler.b(); +- } ++ // } // CraftBukkit + +- this.h[i][this.ticks % 100] = System.nanoTime() - j; ++ // this.h[i][this.ticks % 100] = System.nanoTime() - j; // CraftBukkit + } + + this.methodProfiler.c("connection"); +@@ -559,10 +737,11 @@ + this.o.add(iupdateplayerlistbox); + } + +- public static void main(String[] astring) { ++ public static void main(final OptionSet options) { // CraftBukkit - replaces main(String[] astring) + DispenserRegistry.c(); + + try { ++ /* CraftBukkit start - Replace everything + boolean flag = true; + String s = null; + String s1 = "."; +@@ -636,6 +815,29 @@ + + dedicatedserver.B(); + Runtime.getRuntime().addShutdownHook(new ThreadShutdown("Server Shutdown Thread", dedicatedserver)); ++ */ ++ ++ DedicatedServer dedicatedserver = new DedicatedServer(options); ++ ++ if (options.has("port")) { ++ int port = (Integer) options.valueOf("port"); ++ if (port > 0) { ++ dedicatedserver.setPort(port); ++ } ++ } ++ ++ if (options.has("universe")) { ++ dedicatedserver.universe = (File) options.valueOf("universe"); ++ } else { ++ dedicatedserver.universe = new File("."); ++ } ++ ++ if (options.has("world")) { ++ dedicatedserver.setWorld((String) options.valueOf("world")); ++ } ++ ++ dedicatedserver.primaryThread.start(); ++ // CraftBukkit end + } catch (Exception exception) { + MinecraftServer.LOGGER.fatal("Failed to start the minecraft server", exception); + } +@@ -643,8 +845,10 @@ + } + + public void B() { ++ /* CraftBukkit start - prevent abuse + this.serverThread = new Thread(this, "Server thread"); + this.serverThread.start(); ++ // CraftBukkit end */ + } + + public File d(String s) { +@@ -660,7 +864,14 @@ + } + + public WorldServer getWorldServer(int i) { +- return i == -1 ? this.worldServer[1] : (i == 1 ? this.worldServer[2] : this.worldServer[0]); ++ // CraftBukkit start ++ for (WorldServer world : worlds) { ++ if (world.dimension == i) { ++ return world; ++ } ++ } ++ return worlds.get(0); ++ // CraftBukkit end + } + + public String C() { +@@ -696,17 +907,62 @@ + } + + public String getPlugins() { +- return ""; +- } ++ // CraftBukkit start - Whole method ++ StringBuilder result = new StringBuilder(); ++ org.bukkit.plugin.Plugin[] plugins = server.getPluginManager().getPlugins(); ++ ++ result.append(server.getName()); ++ result.append(" on Bukkit "); ++ result.append(server.getBukkitVersion()); ++ ++ if (plugins.length > 0 && server.getQueryPlugins()) { ++ result.append(": "); ++ ++ for (int i = 0; i < plugins.length; i++) { ++ if (i > 0) { ++ result.append("; "); ++ } + +- public String executeRemoteCommand(String s) { +- RemoteControlCommandListener.getInstance().i(); +- this.p.a(RemoteControlCommandListener.getInstance(), s); +- return RemoteControlCommandListener.getInstance().j(); ++ result.append(plugins[i].getDescription().getName()); ++ result.append(" "); ++ result.append(plugins[i].getDescription().getVersion().replaceAll(";", ",")); ++ } ++ } ++ ++ return result.toString(); ++ // CraftBukkit end ++ } ++ ++ // CraftBukkit start - fire RemoteServerCommandEvent ++ public String executeRemoteCommand(final String s) { ++ Waitable waitable = new Waitable() { ++ @Override ++ protected String evaluate() { ++ RemoteControlCommandListener.getInstance().i(); ++ // Event changes start ++ RemoteServerCommandEvent event = new RemoteServerCommandEvent(remoteConsole, s); ++ server.getPluginManager().callEvent(event); ++ // Event change end ++ ServerCommand serverCommand = new ServerCommand(event.getCommand(), RemoteControlCommandListener.getInstance()); ++ server.dispatchServerCommand(remoteConsole, serverCommand); ++ // this.p.a(RemoteControlCommandListener.getInstance(), s); ++ return RemoteControlCommandListener.getInstance().j(); ++ } ++ }; ++ processQueue.add(waitable); ++ try { ++ return waitable.get(); ++ } catch (java.util.concurrent.ExecutionException e) { ++ throw new RuntimeException("Exception processing rcon command " + s, e.getCause()); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); // Maintain interrupted state ++ throw new RuntimeException("Interrupted processing rcon command " + s, e); ++ } ++ // CraftBukkit end + } + + public boolean isDebugging() { +- return false; ++ return this.getPropertyManager().getBoolean("debug", false); // CraftBukkit - don't hardcode + } + + public void h(String s) { +@@ -721,7 +977,7 @@ + } + + public String getServerModName() { +- return "vanilla"; ++ return server.getName(); // CraftBukkit - cb > vanilla! + } + + public CrashReport b(CrashReport crashreport) { +@@ -734,6 +990,7 @@ + } + + public List tabCompleteCommand(ICommandListener icommandlistener, String s, BlockPosition blockposition) { ++ /* CraftBukkit start - Allow tab-completion of Bukkit commands + ArrayList arraylist = Lists.newArrayList(); + + if (s.startsWith("/")) { +@@ -772,6 +1029,9 @@ + + return arraylist; + } ++ */ ++ return server.tabComplete(icommandlistener, s); ++ // CraftBukkit end + } + + public static MinecraftServer getServer() { +@@ -835,8 +1095,10 @@ + } + + public void a(EnumDifficulty enumdifficulty) { +- for (int i = 0; i < this.worldServer.length; ++i) { +- WorldServer worldserver = this.worldServer[i]; ++ // CraftBukkit start ++ for (int i = 0; i < this.worlds.size(); ++i) { ++ WorldServer worldserver = this.worlds.get(i); ++ // CraftBukkit end + + if (worldserver != null) { + if (worldserver.getWorldData().isHardcore()) { +@@ -878,15 +1140,17 @@ + this.N = true; + this.getConvertable().d(); + +- for (int i = 0; i < this.worldServer.length; ++i) { +- WorldServer worldserver = this.worldServer[i]; ++ // CraftBukkit start ++ for (int i = 0; i < this.worlds.size(); ++i) { ++ WorldServer worldserver = this.worlds.get(i); ++ // CraftBukkit end + + if (worldserver != null) { + worldserver.saveLevel(); + } + } + +- this.getConvertable().e(this.worldServer[0].getDataManager().g()); ++ this.getConvertable().e(this.worlds.get(0).getDataManager().g()); // CraftBukkit + this.safeShutdown(); + } + +@@ -919,9 +1183,11 @@ + int i = 0; + + if (this.worldServer != null) { +- for (int j = 0; j < this.worldServer.length; ++j) { +- if (this.worldServer[j] != null) { +- WorldServer worldserver = this.worldServer[j]; ++ // CraftBukkit start ++ for (int j = 0; j < this.worlds.size(); ++j) { ++ WorldServer worldserver = this.worlds.get(j); ++ if (worldserver != null) { ++ // CraftBukkit end + WorldData worlddata = worldserver.getWorldData(); + + mojangstatisticsgenerator.a("world[" + i + "][dimension]", Integer.valueOf(worldserver.worldProvider.getDimension())); +@@ -954,7 +1220,7 @@ + public abstract boolean ad(); + + public boolean getOnlineMode() { +- return this.onlineMode; ++ return server.getOnlineMode(); // CraftBukkit + } + + public void setOnlineMode(boolean flag) { +@@ -1024,8 +1290,10 @@ + } + + public void setGamemode(EnumGamemode enumgamemode) { +- for (int i = 0; i < this.worldServer.length; ++i) { +- getServer().worldServer[i].getWorldData().setGameType(enumgamemode); ++ // CraftBukkit start ++ for (int i = 0; i < this.worlds.size(); ++i) { ++ getServer().worlds.get(i).getWorldData().setGameType(enumgamemode); ++ // CraftBukkit end + } + + } +@@ -1057,7 +1325,7 @@ + } + + public World getWorld() { +- return this.worldServer[0]; ++ return this.worlds.get(0); // CraftBukkit + } + + public Entity f() { +@@ -1125,11 +1393,10 @@ + } + + public Entity a(UUID uuid) { +- WorldServer[] aworldserver = this.worldServer; +- int i = aworldserver.length; +- +- for (int j = 0; j < i; ++j) { +- WorldServer worldserver = aworldserver[j]; ++ // CraftBukkit start ++ for (int j = 0; j < worlds.size(); ++j) { ++ WorldServer worldserver = worlds.get(j); ++ // CraftBukkit end + + if (worldserver != null) { + Entity entity = worldserver.getEntity(uuid); +@@ -1144,7 +1411,7 @@ + } + + public boolean getSendCommandFeedback() { +- return getServer().worldServer[0].getGameRules().getBoolean("sendCommandFeedback"); ++ return getServer().worlds.get(0).getGameRules().getBoolean("sendCommandFeedback"); // CraftBukkit + } + + public void a(EnumCommandResult enumcommandresult, int i) {} diff --git a/paper-server/nms-patches/MobEffectList.patch b/paper-server/nms-patches/MobEffectList.patch new file mode 100644 index 0000000000..33ebcae25a --- /dev/null +++ b/paper-server/nms-patches/MobEffectList.patch @@ -0,0 +1,74 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/MobEffectList.java 2014-11-27 08:59:46.801421406 +1100 ++++ src/main/java/net/minecraft/server/MobEffectList.java 2014-11-27 08:42:10.120850973 +1100 +@@ -6,6 +6,11 @@ + import java.util.UUID; + import java.util.Map.Entry; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; ++// CraftBukkit end ++ + public class MobEffectList { + + public static final MobEffectList[] byId = new MobEffectList[32]; +@@ -63,6 +68,8 @@ + } + + this.L = j; ++ org.bukkit.potion.PotionEffectType.registerPotionEffectType(new org.bukkit.craftbukkit.potion.CraftPotionEffectType(this)); // CraftBukkit ++ + } + + public static MobEffectList b(String s) { +@@ -94,11 +101,11 @@ + public void tick(EntityLiving entityliving, int i) { + if (this.id == MobEffectList.REGENERATION.id) { + if (entityliving.getHealth() < entityliving.getMaxHealth()) { +- entityliving.heal(1.0F); ++ entityliving.heal(1.0F, RegainReason.MAGIC_REGEN); // CraftBukkit + } + } else if (this.id == MobEffectList.POISON.id) { + if (entityliving.getHealth() > 1.0F) { +- entityliving.damageEntity(DamageSource.MAGIC, 1.0F); ++ entityliving.damageEntity(CraftEventFactory.POISON, 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON + } + } else if (this.id == MobEffectList.WITHER.id) { + entityliving.damageEntity(DamageSource.WITHER, 1.0F); +@@ -106,14 +113,25 @@ + ((EntityHuman) entityliving).applyExhaustion(0.025F * (float) (i + 1)); + } else if (this.id == MobEffectList.SATURATION.id && entityliving instanceof EntityHuman) { + if (!entityliving.world.isStatic) { +- ((EntityHuman) entityliving).getFoodData().eat(i + 1, 1.0F); ++ // CraftBukkit start ++ EntityHuman entityhuman = (EntityHuman) entityliving; ++ int oldFoodLevel = entityhuman.getFoodData().foodLevel; ++ ++ org.bukkit.event.entity.FoodLevelChangeEvent event = CraftEventFactory.callFoodLevelChangeEvent(entityhuman, i + 1 + oldFoodLevel); ++ ++ if (!event.isCancelled()) { ++ entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 1.0F); ++ } ++ ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutUpdateHealth(((EntityPlayer) entityhuman).getBukkitEntity().getScaledHealth(), entityhuman.getFoodData().foodLevel, entityhuman.getFoodData().saturationLevel)); ++ // CraftBukkit end + } + } else if ((this.id != MobEffectList.HEAL.id || entityliving.bl()) && (this.id != MobEffectList.HARM.id || !entityliving.bl())) { + if (this.id == MobEffectList.HARM.id && !entityliving.bl() || this.id == MobEffectList.HEAL.id && entityliving.bl()) { + entityliving.damageEntity(DamageSource.MAGIC, (float) (6 << i)); + } + } else { +- entityliving.heal((float) Math.max(4 << i, 0)); ++ entityliving.heal((float) Math.max(4 << i, 0), RegainReason.MAGIC); // CraftBukkit + } + + } +@@ -132,7 +150,7 @@ + } + } else { + j = (int) (d0 * (double) (4 << i) + 0.5D); +- entityliving.heal((float) j); ++ entityliving.heal((float) j, RegainReason.MAGIC); // CraftBukkit + } + + } diff --git a/paper-server/nms-patches/MobSpawnerAbstract.patch b/paper-server/nms-patches/MobSpawnerAbstract.patch new file mode 100644 index 0000000000..1a93618353 --- /dev/null +++ b/paper-server/nms-patches/MobSpawnerAbstract.patch @@ -0,0 +1,38 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/MobSpawnerAbstract.java 2014-11-27 08:59:46.805421389 +1100 ++++ src/main/java/net/minecraft/server/MobSpawnerAbstract.java 2014-11-27 08:42:10.108850996 +1100 +@@ -4,6 +4,8 @@ + import java.util.Iterator; + import java.util.List; + ++import org.bukkit.event.entity.CreatureSpawnEvent; // CraftBukkit ++ + public abstract class MobSpawnerAbstract { + + public int spawnDelay = 20; +@@ -129,7 +131,7 @@ + + entity.f(nbttagcompound); + if (entity.world != null && flag) { +- entity.world.addEntity(entity); ++ entity.world.addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER); // CraftBukkit + } + + NBTTagCompound nbttagcompound1; +@@ -154,7 +156,7 @@ + entity2.f(nbttagcompound2); + entity2.setPositionRotation(entity1.locX, entity1.locY, entity1.locZ, entity1.yaw, entity1.pitch); + if (entity.world != null && flag) { +- entity.world.addEntity(entity2); ++ entity.world.addEntity(entity2, CreatureSpawnEvent.SpawnReason.SPAWNER); // CraftBukkit + } + + entity1.mount(entity2); +@@ -164,7 +166,7 @@ + } + } else if (entity instanceof EntityLiving && entity.world != null && flag) { + ((EntityInsentient) entity).prepare(entity.world.E(new BlockPosition(entity)), (GroupDataEntity) null); +- entity.world.addEntity(entity); ++ entity.world.addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER); // CraftBukkit + } + + return entity; diff --git a/paper-server/nms-patches/NameReferencingFileConverter.patch b/paper-server/nms-patches/NameReferencingFileConverter.patch new file mode 100644 index 0000000000..621762db65 --- /dev/null +++ b/paper-server/nms-patches/NameReferencingFileConverter.patch @@ -0,0 +1,76 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/NameReferencingFileConverter.java 2014-11-27 08:59:46.805421389 +1100 ++++ src/main/java/net/minecraft/server/NameReferencingFileConverter.java 2014-11-27 08:42:10.168850880 +1100 +@@ -32,7 +32,7 @@ + public static final File c = new File("ops.txt"); + public static final File d = new File("white-list.txt"); + +- static List a(File file, Map map) { ++ static List a(File file, Map map) throws IOException { // CraftBukkit - Added throws + List list = Files.readLines(file, Charsets.UTF_8); + Iterator iterator = list.iterator(); + +@@ -77,9 +77,11 @@ + if (gameprofilebanlist.c().exists()) { + try { + gameprofilebanlist.load(); +- } catch (FileNotFoundException filenotfoundexception) { +- NameReferencingFileConverter.e.warn("Could not load existing file " + gameprofilebanlist.c().getName(), filenotfoundexception); ++ // CraftBukkit start - FileNotFoundException -> IOException, don't print stacetrace ++ } catch (IOException filenotfoundexception) { ++ e.warn("Could not load existing file " + gameprofilebanlist.c().getName() + ", " + filenotfoundexception.getMessage()); + } ++ // CraftBukkit end + } + + try { +@@ -111,9 +113,11 @@ + if (ipbanlist.c().exists()) { + try { + ipbanlist.load(); +- } catch (FileNotFoundException filenotfoundexception) { +- NameReferencingFileConverter.e.warn("Could not load existing file " + ipbanlist.c().getName(), filenotfoundexception); ++ // CraftBukkit start - FileNotFoundException -> IOException, don't print stacetrace ++ } catch (IOException filenotfoundexception) { ++ e.warn("Could not load existing file " + ipbanlist.c().getName() + ", " + filenotfoundexception.getMessage()); + } ++ // CraftBukkit end + } + + try { +@@ -152,9 +156,11 @@ + if (oplist.c().exists()) { + try { + oplist.load(); +- } catch (FileNotFoundException filenotfoundexception) { +- NameReferencingFileConverter.e.warn("Could not load existing file " + oplist.c().getName(), filenotfoundexception); ++ // CraftBukkit start - FileNotFoundException -> IOException, don't print stacetrace ++ } catch (IOException filenotfoundexception) { ++ e.warn("Could not load existing file " + oplist.c().getName() + ", " + filenotfoundexception.getMessage()); + } ++ // CraftBukkit end + } + + try { +@@ -184,9 +190,11 @@ + if (whitelist.c().exists()) { + try { + whitelist.load(); +- } catch (FileNotFoundException filenotfoundexception) { +- NameReferencingFileConverter.e.warn("Could not load existing file " + whitelist.c().getName(), filenotfoundexception); ++ // CraftBukkit start - FileNotFoundException -> IOException, don't print stacetrace ++ } catch (IOException filenotfoundexception) { ++ e.warn("Could not load existing file " + whitelist.c().getName() + ", " + filenotfoundexception.getMessage()); + } ++ // CraftBukkit end + } + + try { +@@ -351,7 +359,7 @@ + + private static File d(PropertyManager propertymanager) { + String s = propertymanager.getString("level-name", "world"); +- File file = new File(s); ++ File file = new File(MinecraftServer.getServer().server.getWorldContainer(), s); // CraftBukkit - Respect container setting + + return new File(file, "players"); + } diff --git a/paper-server/nms-patches/NetworkManager.patch b/paper-server/nms-patches/NetworkManager.patch new file mode 100644 index 0000000000..99a6dc9109 --- /dev/null +++ b/paper-server/nms-patches/NetworkManager.patch @@ -0,0 +1,20 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/NetworkManager.java 2014-11-27 08:59:46.809421371 +1100 ++++ src/main/java/net/minecraft/server/NetworkManager.java 2014-11-27 08:42:10.120850973 +1100 +@@ -41,7 +41,7 @@ + this.g = enumprotocoldirection; + } + +- public void channelActive(ChannelHandlerContext channelhandlercontext) { ++ public void channelActive(ChannelHandlerContext channelhandlercontext) throws Exception { // CraftBukkit - added throws + super.channelActive(channelhandlercontext); + this.i = channelhandlercontext.channel(); + this.j = this.i.remoteAddress(); +@@ -159,7 +159,7 @@ + + public void close(IChatBaseComponent ichatbasecomponent) { + if (this.i.isOpen()) { +- this.i.close().awaitUninterruptibly(); ++ this.i.close(); // We can't wait as this may be called from an event loop. + this.l = ichatbasecomponent; + } + diff --git a/paper-server/nms-patches/Packet.patch b/paper-server/nms-patches/Packet.patch new file mode 100644 index 0000000000..29864db4bc --- /dev/null +++ b/paper-server/nms-patches/Packet.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Packet.java 2014-11-27 08:59:46.813421353 +1100 ++++ src/main/java/net/minecraft/server/Packet.java 2014-11-27 08:42:10.152850911 +1100 +@@ -2,9 +2,9 @@ + + public interface Packet { + +- void a(PacketDataSerializer packetdataserializer); ++ void a(PacketDataSerializer packetdataserializer) throws java.io.IOException; // CraftBukkit - added throws + +- void b(PacketDataSerializer packetdataserializer); ++ void b(PacketDataSerializer packetdataserializer) throws java.io.IOException; // CraftBukkit - added throws + + void a(PacketListener packetlistener); + } diff --git a/paper-server/nms-patches/PacketDataSerializer.patch b/paper-server/nms-patches/PacketDataSerializer.patch new file mode 100644 index 0000000000..20a1268c51 --- /dev/null +++ b/paper-server/nms-patches/PacketDataSerializer.patch @@ -0,0 +1,122 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PacketDataSerializer.java 2014-11-27 08:59:46.809421371 +1100 ++++ src/main/java/net/minecraft/server/PacketDataSerializer.java 2014-11-27 08:42:10.108850996 +1100 +@@ -8,7 +8,6 @@ + import io.netty.buffer.ByteBufProcessor; + import io.netty.handler.codec.DecoderException; + import io.netty.handler.codec.EncoderException; +-import io.netty.util.ReferenceCounted; + import java.io.DataInput; + import java.io.DataOutput; + import java.io.IOException; +@@ -21,6 +20,8 @@ + import java.nio.charset.Charset; + import java.util.UUID; + ++import org.bukkit.craftbukkit.inventory.CraftItemStack; // CraftBukkit ++ + public class PacketDataSerializer extends ByteBuf { + + private final ByteBuf a; +@@ -142,7 +143,7 @@ + } else { + try { + NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) (new ByteBufOutputStream(this))); +- } catch (IOException ioexception) { ++ } catch (Exception ioexception) { // CraftBukkit - IOException -> Exception + throw new EncoderException(ioexception); + } + } +@@ -162,7 +163,7 @@ + } + + public void a(ItemStack itemstack) { +- if (itemstack == null) { ++ if (itemstack == null || itemstack.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem() + this.writeShort(-1); + } else { + this.writeShort(Item.getId(itemstack.getItem())); +@@ -189,6 +190,11 @@ + + itemstack = new ItemStack(Item.getById(short0), b0, short1); + itemstack.setTag(this.h()); ++ // CraftBukkit start ++ if (itemstack.getTag() != null) { ++ CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack)); ++ } ++ // CraftBukkit end + } + + return itemstack; +@@ -416,11 +422,11 @@ + return this.a.getBytes(i, bytebuffer); + } + +- public ByteBuf getBytes(int i, OutputStream outputstream, int j) { ++ public ByteBuf getBytes(int i, OutputStream outputstream, int j) throws IOException { // CraftBukkit - throws IOException + return this.a.getBytes(i, outputstream, j); + } + +- public int getBytes(int i, GatheringByteChannel gatheringbytechannel, int j) { ++ public int getBytes(int i, GatheringByteChannel gatheringbytechannel, int j) throws IOException { // CraftBukkit - throws IOException + return this.a.getBytes(i, gatheringbytechannel, j); + } + +@@ -484,11 +490,11 @@ + return this.a.setBytes(i, bytebuffer); + } + +- public int setBytes(int i, InputStream inputstream, int j) { ++ public int setBytes(int i, InputStream inputstream, int j) throws IOException { // CraftBukkit - throws IOException + return this.a.setBytes(i, inputstream, j); + } + +- public int setBytes(int i, ScatteringByteChannel scatteringbytechannel, int j) { ++ public int setBytes(int i, ScatteringByteChannel scatteringbytechannel, int j) throws IOException { // CraftBukkit - throws IOException + return this.a.setBytes(i, scatteringbytechannel, j); + } + +@@ -580,11 +586,11 @@ + return this.a.readBytes(bytebuffer); + } + +- public ByteBuf readBytes(OutputStream outputstream, int i) { ++ public ByteBuf readBytes(OutputStream outputstream, int i) throws IOException { // CraftBukkit - throws IOException + return this.a.readBytes(outputstream, i); + } + +- public int readBytes(GatheringByteChannel gatheringbytechannel, int i) { ++ public int readBytes(GatheringByteChannel gatheringbytechannel, int i) throws IOException { // CraftBukkit - throws IOException + return this.a.readBytes(gatheringbytechannel, i); + } + +@@ -652,11 +658,11 @@ + return this.a.writeBytes(bytebuffer); + } + +- public int writeBytes(InputStream inputstream, int i) { ++ public int writeBytes(InputStream inputstream, int i) throws IOException { // CraftBukkit - throws IOException + return this.a.writeBytes(inputstream, i); + } + +- public int writeBytes(ScatteringByteChannel scatteringbytechannel, int i) { ++ public int writeBytes(ScatteringByteChannel scatteringbytechannel, int i) throws IOException { // CraftBukkit - throws IOException + return this.a.writeBytes(scatteringbytechannel, i); + } + +@@ -803,16 +809,4 @@ + public boolean release(int i) { + return this.a.release(i); + } +- +- public ReferenceCounted retain(int i) { +- return this.retain(i); +- } +- +- public ReferenceCounted retain() { +- return this.retain(); +- } +- +- public int compareTo(Object object) { +- return this.compareTo((ByteBuf) object); +- } + } diff --git a/paper-server/nms-patches/PacketPlayInBlockPlace.patch b/paper-server/nms-patches/PacketPlayInBlockPlace.patch new file mode 100644 index 0000000000..d986bc094e --- /dev/null +++ b/paper-server/nms-patches/PacketPlayInBlockPlace.patch @@ -0,0 +1,32 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PacketPlayInBlockPlace.java 2014-11-27 08:59:46.813421353 +1100 ++++ src/main/java/net/minecraft/server/PacketPlayInBlockPlace.java 2014-11-27 08:42:10.152850911 +1100 +@@ -9,6 +9,8 @@ + private float e; + private float f; + private float g; ++ ++ public long timestamp; // CraftBukkit + + public PacketPlayInBlockPlace() {} + +@@ -26,6 +28,7 @@ + } + + public void a(PacketDataSerializer packetdataserializer) { ++ timestamp = System.currentTimeMillis(); // CraftBukkit + this.b = packetdataserializer.c(); + this.c = packetdataserializer.readUnsignedByte(); + this.d = packetdataserializer.i(); +@@ -71,7 +74,10 @@ + return this.g; + } + +- public void a(PacketListener packetlistener) { +- this.a((PacketListenerPlayIn) packetlistener); ++ // CraftBukkit start - fix decompile error ++ @Override ++ public void a(PacketListener pl) { ++ a((PacketListenerPlayIn)pl); + } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/PacketPlayInCloseWindow.patch b/paper-server/nms-patches/PacketPlayInCloseWindow.patch new file mode 100644 index 0000000000..14efaf9ce0 --- /dev/null +++ b/paper-server/nms-patches/PacketPlayInCloseWindow.patch @@ -0,0 +1,29 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PacketPlayInCloseWindow.java 2014-11-27 08:59:46.817421336 +1100 ++++ src/main/java/net/minecraft/server/PacketPlayInCloseWindow.java 2014-11-27 08:42:10.168850880 +1100 +@@ -6,6 +6,17 @@ + + public PacketPlayInCloseWindow() {} + ++ // CraftBukkit start ++ @Override ++ public void a(PacketListener pl) { ++ a((PacketListenerPlayIn) pl); ++ } ++ ++ public PacketPlayInCloseWindow(int id) { ++ this.id = id; ++ } ++ // CraftBukkit end ++ + public void a(PacketListenerPlayIn packetlistenerplayin) { + packetlistenerplayin.a(this); + } +@@ -17,8 +28,4 @@ + public void b(PacketDataSerializer packetdataserializer) { + packetdataserializer.writeByte(this.id); + } +- +- public void a(PacketListener packetlistener) { +- this.a((PacketListenerPlayIn) packetlistener); +- } + } diff --git a/paper-server/nms-patches/PacketStatusListener.patch b/paper-server/nms-patches/PacketStatusListener.patch new file mode 100644 index 0000000000..b7aad22405 --- /dev/null +++ b/paper-server/nms-patches/PacketStatusListener.patch @@ -0,0 +1,113 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PacketStatusListener.java 2014-11-27 08:59:46.817421336 +1100 ++++ src/main/java/net/minecraft/server/PacketStatusListener.java 2014-11-27 08:42:10.168850880 +1100 +@@ -1,5 +1,15 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import com.mojang.authlib.GameProfile; ++import java.net.InetSocketAddress; ++import java.util.Iterator; ++ ++import org.bukkit.craftbukkit.util.CraftIconCache; ++import org.bukkit.entity.Player; ++ ++// CraftBukkit end ++ + public class PacketStatusListener implements PacketStatusInListener { + + private final MinecraftServer minecraftServer; +@@ -13,7 +23,93 @@ + public void a(IChatBaseComponent ichatbasecomponent) {} + + public void a(PacketStatusInStart packetstatusinstart) { +- this.networkManager.handle(new PacketStatusOutServerInfo(this.minecraftServer.aE())); ++ // this.networkManager.handle(new PacketStatusOutServerInfo(this.minecraftServer.aE())); ++ // CraftBukkit start - fire ping event ++ final Object[] players = minecraftServer.getPlayerList().players.toArray(); ++ class ServerListPingEvent extends org.bukkit.event.server.ServerListPingEvent { ++ CraftIconCache icon = minecraftServer.server.getServerIcon(); ++ ++ ServerListPingEvent() { ++ super(((InetSocketAddress) networkManager.getSocketAddress()).getAddress(), minecraftServer.getMotd(), minecraftServer.getPlayerList().getMaxPlayers()); ++ } ++ ++ @Override ++ public void setServerIcon(org.bukkit.util.CachedServerIcon icon) { ++ if (!(icon instanceof CraftIconCache)) { ++ throw new IllegalArgumentException(icon + " was not created by " + org.bukkit.craftbukkit.CraftServer.class); ++ } ++ this.icon = (CraftIconCache) icon; ++ } ++ ++ @Override ++ public Iterator iterator() throws UnsupportedOperationException { ++ return new Iterator() { ++ int i; ++ int ret = Integer.MIN_VALUE; ++ EntityPlayer player; ++ ++ @Override ++ public boolean hasNext() { ++ if (player != null) { ++ return true; ++ } ++ final Object[] currentPlayers = players; ++ for (int length = currentPlayers.length, i = this.i; i < length; i++) { ++ final EntityPlayer player = (EntityPlayer) currentPlayers[i]; ++ if (player != null) { ++ this.i = i + 1; ++ this.player = player; ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ @Override ++ public Player next() { ++ if (!hasNext()) { ++ throw new java.util.NoSuchElementException(); ++ } ++ final EntityPlayer player = this.player; ++ this.player = null; ++ this.ret = this.i - 1; ++ return player.getBukkitEntity(); ++ } ++ ++ @Override ++ public void remove() { ++ final Object[] currentPlayers = players; ++ final int i = this.ret; ++ if (i < 0 || currentPlayers[i] == null) { ++ throw new IllegalStateException(); ++ } ++ currentPlayers[i] = null; ++ } ++ }; ++ } ++ } ++ ++ ServerListPingEvent event = new ServerListPingEvent(); ++ this.minecraftServer.server.getPluginManager().callEvent(event); ++ ++ java.util.List profiles = new java.util.ArrayList(players.length); ++ for (Object player : players) { ++ if (player != null) { ++ profiles.add(((EntityPlayer) player).getProfile()); ++ } ++ } ++ ++ ServerPingPlayerSample playerSample = new ServerPingPlayerSample(event.getMaxPlayers(), profiles.size()); ++ playerSample.a(profiles.toArray(new GameProfile[profiles.size()])); ++ ++ ServerPing ping = new ServerPing(); ++ ping.setFavicon(event.icon.value); ++ ping.setMOTD(new ChatComponentText(event.getMotd())); ++ ping.setPlayerSample(playerSample); ++ ping.setServerInfo(new ServerPingServerData(minecraftServer.getServerModName() + " " + minecraftServer.getVersion(), 47)); // TODO: Update when protocol changes ++ ++ this.networkManager.handle(new PacketStatusOutServerInfo(ping)); ++ // CraftBukkit end + } + + public void a(PacketStatusInPing packetstatusinping) { diff --git a/paper-server/nms-patches/Path.patch b/paper-server/nms-patches/Path.patch new file mode 100644 index 0000000000..39db7a87d3 --- /dev/null +++ b/paper-server/nms-patches/Path.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Path.java 2014-11-27 08:59:46.849421195 +1100 ++++ src/main/java/net/minecraft/server/Path.java 2014-11-27 08:42:10.088851036 +1100 +@@ -2,7 +2,7 @@ + + public class Path { + +- private PathPoint[] a = new PathPoint[1024]; ++ private PathPoint[] a = new PathPoint[128]; // CraftBukkit - reduce default size + private int b; + + public Path() {} diff --git a/paper-server/nms-patches/PathfinderGoalBreakDoor.patch b/paper-server/nms-patches/PathfinderGoalBreakDoor.patch new file mode 100644 index 0000000000..c690fcf577 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalBreakDoor.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalBreakDoor.java 2014-11-27 08:59:46.817421336 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalBreakDoor.java 2014-11-27 08:42:10.152850911 +1100 +@@ -63,6 +63,12 @@ + } + + if (this.g == 240 && this.a.world.getDifficulty() == EnumDifficulty.HARD) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.a, this.b.getX(), this.b.getY(), this.b.getZ()).isCancelled()) { ++ this.c(); ++ return; ++ } ++ // CraftBukkit end + this.a.world.setAir(this.b); + this.a.world.triggerEffect(1012, this.b, 0); + this.a.world.triggerEffect(2001, this.b, Block.getId(this.c)); diff --git a/paper-server/nms-patches/PathfinderGoalBreed.patch b/paper-server/nms-patches/PathfinderGoalBreed.patch new file mode 100644 index 0000000000..50c079731a --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalBreed.patch @@ -0,0 +1,23 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalBreed.java 2014-11-27 08:59:46.821421318 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalBreed.java 2014-11-27 08:42:10.164850887 +1100 +@@ -70,6 +70,11 @@ + EntityAgeable entityageable = this.d.createChild(this.e); + + if (entityageable != null) { ++ // CraftBukkit start - set persistence for tame animals ++ if (entityageable instanceof EntityTameableAnimal && ((EntityTameableAnimal) entityageable).isTamed()) { ++ entityageable.persistent = true; ++ } ++ // CraftBukkit end + EntityHuman entityhuman = this.d.co(); + + if (entityhuman == null && this.e.co() != null) { +@@ -89,7 +94,7 @@ + this.e.cq(); + entityageable.setAgeRaw(-24000); + entityageable.setPositionRotation(this.d.locX, this.d.locY, this.d.locZ, 0.0F, 0.0F); +- this.a.addEntity(entityageable); ++ this.a.addEntity(entityageable, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason + Random random = this.d.bb(); + + for (int i = 0; i < 7; ++i) { diff --git a/paper-server/nms-patches/PathfinderGoalDefendVillage.patch b/paper-server/nms-patches/PathfinderGoalDefendVillage.patch new file mode 100644 index 0000000000..2f2260c34e --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalDefendVillage.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalDefendVillage.java 2014-11-27 08:59:46.821421318 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalDefendVillage.java 2014-11-27 08:42:10.172850872 +1100 +@@ -32,7 +32,7 @@ + } + + public void c() { +- this.a.setGoalTarget(this.b); ++ this.a.setGoalTarget(this.b, org.bukkit.event.entity.EntityTargetEvent.TargetReason.DEFEND_VILLAGE, true); // CraftBukkit - reason + super.c(); + } + } diff --git a/paper-server/nms-patches/PathfinderGoalEatTile.patch b/paper-server/nms-patches/PathfinderGoalEatTile.patch new file mode 100644 index 0000000000..88f1cd7997 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalEatTile.patch @@ -0,0 +1,34 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalEatTile.java 2014-11-27 08:59:46.821421318 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalEatTile.java 2014-11-27 08:42:10.108850996 +1100 +@@ -3,6 +3,11 @@ + import com.google.common.base.Predicate; + import com.google.common.base.Predicates; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.Material; ++// CraftBukkit end ++ + public class PathfinderGoalEatTile extends PathfinderGoal { + + private static final Predicate b = BlockStatePredicate.a((Block) Blocks.TALLGRASS).a(BlockLongGrass.TYPE, Predicates.equalTo(EnumTallGrassType.GRASS)); +@@ -50,7 +55,8 @@ + BlockPosition blockposition = new BlockPosition(this.c.locX, this.c.locY, this.c.locZ); + + if (PathfinderGoalEatTile.b.apply(this.d.getType(blockposition))) { +- if (this.d.getGameRules().getBoolean("mobGriefing")) { ++ // CraftBukkit ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.c, this.c.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), Material.AIR, !this.d.getGameRules().getBoolean("mobGriefing")).isCancelled()) { + this.d.setAir(blockposition, false); + } + +@@ -59,7 +65,8 @@ + BlockPosition blockposition1 = blockposition.down(); + + if (this.d.getType(blockposition1).getBlock() == Blocks.GRASS) { +- if (this.d.getGameRules().getBoolean("mobGriefing")) { ++ // CraftBukkit ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.c, this.c.world.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()), Material.DIRT, !this.d.getGameRules().getBoolean("mobGriefing")).isCancelled()) { + this.d.triggerEffect(2001, blockposition1, Block.getId(Blocks.GRASS)); + this.d.setTypeAndData(blockposition1, Blocks.DIRT.getBlockData(), 2); + } diff --git a/paper-server/nms-patches/PathfinderGoalEndermanPickupBlock.patch b/paper-server/nms-patches/PathfinderGoalEndermanPickupBlock.patch new file mode 100644 index 0000000000..31b450c1bd --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalEndermanPickupBlock.patch @@ -0,0 +1,17 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalEndermanPickupBlock.java 2014-11-27 08:59:46.825421301 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalEndermanPickupBlock.java 2014-11-27 08:42:10.164850887 +1100 +@@ -25,8 +25,12 @@ + Block block = iblockdata.getBlock(); + + if (EntityEnderman.co().contains(block)) { +- this.enderman.setCarried(iblockdata); +- world.setTypeUpdate(blockposition, Blocks.AIR.getBlockData()); ++ // CraftBukkit start - Pickup event ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, this.enderman.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), org.bukkit.Material.AIR).isCancelled()) { ++ this.enderman.setCarried(iblockdata); ++ world.setTypeUpdate(blockposition, Blocks.AIR.getBlockData()); ++ } ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/PathfinderGoalEndermanPlaceBlock.patch b/paper-server/nms-patches/PathfinderGoalEndermanPlaceBlock.patch new file mode 100644 index 0000000000..e858f0527c --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalEndermanPlaceBlock.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalEndermanPlaceBlock.java 2014-11-27 08:59:46.825421301 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalEndermanPlaceBlock.java 2014-11-27 08:42:10.172850872 +1100 +@@ -25,8 +25,12 @@ + Block block1 = world.getType(blockposition.down()).getBlock(); + + if (this.a(world, blockposition, this.a.getCarried().getBlock(), block, block1)) { ++ // CraftBukkit start - Place event ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.a, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.a.getCarried().getBlock(), this.a.getCarried().getBlock().toLegacyData(this.a.getCarried())).isCancelled()) { + world.setTypeAndData(blockposition, this.a.getCarried(), 3); + this.a.setCarried(Blocks.AIR.getBlockData()); ++ } ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/PathfinderGoalGhastAttackTarget.patch b/paper-server/nms-patches/PathfinderGoalGhastAttackTarget.patch new file mode 100644 index 0000000000..adc48e2b82 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalGhastAttackTarget.patch @@ -0,0 +1,12 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalGhastAttackTarget.java 2014-11-27 08:59:46.829421283 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalGhastAttackTarget.java 2014-11-27 08:42:10.152850911 +1100 +@@ -43,7 +43,8 @@ + world.a((EntityHuman) null, 1008, new BlockPosition(this.b), 0); + EntityLargeFireball entitylargefireball = new EntityLargeFireball(world, this.b, d2, d3, d4); + +- entitylargefireball.yield = this.b.cd(); ++ // CraftBukkit - set bukkitYield when setting explosionpower ++ entitylargefireball.bukkitYield = entitylargefireball.yield = this.b.cd(); + entitylargefireball.locX = this.b.locX + vec3d.a * d1; + entitylargefireball.locY = this.b.locY + (double) (this.b.length / 2.0F) + 0.5D; + entitylargefireball.locZ = this.b.locZ + vec3d.c * d1; diff --git a/paper-server/nms-patches/PathfinderGoalHurtByTarget.patch b/paper-server/nms-patches/PathfinderGoalHurtByTarget.patch new file mode 100644 index 0000000000..c0763af1b4 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalHurtByTarget.patch @@ -0,0 +1,19 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalHurtByTarget.java 2014-11-27 08:59:46.829421283 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalHurtByTarget.java 2014-11-27 08:42:10.156850903 +1100 +@@ -23,7 +23,7 @@ + } + + public void c() { +- this.e.setGoalTarget(this.e.getLastDamager()); ++ this.e.setGoalTarget(this.e.getLastDamager(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason + this.b = this.e.bd(); + if (this.a) { + double d0 = this.f(); +@@ -58,6 +58,6 @@ + } + + protected void a(EntityCreature entitycreature, EntityLiving entityliving) { +- entitycreature.setGoalTarget(entityliving); ++ entitycreature.setGoalTarget(entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason + } + } diff --git a/paper-server/nms-patches/PathfinderGoalMakeLove.patch b/paper-server/nms-patches/PathfinderGoalMakeLove.patch new file mode 100644 index 0000000000..ce58bcfe0b --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalMakeLove.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalMakeLove.java 2014-11-27 08:59:46.829421283 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalMakeLove.java 2014-11-27 08:42:10.140850934 +1100 +@@ -87,7 +87,7 @@ + this.b.o(false); + entityvillager.setAgeRaw(-24000); + entityvillager.setPositionRotation(this.b.locX, this.b.locY, this.b.locZ, 0.0F, 0.0F); +- this.d.addEntity(entityvillager); ++ this.d.addEntity(entityvillager, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason + this.d.broadcastEntityEffect(entityvillager, (byte) 12); + } + } diff --git a/paper-server/nms-patches/PathfinderGoalNearestAttackableTarget.patch b/paper-server/nms-patches/PathfinderGoalNearestAttackableTarget.patch new file mode 100644 index 0000000000..438278b026 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalNearestAttackableTarget.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalNearestAttackableTarget.java 2014-11-27 08:59:46.833421266 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalNearestAttackableTarget.java 2014-11-27 08:42:10.168850880 +1100 +@@ -48,7 +48,7 @@ + } + + public void c() { +- this.e.setGoalTarget(this.d); ++ this.e.setGoalTarget(this.d, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // Craftbukkit - reason + super.c(); + } + } diff --git a/paper-server/nms-patches/PathfinderGoalNearestAttackableTargetInsentient.patch b/paper-server/nms-patches/PathfinderGoalNearestAttackableTargetInsentient.patch new file mode 100644 index 0000000000..fefd3ad8eb --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalNearestAttackableTargetInsentient.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalNearestAttackableTargetInsentient.java 2014-11-27 08:59:46.833421266 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalNearestAttackableTargetInsentient.java 2014-11-27 08:42:10.084851043 +1100 +@@ -54,7 +54,7 @@ + } + + public void c() { +- this.b.setGoalTarget(this.e); ++ this.b.setGoalTarget(this.e, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY, true); // CraftBukkit - reason + super.c(); + } + diff --git a/paper-server/nms-patches/PathfinderGoalOwnerHurtByTarget.patch b/paper-server/nms-patches/PathfinderGoalOwnerHurtByTarget.patch new file mode 100644 index 0000000000..b8b709f2ba --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalOwnerHurtByTarget.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalOwnerHurtByTarget.java 2014-11-27 08:59:46.833421266 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalOwnerHurtByTarget.java 2014-11-27 08:42:10.096851020 +1100 +@@ -30,7 +30,7 @@ + } + + public void c() { +- this.e.setGoalTarget(this.b); ++ this.e.setGoalTarget(this.b, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_OWNER, true); // CraftBukkit - reason + EntityLiving entityliving = this.a.getOwner(); + + if (entityliving != null) { diff --git a/paper-server/nms-patches/PathfinderGoalOwnerHurtTarget.patch b/paper-server/nms-patches/PathfinderGoalOwnerHurtTarget.patch new file mode 100644 index 0000000000..6e0843f118 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalOwnerHurtTarget.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalOwnerHurtTarget.java 2014-11-27 08:59:46.837421248 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalOwnerHurtTarget.java 2014-11-27 08:42:10.144850927 +1100 +@@ -30,7 +30,7 @@ + } + + public void c() { +- this.e.setGoalTarget(this.b); ++ this.e.setGoalTarget(this.b, org.bukkit.event.entity.EntityTargetEvent.TargetReason.OWNER_ATTACKED_TARGET, true); // CraftBukkit - reason + EntityLiving entityliving = this.a.getOwner(); + + if (entityliving != null) { diff --git a/paper-server/nms-patches/PathfinderGoalPanic.patch b/paper-server/nms-patches/PathfinderGoalPanic.patch new file mode 100644 index 0000000000..e6b5dc8064 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalPanic.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalPanic.java 2014-11-27 08:59:46.837421248 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalPanic.java 2014-11-27 08:42:10.084851043 +1100 +@@ -36,6 +36,12 @@ + } + + public boolean b() { ++ // CraftBukkit start - introduce a temporary timeout hack until this is fixed properly ++ if ((this.b.ticksLived - this.b.bd/*getHurtTimestamp*/()) > 100) { ++ this.b.b((EntityLiving) null); ++ return false; ++ } ++ // CraftBukkit end + return !this.b.getNavigation().m(); + } + } diff --git a/paper-server/nms-patches/PathfinderGoalSelector.patch b/paper-server/nms-patches/PathfinderGoalSelector.patch new file mode 100644 index 0000000000..e4b9428f3f --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalSelector.patch @@ -0,0 +1,32 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalSelector.java 2014-11-27 08:59:46.837421248 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalSelector.java 2014-11-27 08:42:10.164850887 +1100 +@@ -6,11 +6,15 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++import org.bukkit.craftbukkit.util.UnsafeList; // CraftBukkit ++ + public class PathfinderGoalSelector { + + private static final Logger a = LogManager.getLogger(); +- private List b = Lists.newArrayList(); +- private List c = Lists.newArrayList(); ++ // CraftBukkit start - ArrayList -> UnsafeList ++ private List b = new UnsafeList(); ++ private List c = new UnsafeList(); ++ // CraftBukkit end + private final MethodProfiler d; + private int e; + private int f = 3; +@@ -107,9 +111,11 @@ + if (pathfindergoalselectoritem1 != pathfindergoalselectoritem) { + if (pathfindergoalselectoritem.b >= pathfindergoalselectoritem1.b) { + if (!this.a(pathfindergoalselectoritem, pathfindergoalselectoritem1) && this.c.contains(pathfindergoalselectoritem1)) { ++ ((UnsafeList.Itr) iterator).valid = false; // CraftBukkit - mark iterator for reuse + return false; + } + } else if (!pathfindergoalselectoritem1.a.i() && this.c.contains(pathfindergoalselectoritem1)) { ++ ((UnsafeList.Itr) iterator).valid = false; // CraftBukkit - mark iterator for reuse + return false; + } + } diff --git a/paper-server/nms-patches/PathfinderGoalSilverfishHideInBlock.patch b/paper-server/nms-patches/PathfinderGoalSilverfishHideInBlock.patch new file mode 100644 index 0000000000..31d6582bc8 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalSilverfishHideInBlock.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalSilverfishHideInBlock.java 2014-11-27 08:59:46.841421230 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalSilverfishHideInBlock.java 2014-11-27 08:42:10.176850864 +1100 +@@ -51,6 +51,11 @@ + IBlockData iblockdata = world.getType(blockposition); + + if (BlockMonsterEggs.d(iblockdata)) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition.getX(), blockposition.getY(), blockposition.getZ(), Blocks.MONSTER_EGG, Block.getId(BlockMonsterEggs.getById(iblockdata.getBlock().toLegacyData(iblockdata)))).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + world.setTypeAndData(blockposition, Blocks.MONSTER_EGG.getBlockData().set(BlockMonsterEggs.VARIANT, EnumMonsterEggVarient.a(iblockdata)), 3); + this.silverfish.y(); + this.silverfish.die(); diff --git a/paper-server/nms-patches/PathfinderGoalSilverfishWakeOthers.patch b/paper-server/nms-patches/PathfinderGoalSilverfishWakeOthers.patch new file mode 100644 index 0000000000..f8fb184597 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalSilverfishWakeOthers.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalSilverfishWakeOthers.java 2014-11-27 08:59:46.841421230 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalSilverfishWakeOthers.java 2014-11-27 08:42:10.144850927 +1100 +@@ -36,6 +36,11 @@ + IBlockData iblockdata = world.getType(blockposition1); + + if (iblockdata.getBlock() == Blocks.MONSTER_EGG) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), Blocks.AIR, 0).isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end + if (world.getGameRules().getBoolean("mobGriefing")) { + world.setAir(blockposition1, true); + } else { diff --git a/paper-server/nms-patches/PathfinderGoalSit.patch b/paper-server/nms-patches/PathfinderGoalSit.patch new file mode 100644 index 0000000000..f733332142 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalSit.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalSit.java 2014-11-27 08:59:46.845421213 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalSit.java 2014-11-27 08:42:10.096851020 +1100 +@@ -12,7 +12,7 @@ + + public boolean a() { + if (!this.entity.isTamed()) { +- return false; ++ return this.willSit && this.entity.getGoalTarget() == null; // CraftBukkit - Allow sitting for wild animals + } else if (this.entity.V()) { + return false; + } else if (!this.entity.onGround) { diff --git a/paper-server/nms-patches/PathfinderGoalTame.patch b/paper-server/nms-patches/PathfinderGoalTame.patch new file mode 100644 index 0000000000..94aa0e1bf1 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalTame.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalTame.java 2014-11-27 08:59:46.845421213 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalTame.java 2014-11-27 08:42:10.152850911 +1100 +@@ -45,7 +45,8 @@ + int i = this.entity.getTemper(); + int j = this.entity.getMaxDomestication(); + +- if (j > 0 && this.entity.bb().nextInt(j) < i) { ++ // CraftBukkit - fire EntityTameEvent ++ if (j > 0 && this.entity.bb().nextInt(j) < i && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.entity, (EntityHuman) this.entity.passenger).isCancelled() && this.entity.passenger instanceof EntityHuman) { + this.entity.h((EntityHuman) this.entity.passenger); + this.entity.world.broadcastEntityEffect(this.entity, (byte) 7); + return; +@@ -54,8 +55,16 @@ + this.entity.u(5); + } + +- this.entity.passenger.mount((Entity) null); +- this.entity.passenger = null; ++ // CraftBukkit start - Handle dismounting to account for VehicleExitEvent being fired. ++ if (this.entity.passenger != null) { ++ this.entity.passenger.mount((Entity) null); ++ // If the entity still has a passenger, then a plugin cancelled the event. ++ if (this.entity.passenger != null) { ++ return; ++ } ++ } ++ // this.entity.passenger = null; ++ // CraftBukkit end + this.entity.cU(); + this.entity.world.broadcastEntityEffect(this.entity, (byte) 6); + } diff --git a/paper-server/nms-patches/PathfinderGoalTargetNearestPlayer.patch b/paper-server/nms-patches/PathfinderGoalTargetNearestPlayer.patch new file mode 100644 index 0000000000..054d1b3ca6 --- /dev/null +++ b/paper-server/nms-patches/PathfinderGoalTargetNearestPlayer.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PathfinderGoalTargetNearestPlayer.java 2014-11-27 08:59:46.845421213 +1100 ++++ src/main/java/net/minecraft/server/PathfinderGoalTargetNearestPlayer.java 2014-11-27 08:42:10.120850973 +1100 +@@ -59,7 +59,7 @@ + } + + public void c() { +- this.b.setGoalTarget(this.e); ++ this.b.setGoalTarget(this.e, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - added reason + super.c(); + } + diff --git a/paper-server/nms-patches/PlayerChunk.patch b/paper-server/nms-patches/PlayerChunk.patch new file mode 100644 index 0000000000..6170f804b6 --- /dev/null +++ b/paper-server/nms-patches/PlayerChunk.patch @@ -0,0 +1,104 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerChunk.java 2014-11-27 08:59:46.849421195 +1100 ++++ src/main/java/net/minecraft/server/PlayerChunk.java 2014-11-27 08:42:10.136850942 +1100 +@@ -3,6 +3,11 @@ + import com.google.common.collect.Lists; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; ++import java.util.HashMap; ++// CraftBukkit end ++ + class PlayerChunk { + + private final List b; +@@ -12,16 +17,26 @@ + private int f; + private long g; + final PlayerChunkMap playerChunkMap; ++ ++ // CraftBukkit start - add fields ++ private final HashMap players = new HashMap(); ++ private boolean loaded = false; ++ private Runnable loadedRunnable = new Runnable() { ++ public void run() { ++ PlayerChunk.this.loaded = true; ++ } ++ }; ++ // CraftBukkit end + + public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) { + this.playerChunkMap = playerchunkmap; + this.b = Lists.newArrayList(); + this.dirtyBlocks = new short[64]; + this.location = new ChunkCoordIntPair(i, j); +- playerchunkmap.a().chunkProviderServer.getChunkAt(i, j); ++ playerchunkmap.a().chunkProviderServer.getChunkAt(i, j, loadedRunnable); // CraftBukkit + } + +- public void a(EntityPlayer entityplayer) { ++ public void a(final EntityPlayer entityplayer) { // CraftBukkit - added final to argument + if (this.b.contains(entityplayer)) { + PlayerChunkMap.c().debug("Failed to add player. {} already is in chunk {}, {}", new Object[] { entityplayer, Integer.valueOf(this.location.x), Integer.valueOf(this.location.z)}); + } else { +@@ -30,18 +45,50 @@ + } + + this.b.add(entityplayer); +- entityplayer.chunkCoordIntPairQueue.add(this.location); ++ // CraftBukkit start - use async chunk io ++ Runnable playerRunnable; ++ if (this.loaded) { ++ playerRunnable = null; ++ entityplayer.chunkCoordIntPairQueue.add(this.location); ++ } else { ++ playerRunnable = new Runnable() { ++ public void run() { ++ entityplayer.chunkCoordIntPairQueue.add(PlayerChunk.this.location); ++ } ++ }; ++ this.playerChunkMap.a().chunkProviderServer.getChunkAt(this.location.x, this.location.z, playerRunnable); ++ } ++ ++ this.players.put(entityplayer, playerRunnable); ++ // CraftBukkit end + } + } + + public void b(EntityPlayer entityplayer) { + if (this.b.contains(entityplayer)) { ++ // CraftBukkit start - If we haven't loaded yet don't load the chunk just so we can clean it up ++ if (!this.loaded) { ++ ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.a(), this.location.x, this.location.z, this.players.get(entityplayer)); ++ this.b.remove(entityplayer); ++ this.players.remove(entityplayer); ++ ++ if (this.b.isEmpty()) { ++ ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.a(), this.location.x, this.location.z, this.loadedRunnable); ++ long i = (long) this.location.x + 2147483647L | (long) this.location.z + 2147483647L << 32; ++ PlayerChunkMap.b(this.playerChunkMap).remove(i); ++ PlayerChunkMap.c(this.playerChunkMap).remove(this); ++ } ++ ++ return; ++ } ++ // CraftBukkit end + Chunk chunk = PlayerChunkMap.a(this.playerChunkMap).getChunkAt(this.location.x, this.location.z); + + if (chunk.isReady()) { + entityplayer.playerConnection.sendPacket(new PacketPlayOutMapChunk(chunk, true, 0)); + } + ++ this.players.remove(entityplayer); // CraftBukkit + this.b.remove(entityplayer); + entityplayer.chunkCoordIntPairQueue.remove(this.location); + if (this.b.isEmpty()) { +@@ -122,7 +169,7 @@ + if (this.dirtyCount == 64) { + i = this.location.x * 16; + j = this.location.z * 16; +- this.a((Packet) (new PacketPlayOutMapChunk(PlayerChunkMap.a(this.playerChunkMap).getChunkAt(this.location.x, this.location.z), false, this.f))); ++ this.a((Packet) (new PacketPlayOutMapChunk(PlayerChunkMap.a(this.playerChunkMap).getChunkAt(this.location.x, this.location.z), (this.f == 0xFFFF), this.f))); // CraftBukkit - send everything (including biome) if all sections flagged + + for (k = 0; k < 16; ++k) { + if ((this.f & 1 << k) != 0) { diff --git a/paper-server/nms-patches/PlayerChunkMap.patch b/paper-server/nms-patches/PlayerChunkMap.patch new file mode 100644 index 0000000000..48b86df849 --- /dev/null +++ b/paper-server/nms-patches/PlayerChunkMap.patch @@ -0,0 +1,208 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerChunkMap.java 2014-11-27 08:59:46.849421195 +1100 ++++ src/main/java/net/minecraft/server/PlayerChunkMap.java 2014-11-27 08:42:10.152850911 +1100 +@@ -7,17 +7,24 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.util.Collections; ++import java.util.Queue; ++import java.util.LinkedList; ++// CraftBukkit end ++ + public class PlayerChunkMap { + + private static final Logger a = LogManager.getLogger(); + private final WorldServer world; + private final List managedPlayers = Lists.newArrayList(); + private final LongHashMap d = new LongHashMap(); +- private final List e = Lists.newArrayList(); +- private final List f = Lists.newArrayList(); ++ private final Queue e = new java.util.concurrent.ConcurrentLinkedQueue(); // CraftBukkit ArrayList -> ConcurrentLinkedQueue ++ private final Queue f = new java.util.concurrent.ConcurrentLinkedQueue(); // CraftBukkit ArrayList -> ConcurrentLinkedQueue + private int g; + private long h; + private final int[][] i = new int[][] { { 1, 0}, { 0, 1}, { -1, 0}, { 0, -1}}; ++ private boolean wasNotEmpty; // CraftBukkit - add field + + public PlayerChunkMap(WorldServer worldserver) { + this.world = worldserver; +@@ -35,28 +42,39 @@ + + if (i - this.h > 8000L) { + this.h = i; +- +- for (j = 0; j < this.f.size(); ++j) { +- playerchunk = (PlayerChunk) this.f.get(j); ++ ++ // CraftBukkit start - Use iterator ++ java.util.Iterator iterator = this.f.iterator(); ++ while (iterator.hasNext()) { ++ playerchunk = (PlayerChunk) iterator.next(); + playerchunk.b(); + playerchunk.a(); + } + } else { +- for (j = 0; j < this.e.size(); ++j) { +- playerchunk = (PlayerChunk) this.e.get(j); ++ java.util.Iterator iterator = this.e.iterator(); ++ ++ while (iterator.hasNext()) { ++ playerchunk = (PlayerChunk) iterator.next(); + playerchunk.b(); ++ iterator.remove(); ++ // CraftBukkit end + } + } + +- this.e.clear(); ++ // this.e.clear(); // CraftBukkit - Removals are already covered + if (this.managedPlayers.isEmpty()) { ++ if (!wasNotEmpty) return; // CraftBukkit - Only do unload when we go from non-empty to empty + WorldProvider worldprovider = this.world.worldProvider; + + if (!worldprovider.e()) { + this.world.chunkProviderServer.b(); + } ++ // CraftBukkit start ++ wasNotEmpty = false; ++ } else { ++ wasNotEmpty = true; + } +- ++ // CraftBukkit end + } + + public boolean a(int i, int j) { +@@ -77,6 +95,16 @@ + + return playerchunk; + } ++ ++ // CraftBukkit start - add method ++ public final boolean isChunkInUse(int x, int z) { ++ PlayerChunk pi = a(x, z, false); ++ if (pi != null) { ++ return (PlayerChunk.b(pi).size() > 0); ++ } ++ return false; ++ } ++ // CraftBukkit end + + public void flagDirty(BlockPosition blockposition) { + int i = blockposition.getX() >> 4; +@@ -95,13 +123,22 @@ + + entityplayer.d = entityplayer.locX; + entityplayer.e = entityplayer.locZ; ++ ++ // CraftBukkit start - Load nearby chunks first ++ List chunkList = new LinkedList(); + + for (int k = i - this.g; k <= i + this.g; ++k) { + for (int l = j - this.g; l <= j + this.g; ++l) { +- this.a(k, l, true).a(entityplayer); ++ chunkList.add(new ChunkCoordIntPair(k, l)); + } + } +- ++ ++ Collections.sort(chunkList, new ChunkCoordComparator(entityplayer)); ++ for (ChunkCoordIntPair pair : chunkList) { ++ this.a(pair.x, pair.z, true).a(entityplayer); ++ } ++ // CraftBukkit end ++ + this.managedPlayers.add(entityplayer); + this.b(entityplayer); + } +@@ -188,12 +225,13 @@ + int i1 = this.g; + int j1 = i - k; + int k1 = j - l; ++ List chunksToLoad = new LinkedList(); // CraftBukkit + + if (j1 != 0 || k1 != 0) { + for (int l1 = i - i1; l1 <= i + i1; ++l1) { + for (int i2 = j - i1; i2 <= j + i1; ++i2) { + if (!this.a(l1, i2, k, l, i1)) { +- this.a(l1, i2, true).a(entityplayer); ++ chunksToLoad.add(new ChunkCoordIntPair(l1, i2)); // CraftBukkit + } + + if (!this.a(l1 - j1, i2 - k1, i, j, i1)) { +@@ -209,6 +247,17 @@ + this.b(entityplayer); + entityplayer.d = entityplayer.locX; + entityplayer.e = entityplayer.locZ; ++ ++ // CraftBukkit start - send nearest chunks first ++ Collections.sort(chunksToLoad, new ChunkCoordComparator(entityplayer)); ++ for (ChunkCoordIntPair pair : chunksToLoad) { ++ this.a(pair.x, pair.z, true).a(entityplayer); ++ } ++ ++ if (j1 > 1 || j1 < -1 || k1 > 1 || k1 < -1) { ++ Collections.sort(entityplayer.chunkCoordIntPairQueue, new ChunkCoordComparator(entityplayer)); ++ } ++ // CraftBukkit end + } + } + } +@@ -274,11 +323,54 @@ + return playerchunkmap.d; + } + +- static List c(PlayerChunkMap playerchunkmap) { ++ static Queue c(PlayerChunkMap playerchunkmap) { // CraftBukkit List -> Queue + return playerchunkmap.f; + } + +- static List d(PlayerChunkMap playerchunkmap) { ++ static Queue d(PlayerChunkMap playerchunkmap) { // CraftBukkit List -> Queue + return playerchunkmap.e; + } ++ ++ // CraftBukkit start - Sorter to load nearby chunks first ++ private static class ChunkCoordComparator implements java.util.Comparator { ++ private int x; ++ private int z; ++ ++ public ChunkCoordComparator (EntityPlayer entityplayer) { ++ x = (int) entityplayer.locX >> 4; ++ z = (int) entityplayer.locZ >> 4; ++ } ++ ++ public int compare(ChunkCoordIntPair a, ChunkCoordIntPair b) { ++ if (a.equals(b)) { ++ return 0; ++ } ++ ++ // Subtract current position to set center point ++ int ax = a.x - this.x; ++ int az = a.z - this.z; ++ int bx = b.x - this.x; ++ int bz = b.z - this.z; ++ ++ int result = ((ax - bx) * (ax + bx)) + ((az - bz) * (az + bz)); ++ if (result != 0) { ++ return result; ++ } ++ ++ if (ax < 0) { ++ if (bx < 0) { ++ return bz - az; ++ } else { ++ return -1; ++ } ++ } else { ++ if (bx < 0) { ++ return 1; ++ } else { ++ return az - bz; ++ } ++ } ++ } ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/PlayerConnection.patch b/paper-server/nms-patches/PlayerConnection.patch new file mode 100644 index 0000000000..577557e685 --- /dev/null +++ b/paper-server/nms-patches/PlayerConnection.patch @@ -0,0 +1,1458 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerConnection.java 2014-11-27 08:59:46.853421177 +1100 ++++ src/main/java/net/minecraft/server/PlayerConnection.java 2014-11-27 08:42:10.148850918 +1100 +@@ -16,6 +16,48 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.util.concurrent.ExecutionException; ++import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; ++import java.util.HashSet; ++ ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftInventoryView; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.util.CraftChatMessage; ++import org.bukkit.craftbukkit.util.LazyPlayerSet; ++import org.bukkit.craftbukkit.util.Waitable; ++ ++import org.bukkit.Location; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Event; ++import org.bukkit.event.block.Action; ++import org.bukkit.event.block.SignChangeEvent; ++import org.bukkit.event.inventory.ClickType; ++import org.bukkit.event.inventory.CraftItemEvent; ++import org.bukkit.event.inventory.InventoryAction; ++import org.bukkit.event.inventory.InventoryClickEvent; ++import org.bukkit.event.inventory.InventoryCreativeEvent; ++import org.bukkit.event.inventory.InventoryType.SlotType; ++import org.bukkit.event.player.AsyncPlayerChatEvent; ++import org.bukkit.event.player.PlayerAnimationEvent; ++import org.bukkit.event.player.PlayerChatEvent; ++import org.bukkit.event.player.PlayerCommandPreprocessEvent; ++import org.bukkit.event.player.PlayerInteractEntityEvent; ++import org.bukkit.event.player.PlayerInteractAtEntityEvent; ++import org.bukkit.event.player.PlayerItemHeldEvent; ++import org.bukkit.event.player.PlayerKickEvent; ++import org.bukkit.event.player.PlayerMoveEvent; ++import org.bukkit.event.player.PlayerTeleportEvent; ++import org.bukkit.event.player.PlayerToggleFlightEvent; ++import org.bukkit.event.player.PlayerToggleSneakEvent; ++import org.bukkit.event.player.PlayerToggleSprintEvent; ++import org.bukkit.inventory.CraftingInventory; ++import org.bukkit.inventory.InventoryView; ++import org.bukkit.util.NumberConversions; ++// CraftBukkit end ++ + public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerListBox { + + private static final Logger c = LogManager.getLogger(); +@@ -29,13 +71,17 @@ + private int i; + private long j; + private long k; +- private int chatThrottle; ++ // CraftBukkit start - multithreaded fields ++ private volatile int chatThrottle; ++ private static final AtomicIntegerFieldUpdater chatSpamField = AtomicIntegerFieldUpdater.newUpdater(PlayerConnection.class, "chatThrottle"); ++ // CraftBukkit end + private int m; + private IntHashMap n = new IntHashMap(); + private double o; + private double p; + private double q; + public boolean checkMovement = true; ++ private boolean processedDisconnect; // CraftBukkit - added + + public PlayerConnection(MinecraftServer minecraftserver, NetworkManager networkmanager, EntityPlayer entityplayer) { + this.minecraftServer = minecraftserver; +@@ -43,7 +89,37 @@ + networkmanager.a((PacketListener) this); + this.player = entityplayer; + entityplayer.playerConnection = this; ++ ++ // CraftBukkit start - add fields and methods ++ this.server = minecraftserver.server; ++ } ++ ++ private final org.bukkit.craftbukkit.CraftServer server; ++ private int lastTick = MinecraftServer.currentTick; ++ private int lastDropTick = MinecraftServer.currentTick; ++ private int dropCount = 0; ++ private static final int SURVIVAL_PLACE_DISTANCE_SQUARED = 6 * 6; ++ private static final int CREATIVE_PLACE_DISTANCE_SQUARED = 7 * 7; ++ ++ // Get position of last block hit for BlockDamageLevel.STOPPED ++ private double lastPosX = Double.MAX_VALUE; ++ private double lastPosY = Double.MAX_VALUE; ++ private double lastPosZ = Double.MAX_VALUE; ++ private float lastPitch = Float.MAX_VALUE; ++ private float lastYaw = Float.MAX_VALUE; ++ private boolean justTeleported = false; ++ ++ // For the PacketPlayOutBlockPlace hack :( ++ Long lastPacket; ++ ++ // Store the last block right clicked and what type it was ++ private Item lastMaterial; ++ ++ public CraftPlayer getPlayer() { ++ return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity(); + } ++ private final static HashSet invalidItems = new HashSet(java.util.Arrays.asList(8, 9, 10, 11, 26, 34, 36, 43, 51, 52, 55, 59, 60, 62, 63, 64, 68, 71, 74, 75, 83, 90, 92, 93, 94, 104, 105, 115, 117, 118, 119, 125, 127, 132, 140, 141, 142, 144)); // TODO: Check after every update. ++ // CraftBukkit end + + public void c() { + this.h = false; +@@ -57,9 +133,14 @@ + } + + this.minecraftServer.methodProfiler.b(); ++ // CraftBukkit start ++ for (int spam; (spam = this.chatThrottle) > 0 && !chatSpamField.compareAndSet(this, spam, spam - 1); ) ; ++ /* Use thread-safe field access instead + if (this.chatThrottle > 0) { + --this.chatThrottle; + } ++ */ ++ // CraftBukkit end + + if (this.m > 0) { + --this.m; +@@ -76,11 +157,27 @@ + } + + public void disconnect(String s) { ++ // CraftBukkit start - fire PlayerKickEvent ++ String leaveMessage = EnumChatFormat.YELLOW + this.player.getName() + " left the game."; ++ ++ PlayerKickEvent event = new PlayerKickEvent(this.server.getPlayer(this.player), s, leaveMessage); ++ ++ if (this.server.getServer().isRunning()) { ++ this.server.getPluginManager().callEvent(event); ++ } ++ ++ if (event.isCancelled()) { ++ // Do not kick the player ++ return; ++ } ++ // Send the possibly modified leave message ++ s = event.getReason(); ++ // CraftBukkit end + ChatComponentText chatcomponenttext = new ChatComponentText(s); + + this.networkManager.a(new PacketPlayOutKickDisconnect(chatcomponenttext), new PlayerConnectionFuture(this, chatcomponenttext), new GenericFutureListener[0]); + this.networkManager.k(); +- Futures.getUnchecked(this.minecraftServer.postToMainThread(new PlayerConnectionDisconnector(this))); ++ this.minecraftServer.postToMainThread(new PlayerConnectionDisconnector(this)); // CraftBukkit - Don't wait + } + + public void a(PacketPlayInSteerVehicle packetplayinsteervehicle) { +@@ -90,6 +187,13 @@ + + public void a(PacketPlayInFlying packetplayinflying) { + PlayerConnectionUtils.ensureMainThread(packetplayinflying, this, this.player.u()); ++ // CraftBukkit start - Check for NaN ++ if (Double.isNaN(packetplayinflying.x) || Double.isNaN(packetplayinflying.y) || Double.isNaN(packetplayinflying.z)) { ++ c.warn(player.getName() + " was caught trying to crash the server with an invalid position."); ++ getPlayer().kickPlayer("Nope!"); ++ return; ++ } ++ // CraftBukkit end + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + + this.h = true; +@@ -108,8 +212,65 @@ + this.checkMovement = true; + } + } ++ // CraftBukkit start - fire PlayerMoveEvent ++ Player player = this.getPlayer(); ++ Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location. ++ Location to = player.getLocation().clone(); // Start off the To location as the Players current location. ++ ++ // If the packet contains movement information then we update the To location with the correct XYZ. ++ if (packetplayinflying.hasPos && !(packetplayinflying.hasPos && packetplayinflying.y == -999.0D)) { ++ to.setX(packetplayinflying.x); ++ to.setY(packetplayinflying.y); ++ to.setZ(packetplayinflying.z); ++ } ++ ++ // If the packet contains look information then we update the To location with the correct Yaw & Pitch. ++ if (packetplayinflying.hasLook) { ++ to.setYaw(packetplayinflying.yaw); ++ to.setPitch(packetplayinflying.pitch); ++ } ++ ++ // Prevent 40 event-calls for less than a single pixel of movement >.> ++ double delta = Math.pow(this.lastPosX - to.getX(), 2) + Math.pow(this.lastPosY - to.getY(), 2) + Math.pow(this.lastPosZ - to.getZ(), 2); ++ float deltaAngle = Math.abs(this.lastYaw - to.getYaw()) + Math.abs(this.lastPitch - to.getPitch()); ++ ++ if ((delta > 1f / 256 || deltaAngle > 10f) && (this.checkMovement && !this.player.dead)) { ++ this.lastPosX = to.getX(); ++ this.lastPosY = to.getY(); ++ this.lastPosZ = to.getZ(); ++ this.lastYaw = to.getYaw(); ++ this.lastPitch = to.getPitch(); ++ ++ // Skip the first time we do this ++ if (from.getX() != Double.MAX_VALUE) { ++ PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); ++ this.server.getPluginManager().callEvent(event); ++ ++ // If the event is cancelled we move the player back to their old location. ++ if (event.isCancelled()) { ++ this.player.playerConnection.sendPacket(new PacketPlayOutPosition(from.getX(), from.getY() + 1.6200000047683716D, from.getZ(), from.getYaw(), from.getPitch(), Collections.emptySet())); ++ return; ++ } ++ ++ /* If a Plugin has changed the To destination then we teleport the Player ++ there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. ++ We only do this if the Event was not cancelled. */ ++ if (!to.equals(event.getTo()) && !event.isCancelled()) { ++ this.player.getBukkitEntity().teleport(event.getTo(), PlayerTeleportEvent.TeleportCause.UNKNOWN); ++ return; ++ } ++ ++ /* Check to see if the Players Location has some how changed during the call of the event. ++ This can happen due to a plugin teleporting the player instead of using .setTo() */ ++ if (!from.equals(this.getPlayer().getLocation()) && this.justTeleported) { ++ this.justTeleported = false; ++ return; ++ } ++ } ++ } + +- if (this.checkMovement) { ++ if (this.checkMovement && !this.player.dead) { ++ // CraftBukkit end + this.f = this.e; + double d7; + double d8; +@@ -203,12 +364,14 @@ + double d11 = d7 - this.player.locX; + double d12 = d8 - this.player.locY; + double d13 = d9 - this.player.locZ; +- double d14 = Math.min(Math.abs(d11), Math.abs(this.player.motX)); +- double d15 = Math.min(Math.abs(d12), Math.abs(this.player.motY)); +- double d16 = Math.min(Math.abs(d13), Math.abs(this.player.motZ)); ++ // CraftBukkit start - min to max ++ double d14 = Math.max(Math.abs(d11), Math.abs(this.player.motX)); ++ double d15 = Math.max(Math.abs(d12), Math.abs(this.player.motY)); ++ double d16 = Math.max(Math.abs(d13), Math.abs(this.player.motZ)); ++ // CraftBukkit end + double d17 = d14 * d14 + d15 * d15 + d16 * d16; + +- if (d17 > 100.0D && (!this.minecraftServer.S() || !this.minecraftServer.R().equals(this.player.getName()))) { ++ if (d17 > 100.0D && this.checkMovement && (!this.minecraftServer.S() || !this.minecraftServer.R().equals(this.player.getName()))) { // CraftBukkit - Added this.checkMovement condition to solve this check being triggered by teleports + PlayerConnection.c.warn(this.player.getName() + " moved too quickly! " + d11 + "," + d12 + "," + d13 + " (" + d14 + ", " + d15 + ", " + d16 + ")"); + this.a(this.o, this.p, this.q, this.player.yaw, this.player.pitch); + return; +@@ -281,6 +444,49 @@ + } + + public void a(double d0, double d1, double d2, float f, float f1, Set set) { ++ // CraftBukkit start - Delegate to teleport(Location) ++ Player player = this.getPlayer(); ++ Location from = player.getLocation(); ++ Location to = new Location(this.getPlayer().getWorld(), d0, d1, d2, f, f1); ++ PlayerTeleportEvent event = new PlayerTeleportEvent(player, from, to, PlayerTeleportEvent.TeleportCause.UNKNOWN); ++ this.server.getPluginManager().callEvent(event); ++ ++ from = event.getFrom(); ++ to = event.isCancelled() ? from : event.getTo(); ++ ++ this.teleport(to, set); ++ } ++ ++ public void teleport(Location dest) { ++ teleport(dest, Collections.emptySet()); ++ } ++ ++ public void teleport(Location dest, Set set) { ++ double d0, d1, d2; ++ float f, f1; ++ ++ d0 = dest.getX(); ++ d1 = dest.getY(); ++ d2 = dest.getZ(); ++ f = dest.getYaw(); ++ f1 = dest.getPitch(); ++ ++ // TODO: make sure this is the best way to address this. ++ if (Float.isNaN(f)) { ++ f = 0; ++ } ++ ++ if (Float.isNaN(f1)) { ++ f1 = 0; ++ } ++ ++ this.lastPosX = d0; ++ this.lastPosY = d1; ++ this.lastPosZ = d2; ++ this.lastYaw = f; ++ this.lastPitch = f1; ++ this.justTeleported = true; ++ // CraftBukkit end + this.checkMovement = false; + this.o = d0; + this.p = d1; +@@ -314,32 +520,49 @@ + + public void a(PacketPlayInBlockDig packetplayinblockdig) { + PlayerConnectionUtils.ensureMainThread(packetplayinblockdig, this, this.player.u()); ++ if (this.player.dead) return; // CraftBukkit + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + BlockPosition blockposition = packetplayinblockdig.a(); + + this.player.z(); ++ // CraftBukkit start + switch (SwitchHelperCommandActionType.a[packetplayinblockdig.c().ordinal()]) { +- case 1: ++ case 1: // DROP_ITEM + if (!this.player.v()) { ++ // limit how quickly items can be dropped ++ // If the ticks aren't the same then the count starts from 0 and we update the lastDropTick. ++ if (this.lastDropTick != MinecraftServer.currentTick) { ++ this.dropCount = 0; ++ this.lastDropTick = MinecraftServer.currentTick; ++ } else { ++ // Else we increment the drop count and check the amount. ++ this.dropCount++; ++ if (this.dropCount >= 20) { ++ this.c.warn(this.player.getName() + " dropped their items too quickly!"); ++ this.disconnect("You dropped your items too quickly (Hacking?)"); ++ return; ++ } ++ } ++ // CraftBukkit end + this.player.a(false); + } + + return; + +- case 2: ++ case 2: // DROP_ALL_ITEMS + if (!this.player.v()) { + this.player.a(true); + } + + return; + +- case 3: ++ case 3: // RELEASE_USE_ITEM + this.player.bT(); + return; + +- case 4: +- case 5: +- case 6: ++ case 4: // START_DESTROY_BLOCK ++ case 5: // ABORT_DESTROY_BLOCK ++ case 6: // STOP_DESTROY_BLOCK + double d0 = this.player.locX - ((double) blockposition.getX() + 0.5D); + double d1 = this.player.locY - ((double) blockposition.getY() + 0.5D) + 1.5D; + double d2 = this.player.locZ - ((double) blockposition.getZ() + 0.5D); +@@ -354,7 +577,15 @@ + if (!this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.af().a(blockposition)) { + this.player.playerInteractManager.a(blockposition, packetplayinblockdig.b()); + } else { ++ // CraftBukkit start - fire PlayerInteractEvent ++ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, blockposition, packetplayinblockdig.b(), this.player.inventory.getItemInHand()); + this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition)); ++ // Update any tile entity data for this block ++ TileEntity tileentity = worldserver.getTileEntity(blockposition); ++ if (tileentity != null) { ++ this.player.playerConnection.sendPacket(tileentity.getUpdatePacket()); ++ } ++ // CraftBukkit end + } + } else { + if (packetplayinblockdig.c() == EnumPlayerDigType.STOP_DESTROY_BLOCK) { +@@ -374,11 +605,38 @@ + default: + throw new IllegalArgumentException("Invalid player action"); + } ++ // CraftBukkit end + } + + public void a(PacketPlayInBlockPlace packetplayinblockplace) { + PlayerConnectionUtils.ensureMainThread(packetplayinblockplace, this, this.player.u()); + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); ++ ++ // CraftBukkit start ++ if (this.player.dead) return; ++ ++ // This is a horrible hack needed because the client sends 2 packets on 'right mouse click' ++ // aimed at a block. We shouldn't need to get the second packet if the data is handled ++ // but we cannot know what the client will do, so we might still get it ++ // ++ // If the time between packets is small enough, and the 'signature' similar, we discard the ++ // second one. This sadly has to remain until Mojang makes their packets saner. :( ++ // -- Grum ++ if (packetplayinblockplace.getFace() == 255) { ++ if (packetplayinblockplace.getItemStack() != null && packetplayinblockplace.getItemStack().getItem() == this.lastMaterial && this.lastPacket != null && packetplayinblockplace.timestamp - this.lastPacket < 100) { ++ this.lastPacket = null; ++ return; ++ } ++ } else { ++ this.lastMaterial = packetplayinblockplace.getItemStack() == null ? null : packetplayinblockplace.getItemStack().getItem(); ++ this.lastPacket = packetplayinblockplace.timestamp; ++ } ++ // CraftBukkit - if rightclick decremented the item, always send the update packet. */ ++ // this is not here for CraftBukkit's own functionality; rather it is to fix ++ // a notch bug where the item doesn't update correctly. ++ boolean always = false; ++ // CraftBukkit end ++ + ItemStack itemstack = this.player.inventory.getItemInHand(); + boolean flag = false; + BlockPosition blockposition = packetplayinblockplace.a(); +@@ -390,7 +648,18 @@ + return; + } + +- this.player.playerInteractManager.useItem(this.player, worldserver, itemstack); ++ // CraftBukkit start ++ int itemstackAmount = itemstack.count; ++ org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemstack); ++ if (event.useItemInHand() != Event.Result.DENY) { ++ this.player.playerInteractManager.useItem(this.player, this.player.world, itemstack); ++ } ++ ++ // CraftBukkit - notch decrements the counter by 1 in the above method with food, ++ // snowballs and so forth, but he does it in a place that doesn't cause the ++ // inventory update packet to get sent ++ always = (itemstack.count != itemstackAmount) || itemstack.getItem() == Item.getItemOf(Blocks.WATERLILY); ++ // CraftBukkit end + } else if (blockposition.getY() >= this.minecraftServer.getMaxBuildHeight() - 1 && (enumdirection == EnumDirection.UP || blockposition.getY() >= this.minecraftServer.getMaxBuildHeight())) { + ChatMessage chatmessage = new ChatMessage("build.tooHigh", new Object[] { Integer.valueOf(this.minecraftServer.getMaxBuildHeight())}); + +@@ -398,9 +667,21 @@ + this.player.playerConnection.sendPacket(new PacketPlayOutChat(chatmessage)); + flag = true; + } else { ++ // CraftBukkit start - Check if we can actually do something over this large a distance ++ Location eyeLoc = this.getPlayer().getEyeLocation(); ++ double reachDistance = NumberConversions.square(eyeLoc.getX() - blockposition.getX()) + NumberConversions.square(eyeLoc.getY() - blockposition.getY()) + NumberConversions.square(eyeLoc.getZ() - blockposition.getZ()); ++ if (reachDistance > (this.getPlayer().getGameMode() == org.bukkit.GameMode.CREATIVE ? CREATIVE_PLACE_DISTANCE_SQUARED : SURVIVAL_PLACE_DISTANCE_SQUARED)) { ++ return; ++ } ++ ++ if (!worldserver.af().a(blockposition)) { ++ return; ++ } ++ + if (this.checkMovement && this.player.e((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && !this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.af().a(blockposition)) { +- this.player.playerInteractManager.interact(this.player, worldserver, itemstack, blockposition, enumdirection, packetplayinblockplace.d(), packetplayinblockplace.e(), packetplayinblockplace.f()); ++ always = !this.player.playerInteractManager.interact(this.player, worldserver, itemstack, blockposition, enumdirection, packetplayinblockplace.d(), packetplayinblockplace.e(), packetplayinblockplace.f()); + } ++ // CraftBukkit end + + flag = true; + } +@@ -423,7 +704,8 @@ + + this.player.activeContainer.b(); + this.player.g = false; +- if (!ItemStack.matches(this.player.inventory.getItemInHand(), packetplayinblockplace.getItemStack())) { ++ // CraftBukkit - TODO CHECK IF NEEDED -- new if structure might not need 'always'. Kept it in for now, but may be able to remove in future ++ if (!ItemStack.matches(this.player.inventory.getItemInHand(), packetplayinblockplace.getItemStack()) || always) { + this.sendPacket(new PacketPlayOutSetSlot(this.player.activeContainer.windowId, slot.rawSlotIndex, this.player.inventory.getItemInHand())); + } + } +@@ -437,8 +719,8 @@ + WorldServer[] aworldserver = this.minecraftServer.worldServer; + int i = aworldserver.length; + +- for (int j = 0; j < i; ++j) { +- WorldServer worldserver = aworldserver[j]; ++ // CraftBukkit - use the worlds array list ++ for (WorldServer worldserver : minecraftServer.worlds) { + + if (worldserver != null) { + entity = packetplayinspectate.a(worldserver); +@@ -455,6 +737,7 @@ + WorldServer worldserver1 = this.player.u(); + WorldServer worldserver2 = (WorldServer) entity.world; + ++ /* CraftBukkit start - replace with bukkit handling for multi-world + this.player.dimension = entity.dimension; + this.sendPacket(new PacketPlayOutRespawn(this.player.dimension, worldserver1.getDifficulty(), worldserver1.getWorldData().getType(), this.player.playerInteractManager.getGameMode())); + worldserver1.removeEntity(this.player); +@@ -472,6 +755,9 @@ + this.player.playerInteractManager.a(worldserver2); + this.minecraftServer.getPlayerList().b(this.player, worldserver2); + this.minecraftServer.getPlayerList().updateClient(this.player); ++ */ ++ this.player.getBukkitEntity().teleport(entity.getBukkitEntity()); ++ // CraftBukkit end + } else { + this.player.enderTeleportTo(entity.locX, entity.locY, entity.locZ); + } +@@ -483,14 +769,29 @@ + public void a(PacketPlayInResourcePackStatus packetplayinresourcepackstatus) {} + + public void a(IChatBaseComponent ichatbasecomponent) { +- PlayerConnection.c.info(this.player.getName() + " lost connection: " + ichatbasecomponent); ++ // CraftBukkit start - Rarely it would send a disconnect line twice ++ if (this.processedDisconnect) { ++ return; ++ } else { ++ this.processedDisconnect = true; ++ } ++ // CraftBukkit end ++ c.info(this.player.getName() + " lost connection: " + ichatbasecomponent.c()); // CraftBukkit - Don't toString the component + this.minecraftServer.aF(); ++ // CraftBukkit start - Replace vanilla quit message handling with our own. ++ /* + ChatMessage chatmessage = new ChatMessage("multiplayer.player.left", new Object[] { this.player.getScoreboardDisplayName()}); + + chatmessage.getChatModifier().setColor(EnumChatFormat.YELLOW); + this.minecraftServer.getPlayerList().sendMessage(chatmessage); ++ */ ++ + this.player.q(); +- this.minecraftServer.getPlayerList().disconnect(this.player); ++ String quitMessage = this.minecraftServer.getPlayerList().disconnect(this.player); ++ if ((quitMessage != null) && (quitMessage.length() > 0)) { ++ this.minecraftServer.getPlayerList().sendMessage(CraftChatMessage.fromString(quitMessage)); ++ } ++ // CraftBukkit end + if (this.minecraftServer.S() && this.player.getName().equals(this.minecraftServer.R())) { + PlayerConnection.c.info("Stopping singleplayer server as player logged out"); + this.minecraftServer.safeShutdown(); +@@ -511,6 +812,15 @@ + return; + } + } ++ ++ // CraftBukkit start ++ if (packet == null) { ++ return; ++ } else if (packet instanceof PacketPlayOutSpawnPosition) { ++ PacketPlayOutSpawnPosition packet6 = (PacketPlayOutSpawnPosition) packet; ++ this.player.compassTarget = new Location(this.getPlayer().getWorld(), packet6.position.getX(), packet6.position.getY(), packet6.position.getZ()); ++ } ++ // CraftBukkit end + + try { + this.networkManager.handle(packet); +@@ -524,18 +834,34 @@ + } + + public void a(PacketPlayInHeldItemSlot packetplayinhelditemslot) { ++ // CraftBukkit start ++ if (this.player.dead) return; + PlayerConnectionUtils.ensureMainThread(packetplayinhelditemslot, this, this.player.u()); + if (packetplayinhelditemslot.a() >= 0 && packetplayinhelditemslot.a() < PlayerInventory.getHotbarSize()) { ++ PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getPlayer(), this.player.inventory.itemInHandIndex, packetplayinhelditemslot.a()); ++ this.server.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ this.sendPacket(new PacketPlayOutHeldItemSlot(this.player.inventory.itemInHandIndex)); ++ this.player.z(); // RENAME ++ return; ++ } ++ // CraftBukkit end + this.player.inventory.itemInHandIndex = packetplayinhelditemslot.a(); + this.player.z(); + } else { + PlayerConnection.c.warn(this.player.getName() + " tried to set an invalid carried item"); ++ this.disconnect("Nope!"); // CraftBukkit + } + } + + public void a(PacketPlayInChat packetplayinchat) { +- PlayerConnectionUtils.ensureMainThread(packetplayinchat, this, this.player.u()); +- if (this.player.getChatFlags() == EnumChatVisibility.HIDDEN) { ++ // CraftBukkit start - async chat ++ boolean isSync = packetplayinchat.a().startsWith("/"); ++ if (packetplayinchat.a().startsWith("/")) { ++ PlayerConnectionUtils.ensureMainThread(packetplayinchat, this, this.player.u()); ++ } ++ // CraftBukkit end ++ if (this.player.dead || this.player.getChatFlags() == EnumChatVisibility.HIDDEN) { // CraftBukkit - dead men tell no tales + ChatMessage chatmessage = new ChatMessage("chat.cannotSend", new Object[0]); + + chatmessage.getChatModifier().setColor(EnumChatFormat.RED); +@@ -548,39 +874,248 @@ + + for (int i = 0; i < s.length(); ++i) { + if (!SharedConstants.isAllowedChatCharacter(s.charAt(i))) { +- this.disconnect("Illegal characters in chat"); ++ // CraftBukkit start - threadsafety ++ if (!isSync) { ++ Waitable waitable = new Waitable() { ++ @Override ++ protected Object evaluate() { ++ PlayerConnection.this.disconnect("Illegal characters in chat"); ++ return null; ++ } ++ }; ++ ++ this.minecraftServer.processQueue.add(waitable); ++ ++ try { ++ waitable.get(); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); ++ } catch (ExecutionException e) { ++ throw new RuntimeException(e); ++ } ++ } else { ++ this.disconnect("Illegal characters in chat"); ++ } ++ // CraftBukkit end + return; + } + } + +- if (s.startsWith("/")) { +- this.handleCommand(s); ++ // CraftBukkit start ++ if (isSync) { ++ try { ++ this.minecraftServer.server.playerCommandState = true; ++ this.handleCommand(s); ++ } finally { ++ this.minecraftServer.server.playerCommandState = false; ++ } ++ } else if (s.isEmpty()) { ++ c.warn(this.player.getName() + " tried to send an empty message"); ++ } else if (getPlayer().isConversing()) { ++ getPlayer().acceptConversationInput(s); ++ } else if (this.player.getChatFlags() == EnumChatVisibility.SYSTEM) { // Re-add "Command Only" flag check ++ ChatMessage chatmessage = new ChatMessage("chat.cannotSend", new Object[0]); ++ ++ chatmessage.getChatModifier().setColor(EnumChatFormat.RED); ++ this.sendPacket(new PacketPlayOutChat(chatmessage)); ++ } else if (true) { ++ this.chat(s, true); ++ // CraftBukkit end - the below is for reference. :) + } else { + ChatMessage chatmessage1 = new ChatMessage("chat.type.text", new Object[] { this.player.getScoreboardDisplayName(), s}); + + this.minecraftServer.getPlayerList().sendMessage(chatmessage1, false); + } + +- this.chatThrottle += 20; +- if (this.chatThrottle > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) { +- this.disconnect("disconnect.spam"); +- } ++ // CraftBukkit start - replaced with thread safe throttle ++ // this.chatThrottle += 20; ++ if (chatSpamField.addAndGet(this, 20) > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) { ++ if (!isSync) { ++ Waitable waitable = new Waitable() { ++ @Override ++ protected Object evaluate() { ++ PlayerConnection.this.disconnect("disconnect.spam"); ++ return null; ++ } ++ }; ++ ++ this.minecraftServer.processQueue.add(waitable); + ++ try { ++ waitable.get(); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); ++ } catch (ExecutionException e) { ++ throw new RuntimeException(e); ++ } ++ } else { ++ this.disconnect("disconnect.spam"); ++ } ++ // CraftBukkit end ++ } + } + } ++ ++ // CraftBukkit start - add method ++ public void chat(String s, boolean async) { ++ if (s.isEmpty() || this.player.getChatFlags() == EnumChatVisibility.HIDDEN) { ++ return; ++ } ++ ++ if (!async && s.startsWith("/")) { ++ this.handleCommand(s); ++ } else if (this.player.getChatFlags() == EnumChatVisibility.SYSTEM) { ++ // Do nothing, this is coming from a plugin ++ } else { ++ Player player = this.getPlayer(); ++ AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(async, player, s, new LazyPlayerSet()); ++ this.server.getPluginManager().callEvent(event); ++ ++ if (PlayerChatEvent.getHandlerList().getRegisteredListeners().length != 0) { ++ // Evil plugins still listening to deprecated event ++ final PlayerChatEvent queueEvent = new PlayerChatEvent(player, event.getMessage(), event.getFormat(), event.getRecipients()); ++ queueEvent.setCancelled(event.isCancelled()); ++ Waitable waitable = new Waitable() { ++ @Override ++ protected Object evaluate() { ++ org.bukkit.Bukkit.getPluginManager().callEvent(queueEvent); ++ ++ if (queueEvent.isCancelled()) { ++ return null; ++ } ++ ++ String message = String.format(queueEvent.getFormat(), queueEvent.getPlayer().getDisplayName(), queueEvent.getMessage()); ++ PlayerConnection.this.minecraftServer.console.sendMessage(message); ++ if (((LazyPlayerSet) queueEvent.getRecipients()).isLazy()) { ++ for (Object player : PlayerConnection.this.minecraftServer.getPlayerList().players) { ++ ((EntityPlayer) player).sendMessage(CraftChatMessage.fromString(message)); ++ } ++ } else { ++ for (Player player : queueEvent.getRecipients()) { ++ player.sendMessage(message); ++ } ++ } ++ return null; ++ }}; ++ if (async) { ++ minecraftServer.processQueue.add(waitable); ++ } else { ++ waitable.run(); ++ } ++ try { ++ waitable.get(); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on! ++ } catch (ExecutionException e) { ++ throw new RuntimeException("Exception processing chat event", e.getCause()); ++ } ++ } else { ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ s = String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()); ++ minecraftServer.console.sendMessage(s); ++ if (((LazyPlayerSet) event.getRecipients()).isLazy()) { ++ for (Object recipient : minecraftServer.getPlayerList().players) { ++ ((EntityPlayer) recipient).sendMessage(CraftChatMessage.fromString(s)); ++ } ++ } else { ++ for (Player recipient : event.getRecipients()) { ++ recipient.sendMessage(s); ++ } ++ } ++ } ++ } ++ } ++ // CraftBukkit end + + private void handleCommand(String s) { +- this.minecraftServer.getCommandHandler().a(this.player, s); ++ // CraftBukkit start - whole method ++ this.c.info(this.player.getName() + " issued server command: " + s); ++ ++ CraftPlayer player = this.getPlayer(); ++ ++ PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(player, s, new LazyPlayerSet()); ++ this.server.getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ try { ++ if (this.server.dispatchCommand(event.getPlayer(), event.getMessage().substring(1))) { ++ return; ++ } ++ } catch (org.bukkit.command.CommandException ex) { ++ player.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command"); ++ java.util.logging.Logger.getLogger(PlayerConnection.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); ++ return; ++ } ++ // this.minecraftServer.getCommandHandler().a(this.player, s); ++ // CraftBukkit end + } + + public void a(PacketPlayInArmAnimation packetplayinarmanimation) { ++ if (this.player.dead) return; // CraftBukkit + PlayerConnectionUtils.ensureMainThread(packetplayinarmanimation, this, this.player.u()); + this.player.z(); ++ // CraftBukkit start - Raytrace to look for 'rogue armswings' ++ float f = 1.0F; ++ float f1 = this.player.lastPitch + (this.player.pitch - this.player.lastPitch) * f; ++ float f2 = this.player.lastYaw + (this.player.yaw - this.player.lastYaw) * f; ++ double d0 = this.player.lastX + (this.player.locX - this.player.lastX) * (double) f; ++ double d1 = this.player.lastY + (this.player.locY - this.player.lastY) * (double) f + 1.62D - (double) this.player.getHeadHeight(); ++ double d2 = this.player.lastZ + (this.player.locZ - this.player.lastZ) * (double) f; ++ Vec3D vec3d = new Vec3D(d0, d1, d2); ++ ++ float f3 = MathHelper.cos(-f2 * 0.017453292F - 3.1415927F); ++ float f4 = MathHelper.sin(-f2 * 0.017453292F - 3.1415927F); ++ float f5 = -MathHelper.cos(-f1 * 0.017453292F); ++ float f6 = MathHelper.sin(-f1 * 0.017453292F); ++ float f7 = f4 * f5; ++ float f8 = f3 * f5; ++ double d3 = 5.0D; ++ Vec3D vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3); ++ MovingObjectPosition movingobjectposition = this.player.world.rayTrace(vec3d, vec3d1, false); ++ ++ if (movingobjectposition == null || movingobjectposition.type != EnumMovingObjectType.BLOCK) { ++ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.inventory.getItemInHand()); ++ } ++ ++ // Arm swing animation ++ PlayerAnimationEvent event = new PlayerAnimationEvent(this.getPlayer()); ++ this.server.getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) return; ++ // CraftBukkit end + this.player.bv(); + } + + public void a(PacketPlayInEntityAction packetplayinentityaction) { + PlayerConnectionUtils.ensureMainThread(packetplayinentityaction, this, this.player.u()); ++ // CraftBukkit start ++ if (this.player.dead) return; ++ switch (packetplayinentityaction.b()) { ++ case START_SNEAKING: ++ case STOP_SNEAKING: ++ PlayerToggleSneakEvent event = new PlayerToggleSneakEvent(this.getPlayer(), packetplayinentityaction.b() == EnumPlayerAction.START_SNEAKING); ++ this.server.getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ break; ++ case START_SPRINTING: ++ case STOP_SPRINTING: ++ PlayerToggleSprintEvent e2 = new PlayerToggleSprintEvent(this.getPlayer(), packetplayinentityaction.b() == EnumPlayerAction.START_SPRINTING); ++ this.server.getPluginManager().callEvent(e2); ++ ++ if (e2.isCancelled()) { ++ return; ++ } ++ break; ++ } + this.player.z(); + switch (SwitchHelperCommandActionType.b[packetplayinentityaction.b().ordinal()]) { + case 1: +@@ -601,7 +1136,7 @@ + + case 5: + this.player.a(false, true, true); +- this.checkMovement = false; ++ // this.checkMovement = false; // CraftBukkit - this is handled in teleport + break; + + case 6: +@@ -623,6 +1158,7 @@ + } + + public void a(PacketPlayInUseEntity packetplayinuseentity) { ++ if (this.player.dead) return; // CraftBukkit + PlayerConnectionUtils.ensureMainThread(packetplayinuseentity, this, this.player.u()); + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); + Entity entity = packetplayinuseentity.a((World) worldserver); +@@ -637,18 +1173,72 @@ + } + + if (this.player.h(entity) < d0) { ++ ItemStack itemInHand = this.player.inventory.getItemInHand(); // CraftBukkit ++ ++ if (packetplayinuseentity.a() == EnumEntityUseAction.INTERACT ++ || packetplayinuseentity.a() == EnumEntityUseAction.INTERACT_AT) { ++ // CraftBukkit start ++ boolean triggerTagUpdate = itemInHand != null && itemInHand.getItem() == Items.NAME_TAG && entity instanceof EntityInsentient; ++ boolean triggerChestUpdate = itemInHand != null && itemInHand.getItem() == Item.getItemOf(Blocks.CHEST) && entity instanceof EntityHorse; ++ boolean triggerLeashUpdate = itemInHand != null && itemInHand.getItem() == Items.LEAD && entity instanceof EntityInsentient; ++ PlayerInteractEntityEvent event; ++ if (packetplayinuseentity.a() == EnumEntityUseAction.INTERACT) { ++ event = new PlayerInteractEntityEvent((Player) this.getPlayer(), entity.getBukkitEntity()); ++ } else { ++ Vec3D target = packetplayinuseentity.b(); ++ event = new PlayerInteractAtEntityEvent((Player) this.getPlayer(), entity.getBukkitEntity(), new org.bukkit.util.Vector(target.a, target.b, target.c)); ++ } ++ this.server.getPluginManager().callEvent(event); ++ ++ if (triggerLeashUpdate && (event.isCancelled() || this.player.inventory.getItemInHand() == null || this.player.inventory.getItemInHand().getItem() != Items.LEAD)) { ++ // Refresh the current leash state ++ this.sendPacket(new PacketPlayOutAttachEntity(1, entity, ((EntityInsentient) entity).getLeashHolder())); ++ } ++ ++ if (triggerTagUpdate && (event.isCancelled() || this.player.inventory.getItemInHand() == null || this.player.inventory.getItemInHand().getItem() != Items.NAME_TAG)) { ++ // Refresh the current entity metadata ++ this.sendPacket(new PacketPlayOutEntityMetadata(entity.getId(), entity.datawatcher, true)); ++ } ++ if (triggerChestUpdate && (event.isCancelled() || this.player.inventory.getItemInHand() == null || this.player.inventory.getItemInHand().getItem() != Item.getItemOf(Blocks.CHEST))) { ++ this.sendPacket(new PacketPlayOutEntityMetadata(entity.getId(), entity.datawatcher, true)); ++ } ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ } ++ + if (packetplayinuseentity.a() == EnumEntityUseAction.INTERACT) { + this.player.u(entity); ++ ++ // CraftBukkit start ++ if (itemInHand != null && itemInHand.count <= -1) { ++ this.player.updateInventory(this.player.activeContainer); ++ } ++ // CraftBukkit end + } else if (packetplayinuseentity.a() == EnumEntityUseAction.INTERACT_AT) { + entity.a((EntityHuman) this.player, packetplayinuseentity.b()); ++ ++ // CraftBukkit start ++ if (itemInHand != null && itemInHand.count <= -1) { ++ this.player.updateInventory(this.player.activeContainer); ++ } ++ // CraftBukkit end + } else if (packetplayinuseentity.a() == EnumEntityUseAction.ATTACK) { +- if (entity instanceof EntityItem || entity instanceof EntityExperienceOrb || entity instanceof EntityArrow || entity == this.player) { ++ if (entity instanceof EntityItem || entity instanceof EntityExperienceOrb || entity instanceof EntityArrow || (entity == this.player && !player.v())) { // CraftBukkit, RENAME + this.disconnect("Attempting to attack an invalid entity"); + this.minecraftServer.warning("Player " + this.player.getName() + " tried to attack an invalid entity"); + return; + } + + this.player.attack(entity); ++ ++ // CraftBukkit start ++ if (itemInHand != null && itemInHand.count <= -1) { ++ this.player.updateInventory(this.player.activeContainer); ++ } ++ // CraftBukkit end + } + } + } +@@ -663,7 +1253,8 @@ + switch (SwitchHelperCommandActionType.c[enumclientcommand.ordinal()]) { + case 1: + if (this.player.viewingCredits) { +- this.player = this.minecraftServer.getPlayerList().moveToWorld(this.player, 0, true); ++ // this.player = this.minecraftServer.getPlayerList().moveToWorld(this.player, 0, true); ++ this.minecraftServer.getPlayerList().changeDimension(this.player, 0, PlayerTeleportEvent.TeleportCause.END_PORTAL); // CraftBukkit - reroute logic through custom portal management + } else if (this.player.u().getWorldData().isHardcore()) { + if (this.minecraftServer.S() && this.player.getName().equals(this.minecraftServer.R())) { + this.player.playerConnection.disconnect("You have died. Game over, man, it\'s game over!"); +@@ -694,11 +1285,17 @@ + } + + public void a(PacketPlayInCloseWindow packetplayinclosewindow) { ++ if (this.player.dead) return; // CraftBukkit + PlayerConnectionUtils.ensureMainThread(packetplayinclosewindow, this, this.player.u()); ++ ++ CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit ++ + this.player.p(); + } + + public void a(PacketPlayInWindowClick packetplayinwindowclick) { ++ if (this.player.dead) return; // CraftBukkit ++ + PlayerConnectionUtils.ensureMainThread(packetplayinwindowclick, this, this.player.u()); + this.player.z(); + if (this.player.activeContainer.windowId == packetplayinwindowclick.a() && this.player.activeContainer.c(this.player)) { +@@ -711,7 +1308,263 @@ + + this.player.a(this.player.activeContainer, (List) arraylist); + } else { +- ItemStack itemstack = this.player.activeContainer.clickItem(packetplayinwindowclick.b(), packetplayinwindowclick.c(), packetplayinwindowclick.f(), this.player); ++ // ItemStack itemstack = this.player.activeContainer.clickItem(packetplayinwindowclick.b(), packetplayinwindowclick.c(), packetplayinwindowclick.f(), this.player); ++ // CraftBukkit start - Call InventoryClickEvent ++ if (packetplayinwindowclick.b() < -1 && packetplayinwindowclick.b() != -999) { ++ return; ++ } ++ ++ InventoryView inventory = this.player.activeContainer.getBukkitView(); ++ SlotType type = CraftInventoryView.getSlotType(inventory, packetplayinwindowclick.b()); ++ ++ InventoryClickEvent event = null; ++ ClickType click = ClickType.UNKNOWN; ++ InventoryAction action = InventoryAction.UNKNOWN; ++ ++ ItemStack itemstack = null; ++ ++ if (packetplayinwindowclick.b() == -1) { ++ type = SlotType.OUTSIDE; // override ++ click = packetplayinwindowclick.c() == 0 ? ClickType.WINDOW_BORDER_LEFT : ClickType.WINDOW_BORDER_RIGHT; ++ action = InventoryAction.NOTHING; ++ } else if (packetplayinwindowclick.f() == 0) { ++ if (packetplayinwindowclick.c() == 0) { ++ click = ClickType.LEFT; ++ } else if (packetplayinwindowclick.c() == 1) { ++ click = ClickType.RIGHT; ++ } ++ if (packetplayinwindowclick.c() == 0 || packetplayinwindowclick.c() == 1) { ++ action = InventoryAction.NOTHING; // Don't want to repeat ourselves ++ if (packetplayinwindowclick.b() == -999) { ++ if (player.inventory.getCarried() != null) { ++ action = packetplayinwindowclick.c() == 0 ? InventoryAction.DROP_ALL_CURSOR : InventoryAction.DROP_ONE_CURSOR; ++ } ++ } else { ++ Slot slot = this.player.activeContainer.getSlot(packetplayinwindowclick.b()); ++ if (slot != null) { ++ ItemStack clickedItem = slot.getItem(); ++ ItemStack cursor = player.inventory.getCarried(); ++ if (clickedItem == null) { ++ if (cursor != null) { ++ action = packetplayinwindowclick.c() == 0 ? InventoryAction.PLACE_ALL : InventoryAction.PLACE_ONE; ++ } ++ } else if (slot.isAllowed(player)) { ++ if (cursor == null) { ++ action = packetplayinwindowclick.c() == 0 ? InventoryAction.PICKUP_ALL : InventoryAction.PICKUP_HALF; ++ } else if (slot.isAllowed(cursor)) { ++ if (clickedItem.doMaterialsMatch(cursor) && ItemStack.equals(clickedItem, cursor)) { ++ int toPlace = packetplayinwindowclick.c() == 0 ? cursor.count : 1; ++ toPlace = Math.min(toPlace, clickedItem.getMaxStackSize() - clickedItem.count); ++ toPlace = Math.min(toPlace, slot.inventory.getMaxStackSize() - clickedItem.count); ++ if (toPlace == 1) { ++ action = InventoryAction.PLACE_ONE; ++ } else if (toPlace == cursor.count) { ++ action = InventoryAction.PLACE_ALL; ++ } else if (toPlace < 0) { ++ action = toPlace != -1 ? InventoryAction.PICKUP_SOME : InventoryAction.PICKUP_ONE; // this happens with oversized stacks ++ } else if (toPlace != 0) { ++ action = InventoryAction.PLACE_SOME; ++ } ++ } else if (cursor.count <= slot.getMaxStackSize()) { ++ action = InventoryAction.SWAP_WITH_CURSOR; ++ } ++ } else if (cursor.getItem() == clickedItem.getItem() && (!cursor.usesData() || cursor.getData() == clickedItem.getData()) && ItemStack.equals(cursor, clickedItem)) { ++ if (clickedItem.count >= 0) { ++ if (clickedItem.count + cursor.count <= cursor.getMaxStackSize()) { ++ // As of 1.5, this is result slots only ++ action = InventoryAction.PICKUP_ALL; ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ } else if (packetplayinwindowclick.f() == 1) { ++ if (packetplayinwindowclick.c() == 0) { ++ click = ClickType.SHIFT_LEFT; ++ } else if (packetplayinwindowclick.c() == 1) { ++ click = ClickType.SHIFT_RIGHT; ++ } ++ if (packetplayinwindowclick.c() == 0 || packetplayinwindowclick.c() == 1) { ++ if (packetplayinwindowclick.b() < 0) { ++ action = InventoryAction.NOTHING; ++ } else { ++ Slot slot = this.player.activeContainer.getSlot(packetplayinwindowclick.b()); ++ if (slot != null && slot.isAllowed(this.player) && slot.hasItem()) { ++ action = InventoryAction.MOVE_TO_OTHER_INVENTORY; ++ } else { ++ action = InventoryAction.NOTHING; ++ } ++ } ++ } ++ } else if (packetplayinwindowclick.f() == 2) { ++ if (packetplayinwindowclick.c() >= 0 && packetplayinwindowclick.c() < 9) { ++ click = ClickType.NUMBER_KEY; ++ Slot clickedSlot = this.player.activeContainer.getSlot(packetplayinwindowclick.b()); ++ if (clickedSlot.isAllowed(player)) { ++ ItemStack hotbar = this.player.inventory.getItem(packetplayinwindowclick.c()); ++ boolean canCleanSwap = hotbar == null || (clickedSlot.inventory == player.inventory && clickedSlot.isAllowed(hotbar)); // the slot will accept the hotbar item ++ if (clickedSlot.hasItem()) { ++ if (canCleanSwap) { ++ action = InventoryAction.HOTBAR_SWAP; ++ } else { ++ int firstEmptySlot = player.inventory.getFirstEmptySlotIndex(); ++ if (firstEmptySlot > -1) { ++ action = InventoryAction.HOTBAR_MOVE_AND_READD; ++ } else { ++ action = InventoryAction.NOTHING; // This is not sane! Mojang: You should test for other slots of same type ++ } ++ } ++ } else if (!clickedSlot.hasItem() && hotbar != null && clickedSlot.isAllowed(hotbar)) { ++ action = InventoryAction.HOTBAR_SWAP; ++ } else { ++ action = InventoryAction.NOTHING; ++ } ++ } else { ++ action = InventoryAction.NOTHING; ++ } ++ // Special constructor for number key ++ event = new InventoryClickEvent(inventory, type, packetplayinwindowclick.b(), click, action, packetplayinwindowclick.c()); ++ } ++ } else if (packetplayinwindowclick.f() == 3) { ++ if (packetplayinwindowclick.c() == 2) { ++ click = ClickType.MIDDLE; ++ if (packetplayinwindowclick.b() == -999) { ++ action = InventoryAction.NOTHING; ++ } else { ++ Slot slot = this.player.activeContainer.getSlot(packetplayinwindowclick.b()); ++ if (slot != null && slot.hasItem() && player.abilities.canInstantlyBuild && player.inventory.getCarried() == null) { ++ action = InventoryAction.CLONE_STACK; ++ } else { ++ action = InventoryAction.NOTHING; ++ } ++ } ++ } else { ++ click = ClickType.UNKNOWN; ++ action = InventoryAction.UNKNOWN; ++ } ++ } else if (packetplayinwindowclick.f() == 4) { ++ if (packetplayinwindowclick.b() >= 0) { ++ if (packetplayinwindowclick.c() == 0) { ++ click = ClickType.DROP; ++ Slot slot = this.player.activeContainer.getSlot(packetplayinwindowclick.b()); ++ if (slot != null && slot.hasItem() && slot.isAllowed(player) && slot.getItem() != null && slot.getItem().getItem() != Item.getItemOf(Blocks.AIR)) { ++ action = InventoryAction.DROP_ONE_SLOT; ++ } else { ++ action = InventoryAction.NOTHING; ++ } ++ } else if (packetplayinwindowclick.c() == 1) { ++ click = ClickType.CONTROL_DROP; ++ Slot slot = this.player.activeContainer.getSlot(packetplayinwindowclick.b()); ++ if (slot != null && slot.hasItem() && slot.isAllowed(player) && slot.getItem() != null && slot.getItem().getItem() != Item.getItemOf(Blocks.AIR)) { ++ action = InventoryAction.DROP_ALL_SLOT; ++ } else { ++ action = InventoryAction.NOTHING; ++ } ++ } ++ } else { ++ // Sane default (because this happens when they are holding nothing. Don't ask why.) ++ click = ClickType.LEFT; ++ if (packetplayinwindowclick.c() == 1) { ++ click = ClickType.RIGHT; ++ } ++ action = InventoryAction.NOTHING; ++ } ++ } else if (packetplayinwindowclick.f() == 5) { ++ itemstack = this.player.activeContainer.clickItem(packetplayinwindowclick.b(), packetplayinwindowclick.c(), 5, this.player); ++ } else if (packetplayinwindowclick.f() == 6) { ++ click = ClickType.DOUBLE_CLICK; ++ action = InventoryAction.NOTHING; ++ if (packetplayinwindowclick.b() >= 0 && this.player.inventory.getCarried() != null) { ++ ItemStack cursor = this.player.inventory.getCarried(); ++ action = InventoryAction.NOTHING; ++ // Quick check for if we have any of the item ++ if (inventory.getTopInventory().contains(org.bukkit.Material.getMaterial(Item.getId(cursor.getItem()))) || inventory.getBottomInventory().contains(org.bukkit.Material.getMaterial(Item.getId(cursor.getItem())))) { ++ action = InventoryAction.COLLECT_TO_CURSOR; ++ } ++ } ++ } ++ // TODO check on updates ++ ++ if (packetplayinwindowclick.f() != 5) { ++ if (click == ClickType.NUMBER_KEY) { ++ event = new InventoryClickEvent(inventory, type, packetplayinwindowclick.b(), click, action, packetplayinwindowclick.c()); ++ } else { ++ event = new InventoryClickEvent(inventory, type, packetplayinwindowclick.b(), click, action); ++ } ++ ++ org.bukkit.inventory.Inventory top = inventory.getTopInventory(); ++ if (packetplayinwindowclick.b() == 0 && top instanceof CraftingInventory) { ++ org.bukkit.inventory.Recipe recipe = ((CraftingInventory) top).getRecipe(); ++ if (recipe != null) { ++ if (click == ClickType.NUMBER_KEY) { ++ event = new CraftItemEvent(recipe, inventory, type, packetplayinwindowclick.b(), click, action, packetplayinwindowclick.c()); ++ } else { ++ event = new CraftItemEvent(recipe, inventory, type, packetplayinwindowclick.b(), click, action); ++ } ++ } ++ } ++ ++ server.getPluginManager().callEvent(event); ++ ++ switch (event.getResult()) { ++ case ALLOW: ++ case DEFAULT: ++ itemstack = this.player.activeContainer.clickItem(packetplayinwindowclick.b(), packetplayinwindowclick.c(), packetplayinwindowclick.f(), this.player); ++ break; ++ case DENY: ++ /* Needs enum constructor in InventoryAction ++ if (action.modifiesOtherSlots()) { ++ ++ } else { ++ if (action.modifiesCursor()) { ++ this.player.playerConnection.sendPacket(new Packet103SetSlot(-1, -1, this.player.inventory.getCarried())); ++ } ++ if (action.modifiesClicked()) { ++ this.player.playerConnection.sendPacket(new Packet103SetSlot(this.player.activeContainer.windowId, packet102windowclick.slot, this.player.activeContainer.getSlot(packet102windowclick.slot).getItem())); ++ } ++ }*/ ++ switch (action) { ++ // Modified other slots ++ case PICKUP_ALL: ++ case MOVE_TO_OTHER_INVENTORY: ++ case HOTBAR_MOVE_AND_READD: ++ case HOTBAR_SWAP: ++ case COLLECT_TO_CURSOR: ++ case UNKNOWN: ++ this.player.updateInventory(this.player.activeContainer); ++ break; ++ // Modified cursor and clicked ++ case PICKUP_SOME: ++ case PICKUP_HALF: ++ case PICKUP_ONE: ++ case PLACE_ALL: ++ case PLACE_SOME: ++ case PLACE_ONE: ++ case SWAP_WITH_CURSOR: ++ this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, this.player.inventory.getCarried())); ++ this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(this.player.activeContainer.windowId, packetplayinwindowclick.b(), this.player.activeContainer.getSlot(packetplayinwindowclick.b()).getItem())); ++ break; ++ // Modified clicked only ++ case DROP_ALL_SLOT: ++ case DROP_ONE_SLOT: ++ this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(this.player.activeContainer.windowId, packetplayinwindowclick.b(), this.player.activeContainer.getSlot(packetplayinwindowclick.b()).getItem())); ++ break; ++ // Modified cursor only ++ case DROP_ALL_CURSOR: ++ case DROP_ONE_CURSOR: ++ case CLONE_STACK: ++ this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, this.player.inventory.getCarried())); ++ break; ++ // Nothing ++ case NOTHING: ++ break; ++ } ++ return; ++ } ++ } ++ // CraftBukkit end + + if (ItemStack.matches(packetplayinwindowclick.e(), itemstack)) { + this.player.playerConnection.sendPacket(new PacketPlayOutTransaction(packetplayinwindowclick.a(), packetplayinwindowclick.d(), true)); +@@ -772,8 +1625,50 @@ + } + + boolean flag1 = packetplayinsetcreativeslot.a() >= 1 && packetplayinsetcreativeslot.a() < 36 + PlayerInventory.getHotbarSize(); +- boolean flag2 = itemstack == null || itemstack.getItem() != null; ++ // CraftBukkit - Add invalidItems check ++ boolean flag2 = itemstack == null || itemstack.getItem() != null && !invalidItems.contains(Item.getId(itemstack.getItem())); + boolean flag3 = itemstack == null || itemstack.getData() >= 0 && itemstack.count <= 64 && itemstack.count > 0; ++ ++ ++ // CraftBukkit start - Call click event ++ if (flag || (flag1 && !ItemStack.matches(this.player.defaultContainer.getSlot(packetplayinsetcreativeslot.a()).getItem(), packetplayinsetcreativeslot.getItemStack()))) { // Insist on valid slot ++ ++ org.bukkit.entity.HumanEntity player = this.player.getBukkitEntity(); ++ InventoryView inventory = new CraftInventoryView(player, player.getInventory(), this.player.defaultContainer); ++ org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packetplayinsetcreativeslot.getItemStack()); ++ ++ SlotType type = SlotType.QUICKBAR; ++ if (flag) { ++ type = SlotType.OUTSIDE; ++ } else if (packetplayinsetcreativeslot.a() < 36) { ++ if (packetplayinsetcreativeslot.a() >= 5 && packetplayinsetcreativeslot.a() < 9) { ++ type = SlotType.ARMOR; ++ } else { ++ type = SlotType.CONTAINER; ++ } ++ } ++ InventoryCreativeEvent event = new InventoryCreativeEvent(inventory, type, flag ? -999 : packetplayinsetcreativeslot.a(), item); ++ server.getPluginManager().callEvent(event); ++ ++ itemstack = CraftItemStack.asNMSCopy(event.getCursor()); ++ ++ switch (event.getResult()) { ++ case ALLOW: ++ // Plugin cleared the id / stacksize checks ++ flag2 = flag3 = true; ++ break; ++ case DEFAULT: ++ break; ++ case DENY: ++ // Reset the slot ++ if (packetplayinsetcreativeslot.a() >= 0) { ++ this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(this.player.defaultContainer.windowId, packetplayinsetcreativeslot.a(), this.player.defaultContainer.getSlot(packetplayinsetcreativeslot.a()).getItem())); ++ this.player.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, null)); ++ } ++ return; ++ } ++ } ++ // CraftBukkit end + + if (flag1 && flag2 && flag3) { + if (itemstack == null) { +@@ -796,6 +1691,7 @@ + } + + public void a(PacketPlayInTransaction packetplayintransaction) { ++ if (this.player.dead) return; // CraftBukkit + PlayerConnectionUtils.ensureMainThread(packetplayintransaction, this, this.player.u()); + Short oshort = (Short) this.n.get(this.player.activeContainer.windowId); + +@@ -806,6 +1702,7 @@ + } + + public void a(PacketPlayInUpdateSign packetplayinupdatesign) { ++ if (this.player.dead) return; // CraftBukkit + PlayerConnectionUtils.ensureMainThread(packetplayinupdatesign, this, this.player.u()); + this.player.z(); + WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension); +@@ -822,10 +1719,24 @@ + + if (!tileentitysign.b() || tileentitysign.c() != this.player) { + this.minecraftServer.warning("Player " + this.player.getName() + " just tried to change non-editable sign"); ++ this.sendPacket(new PacketPlayOutUpdateSign(tileentity.world, packetplayinupdatesign.a(), tileentitysign.lines)); // CraftBukkit + return; + } + +- System.arraycopy(packetplayinupdatesign.b(), 0, tileentitysign.lines, 0, 4); ++ // CraftBukkit start ++ Player player = this.server.getPlayer(this.player); ++ int x = packetplayinupdatesign.a().getX(); ++ int y = packetplayinupdatesign.a().getY(); ++ int z = packetplayinupdatesign.a().getZ(); ++ SignChangeEvent event = new SignChangeEvent((org.bukkit.craftbukkit.block.CraftBlock) player.getWorld().getBlockAt(x, y, z), this.server.getPlayer(this.player), org.bukkit.craftbukkit.block.CraftSign.revertComponents(packetplayinupdatesign.b())); ++ this.server.getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ System.arraycopy(org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.getLines()), 0, tileentitysign.lines, 0, 4); ++ tileentitysign.isEditable = false; ++ } ++ // System.arraycopy(packetplayinupdatesign.b(), 0, tileentitysign.lines, 0, 4); ++ // CraftBukkit end + tileentitysign.update(); + worldserver.notify(blockposition); + } +@@ -847,11 +1758,28 @@ + + public void a(PacketPlayInAbilities packetplayinabilities) { + PlayerConnectionUtils.ensureMainThread(packetplayinabilities, this, this.player.u()); +- this.player.abilities.isFlying = packetplayinabilities.isFlying() && this.player.abilities.canFly; ++ // CraftBukkit start ++ if (this.player.abilities.canFly && this.player.abilities.isFlying != packetplayinabilities.isFlying()) { ++ PlayerToggleFlightEvent event = new PlayerToggleFlightEvent(this.server.getPlayer(this.player), packetplayinabilities.isFlying()); ++ this.server.getPluginManager().callEvent(event); ++ if (!event.isCancelled()) { ++ this.player.abilities.isFlying = packetplayinabilities.isFlying(); // Actually set the player's flying status ++ } else { ++ this.player.updateAbilities(); // Tell the player their ability was reverted ++ } ++ } ++ // CraftBukkit end + } + + public void a(PacketPlayInTabComplete packetplayintabcomplete) { + PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.u()); ++ // CraftBukkit start ++ if (chatSpamField.addAndGet(this, 20) > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) { ++ this.disconnect("disconnect.spam"); ++ return; ++ } ++ // CraftBukkit end ++ + ArrayList arraylist = Lists.newArrayList(); + Iterator iterator = this.minecraftServer.tabCompleteCommand(this.player, packetplayintabcomplete.a(), packetplayintabcomplete.b()).iterator(); + +@@ -891,13 +1819,15 @@ + itemstack1 = this.player.inventory.getItemInHand(); + if (itemstack1 != null) { + if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) { +- itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8)); ++ // itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8)); ++ CraftEventFactory.handleEditBookEvent(player, itemstack); // CraftBukkit + } + + return; + } + } catch (Exception exception) { + PlayerConnection.c.error("Couldn\'t handle book info", exception); ++ this.disconnect("Invalid book data!"); // CraftBukkit + return; + } finally { + packetdataserializer.release(); +@@ -909,27 +1839,31 @@ + + try { + itemstack = packetdataserializer.i(); +- if (itemstack == null) { +- return; +- } ++ if (itemstack != null) { ++ if (!ItemWrittenBook.b(itemstack.getTag())) { ++ throw new IOException("Invalid book tag!"); ++ } + +- if (!ItemWrittenBook.b(itemstack.getTag())) { +- throw new IOException("Invalid book tag!"); +- } ++ itemstack1 = this.player.inventory.getItemInHand(); ++ if (itemstack1 == null) { ++ return; ++ } + +- itemstack1 = this.player.inventory.getItemInHand(); +- if (itemstack1 != null) { + if (itemstack.getItem() == Items.WRITTEN_BOOK && itemstack1.getItem() == Items.WRITABLE_BOOK) { +- itemstack1.a("author", (NBTBase) (new NBTTagString(this.player.getName()))); +- itemstack1.a("title", (NBTBase) (new NBTTagString(itemstack.getTag().getString("title")))); +- itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8)); +- itemstack1.setItem(Items.WRITTEN_BOOK); ++ // CraftBukkit start ++ // itemstack1.a("author", (NBTBase) (new NBTTagString(this.player.getName()))); ++ // itemstack1.a("title", (NBTBase) (new NBTTagString(itemstack.getTag().getString("title")))); ++ // itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8)); ++ // itemstack1.setItem(Items.WRITTEN_BOOK); ++ CraftEventFactory.handleEditBookEvent(player, itemstack); ++ // CraftBukkit end + } + + return; + } + } catch (Exception exception1) { + PlayerConnection.c.error("Couldn\'t sign book", exception1); ++ this.disconnect("Invalid book data!"); // CraftBukkit + return; + } finally { + packetdataserializer.release(); +@@ -946,6 +1880,7 @@ + } + } catch (Exception exception2) { + PlayerConnection.c.error("Couldn\'t select trade", exception2); ++ this.disconnect("Invalid trade data!"); // CraftBukkit + } + } else if ("MC|AdvCdm".equals(packetplayincustompayload.a())) { + if (!this.minecraftServer.getEnableCommandBlock()) { +@@ -986,6 +1921,7 @@ + } + } catch (Exception exception3) { + PlayerConnection.c.error("Couldn\'t set command block", exception3); ++ this.disconnect("Invalid CommandBlock data!"); // CraftBukkit + } finally { + packetdataserializer.release(); + } +@@ -1011,6 +1947,7 @@ + } + } catch (Exception exception4) { + PlayerConnection.c.error("Couldn\'t set beacon", exception4); ++ this.disconnect("Invalid beacon data!"); // CraftBukkit + } + } + } else if ("MC|ItemName".equals(packetplayincustompayload.a()) && this.player.activeContainer instanceof ContainerAnvil) { +@@ -1026,6 +1963,27 @@ + containeranvil.a(""); + } + } ++ // CraftBukkit start ++ else if (packetplayincustompayload.a().equals("REGISTER")) { ++ String channels = packetplayincustompayload.b().toString(com.google.common.base.Charsets.UTF_8); ++ for (String channel : channels.split("\0")) { ++ getPlayer().addChannel(channel); ++ } ++ } else if (packetplayincustompayload.a().equals("UNREGISTER")) { ++ String channels = packetplayincustompayload.b().toString(com.google.common.base.Charsets.UTF_8); ++ for (String channel : channels.split("\0")) { ++ getPlayer().removeChannel(channel); ++ } ++ } else { ++ byte[] data = new byte[packetplayincustompayload.b().readableBytes()]; ++ packetplayincustompayload.b().readBytes(data); ++ server.getMessenger().dispatchIncomingMessage(player.getBukkitEntity(), packetplayincustompayload.a(), data); ++ } ++ // CraftBukkit end ++ } + ++ // CraftBukkit start - Add "isDisconnected" method ++ public final boolean isDisconnected() { ++ return !this.player.joining && !NetworkManager.a(this.networkManager).config().isAutoRead(); + } + } diff --git a/paper-server/nms-patches/PlayerDatFileConverter.patch b/paper-server/nms-patches/PlayerDatFileConverter.patch new file mode 100644 index 0000000000..a1286509e6 --- /dev/null +++ b/paper-server/nms-patches/PlayerDatFileConverter.patch @@ -0,0 +1,33 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerDatFileConverter.java 2014-11-27 08:59:46.857421159 +1100 ++++ src/main/java/net/minecraft/server/PlayerDatFileConverter.java 2014-11-27 08:42:10.168850880 +1100 +@@ -47,6 +47,30 @@ + private void a(File file, String s, String s1) { + File file1 = new File(this.d, s + ".dat"); + File file2 = new File(file, s1 + ".dat"); ++ ++ // CraftBukkit start - Use old file name to seed lastKnownName ++ NBTTagCompound root = null; ++ ++ try { ++ root = NBTCompressedStreamTools.a(new java.io.FileInputStream(file1)); ++ } catch (Exception exception) { ++ exception.printStackTrace(); ++ } ++ ++ if (root != null) { ++ if (!root.hasKey("bukkit")) { ++ root.set("bukkit", new NBTTagCompound()); ++ } ++ NBTTagCompound data = root.getCompound("bukkit"); ++ data.setString("lastKnownName", s); ++ ++ try { ++ NBTCompressedStreamTools.a(root, new java.io.FileOutputStream(file2)); ++ } catch (Exception exception) { ++ exception.printStackTrace(); ++ } ++ } ++ // CraftBukkit end + + NameReferencingFileConverter.a(file); + if (!file1.renameTo(file2)) { diff --git a/paper-server/nms-patches/PlayerInteractManager.patch b/paper-server/nms-patches/PlayerInteractManager.patch new file mode 100644 index 0000000000..ac0ab56914 --- /dev/null +++ b/paper-server/nms-patches/PlayerInteractManager.patch @@ -0,0 +1,289 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerInteractManager.java 2014-11-27 08:59:46.857421159 +1100 ++++ src/main/java/net/minecraft/server/PlayerInteractManager.java 2014-11-27 08:42:10.108850996 +1100 +@@ -1,5 +1,13 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.event.block.BlockBreakEvent; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.Event; ++import org.bukkit.event.block.Action; ++import org.bukkit.event.player.PlayerInteractEvent; ++// CraftBukkit end ++ + public class PlayerInteractManager { + + public World world; +@@ -50,7 +58,7 @@ + } + + public void a() { +- ++this.currentTick; ++ this.currentTick = MinecraftServer.currentTick; // CraftBukkit; + float f; + int i; + +@@ -95,6 +103,19 @@ + } + + public void a(BlockPosition blockposition, EnumDirection enumdirection) { ++ // CraftBukkit start ++ PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, blockposition, enumdirection, this.player.inventory.getItemInHand()); ++ if (event.isCancelled()) { ++ // Let the client know the block still exists ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ // Update any tile entity data for this block ++ TileEntity tileentity = this.world.getTileEntity(blockposition); ++ if (tileentity != null) { ++ this.player.playerConnection.sendPacket(tileentity.getUpdatePacket()); ++ } ++ return; ++ } ++ // CraftBukkit end + if (this.isCreative()) { + if (!this.world.douseFire((EntityHuman) null, blockposition, enumdirection)) { + this.breakBlock(blockposition); +@@ -121,15 +142,49 @@ + } + } + +- this.world.douseFire((EntityHuman) null, blockposition, enumdirection); ++ // this.world.douseFire((EntityHuman) null, blockposition, enumdirection); // CraftBukkit - Moved down + this.lastDigTick = this.currentTick; + float f = 1.0F; + +- if (block.getMaterial() != Material.AIR) { ++ // CraftBukkit start - Swings at air do *NOT* exist. ++ if (event.useInteractedBlock() == Event.Result.DENY) { ++ // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. ++ IBlockData data = this.world.getType(blockposition); ++ if (block == Blocks.WOODEN_DOOR) { ++ // For some reason *BOTH* the bottom/top part have to be marked updated. ++ boolean bottom = data.get(BlockDoor.HALF) == EnumDoorHalf.LOWER; ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, bottom ? blockposition.up() : blockposition.down())); ++ } else if (block == Blocks.TRAPDOOR) { ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ } ++ } else if (block.getMaterial() != Material.AIR) { + block.attack(this.world, blockposition, this.player); + f = block.getDamage(this.player, this.player.world, blockposition); ++ // Allow fire punching to be blocked ++ this.world.douseFire((EntityHuman) null, blockposition, enumdirection); ++ } ++ ++ if (event.useItemInHand() == Event.Result.DENY) { ++ // If we 'insta destroyed' then the client needs to be informed. ++ if (f > 1.0f) { ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ } ++ return; ++ } ++ org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.player.inventory.getItemInHand(), f >= 1.0f); ++ ++ if (blockEvent.isCancelled()) { ++ // Let the client know the block still exists ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ return; + } + ++ if (blockEvent.getInstaBreak()) { ++ f = 2.0f; ++ } ++ // CraftBukkit end ++ + if (block.getMaterial() != Material.AIR && f >= 1.0F) { + this.breakBlock(blockposition); + } else { +@@ -146,6 +201,7 @@ + + public void a(BlockPosition blockposition) { + if (blockposition.equals(this.f)) { ++ this.currentTick = MinecraftServer.currentTick; // CraftBukkit + int i = this.currentTick - this.lastDigTick; + Block block = this.world.getType(blockposition).getBlock(); + +@@ -163,6 +219,10 @@ + this.j = this.lastDigTick; + } + } ++ // CraftBukkit start - Force block reset to client ++ } else { ++ this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ // CraftBukkit end + } + + } +@@ -186,12 +246,72 @@ + } + + public boolean breakBlock(BlockPosition blockposition) { +- if (this.gamemode.d() && this.player.bz() != null && this.player.bz().getItem() instanceof ItemSword) { ++ // CraftBukkit start - fire BlockBreakEvent ++ BlockBreakEvent event = null; ++ ++ if (this.player instanceof EntityPlayer) { ++ org.bukkit.block.Block block = this.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ ++ // Sword + Creative mode pre-cancel ++ boolean isSwordNoBreak = this.gamemode.d() && this.player.bz() != null && this.player.bz().getItem() instanceof ItemSword; ++ ++ // Tell client the block is gone immediately then process events ++ // Don't tell the client if its a creative sword break because its not broken! ++ if (world.getTileEntity(blockposition) == null && !isSwordNoBreak) { ++ PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(this.world, blockposition); ++ packet.block = Blocks.AIR.getBlockData(); ++ ((EntityPlayer) this.player).playerConnection.sendPacket(packet); ++ } ++ ++ event = new BlockBreakEvent(block, this.player.getBukkitEntity()); ++ ++ // Sword + Creative mode pre-cancel ++ event.setCancelled(isSwordNoBreak); ++ ++ // Calculate default block experience ++ IBlockData nmsData = this.world.getType(blockposition); ++ Block nmsBlock = nmsData.getBlock(); ++ ++ if (nmsBlock != null && !event.isCancelled() && !this.isCreative() && this.player.b(nmsBlock)) { ++ // Copied from block.a(World world, EntityHuman entityhuman, BlockPosition blockposition, IBlockData iblockdata, TileEntity tileentity) ++ if (!(nmsBlock.G() && EnchantmentManager.hasSilkTouchEnchantment(this.player))) { ++ int data = block.getData(); ++ int bonusLevel = EnchantmentManager.getBonusBlockLootEnchantmentLevel(this.player); ++ ++ event.setExpToDrop(nmsBlock.getExpDrop(this.world, nmsData, bonusLevel)); ++ } ++ } ++ ++ this.world.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ if (isSwordNoBreak) { ++ return false; ++ } ++ // Let the client know the block still exists ++ ((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition)); ++ // Update any tile entity data for this block ++ TileEntity tileentity = this.world.getTileEntity(blockposition); ++ if (tileentity != null) { ++ this.player.playerConnection.sendPacket(tileentity.getUpdatePacket()); ++ } ++ return false; ++ } ++ } ++ if (false && this.gamemode.d() && this.player.bz() != null && this.player.bz().getItem() instanceof ItemSword) { + return false; + } else { + IBlockData iblockdata = this.world.getType(blockposition); ++ if (iblockdata.getBlock() == Blocks.AIR) return false; // CraftBukkit - A plugin set block to air without cancelling + TileEntity tileentity = this.world.getTileEntity(blockposition); +- ++ ++ // CraftBukkit start - Special case skulls, their item data comes from a tile entity ++ if (iblockdata.getBlock() == Blocks.SKULL && !this.isCreative()) { ++ iblockdata.getBlock().dropNaturally(world, blockposition, iblockdata, 1.0F, 0); ++ return this.c(blockposition); ++ } ++ // CraftBukkit end ++ + if (this.gamemode.c()) { + if (this.gamemode == EnumGamemode.SPECTATOR) { + return false; +@@ -229,7 +349,13 @@ + if (flag && flag1) { + iblockdata.getBlock().a(this.world, this.player, blockposition, iblockdata, tileentity); + } ++ } ++ ++ // CraftBukkit start - Drop event experience ++ if (flag && event != null) { ++ iblockdata.getBlock().dropExperience(this.world, blockposition, event.getExpToDrop()); + } ++ // CraftBukkit end + + return flag; + } +@@ -268,6 +394,7 @@ + } + + public boolean interact(EntityHuman entityhuman, World world, ItemStack itemstack, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2) { ++ /* CraftBukkit start - whole method + if (this.gamemode == EnumGamemode.SPECTATOR) { + TileEntity tileentity = world.getTileEntity(blockposition); + +@@ -312,6 +439,75 @@ + return itemstack.placeItem(entityhuman, world, blockposition, enumdirection, f, f1, f2); + } + } ++ // Interract event */ ++ IBlockData blockdata = world.getType(blockposition); ++ boolean result = false; ++ if (blockdata.getBlock() != Blocks.AIR) { ++ boolean cancelledBlock = false; ++ ++ if (this.gamemode == EnumGamemode.SPECTATOR) { ++ TileEntity tileentity = world.getTileEntity(blockposition); ++ cancelledBlock = !(tileentity instanceof ITileInventory || tileentity instanceof IInventory); ++ } ++ ++ PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(entityhuman, Action.RIGHT_CLICK_BLOCK, blockposition, enumdirection, itemstack, cancelledBlock); ++ ++ if (event.useInteractedBlock() == Event.Result.DENY) { ++ // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door. ++ if (blockdata.getBlock() instanceof BlockDoor) { ++ boolean bottom = blockdata.get(BlockDoor.HALF) == EnumDoorHalf.LOWER; ++ ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? blockposition.up() : blockposition.down())); ++ } ++ result = (event.useItemInHand() != Event.Result.ALLOW); ++ } else if (this.gamemode == EnumGamemode.SPECTATOR) { ++ TileEntity tileentity = world.getTileEntity(blockposition); ++ ++ if (tileentity instanceof ITileInventory) { ++ Block block = world.getType(blockposition).getBlock(); ++ ITileInventory itileinventory = (ITileInventory) tileentity; ++ ++ if (itileinventory instanceof TileEntityChest && block instanceof BlockChest) { ++ itileinventory = ((BlockChest) block).d(world, blockposition); ++ } ++ ++ if (itileinventory != null) { ++ entityhuman.openContainer(itileinventory); ++ return true; ++ } ++ } else if (tileentity instanceof IInventory) { ++ entityhuman.openContainer((IInventory) tileentity); ++ return true; ++ } ++ ++ return false; ++ } else if (!entityhuman.isSneaking() || itemstack == null) { ++ result = blockdata.getBlock().interact(world, blockposition, blockdata, entityhuman, enumdirection, f, f1, f2); ++ } ++ ++ if (itemstack != null && !result) { ++ int j1 = itemstack.getData(); ++ int k1 = itemstack.count; ++ ++ result = itemstack.placeItem(entityhuman, world, blockposition, enumdirection, f, f1, f2); ++ ++ // The item count should not decrement in Creative mode. ++ if (this.isCreative()) { ++ itemstack.setData(j1); ++ itemstack.count = k1; ++ } ++ } ++ ++ // If we have 'true' and no explicit deny *or* an explicit allow -- run the item part of the hook ++ if (itemstack != null && ((!result && event.useItemInHand() != Event.Result.DENY) || event.useItemInHand() == Event.Result.ALLOW)) { ++ if (itemstack.getItem() instanceof ItemBucket) { ++ this.useItem(entityhuman, world, itemstack); ++ } else { ++ itemstack.placeItem(entityhuman, world, blockposition, enumdirection, f, f1, f2); ++ } ++ } ++ } ++ return result; ++ // CraftBukkit end + } + + public void a(WorldServer worldserver) { diff --git a/paper-server/nms-patches/PlayerInventory.patch b/paper-server/nms-patches/PlayerInventory.patch new file mode 100644 index 0000000000..e4b366708f --- /dev/null +++ b/paper-server/nms-patches/PlayerInventory.patch @@ -0,0 +1,100 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerInventory.java 2014-11-27 08:59:46.861421142 +1100 ++++ src/main/java/net/minecraft/server/PlayerInventory.java 2014-11-27 08:42:10.172850872 +1100 +@@ -2,6 +2,13 @@ + + import java.util.concurrent.Callable; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class PlayerInventory implements IInventory { + + public ItemStack[] items = new ItemStack[36]; +@@ -10,6 +17,39 @@ + public EntityHuman player; + private ItemStack f; + public boolean e; ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public ItemStack[] getArmorContents() { ++ return this.armor; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return this.player.getBukkitEntity(); ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public PlayerInventory(EntityHuman entityhuman) { + this.player = entityhuman; +@@ -42,6 +82,22 @@ + + return -1; + } ++ ++ // CraftBukkit start - Watch method above! :D ++ public int canHold(ItemStack itemstack) { ++ int remains = itemstack.count; ++ for (int i = 0; i < this.items.length; ++i) { ++ if (this.items[i] == null) return itemstack.count; ++ ++ // Taken from firstPartial(ItemStack) ++ if (this.items[i] != null && this.items[i].getItem() == itemstack.getItem() && this.items[i].isStackable() && this.items[i].count < this.items[i].getMaxStackSize() && this.items[i].count < this.getMaxStackSize() && (!this.items[i].usesData() || this.items[i].getData() == itemstack.getData()) && ItemStack.equals(this.items[i], itemstack)) { ++ remains -= (this.items[i].getMaxStackSize() < this.getMaxStackSize() ? this.items[i].getMaxStackSize() : this.getMaxStackSize()) - this.items[i].count; ++ } ++ if (remains <= 0) return itemstack.count; ++ } ++ return itemstack.count - remains; ++ } ++ // CraftBukkit end + + public int getFirstEmptySlotIndex() { + for (int i = 0; i < this.items.length; ++i) { +@@ -382,7 +438,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public boolean b(Block block) { +@@ -458,6 +514,11 @@ + } + + public ItemStack getCarried() { ++ // CraftBukkit start ++ if (this.f != null && this.f.count == 0) { ++ this.setCarried(null); ++ } ++ // CraftBukkit end + return this.f; + } + diff --git a/paper-server/nms-patches/PlayerList.patch b/paper-server/nms-patches/PlayerList.patch new file mode 100644 index 0000000000..f38a5b9d37 --- /dev/null +++ b/paper-server/nms-patches/PlayerList.patch @@ -0,0 +1,788 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerList.java 2014-11-27 08:59:46.861421142 +1100 ++++ src/main/java/net/minecraft/server/PlayerList.java 2014-11-27 08:42:10.160850895 +1100 +@@ -18,6 +18,25 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.Location; ++import org.bukkit.TravelAgent; ++import org.bukkit.entity.Player; ++import org.bukkit.event.player.PlayerChangedWorldEvent; ++import org.bukkit.event.player.PlayerPortalEvent; ++import org.bukkit.event.player.PlayerJoinEvent; ++import org.bukkit.event.player.PlayerLoginEvent; ++import org.bukkit.event.player.PlayerQuitEvent; ++import org.bukkit.event.player.PlayerRespawnEvent; ++import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; ++import org.bukkit.util.Vector; ++// CraftBukkit end ++ + public abstract class PlayerList { + + public static final File a = new File("banned-players.json"); +@@ -27,7 +46,7 @@ + private static final Logger h = LogManager.getLogger(); + private static final SimpleDateFormat i = new SimpleDateFormat("yyyy-MM-dd \'at\' HH:mm:ss z"); + private final MinecraftServer server; +- public final List players = Lists.newArrayList(); ++ public final List players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety + public final Map f = Maps.newHashMap(); + private final GameProfileBanList k; + private final IpBanList l; +@@ -42,7 +61,15 @@ + private boolean t; + private int u; + ++ // CraftBukkit start ++ private CraftServer cserver; ++ + public PlayerList(MinecraftServer minecraftserver) { ++ this.cserver = minecraftserver.server = new CraftServer(minecraftserver, this); ++ minecraftserver.console = org.bukkit.craftbukkit.command.ColouredConsoleSender.getInstance(); ++ minecraftserver.reader.addCompleter(new org.bukkit.craftbukkit.command.ConsoleCommandCompleter(minecraftserver.server)); ++ // CraftBukkit end ++ + this.k = new GameProfileBanList(PlayerList.a); + this.l = new IpBanList(PlayerList.b); + this.operators = new OpList(PlayerList.c); +@@ -71,7 +98,8 @@ + s1 = networkmanager.getSocketAddress().toString(); + } + +- PlayerList.h.info(entityplayer.getName() + "[" + s1 + "] logged in with entity id " + entityplayer.getId() + " at (" + entityplayer.locX + ", " + entityplayer.locY + ", " + entityplayer.locZ + ")"); ++ // CraftBukkit - Moved message to after join ++ // PlayerList.h.info(entityplayer.getName() + "[" + s1 + "] logged in with entity id " + entityplayer.getId() + " at (" + entityplayer.locX + ", " + entityplayer.locY + ", " + entityplayer.locZ + ")"); + WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); + WorldData worlddata = worldserver.getWorldData(); + BlockPosition blockposition = worldserver.getSpawn(); +@@ -80,6 +108,7 @@ + PlayerConnection playerconnection = new PlayerConnection(this.server, networkmanager, entityplayer); + + playerconnection.sendPacket(new PacketPlayOutLogin(entityplayer.getId(), entityplayer.playerInteractManager.getGameMode(), worlddata.isHardcore(), worldserver.worldProvider.getDimension(), worldserver.getDifficulty(), this.getMaxPlayers(), worlddata.getType(), worldserver.getGameRules().getBoolean("reducedDebugInfo"))); ++ entityplayer.getBukkitEntity().sendSupportedChannels(); // CraftBukkit + playerconnection.sendPacket(new PacketPlayOutCustomPayload("MC|Brand", (new PacketDataSerializer(Unpooled.buffer())).a(this.getServer().getServerModName()))); + playerconnection.sendPacket(new PacketPlayOutServerDifficulty(worlddata.y(), worlddata.z())); + playerconnection.sendPacket(new PacketPlayOutSpawnPosition(blockposition)); +@@ -89,6 +118,7 @@ + entityplayer.getStatisticManager().updateStatistics(entityplayer); + this.sendScoreboard((ScoreboardServer) worldserver.getScoreboard(), entityplayer); + this.server.aF(); ++ /* CraftBukkit start - login message is handled in the event + ChatMessage chatmessage; + + if (!entityplayer.getName().equalsIgnoreCase(s)) { +@@ -99,7 +129,9 @@ + + chatmessage.getChatModifier().setColor(EnumChatFormat.YELLOW); + this.sendMessage(chatmessage); ++ // CraftBukkit end */ + this.onPlayerJoin(entityplayer); ++ worldserver = server.getWorldServer(entityplayer.dimension); // CraftBukkit - Update in case join event changed it + playerconnection.a(entityplayer.locX, entityplayer.locY, entityplayer.locZ, entityplayer.yaw, entityplayer.pitch); + this.b(entityplayer, worldserver); + if (this.server.getResourcePack().length() > 0) { +@@ -126,6 +158,8 @@ + } + } + ++ // CraftBukkit - Moved from above, added world ++ PlayerList.h.info(entityplayer.getName() + "[" + s1 + "] logged in with entity id " + entityplayer.getId() + " at ([" + entityplayer.world.worldData.getName() + "] " + entityplayer.locX + ", " + entityplayer.locY + ", " + entityplayer.locZ + ")"); + } + + public void sendScoreboard(ScoreboardServer scoreboardserver, EntityPlayer entityplayer) { +@@ -158,6 +192,7 @@ + } + + public void setPlayerFileData(WorldServer[] aworldserver) { ++ if (playerFileData != null) return; // CraftBukkit + this.playerFileData = aworldserver[0].getDataManager().getPlayerFileData(); + aworldserver[0].af().a((IWorldBorderListener) (new WorldBorderListener(this))); + } +@@ -178,7 +213,7 @@ + } + + public NBTTagCompound a(EntityPlayer entityplayer) { +- NBTTagCompound nbttagcompound = this.server.worldServer[0].getWorldData().i(); ++ NBTTagCompound nbttagcompound = this.server.worlds.get(0).getWorldData().i(); // CraftBukkit + NBTTagCompound nbttagcompound1; + + if (entityplayer.getName().equals(this.server.R()) && nbttagcompound != null) { +@@ -205,30 +240,69 @@ + public void onPlayerJoin(EntityPlayer entityplayer) { + this.players.add(entityplayer); + this.f.put(entityplayer.getUniqueID(), entityplayer); +- this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[] { entityplayer})); ++ // this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[] { entityplayer})); // CraftBukkit - replaced with loop below + WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); + +- worldserver.addEntity(entityplayer); +- this.a(entityplayer, (WorldServer) null); ++ // CraftBukkit start ++ PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(cserver.getPlayer(entityplayer), "\u00A7e" + entityplayer.getName() + " joined the game."); ++ cserver.getPluginManager().callEvent(playerJoinEvent); ++ ++ String joinMessage = playerJoinEvent.getJoinMessage(); ++ ++ if (joinMessage != null && joinMessage.length() > 0) { ++ for (IChatBaseComponent line : org.bukkit.craftbukkit.util.CraftChatMessage.fromString(joinMessage)) { ++ server.getPlayerList().sendAll(new PacketPlayOutChat(line)); ++ } ++ } ++ ++ ChunkIOExecutor.adjustPoolSize(getPlayerCount()); ++ // CraftBukkit end ++ ++ // CraftBukkit start - sendAll above replaced with this loop ++ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, entityplayer); + + for (int i = 0; i < this.players.size(); ++i) { + EntityPlayer entityplayer1 = (EntityPlayer) this.players.get(i); + ++ if (entityplayer1.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) { ++ entityplayer1.playerConnection.sendPacket(packet); ++ } ++ ++ if (!entityplayer.getBukkitEntity().canSee(entityplayer1.getBukkitEntity())) { ++ continue; ++ } ++ + entityplayer.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[] { entityplayer1})); + } ++ // CraftBukkit end + ++ // CraftBukkit start - Only add if the player wasn't moved in the event ++ if (entityplayer.world == worldserver && !worldserver.players.contains(entityplayer)) { ++ worldserver.addEntity(entityplayer); ++ this.a(entityplayer, (WorldServer) null); ++ } ++ // CraftBukkit end + } + + public void d(EntityPlayer entityplayer) { + entityplayer.u().getPlayerChunkMap().movePlayer(entityplayer); + } + +- public void disconnect(EntityPlayer entityplayer) { ++ public String disconnect(EntityPlayer entityplayer) { // CraftBukkit - return string + entityplayer.b(StatisticList.f); ++ ++ // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(entityplayer); ++ ++ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(entityplayer), "\u00A7e" + entityplayer.getName() + " left the game."); ++ cserver.getPluginManager().callEvent(playerQuitEvent); ++ entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); ++ // CraftBukkit end ++ + this.savePlayerFile(entityplayer); + WorldServer worldserver = entityplayer.u(); + +- if (entityplayer.vehicle != null) { ++ if (entityplayer.vehicle != null && !(entityplayer.vehicle instanceof EntityPlayer)) { // CraftBukkit - Don't remove players + worldserver.removeEntity(entityplayer.vehicle); + PlayerList.h.debug("removing player mount"); + } +@@ -238,13 +312,40 @@ + this.players.remove(entityplayer); + this.f.remove(entityplayer.getUniqueID()); + this.o.remove(entityplayer.getUniqueID()); +- this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[] { entityplayer})); ++ // CraftBukkit start ++ // this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[] { entityplayer})); ++ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, entityplayer); ++ for (int i = 0; i < players.size(); i++) { ++ EntityPlayer entityplayer1 = (EntityPlayer) this.players.get(i); ++ ++ if (entityplayer1.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) { ++ entityplayer1.playerConnection.sendPacket(packet); ++ } else { ++ entityplayer1.getBukkitEntity().removeDisconnectingPlayer(entityplayer.getBukkitEntity()); ++ } ++ } ++ // This removes the scoreboard (and player reference) for the specific player in the manager ++ cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity()); ++ // CraftBukkit end ++ ++ ChunkIOExecutor.adjustPoolSize(this.getPlayerCount()); // CraftBukkit ++ ++ return playerQuitEvent.getQuitMessage(); // CraftBukkit + } + +- public String attemptLogin(SocketAddress socketaddress, GameProfile gameprofile) { ++ // CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer ++ public EntityPlayer attemptLogin(LoginListener loginlistener, GameProfile gameprofile, String hostname) { ++ // Instead of kicking then returning, we need to store the kick reason ++ // in the event, check with plugins to see if it's ok, and THEN kick ++ // depending on the outcome. ++ SocketAddress socketaddress = loginlistener.networkManager.getSocketAddress(); ++ ++ EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), gameprofile, new PlayerInteractManager(server.getWorldServer(0))); ++ Player player = entity.getBukkitEntity(); ++ PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress()); + String s; + +- if (this.k.isBanned(gameprofile)) { ++ if (getProfileBans().isBanned(gameprofile) && !getProfileBans().get(gameprofile).hasExpired()) { + GameProfileBanEntry gameprofilebanentry = (GameProfileBanEntry) this.k.get(gameprofile); + + s = "You are banned from this server!\nReason: " + gameprofilebanentry.getReason(); +@@ -252,10 +353,12 @@ + s = s + "\nYour ban will be removed on " + PlayerList.i.format(gameprofilebanentry.getExpires()); + } + +- return s; ++ // return s; ++ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, s); + } else if (!this.isWhitelisted(gameprofile)) { +- return "You are not white-listed on this server!"; +- } else if (this.l.isBanned(socketaddress)) { ++ // return "You are not white-listed on this server!"; ++ event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, "You are not white-listed on this server!"); ++ } else if (getIPBans().isBanned(socketaddress) && !getIPBans().get(socketaddress).hasExpired()) { + IpBanEntry ipbanentry = this.l.get(socketaddress); + + s = "Your IP address is banned from this server!\nReason: " + ipbanentry.getReason(); +@@ -263,13 +366,24 @@ + s = s + "\nYour ban will be removed on " + PlayerList.i.format(ipbanentry.getExpires()); + } + +- return s; ++ // return s; ++ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, s); + } else { +- return this.players.size() >= this.maxPlayers ? "The server is full!" : null; ++ // return this.players.size() >= this.maxPlayers ? "The server is full!" : null; ++ if (this.players.size() >= this.maxPlayers) { ++ event.disallow(PlayerLoginEvent.Result.KICK_FULL, "The server is full"); ++ } ++ } ++ ++ cserver.getPluginManager().callEvent(event); ++ if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { ++ loginlistener.disconnect(event.getKickMessage()); ++ return null; + } ++ return entity; + } + +- public EntityPlayer processLogin(GameProfile gameprofile) { ++ public EntityPlayer processLogin(GameProfile gameprofile, EntityPlayer player) { // CraftBukkit - added EntityPlayer + UUID uuid = EntityHuman.a(gameprofile); + ArrayList arraylist = Lists.newArrayList(); + +@@ -289,6 +403,7 @@ + entityplayer.playerConnection.disconnect("You logged in from another location"); + } + ++ /* CraftBukkit start + Object object; + + if (this.server.W()) { +@@ -298,17 +413,25 @@ + } + + return new EntityPlayer(this.server, this.server.getWorldServer(0), gameprofile, (PlayerInteractManager) object); ++ // */ ++ return player; ++ // CraftBukkit end + } + ++ // CraftBukkit start + public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, boolean flag) { ++ return this.moveToWorld(entityplayer, i, flag, null, true); ++ } ++ public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, boolean flag, Location location, boolean avoidSuffocation) { + entityplayer.u().getTracker().untrackPlayer(entityplayer); +- entityplayer.u().getTracker().untrackEntity(entityplayer); ++ // entityplayer.u().getTracker().untrackEntity(entityplayer); // CraftBukkit + entityplayer.u().getPlayerChunkMap().removePlayer(entityplayer); + this.players.remove(entityplayer); + this.server.getWorldServer(entityplayer.dimension).removeEntity(entityplayer); + BlockPosition blockposition = entityplayer.getBed(); + boolean flag1 = entityplayer.isRespawnForced(); + ++ /* CraftBukkit start + entityplayer.dimension = i; + Object object; + +@@ -319,80 +442,270 @@ + } + + EntityPlayer entityplayer1 = new EntityPlayer(this.server, this.server.getWorldServer(entityplayer.dimension), entityplayer.getProfile(), (PlayerInteractManager) object); ++ // */ ++ EntityPlayer entityplayer1 = entityplayer; ++ org.bukkit.World fromWorld = entityplayer.getBukkitEntity().getWorld(); ++ entityplayer.viewingCredits = false; ++ // CraftBukkit end + + entityplayer1.playerConnection = entityplayer.playerConnection; + entityplayer1.copyTo(entityplayer, flag); + entityplayer1.d(entityplayer.getId()); + entityplayer1.o(entityplayer); +- WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); ++ // WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); // CraftBukkit - handled later + +- this.a(entityplayer1, entityplayer, worldserver); ++ // this.a(entityplayer1, entityplayer, worldserver); // CraftBukkit - removed + BlockPosition blockposition1; + +- if (blockposition != null) { +- blockposition1 = EntityHuman.getBed(this.server.getWorldServer(entityplayer.dimension), blockposition, flag1); +- if (blockposition1 != null) { +- entityplayer1.setPositionRotation((double) ((float) blockposition1.getX() + 0.5F), (double) ((float) blockposition1.getY() + 0.1F), (double) ((float) blockposition1.getZ() + 0.5F), 0.0F, 0.0F); +- entityplayer1.setRespawnPosition(blockposition, flag1); +- } else { +- entityplayer1.playerConnection.sendPacket(new PacketPlayOutGameStateChange(0, 0.0F)); ++ // CraftBukkit start - fire PlayerRespawnEvent ++ if (location == null) { ++ boolean isBedSpawn = false; ++ CraftWorld cworld = (CraftWorld) this.server.server.getWorld(entityplayer.spawnWorld); ++ if (cworld != null && blockposition != null) { ++ blockposition1 = EntityHuman.getBed(cworld.getHandle(), blockposition, flag1); ++ if (blockposition1 != null) { ++ isBedSpawn = true; ++ location = new Location(cworld, blockposition1.getX() + 0.5, blockposition1.getY(), blockposition1.getZ() + 0.5); ++ } else { ++ entityplayer1.setRespawnPosition(null, true); ++ entityplayer1.playerConnection.sendPacket(new PacketPlayOutGameStateChange(0, 0.0F)); ++ } + } ++ ++ if (location == null) { ++ cworld = (CraftWorld) this.server.server.getWorlds().get(0); ++ blockposition = cworld.getHandle().getSpawn(); ++ location = new Location(cworld, blockposition.getX() + 0.5, blockposition.getY(), blockposition.getZ() + 0.5); ++ } ++ ++ Player respawnPlayer = cserver.getPlayer(entityplayer1); ++ PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(respawnPlayer, location, isBedSpawn); ++ cserver.getPluginManager().callEvent(respawnEvent); ++ ++ location = respawnEvent.getRespawnLocation(); ++ entityplayer.reset(); ++ } else { ++ location.setWorld(server.getWorldServer(i).getWorld()); + } ++ WorldServer worldserver = ((CraftWorld) location.getWorld()).getHandle(); ++ entityplayer1.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); ++ // CraftBukkit end + + worldserver.chunkProviderServer.getChunkAt((int) entityplayer1.locX >> 4, (int) entityplayer1.locZ >> 4); + +- while (!worldserver.getCubes(entityplayer1, entityplayer1.getBoundingBox()).isEmpty() && entityplayer1.locY < 256.0D) { ++ while (avoidSuffocation && !worldserver.getCubes(entityplayer1, entityplayer1.getBoundingBox()).isEmpty() && entityplayer1.locY < 256.0D) { // CraftBukkit + entityplayer1.setPosition(entityplayer1.locX, entityplayer1.locY + 1.0D, entityplayer1.locZ); + } + +- entityplayer1.playerConnection.sendPacket(new PacketPlayOutRespawn(entityplayer1.dimension, entityplayer1.world.getDifficulty(), entityplayer1.world.getWorldData().getType(), entityplayer1.playerInteractManager.getGameMode())); ++ // CraftBukkit start ++ byte actualDimension = (byte) (worldserver.getWorld().getEnvironment().getId()); ++ // Force the client to refresh their chunk cache ++ entityplayer1.playerConnection.sendPacket(new PacketPlayOutRespawn((byte) (actualDimension >= 0 ? -1 : 0), worldserver.getDifficulty(), worldserver.getWorldData().getType(), entityplayer.playerInteractManager.getGameMode())); ++ entityplayer1.playerConnection.sendPacket(new PacketPlayOutRespawn(actualDimension, worldserver.getDifficulty(), worldserver.getWorldData().getType(), entityplayer1.playerInteractManager.getGameMode())); ++ entityplayer1.spawnIn(worldserver); ++ entityplayer1.dead = false; ++ entityplayer1.playerConnection.teleport(new Location(worldserver.getWorld(), entityplayer1.locX, entityplayer1.locY, entityplayer1.locZ, entityplayer1.yaw, entityplayer1.pitch)); ++ entityplayer1.setSneaking(false); + blockposition1 = worldserver.getSpawn(); +- entityplayer1.playerConnection.a(entityplayer1.locX, entityplayer1.locY, entityplayer1.locZ, entityplayer1.yaw, entityplayer1.pitch); ++ // entityplayer1.playerConnection.a(entityplayer1.locX, entityplayer1.locY, entityplayer1.locZ, entityplayer1.yaw, entityplayer1.pitch); ++ // CraftBukkit end + entityplayer1.playerConnection.sendPacket(new PacketPlayOutSpawnPosition(blockposition1)); + entityplayer1.playerConnection.sendPacket(new PacketPlayOutExperience(entityplayer1.exp, entityplayer1.expTotal, entityplayer1.expLevel)); + this.b(entityplayer1, worldserver); +- worldserver.getPlayerChunkMap().addPlayer(entityplayer1); +- worldserver.addEntity(entityplayer1); +- this.players.add(entityplayer1); +- this.f.put(entityplayer1.getUniqueID(), entityplayer1); +- entityplayer1.syncInventory(); ++ if (!entityplayer.playerConnection.isDisconnected()) { ++ worldserver.getPlayerChunkMap().addPlayer(entityplayer1); ++ worldserver.addEntity(entityplayer1); ++ this.players.add(entityplayer1); ++ this.f.put(entityplayer1.getUniqueID(), entityplayer1); ++ } ++ // Added from changeDimension ++ updateClient(entityplayer); // Update health, etc... ++ entityplayer.updateAbilities(); ++ for (Object o1 : entityplayer.getEffects()) { ++ MobEffect mobEffect = (MobEffect) o1; ++ entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(entityplayer.getId(), mobEffect)); ++ } ++ // entityplayer1.syncInventory(); ++ // CraftBukkit end + entityplayer1.setHealth(entityplayer1.getHealth()); ++ ++ // CraftBukkit start ++ // Don't fire on respawn ++ if (fromWorld != location.getWorld()) { ++ PlayerChangedWorldEvent event = new PlayerChangedWorldEvent(entityplayer.getBukkitEntity(), fromWorld); ++ server.server.getPluginManager().callEvent(event); ++ } ++ ++ // Save player file again if they were disconnected ++ if (entityplayer.playerConnection.isDisconnected()) { ++ this.savePlayerFile(entityplayer); ++ } ++ // CraftBukkit end ++ + return entityplayer1; + } + +- public void changeDimension(EntityPlayer entityplayer, int i) { +- int j = entityplayer.dimension; +- WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension); ++ // CraftBukkit start - Replaced the standard handling of portals with a more customised method. ++ public void changeDimension(EntityPlayer entityplayer, int i, TeleportCause cause) { ++ WorldServer exitWorld = null; ++ if (entityplayer.dimension < CraftWorld.CUSTOM_DIMENSION_OFFSET) { // plugins must specify exit from custom Bukkit worlds ++ // only target existing worlds (compensate for allow-nether/allow-end as false) ++ for (WorldServer world : this.server.worlds) { ++ if (world.dimension == i) { ++ exitWorld = world; ++ } ++ } ++ } + +- entityplayer.dimension = i; +- WorldServer worldserver1 = this.server.getWorldServer(entityplayer.dimension); ++ Location enter = entityplayer.getBukkitEntity().getLocation(); ++ Location exit = null; ++ boolean useTravelAgent = false; // don't use agent for custom worlds or return from THE_END ++ if (exitWorld != null) { ++ if ((cause == TeleportCause.END_PORTAL) && (i == 0)) { ++ // THE_END -> NORMAL; use bed if available, otherwise default spawn ++ exit = ((org.bukkit.craftbukkit.entity.CraftPlayer) entityplayer.getBukkitEntity()).getBedSpawnLocation(); ++ if (exit == null || ((CraftWorld) exit.getWorld()).getHandle().dimension != 0) { ++ exit = exitWorld.getWorld().getSpawnLocation(); ++ } ++ } else { ++ // NORMAL <-> NETHER or NORMAL -> THE_END ++ exit = this.calculateTarget(enter, exitWorld); ++ useTravelAgent = true; ++ } ++ } + +- entityplayer.playerConnection.sendPacket(new PacketPlayOutRespawn(entityplayer.dimension, entityplayer.world.getDifficulty(), entityplayer.world.getWorldData().getType(), entityplayer.playerInteractManager.getGameMode())); +- worldserver.removeEntity(entityplayer); +- entityplayer.dead = false; +- this.changeWorld(entityplayer, j, worldserver, worldserver1); +- this.a(entityplayer, worldserver); +- entityplayer.playerConnection.a(entityplayer.locX, entityplayer.locY, entityplayer.locZ, entityplayer.yaw, entityplayer.pitch); +- entityplayer.playerInteractManager.a(worldserver1); +- this.b(entityplayer, worldserver1); +- this.updateClient(entityplayer); +- Iterator iterator = entityplayer.getEffects().iterator(); ++ TravelAgent agent = exit != null ? (TravelAgent) ((CraftWorld) exit.getWorld()).getHandle().getTravelAgent() : org.bukkit.craftbukkit.CraftTravelAgent.DEFAULT; // return arbitrary TA to compensate for implementation dependent plugins ++ PlayerPortalEvent event = new PlayerPortalEvent(entityplayer.getBukkitEntity(), enter, exit, agent, cause); ++ event.useTravelAgent(useTravelAgent); ++ Bukkit.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled() || event.getTo() == null) { ++ return; ++ } ++ ++ exit = event.useTravelAgent() ? event.getPortalTravelAgent().findOrCreate(event.getTo()) : event.getTo(); ++ if (exit == null) { ++ return; ++ } ++ exitWorld = ((CraftWorld) exit.getWorld()).getHandle(); ++ ++ Vector velocity = entityplayer.getBukkitEntity().getVelocity(); ++ boolean before = exitWorld.chunkProviderServer.forceChunkLoad; ++ exitWorld.chunkProviderServer.forceChunkLoad = true; ++ exitWorld.getTravelAgent().adjustExit(entityplayer, exit, velocity); ++ exitWorld.chunkProviderServer.forceChunkLoad = before; ++ ++ this.moveToWorld(entityplayer, exitWorld.dimension, true, exit, false); // Vanilla doesn't check for suffocation when handling portals, so neither should we ++ if (entityplayer.motX != velocity.getX() || entityplayer.motY != velocity.getY() || entityplayer.motZ != velocity.getZ()) { ++ entityplayer.getBukkitEntity().setVelocity(velocity); ++ } ++ } + +- while (iterator.hasNext()) { +- MobEffect mobeffect = (MobEffect) iterator.next(); ++ public void changeWorld(Entity entity, int i, WorldServer worldserver, WorldServer worldserver1) { ++ // CraftBukkit start - Split into modular functions ++ Location exit = calculateTarget(entity.getBukkitEntity().getLocation(), worldserver1); ++ repositionEntity(entity, exit, true); ++ } ++ ++ // Copy of original changeWorld(Entity, int, WorldServer, WorldServer) method with only location calculation logic ++ public Location calculateTarget(Location enter, World target) { ++ WorldServer worldserver = ((CraftWorld) enter.getWorld()).getHandle(); ++ WorldServer worldserver1 = ((CraftWorld) target.getWorld()).getHandle(); ++ int i = worldserver.dimension; ++ ++ double y = enter.getY(); ++ float yaw = enter.getYaw(); ++ float pitch = enter.getPitch(); ++ double d0 = enter.getX(); ++ double d1 = enter.getZ(); ++ double d2 = 8.0D; ++ /* ++ double d0 = entity.locX; ++ double d1 = entity.locZ; ++ double d2 = 8.0D; ++ float f = entity.yaw; ++ ++ worldserver.methodProfiler.a("moving"); ++ */ ++ if (worldserver1.dimension == -1) { ++ d0 = MathHelper.a(d0 / d2, worldserver1.af().b() + 16.0D, worldserver1.af().d() - 16.0D); ++ d1 = MathHelper.a(d1 / d2, worldserver1.af().c() + 16.0D, worldserver1.af().e() - 16.0D); ++ /* ++ entity.setPositionRotation(d0, entity.locY, d1, entity.yaw, entity.pitch); ++ if (entity.isAlive()) { ++ worldserver.entityJoinedWorld(entity, false); ++ } ++ */ ++ } else if (worldserver1.dimension == 0) { ++ d0 = MathHelper.a(d0 * d2, worldserver1.af().b() + 16.0D, worldserver1.af().d() - 16.0D); ++ d1 = MathHelper.a(d1 * d2, worldserver1.af().c() + 16.0D, worldserver1.af().e() - 16.0D); ++ /* ++ entity.setPositionRotation(d0, entity.locY, d1, entity.yaw, entity.pitch); ++ if (entity.isAlive()) { ++ worldserver.entityJoinedWorld(entity, false); ++ } ++ */ ++ } else { ++ BlockPosition blockposition; ++ ++ if (i == 1) { ++ // use default NORMAL world spawn instead of target ++ worldserver1 = this.server.worlds.get(0); ++ blockposition = worldserver1.getSpawn(); ++ } else { ++ blockposition = worldserver1.getDimensionSpawn(); ++ } ++ ++ d0 = (double) blockposition.getX(); ++ y = (double) blockposition.getY(); ++ d1 = (double) blockposition.getZ(); ++ /* ++ entity.setPositionRotation(d0, entity.locY, d1, 90.0F, 0.0F); ++ if (entity.isAlive()) { ++ worldserver.entityJoinedWorld(entity, false); ++ } ++ */ ++ } + +- entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(entityplayer.getId(), mobeffect)); ++ // worldserver.methodProfiler.b(); ++ if (i != 1) { ++ worldserver.methodProfiler.a("placing"); ++ d0 = (double) MathHelper.clamp((int) d0, -29999872, 29999872); ++ d1 = (double) MathHelper.clamp((int) d1, -29999872, 29999872); ++ /* ++ if (entity.isAlive()) { ++ entity.setPositionRotation(d0, entity.locY, d1, entity.yaw, entity.pitch); ++ worldserver1.getTravelAgent().a(entity, f); ++ worldserver1.addEntity(entity); ++ worldserver1.entityJoinedWorld(entity, false); ++ } ++ ++ worldserver.methodProfiler.b(); ++ */ + } + ++ // entity.spawnIn(worldserver1); ++ return new Location(worldserver1.getWorld(), d0, y, d1, yaw, pitch); + } + +- public void changeWorld(Entity entity, int i, WorldServer worldserver, WorldServer worldserver1) { ++ // copy of original a(Entity, int, WorldServer, WorldServer) method with only entity repositioning logic ++ public void repositionEntity(Entity entity, Location exit, boolean portal) { ++ WorldServer worldserver = (WorldServer) entity.world; ++ WorldServer worldserver1 = ((CraftWorld) exit.getWorld()).getHandle(); ++ int i = worldserver.dimension; ++ ++ /* + double d0 = entity.locX; + double d1 = entity.locZ; + double d2 = 8.0D; + float f = entity.yaw; + + worldserver.methodProfiler.a("moving"); ++ */ ++ entity.setPositionRotation(exit.getX(), exit.getY(), exit.getZ(), exit.getYaw(), exit.getPitch()); ++ if (entity.isAlive()) { ++ worldserver.entityJoinedWorld(entity, false); ++ } ++ /* + if (entity.dimension == -1) { + d0 = MathHelper.a(d0 / d2, worldserver1.af().b() + 16.0D, worldserver1.af().d() - 16.0D); + d1 = MathHelper.a(d1 / d2, worldserver1.af().c() + 16.0D, worldserver1.af().e() - 16.0D); +@@ -411,6 +724,8 @@ + BlockPosition blockposition; + + if (i == 1) { ++ // use default NORMAL world spawn instead of target ++ worldserver1 = this.server.worlds.get(0); + blockposition = worldserver1.getSpawn(); + } else { + blockposition = worldserver1.getDimensionSpawn(); +@@ -424,15 +739,26 @@ + worldserver.entityJoinedWorld(entity, false); + } + } ++ */ + + worldserver.methodProfiler.b(); + if (i != 1) { + worldserver.methodProfiler.a("placing"); ++ /* + d0 = (double) MathHelper.clamp((int) d0, -29999872, 29999872); + d1 = (double) MathHelper.clamp((int) d1, -29999872, 29999872); ++ */ + if (entity.isAlive()) { +- entity.setPositionRotation(d0, entity.locY, d1, entity.yaw, entity.pitch); +- worldserver1.getTravelAgent().a(entity, f); ++ // entity.setPositionRotation(d0, entity.locY, d1, entity.yaw, entity.pitch); ++ // worldserver1.getTravelAgent().a(entity, f); ++ if (portal) { ++ Vector velocity = entity.getBukkitEntity().getVelocity(); ++ worldserver1.getTravelAgent().adjustExit(entity, exit, velocity); ++ entity.setPositionRotation(exit.getX(), exit.getY(), exit.getZ(), exit.getYaw(), exit.getPitch()); ++ if (entity.motX != velocity.getX() || entity.motY != velocity.getY() || entity.motZ != velocity.getZ()) { ++ entity.getBukkitEntity().setVelocity(velocity); ++ } ++ } + worldserver1.addEntity(entity); + worldserver1.entityJoinedWorld(entity, false); + } +@@ -441,6 +767,7 @@ + } + + entity.spawnIn(worldserver1); ++ // CraftBukkit end + } + + public void tick() { +@@ -549,10 +876,24 @@ + + public void addOp(GameProfile gameprofile) { + this.operators.add(new OpListEntry(gameprofile, this.server.p())); ++ ++ // CraftBukkit start ++ Player player = server.server.getPlayer(gameprofile.getId()); ++ if (player != null) { ++ player.recalculatePermissions(); ++ } ++ // CraftBukkit end + } + + public void removeOp(GameProfile gameprofile) { + this.operators.remove(gameprofile); ++ ++ // CraftBukkit start ++ Player player = server.server.getPlayer(gameprofile.getId()); ++ if (player != null) { ++ player.recalculatePermissions(); ++ } ++ // CraftBukkit end + } + + public boolean isWhitelisted(GameProfile gameprofile) { +@@ -560,7 +901,7 @@ + } + + public boolean isOp(GameProfile gameprofile) { +- return this.operators.d(gameprofile) || this.server.S() && this.server.worldServer[0].getWorldData().v() && this.server.R().equalsIgnoreCase(gameprofile.getName()) || this.t; ++ return this.operators.d(gameprofile) || this.server.S() && this.server.worlds.get(0).getWorldData().v() && this.server.R().equalsIgnoreCase(gameprofile.getName()) || this.t; // CraftBukkit + } + + public EntityPlayer getPlayer(String s) { +@@ -587,6 +928,12 @@ + for (int j = 0; j < this.players.size(); ++j) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(j); + ++ // CraftBukkit start - Test if player receiving packet can see the source of the packet ++ if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { ++ continue; ++ } ++ // CraftBukkit end ++ + if (entityplayer != entityhuman && entityplayer.dimension == i) { + double d4 = d0 - entityplayer.locX; + double d5 = d1 - entityplayer.locY; +@@ -634,21 +981,25 @@ + public void reloadWhitelist() {} + + public void b(EntityPlayer entityplayer, WorldServer worldserver) { +- WorldBorder worldborder = this.server.worldServer[0].af(); ++ WorldBorder worldborder = this.server.worlds.get(0).af(); // CraftBukkit + + entityplayer.playerConnection.sendPacket(new PacketPlayOutWorldBorder(worldborder, EnumWorldBorderAction.INITIALIZE)); + entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateTime(worldserver.getTime(), worldserver.getDayTime(), worldserver.getGameRules().getBoolean("doDaylightCycle"))); + if (worldserver.S()) { +- entityplayer.playerConnection.sendPacket(new PacketPlayOutGameStateChange(1, 0.0F)); +- entityplayer.playerConnection.sendPacket(new PacketPlayOutGameStateChange(7, worldserver.j(1.0F))); +- entityplayer.playerConnection.sendPacket(new PacketPlayOutGameStateChange(8, worldserver.h(1.0F))); ++ // CraftBukkit start - handle player weather ++ // entityplayer.playerConnection.sendPacket(new PacketPlayOutGameStateChange(1, 0.0F)); ++ // entityplayer.playerConnection.sendPacket(new PacketPlayOutGameStateChange(7, worldserver.j(1.0F))); ++ // entityplayer.playerConnection.sendPacket(new PacketPlayOutGameStateChange(8, worldserver.h(1.0F))); ++ entityplayer.setPlayerWeather(org.bukkit.WeatherType.DOWNFALL, false); ++ // CraftBukkit end + } + + } + + public void updateClient(EntityPlayer entityplayer) { + entityplayer.updateInventory(entityplayer.defaultContainer); +- entityplayer.triggerHealthUpdate(); ++ // entityplayer.triggerHealthUpdate(); ++ entityplayer.getBukkitEntity().updateScaledHealth(); // CraftBukkit - Update scaled health on respawn and worldchange + entityplayer.playerConnection.sendPacket(new PacketPlayOutHeldItemSlot(entityplayer.inventory.itemInHandIndex)); + } + +@@ -661,7 +1012,7 @@ + } + + public String[] getSeenPlayers() { +- return this.server.worldServer[0].getDataManager().getPlayerFileData().getSeenPlayers(); ++ return this.server.worlds.get(0).getDataManager().getPlayerFileData().getSeenPlayers(); // CraftBukkit + } + + public boolean getHasWhitelist() { +@@ -711,10 +1062,17 @@ + + public void v() { + for (int i = 0; i < this.players.size(); ++i) { +- ((EntityPlayer) this.players.get(i)).playerConnection.disconnect("Server closed"); ++ ((EntityPlayer) this.players.get(i)).playerConnection.disconnect(this.server.server.getShutdownMessage()); // CraftBukkit - add custom shutdown message + } ++ } + ++ // CraftBukkit start ++ public void sendMessage(IChatBaseComponent[] iChatBaseComponents) { ++ for (IChatBaseComponent component : iChatBaseComponents) { ++ sendMessage(component, true); ++ } + } ++ // CraftBukkit end + + public void sendMessage(IChatBaseComponent ichatbasecomponent, boolean flag) { + this.server.sendMessage(ichatbasecomponent); +@@ -754,11 +1112,10 @@ + public void a(int i) { + this.r = i; + if (this.server.worldServer != null) { +- WorldServer[] aworldserver = this.server.worldServer; +- int j = aworldserver.length; +- +- for (int k = 0; k < j; ++k) { +- WorldServer worldserver = aworldserver[k]; ++ // CraftBukkit start ++ for (int k = 0; k < server.worlds.size(); ++k) { ++ WorldServer worldserver = server.worlds.get(0); ++ // CraftBukkit end + + if (worldserver != null) { + worldserver.getPlayerChunkMap().a(i); diff --git a/paper-server/nms-patches/PlayerSelector.patch b/paper-server/nms-patches/PlayerSelector.patch new file mode 100644 index 0000000000..e5583a10ca --- /dev/null +++ b/paper-server/nms-patches/PlayerSelector.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PlayerSelector.java 2014-11-27 08:59:46.865421124 +1100 ++++ src/main/java/net/minecraft/server/PlayerSelector.java 2014-11-27 08:42:10.140850934 +1100 +@@ -52,6 +52,11 @@ + } + + public static List getPlayers(ICommandListener icommandlistener, String s, Class oclass) { ++ // CraftBukkit start - disable playerselections for ICommandListeners other than command blocks ++ if (!(icommandlistener instanceof CommandBlockListenerAbstract)) { ++ return com.google.common.collect.ImmutableList.of(); ++ } ++ // CraftBukkit end + Matcher matcher = PlayerSelector.a.matcher(s); + + if (matcher.matches() && icommandlistener.a(1, "@")) { diff --git a/paper-server/nms-patches/PortalCreator.patch b/paper-server/nms-patches/PortalCreator.patch new file mode 100644 index 0000000000..5bb4eae90b --- /dev/null +++ b/paper-server/nms-patches/PortalCreator.patch @@ -0,0 +1,102 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PortalCreator.java 2014-11-27 08:59:46.865421124 +1100 ++++ src/main/java/net/minecraft/server/PortalCreator.java 2014-11-27 08:42:10.132850949 +1100 +@@ -1,5 +1,7 @@ + package net.minecraft.server; + ++import org.bukkit.event.world.PortalCreateEvent; // CraftBukkit ++ + public class PortalCreator { + + private final World a; +@@ -10,6 +12,7 @@ + private BlockPosition f; + private int g; + private int h; ++ java.util.Collection blocks = new java.util.HashSet(); // CraftBukkit - add field + + public PortalCreator(World world, BlockPosition blockposition, EnumAxis enumaxis) { + this.a = world; +@@ -60,6 +63,10 @@ + } + + protected int a() { ++ // CraftBukkit start ++ this.blocks.clear(); ++ org.bukkit.World bworld = this.a.getWorld(); ++ // CraftBukkit end + int i; + + label56: +@@ -80,11 +87,21 @@ + block = this.a.getType(blockposition.shift(this.d)).getBlock(); + if (block != Blocks.OBSIDIAN) { + break label56; ++ // CraftBukkit start - add the block to our list ++ } else { ++ BlockPosition pos = blockposition.shift(this.d); ++ blocks.add(bworld.getBlockAt(pos.getX(), pos.getY(), pos.getZ())); ++ // CraftBukkit end + } + } else if (i == this.h - 1) { + block = this.a.getType(blockposition.shift(this.c)).getBlock(); + if (block != Blocks.OBSIDIAN) { + break label56; ++ // CraftBukkit start - add the block to our list ++ } else { ++ BlockPosition pos = blockposition.shift(this.c); ++ blocks.add(bworld.getBlockAt(pos.getX(), pos.getY(), pos.getZ())); ++ // CraftBukkit end + } + } + } +@@ -94,6 +111,11 @@ + if (this.a.getType(this.f.shift(this.c, i).up(this.g)).getBlock() != Blocks.OBSIDIAN) { + this.g = 0; + break; ++ // CraftBukkit start - add the block to our list ++ } else { ++ BlockPosition pos = this.f.shift(this.c, i).up(this.g); ++ blocks.add(bworld.getBlockAt(pos.getX(), pos.getY(), pos.getZ())); ++ // CraftBukkit end + } + } + +@@ -115,15 +137,36 @@ + return this.f != null && this.h >= 2 && this.h <= 21 && this.g >= 3 && this.g <= 21; + } + +- public void c() { ++ // CraftBukkit start - return boolean ++ public boolean c() { ++ org.bukkit.World bworld = this.a.getWorld(); ++ ++ // Copy below for loop + for (int i = 0; i < this.h; ++i) { + BlockPosition blockposition = this.f.shift(this.c, i); + + for (int j = 0; j < this.g; ++j) { +- this.a.setTypeAndData(blockposition.up(j), Blocks.PORTAL.getBlockData().set(BlockPortal.AXIS, this.b), 2); ++ BlockPosition pos = blockposition.up(j); ++ blocks.add(bworld.getBlockAt(pos.getX(), pos.getY(), pos.getZ())); + } + } + ++ PortalCreateEvent event = new PortalCreateEvent(blocks, bworld, PortalCreateEvent.CreateReason.FIRE); ++ this.a.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end ++ for (int i = 0; i < this.h; ++i) { ++ BlockPosition blockposition = this.f.shift(this.c, i); ++ ++ for (int j = 0; j < this.g; ++j) { ++ this.a.setTypeAndData(blockposition.up(j), Blocks.PORTAL.getBlockData().set(BlockPortal.AXIS, this.b), 2); ++ } ++ } ++ ++ return true; // Craft Bukkit + } + + public static int a(PortalCreator portalcreator) { diff --git a/paper-server/nms-patches/PortalTravelAgent.patch b/paper-server/nms-patches/PortalTravelAgent.patch new file mode 100644 index 0000000000..1a6d02d98c --- /dev/null +++ b/paper-server/nms-patches/PortalTravelAgent.patch @@ -0,0 +1,273 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PortalTravelAgent.java 2014-11-27 08:59:46.869421107 +1100 ++++ src/main/java/net/minecraft/server/PortalTravelAgent.java 2014-11-27 08:42:10.096851020 +1100 +@@ -5,6 +5,12 @@ + import java.util.List; + import java.util.Random; + ++// CraftBukkit start ++import org.bukkit.Location; ++import org.bukkit.event.entity.EntityPortalExitEvent; ++import org.bukkit.util.Vector; ++// CraftBukkit end ++ + public class PortalTravelAgent { + + private final WorldServer a; +@@ -27,8 +33,21 @@ + int i = MathHelper.floor(entity.locX); + int j = MathHelper.floor(entity.locY) - 1; + int k = MathHelper.floor(entity.locZ); ++ // CraftBukkit start - Modularize end portal creation ++ BlockPosition created = this.createEndPortal(entity.locX, entity.locY, entity.locZ); ++ entity.setPositionRotation((double) created.getX(), (double) created.getY(), (double) created.getZ(), entity.yaw, 0.0F); ++ entity.motX = entity.motY = entity.motZ = 0.0D; ++ } ++ } ++ ++ // Split out from original a(Entity, double, double, double, float) method in order to enable being called from createPortal ++ private BlockPosition createEndPortal(double x, double y, double z) { ++ int i = MathHelper.floor(x); ++ int j = MathHelper.floor(y) - 1; ++ int k = MathHelper.floor(z); + byte b0 = 1; + byte b1 = 0; ++ // CraftBukkit end + + for (int l = -2; l <= 2; ++l) { + for (int i1 = -2; i1 <= 2; ++i1) { +@@ -43,16 +62,63 @@ + } + } + +- entity.setPositionRotation((double) i, (double) j, (double) k, entity.yaw, 0.0F); +- entity.motX = entity.motY = entity.motZ = 0.0D; ++ // CraftBukkit start ++ return new BlockPosition(i, k, k); ++ } ++ ++ // use logic based on creation to verify end portal ++ private BlockPosition findEndPortal(BlockPosition portal) { ++ int i = portal.getX(); ++ int j = portal.getY() - 1; ++ int k = portal.getZ(); ++ byte b0 = 1; ++ byte b1 = 0; ++ ++ for (int l = -2; l <= 2; ++l) { ++ for (int i1 = -2; i1 <= 2; ++i1) { ++ for (int j1 = -1; j1 < 3; ++j1) { ++ int k1 = i + i1 * b0 + l * b1; ++ int l1 = j + j1; ++ int i2 = k + i1 * b1 - l * b0; ++ boolean flag = j1 < 0; ++ ++ if (this.a.getType(new BlockPosition(k1, l1, i2)).getBlock() != (flag ? Blocks.OBSIDIAN : Blocks.AIR)) { ++ return null; ++ } ++ } ++ } + } ++ return new BlockPosition(i, j, k); + } ++ // CraftBukkit end + + public boolean b(Entity entity, float f) { +- boolean flag = true; ++ // CraftBukkit start - Modularize portal search process and entity teleportation ++ BlockPosition found = this.findPortal(entity.locX, entity.locY, entity.locZ, 128); ++ if (found == null) { ++ return false; ++ } ++ ++ Location exit = new Location(this.a.getWorld(), found.getX(), found.getY(), found.getZ(), f, entity.pitch); ++ Vector velocity = entity.getBukkitEntity().getVelocity(); ++ this.adjustExit(entity, exit, velocity); ++ entity.setPositionRotation(exit.getX(), exit.getY(), exit.getZ(), exit.getYaw(), exit.getPitch()); ++ if (entity.motX != velocity.getX() || entity.motY != velocity.getY() || entity.motZ != velocity.getZ()) { ++ entity.getBukkitEntity().setVelocity(velocity); ++ } ++ return true; ++ } ++ ++ public BlockPosition findPortal(double x, double y, double z, int short1) { ++ if (this.a.getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END) { ++ return this.findEndPortal(this.a.worldProvider.h()); ++ } ++ // CraftBukkit end + double d0 = -1.0D; +- int i = MathHelper.floor(entity.locX); +- int j = MathHelper.floor(entity.locZ); ++ // CraftBukkit start ++ int i = MathHelper.floor(x); ++ int j = MathHelper.floor(z); ++ // CraftBukkit end + boolean flag1 = true; + Object object = BlockPosition.ZERO; + long k = ChunkCoordIntPair.a(i, j); +@@ -65,7 +131,7 @@ + chunkcoordinatesportal.b = this.a.getTime(); + flag1 = false; + } else { +- BlockPosition blockposition = new BlockPosition(entity); ++ BlockPosition blockposition = new BlockPosition(x, y, z); + + for (int l = -128; l <= 128; ++l) { + BlockPosition blockposition1; +@@ -95,7 +161,29 @@ + this.c.put(k, new ChunkCoordinatesPortal(this, (BlockPosition) object, this.a.getTime())); + this.d.add(Long.valueOf(k)); + } ++ // CraftBukkit start - Move entity teleportation logic into exit ++ return (BlockPosition) object; ++ } else { ++ return null; ++ } ++ } + ++ // Entity repositioning logic split out from original b method and combined with repositioning logic for The End from original a method ++ public void adjustExit(Entity entity, Location position, Vector velocity) { ++ Location from = position.clone(); ++ Vector before = velocity.clone(); ++ BlockPosition object = new BlockPosition(position.getBlockX(), position.getBlockY(), position.getBlockZ()); ++ float f = position.getYaw(); ++ ++ if (this.a.getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END) { ++ // entity.setPositionRotation((double) i, (double) j, (double) k, entity.yaw, 0.0F); ++ // entity.motX = entity.motY = entity.motZ = 0.0D; ++ position.setPitch(0.0F); ++ velocity.setX(0); ++ velocity.setY(0); ++ velocity.setZ(0); ++ } else { ++ // CraftBukkit end + double d2 = (double) ((BlockPosition) object).getX() + 0.5D; + double d3 = (double) ((BlockPosition) object).getY() + 0.5D; + double d4 = (double) ((BlockPosition) object).getZ() + 0.5D; +@@ -170,21 +258,46 @@ + f6 = 1.0F; + } + +- double d5 = entity.motX; +- double d6 = entity.motZ; +- +- entity.motX = d5 * (double) f3 + d6 * (double) f6; +- entity.motZ = d5 * (double) f5 + d6 * (double) f4; +- entity.yaw = f - (float) (enumdirection1.b() * 90) + (float) (enumdirection.b() * 90); ++ // CraftBukkit start ++ double d5 = velocity.getX(); ++ double d6 = velocity.getZ(); ++ // CraftBukkit end ++ ++ // CraftBukkit start - Adjust position and velocity instances instead of entity ++ velocity.setX(d5 * (double) f3 + d6 * (double) f6); ++ velocity.setZ(d5 * (double) f5 + d6 * (double) f4); ++ f = f - (float) (enumdirection1.b() * 90) + (float) (enumdirection.b() * 90); + } else { +- entity.motX = entity.motY = entity.motZ = 0.0D; ++ velocity.setX(0); ++ velocity.setY(0); ++ velocity.setZ(0); + } + +- entity.setPositionRotation(d2, d3, d4, entity.yaw, entity.pitch); +- return true; ++ // entity.setPositionRotation(d2, d3, d4, entity.yaw, entity.pitch); ++ position.setX(d2); ++ position.setY(d3); ++ position.setZ(d4); ++ position.setYaw(f); ++ } ++ EntityPortalExitEvent event = new EntityPortalExitEvent(entity.getBukkitEntity(), from, position, before, velocity); ++ this.a.getServer().getPluginManager().callEvent(event); ++ Location to = event.getTo(); ++ if (event.isCancelled() || to == null || !entity.isAlive()) { ++ position.setX(from.getX()); ++ position.setY(from.getY()); ++ position.setZ(from.getZ()); ++ position.setYaw(from.getYaw()); ++ position.setPitch(from.getPitch()); ++ velocity.copy(before); + } else { +- return false; ++ position.setX(to.getX()); ++ position.setY(to.getY()); ++ position.setZ(to.getZ()); ++ position.setYaw(to.getYaw()); ++ position.setPitch(to.getPitch()); ++ velocity.copy(event.getAfter()); // event.getAfter() will never be null, as setAfter() will cause an NPE if null is passed in + } ++ // CraftBukkit end + } + + private boolean a(BlockPosition blockposition) { +@@ -192,11 +305,22 @@ + } + + public boolean a(Entity entity) { +- byte b0 = 16; ++ // CraftBukkit start - Allow for portal creation to be based on coordinates instead of entity ++ return this.createPortal(entity.locX, entity.locY, entity.locZ, 16); ++ } ++ ++ public boolean createPortal(double x, double y, double z, int b0) { ++ if (this.a.getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END) { ++ createEndPortal(x, y, z); ++ return true; ++ } ++ // CraftBukkit end + double d0 = -1.0D; +- int i = MathHelper.floor(entity.locX); +- int j = MathHelper.floor(entity.locY); +- int k = MathHelper.floor(entity.locZ); ++ // CraftBukkit start ++ int i = MathHelper.floor(x); ++ int j = MathHelper.floor(y); ++ int k = MathHelper.floor(z); ++ // CraftBukkit end + int l = i; + int i1 = j; + int j1 = k; +@@ -220,10 +344,10 @@ + double d4; + + for (i2 = i - b0; i2 <= i + b0; ++i2) { +- d1 = (double) i2 + 0.5D - entity.locX; ++ d1 = (double) i2 + 0.5D - x; // CraftBukkit + + for (j2 = k - b0; j2 <= k + b0; ++j2) { +- d2 = (double) j2 + 0.5D - entity.locZ; ++ d2 = (double) j2 + 0.5D - z; // CraftBukkit + + label271: + for (k2 = this.a.V() - 1; k2 >= 0; --k2) { +@@ -254,7 +378,7 @@ + } + } + +- d3 = (double) k2 + 0.5D - entity.locY; ++ d3 = (double) k2 + 0.5D - y; // CraftBukkit + d4 = d1 * d1 + d3 * d3 + d2 * d2; + if (d0 < 0.0D || d4 < d0) { + d0 = d4; +@@ -271,10 +395,10 @@ + + if (d0 < 0.0D) { + for (i2 = i - b0; i2 <= i + b0; ++i2) { +- d1 = (double) i2 + 0.5D - entity.locX; ++ d1 = (double) i2 + 0.5D - x; // CraftBukkit + + for (j2 = k - b0; j2 <= k + b0; ++j2) { +- d2 = (double) j2 + 0.5D - entity.locZ; ++ d2 = (double) j2 + 0.5D - z; // CraftBukkit + + label219: + for (k2 = this.a.V() - 1; k2 >= 0; --k2) { +@@ -298,7 +422,7 @@ + } + } + +- d3 = (double) k2 + 0.5D - entity.locY; ++ d3 = (double) k2 + 0.5D - y; // CraftBukkit + d4 = d1 * d1 + d3 * d3 + d2 * d2; + if (d0 < 0.0D || d4 < d0) { + d0 = d4; diff --git a/paper-server/nms-patches/PropertyManager.patch b/paper-server/nms-patches/PropertyManager.patch new file mode 100644 index 0000000000..9812b4397a --- /dev/null +++ b/paper-server/nms-patches/PropertyManager.patch @@ -0,0 +1,94 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/PropertyManager.java 2014-11-27 08:59:46.869421107 +1100 ++++ src/main/java/net/minecraft/server/PropertyManager.java 2014-11-27 08:42:10.100851012 +1100 +@@ -8,6 +8,8 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++import joptsimple.OptionSet; // CraftBukkit ++ + public class PropertyManager { + + private static final Logger a = LogManager.getLogger(); +@@ -39,8 +41,25 @@ + PropertyManager.a.warn(file + " does not exist"); + this.a(); + } ++ } ++ ++ // CraftBukkit start ++ private OptionSet options = null; ++ ++ public PropertyManager(final OptionSet options) { ++ this((File) options.valueOf("config")); ++ ++ this.options = options; ++ } ++ ++ private T getOverride(String name, T value) { ++ if ((this.options != null) && (this.options.has(name))) { ++ return (T) this.options.valueOf(name); ++ } + ++ return value; + } ++ // CraftBukkit end + + public void a() { + PropertyManager.a.info("Generating new properties file"); +@@ -51,6 +70,12 @@ + FileOutputStream fileoutputstream = null; + + try { ++ // CraftBukkit start - Don't attempt writing to file if it's read only ++ if (this.file.exists() && !this.file.canWrite()) { ++ return; ++ } ++ // CraftBukkit end ++ + fileoutputstream = new FileOutputStream(this.file); + this.properties.store(fileoutputstream, "Minecraft server properties"); + } catch (Exception exception) { +@@ -80,36 +105,36 @@ + this.savePropertiesFile(); + } + +- return this.properties.getProperty(s, s1); ++ return getOverride(s, this.properties.getProperty(s, s1)); // CraftBukkit + } + + public int getInt(String s, int i) { + try { +- return Integer.parseInt(this.getString(s, "" + i)); ++ return getOverride(s, Integer.parseInt(this.getString(s, "" + i))); // CraftBukkit + } catch (Exception exception) { + this.properties.setProperty(s, "" + i); + this.savePropertiesFile(); +- return i; ++ return getOverride(s, i); // CraftBukkit + } + } + + public long getLong(String s, long i) { + try { +- return Long.parseLong(this.getString(s, "" + i)); ++ return getOverride(s, Long.parseLong(this.getString(s, "" + i))); // CraftBukkit + } catch (Exception exception) { + this.properties.setProperty(s, "" + i); + this.savePropertiesFile(); +- return i; ++ return getOverride(s ,i); // CraftBukkit + } + } + + public boolean getBoolean(String s, boolean flag) { + try { +- return Boolean.parseBoolean(this.getString(s, "" + flag)); ++ return getOverride(s, Boolean.parseBoolean(this.getString(s, "" + flag))); // CraftBukkit + } catch (Exception exception) { + this.properties.setProperty(s, "" + flag); + this.savePropertiesFile(); +- return flag; ++ return getOverride(s, flag); // CraftBukkit + } + } + diff --git a/paper-server/nms-patches/RecipeArmorDye.patch b/paper-server/nms-patches/RecipeArmorDye.patch new file mode 100644 index 0000000000..80002455b4 --- /dev/null +++ b/paper-server/nms-patches/RecipeArmorDye.patch @@ -0,0 +1,18 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipeArmorDye.java 2014-11-27 08:59:46.869421107 +1100 ++++ src/main/java/net/minecraft/server/RecipeArmorDye.java 2014-11-27 08:42:10.116850981 +1100 +@@ -3,9 +3,13 @@ + import com.google.common.collect.Lists; + import java.util.ArrayList; + +-public class RecipeArmorDye implements IRecipe { ++public class RecipeArmorDye extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + +- public RecipeArmorDye() {} ++ // CraftBukkit start - Delegate to new parent class with bogus info ++ public RecipeArmorDye() { ++ super(new ItemStack(Items.LEATHER_HELMET, 0, 0), java.util.Arrays.asList(new ItemStack(Items.DYE, 0, 5))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + ItemStack itemstack = null; diff --git a/paper-server/nms-patches/RecipeBookClone.patch b/paper-server/nms-patches/RecipeBookClone.patch new file mode 100644 index 0000000000..5d14c2dbaa --- /dev/null +++ b/paper-server/nms-patches/RecipeBookClone.patch @@ -0,0 +1,17 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipeBookClone.java 2014-11-27 08:59:46.873421089 +1100 ++++ src/main/java/net/minecraft/server/RecipeBookClone.java 2014-11-27 08:42:10.144850927 +1100 +@@ -1,8 +1,12 @@ + package net.minecraft.server; + +-public class RecipeBookClone implements IRecipe { ++public class RecipeBookClone extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + +- public RecipeBookClone() {} ++ // CraftBukkit start - Delegate to new parent class ++ public RecipeBookClone() { ++ super(new ItemStack(Items.WRITTEN_BOOK, 0, -1), java.util.Arrays.asList(new ItemStack(Items.WRITABLE_BOOK, 0, 0))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + int i = 0; diff --git a/paper-server/nms-patches/RecipeFireworks.patch b/paper-server/nms-patches/RecipeFireworks.patch new file mode 100644 index 0000000000..b7b388d0ba --- /dev/null +++ b/paper-server/nms-patches/RecipeFireworks.patch @@ -0,0 +1,21 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipeFireworks.java 2014-11-27 08:59:46.873421089 +1100 ++++ src/main/java/net/minecraft/server/RecipeFireworks.java 2014-11-27 08:42:10.088851036 +1100 +@@ -3,11 +3,15 @@ + import com.google.common.collect.Lists; + import java.util.ArrayList; + +-public class RecipeFireworks implements IRecipe { ++public class RecipeFireworks extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + + private ItemStack a; +- +- public RecipeFireworks() {} ++ ++ // CraftBukkit start - Delegate to new parent class with bogus info ++ public RecipeFireworks() { ++ super(new ItemStack(Items.FIREWORKS, 0, 0), java.util.Arrays.asList(new ItemStack(Items.GUNPOWDER, 0, 5))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + this.a = null; diff --git a/paper-server/nms-patches/RecipeMapClone.patch b/paper-server/nms-patches/RecipeMapClone.patch new file mode 100644 index 0000000000..a33ee9e9a7 --- /dev/null +++ b/paper-server/nms-patches/RecipeMapClone.patch @@ -0,0 +1,17 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipeMapClone.java 2014-11-27 08:59:46.873421089 +1100 ++++ src/main/java/net/minecraft/server/RecipeMapClone.java 2014-11-27 08:42:10.152850911 +1100 +@@ -1,8 +1,12 @@ + package net.minecraft.server; + +-public class RecipeMapClone implements IRecipe { ++public class RecipeMapClone extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + +- public RecipeMapClone() {} ++ // CraftBukkit start - Delegate to new parent class ++ public RecipeMapClone() { ++ super(new ItemStack(Items.MAP, 0, -1), java.util.Arrays.asList(new ItemStack(Items.MAP, 0, 0))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + int i = 0; diff --git a/paper-server/nms-patches/RecipeRepair.patch b/paper-server/nms-patches/RecipeRepair.patch new file mode 100644 index 0000000000..51349bb2ce --- /dev/null +++ b/paper-server/nms-patches/RecipeRepair.patch @@ -0,0 +1,39 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipeRepair.java 2014-11-27 08:59:46.877421071 +1100 ++++ src/main/java/net/minecraft/server/RecipeRepair.java 2014-11-27 08:42:10.148850918 +1100 +@@ -3,9 +3,13 @@ + import com.google.common.collect.Lists; + import java.util.ArrayList; + +-public class RecipeRepair implements IRecipe { ++public class RecipeRepair extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + +- public RecipeRepair() {} ++ // CraftBukkit start - Delegate to new parent class ++ public RecipeRepair() { ++ super(new ItemStack(Items.LEATHER_HELMET), java.util.Arrays.asList(new ItemStack(Items.LEATHER_HELMET))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + ArrayList arraylist = Lists.newArrayList(); +@@ -61,8 +65,18 @@ + if (i1 < 0) { + i1 = 0; + } +- +- return new ItemStack(itemstack2.getItem(), 1, i1); ++ ++ // CraftBukkit start - Construct a dummy repair recipe ++ ItemStack result = new ItemStack(itemstack.getItem(), 1, i1); ++ java.util.List ingredients = new ArrayList(); ++ ingredients.add(itemstack2.cloneItemStack()); ++ ingredients.add(itemstack.cloneItemStack()); ++ ShapelessRecipes recipe = new ShapelessRecipes(result.cloneItemStack(), ingredients); ++ inventorycrafting.currentRecipe = recipe; ++ result = org.bukkit.craftbukkit.event.CraftEventFactory.callPreCraftEvent(inventorycrafting, result, CraftingManager.getInstance().lastCraftView, true); ++ return result; ++ // return new ItemStack(itemstack2.getItem(), 1, i1); ++ // CraftBukkit end + } + } + diff --git a/paper-server/nms-patches/RecipesBannerInnerClass1.patch b/paper-server/nms-patches/RecipesBannerInnerClass1.patch new file mode 100644 index 0000000000..7847163241 --- /dev/null +++ b/paper-server/nms-patches/RecipesBannerInnerClass1.patch @@ -0,0 +1,17 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipesBannerInnerClass1.java 2014-11-27 08:59:46.877421071 +1100 ++++ src/main/java/net/minecraft/server/RecipesBannerInnerClass1.java 2014-11-27 08:42:10.084851043 +1100 +@@ -1,8 +1,12 @@ + package net.minecraft.server; + +-class RecipesBannerInnerClass1 implements IRecipe { ++class RecipesBannerInnerClass1 extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + +- private RecipesBannerInnerClass1() {} ++ // CraftBukkit start - Delegate to new parent class with bogus info ++ private RecipesBannerInnerClass1() { ++ super(new ItemStack(Items.BANNER, 0, 0), java.util.Arrays.asList(new ItemStack(Items.BANNER))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + ItemStack itemstack = null; diff --git a/paper-server/nms-patches/RecipesBannerInnerClass2.patch b/paper-server/nms-patches/RecipesBannerInnerClass2.patch new file mode 100644 index 0000000000..3fa03250a4 --- /dev/null +++ b/paper-server/nms-patches/RecipesBannerInnerClass2.patch @@ -0,0 +1,17 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipesBannerInnerClass2.java 2014-11-27 08:59:46.881421054 +1100 ++++ src/main/java/net/minecraft/server/RecipesBannerInnerClass2.java 2014-11-27 08:42:10.164850887 +1100 +@@ -1,8 +1,12 @@ + package net.minecraft.server; + +-class RecipesBannerInnerClass2 implements IRecipe { ++class RecipesBannerInnerClass2 extends ShapelessRecipes implements IRecipe { // CraftBukkit - added extends + +- private RecipesBannerInnerClass2() {} ++ // CraftBukkit start - Delegate to new parent class with bogus info ++ private RecipesBannerInnerClass2() { ++ super(new ItemStack(Items.BANNER, 0, 0), java.util.Arrays.asList(new ItemStack(Items.DYE, 0, 5))); ++ } ++ // CraftBukkit end + + public boolean a(InventoryCrafting inventorycrafting, World world) { + boolean flag = false; diff --git a/paper-server/nms-patches/RecipesFurnace.patch b/paper-server/nms-patches/RecipesFurnace.patch new file mode 100644 index 0000000000..be4d28fbdd --- /dev/null +++ b/paper-server/nms-patches/RecipesFurnace.patch @@ -0,0 +1,49 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RecipesFurnace.java 2014-11-27 08:59:46.881421054 +1100 ++++ src/main/java/net/minecraft/server/RecipesFurnace.java 2014-11-27 08:42:10.132850949 +1100 +@@ -10,6 +10,7 @@ + private static final RecipesFurnace a = new RecipesFurnace(); + public Map recipes = Maps.newHashMap(); + private Map c = Maps.newHashMap(); ++ public Map customRecipes = Maps.newHashMap(); // CraftBukkit - add field + + public static RecipesFurnace getInstance() { + return RecipesFurnace.a; +@@ -52,6 +53,12 @@ + this.registerRecipe(Blocks.LAPIS_ORE, new ItemStack(Items.DYE, 1, EnumColor.BLUE.getInvColorIndex()), 0.2F); + this.registerRecipe(Blocks.QUARTZ_ORE, new ItemStack(Items.QUARTZ), 0.2F); + } ++ ++ // CraftBukkit start - add method ++ public void registerRecipe(ItemStack itemstack, ItemStack itemstack1) { ++ this.customRecipes.put(itemstack, itemstack1); ++ } ++ // CraftBukkit end + + public void registerRecipe(Block block, ItemStack itemstack, float f) { + this.a(Item.getItemOf(block), itemstack, f); +@@ -67,13 +74,23 @@ + } + + public ItemStack getResult(ItemStack itemstack) { +- Iterator iterator = this.recipes.entrySet().iterator(); ++ // CraftBukkit start - initialize to customRecipes ++ boolean vanilla = false; ++ Iterator iterator = this.customRecipes.entrySet().iterator(); ++ // CraftBukkit end + + Entry entry; + + do { + if (!iterator.hasNext()) { +- return null; ++ // CraftBukkit start - fall back to vanilla recipes ++ if (!vanilla && !recipes.isEmpty()) { ++ iterator = this.recipes.entrySet().iterator(); ++ vanilla = true; ++ } else { ++ return null; ++ } ++ // CraftBukkit end + } + + entry = (Entry) iterator.next(); diff --git a/paper-server/nms-patches/RegionFile.patch b/paper-server/nms-patches/RegionFile.patch new file mode 100644 index 0000000000..80999d9c12 --- /dev/null +++ b/paper-server/nms-patches/RegionFile.patch @@ -0,0 +1,81 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RegionFile.java 2014-11-27 08:59:46.881421054 +1100 ++++ src/main/java/net/minecraft/server/RegionFile.java 2014-11-27 08:42:10.160850895 +1100 +@@ -86,8 +86,46 @@ + } catch (IOException ioexception) { + ioexception.printStackTrace(); + } ++ } ++ ++ // CraftBukkit start - This is a copy (sort of) of the method below it, make sure they stay in sync ++ public synchronized boolean chunkExists(int i, int j) { ++ if (this.d(i, j)) { ++ return false; ++ } else { ++ try { ++ int k = this.e(i, j); ++ ++ if (k == 0) { ++ return false; ++ } else { ++ int l = k >> 8; ++ int i1 = k & 255; ++ ++ if (l + i1 > this.f.size()) { ++ return false; ++ } ++ ++ this.c.seek((long) (l * 4096)); ++ int j1 = this.c.readInt(); ++ ++ if (j1 > 4096 * i1 || j1 <= 0) { ++ return false; ++ } ++ ++ byte b0 = this.c.readByte(); ++ if (b0 == 1 || b0 == 2) { ++ return true; ++ } ++ } ++ } catch (IOException ioexception) { ++ return false; ++ } ++ } + ++ return false; + } ++ // CraftBukkit end + + public synchronized DataInputStream a(int i, int j) { + if (this.d(i, j)) { +@@ -214,7 +252,7 @@ + + } + +- private void a(int i, byte[] abyte, int j) { ++ private void a(int i, byte[] abyte, int j) throws IOException { // CraftBukkit - added throws + this.c.seek((long) (i * 4096)); + this.c.writeInt(j + 1); + this.c.writeByte(2); +@@ -233,19 +271,19 @@ + return this.e(i, j) != 0; + } + +- private void a(int i, int j, int k) { ++ private void a(int i, int j, int k) throws IOException { // CraftBukkit - added throws + this.d[i + j * 32] = k; + this.c.seek((long) ((i + j * 32) * 4)); + this.c.writeInt(k); + } + +- private void b(int i, int j, int k) { ++ private void b(int i, int j, int k) throws IOException { // CraftBukkit - added throws + this.e[i + j * 32] = k; + this.c.seek((long) (4096 + (i + j * 32) * 4)); + this.c.writeInt(k); + } + +- public void c() { ++ public void c() throws IOException { // CraftBukkit - added throws + if (this.c != null) { + this.c.close(); + } diff --git a/paper-server/nms-patches/RemoteControlCommandListener.patch b/paper-server/nms-patches/RemoteControlCommandListener.patch new file mode 100644 index 0000000000..9cf48bf63d --- /dev/null +++ b/paper-server/nms-patches/RemoteControlCommandListener.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/RemoteControlCommandListener.java 2014-11-27 08:59:46.885421036 +1100 ++++ src/main/java/net/minecraft/server/RemoteControlCommandListener.java 2014-11-27 08:42:10.152850911 +1100 +@@ -26,6 +26,12 @@ + public IChatBaseComponent getScoreboardDisplayName() { + return new ChatComponentText(this.getName()); + } ++ ++ // CraftBukkit start - Send a String ++ public void sendMessage(String message) { ++ this.b.append(message); ++ } ++ // CraftBukkit end + + public void sendMessage(IChatBaseComponent ichatbasecomponent) { + this.b.append(ichatbasecomponent.c()); diff --git a/paper-server/nms-patches/ScoreboardServer.patch b/paper-server/nms-patches/ScoreboardServer.patch new file mode 100644 index 0000000000..4b480d137c --- /dev/null +++ b/paper-server/nms-patches/ScoreboardServer.patch @@ -0,0 +1,126 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ScoreboardServer.java 2014-11-27 08:59:46.885421036 +1100 ++++ src/main/java/net/minecraft/server/ScoreboardServer.java 2014-11-27 08:42:10.164850887 +1100 +@@ -21,7 +21,7 @@ + public void handleScoreChanged(ScoreboardScore scoreboardscore) { + super.handleScoreChanged(scoreboardscore); + if (this.b.contains(scoreboardscore.getObjective())) { +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardScore(scoreboardscore)); ++ this.sendAll(new PacketPlayOutScoreboardScore(scoreboardscore)); // CraftBukkit - Internal packet method + } + + this.b(); +@@ -29,13 +29,13 @@ + + public void handlePlayerRemoved(String s) { + super.handlePlayerRemoved(s); +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardScore(s)); ++ this.sendAll(new PacketPlayOutScoreboardScore(s)); // CraftBukkit - Internal packet method + this.b(); + } + + public void a(String s, ScoreboardObjective scoreboardobjective) { + super.a(s, scoreboardobjective); +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardScore(s, scoreboardobjective)); ++ this.sendAll(new PacketPlayOutScoreboardScore(s, scoreboardobjective)); // CraftBukkit - Internal packet method + this.b(); + } + +@@ -45,7 +45,7 @@ + super.setDisplaySlot(i, scoreboardobjective); + if (scoreboardobjective1 != scoreboardobjective && scoreboardobjective1 != null) { + if (this.h(scoreboardobjective1) > 0) { +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardDisplayObjective(i, scoreboardobjective)); ++ this.sendAll(new PacketPlayOutScoreboardDisplayObjective(i, scoreboardobjective)); // CraftBukkit - Internal packet method + } else { + this.g(scoreboardobjective1); + } +@@ -53,7 +53,7 @@ + + if (scoreboardobjective != null) { + if (this.b.contains(scoreboardobjective)) { +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardDisplayObjective(i, scoreboardobjective)); ++ this.sendAll(new PacketPlayOutScoreboardDisplayObjective(i, scoreboardobjective)); // CraftBukkit - Internal packet method + } else { + this.e(scoreboardobjective); + } +@@ -66,7 +66,7 @@ + if (super.addPlayerToTeam(s, s1)) { + ScoreboardTeam scoreboardteam = this.getTeam(s1); + +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 3)); ++ this.sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 3)); // CraftBukkit - Internal packet method + this.b(); + return true; + } else { +@@ -76,7 +76,7 @@ + + public void removePlayerFromTeam(String s, ScoreboardTeam scoreboardteam) { + super.removePlayerFromTeam(s, scoreboardteam); +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 4)); ++ this.sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, Arrays.asList(new String[] { s}), 4)); // CraftBukkit - Internal packet method + this.b(); + } + +@@ -88,7 +88,7 @@ + public void handleObjectiveChanged(ScoreboardObjective scoreboardobjective) { + super.handleObjectiveChanged(scoreboardobjective); + if (this.b.contains(scoreboardobjective)) { +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardObjective(scoreboardobjective, 2)); ++ this.sendAll(new PacketPlayOutScoreboardObjective(scoreboardobjective, 2)); // CraftBukkit - Internal packet method + } + + this.b(); +@@ -105,19 +105,19 @@ + + public void handleTeamAdded(ScoreboardTeam scoreboardteam) { + super.handleTeamAdded(scoreboardteam); +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, 0)); ++ this.sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, 0)); // CraftBukkit - Internal packet method + this.b(); + } + + public void handleTeamChanged(ScoreboardTeam scoreboardteam) { + super.handleTeamChanged(scoreboardteam); +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, 2)); ++ this.sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, 2)); // CraftBukkit - Internal packet method + this.b(); + } + + public void handleTeamRemoved(ScoreboardTeam scoreboardteam) { + super.handleTeamRemoved(scoreboardteam); +- this.a.getPlayerList().sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, 1)); ++ this.sendAll(new PacketPlayOutScoreboardTeam(scoreboardteam, 1)); // CraftBukkit - Internal packet method + this.b(); + } + +@@ -160,6 +160,7 @@ + + while (iterator.hasNext()) { + EntityPlayer entityplayer = (EntityPlayer) iterator.next(); ++ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board + Iterator iterator1 = list.iterator(); + + while (iterator1.hasNext()) { +@@ -192,6 +193,7 @@ + + while (iterator.hasNext()) { + EntityPlayer entityplayer = (EntityPlayer) iterator.next(); ++ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board + Iterator iterator1 = list.iterator(); + + while (iterator1.hasNext()) { +@@ -215,4 +217,14 @@ + + return i; + } ++ ++ // CraftBukkit start - Send to players ++ private void sendAll(Packet packet) { ++ for (EntityPlayer entityplayer : (List) this.a.getPlayerList().players) { ++ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() == this) { ++ entityplayer.playerConnection.sendPacket(packet); ++ } ++ } ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/SecondaryWorldServer.patch b/paper-server/nms-patches/SecondaryWorldServer.patch new file mode 100644 index 0000000000..935246b60c --- /dev/null +++ b/paper-server/nms-patches/SecondaryWorldServer.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/SecondaryWorldServer.java 2014-11-27 08:59:46.889421019 +1100 ++++ src/main/java/net/minecraft/server/SecondaryWorldServer.java 2014-11-27 08:42:10.088851036 +1100 +@@ -4,8 +4,10 @@ + + private WorldServer a; + +- public SecondaryWorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, int i, WorldServer worldserver, MethodProfiler methodprofiler) { +- super(minecraftserver, idatamanager, new SecondaryWorldData(worldserver.getWorldData()), i, methodprofiler); ++ // CraftBukkit start - Add WorldData, Environment and ChunkGenerator arguments ++ public SecondaryWorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, int i, WorldServer worldserver, MethodProfiler methodprofiler, WorldData worldData, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { ++ super(minecraftserver, idatamanager, worldData, i, methodprofiler, env, gen); ++ // CraftBukkit end + this.a = worldserver; + worldserver.af().a((IWorldBorderListener) (new SecondaryWorldServerInnerClass1(this))); + } diff --git a/paper-server/nms-patches/ShapedRecipes.patch b/paper-server/nms-patches/ShapedRecipes.patch new file mode 100644 index 0000000000..5b3908ceb2 --- /dev/null +++ b/paper-server/nms-patches/ShapedRecipes.patch @@ -0,0 +1,77 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ShapedRecipes.java 2014-11-27 08:59:46.889421019 +1100 ++++ src/main/java/net/minecraft/server/ShapedRecipes.java 2014-11-27 08:42:10.164850887 +1100 +@@ -1,5 +1,11 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; ++// CraftBukkit end ++ ++ + public class ShapedRecipes implements IRecipe { + + private final int width; +@@ -14,6 +20,62 @@ + this.items = aitemstack; + this.result = itemstack; + } ++ ++ // CraftBukkit start ++ public org.bukkit.inventory.ShapedRecipe toBukkitRecipe() { ++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result); ++ CraftShapedRecipe recipe = new CraftShapedRecipe(result, this); ++ switch (this.height) { ++ case 1: ++ switch (this.width) { ++ case 1: ++ recipe.shape("a"); ++ break; ++ case 2: ++ recipe.shape("ab"); ++ break; ++ case 3: ++ recipe.shape("abc"); ++ break; ++ } ++ break; ++ case 2: ++ switch (this.width) { ++ case 1: ++ recipe.shape("a","b"); ++ break; ++ case 2: ++ recipe.shape("ab","cd"); ++ break; ++ case 3: ++ recipe.shape("abc","def"); ++ break; ++ } ++ break; ++ case 3: ++ switch (this.width) { ++ case 1: ++ recipe.shape("a","b","c"); ++ break; ++ case 2: ++ recipe.shape("ab","cd","ef"); ++ break; ++ case 3: ++ recipe.shape("abc","def","ghi"); ++ break; ++ } ++ break; ++ } ++ char c = 'a'; ++ for (ItemStack stack : this.items) { ++ if (stack != null) { ++ recipe.setIngredient(c, org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(stack.getItem()), stack.getData()); ++ } ++ c++; ++ } ++ return recipe; ++ } ++ // CraftBukkit end + + public ItemStack b() { + return this.result; diff --git a/paper-server/nms-patches/ShapelessRecipes.patch b/paper-server/nms-patches/ShapelessRecipes.patch new file mode 100644 index 0000000000..7e4230c91e --- /dev/null +++ b/paper-server/nms-patches/ShapelessRecipes.patch @@ -0,0 +1,35 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ShapelessRecipes.java 2014-11-27 08:59:46.889421019 +1100 ++++ src/main/java/net/minecraft/server/ShapelessRecipes.java 2014-11-27 08:42:10.128850958 +1100 +@@ -5,6 +5,11 @@ + import java.util.Iterator; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; ++// CraftBukkit end ++ + public class ShapelessRecipes implements IRecipe { + + private final ItemStack result; +@@ -14,6 +19,20 @@ + this.result = itemstack; + this.ingredients = list; + } ++ ++ // CraftBukkit start ++ @SuppressWarnings("unchecked") ++ public org.bukkit.inventory.ShapelessRecipe toBukkitRecipe() { ++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result); ++ CraftShapelessRecipe recipe = new CraftShapelessRecipe(result, this); ++ for (ItemStack stack : (List) this.ingredients) { ++ if (stack != null) { ++ recipe.addIngredient(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(stack.getItem()), stack.getData()); ++ } ++ } ++ return recipe; ++ } ++ // CraftBukkit end + + public ItemStack b() { + return this.result; diff --git a/paper-server/nms-patches/SlotFurnaceResult.patch b/paper-server/nms-patches/SlotFurnaceResult.patch new file mode 100644 index 0000000000..626529dee6 --- /dev/null +++ b/paper-server/nms-patches/SlotFurnaceResult.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/SlotFurnaceResult.java 2014-11-27 08:59:46.893421001 +1100 ++++ src/main/java/net/minecraft/server/SlotFurnaceResult.java 2014-11-27 08:42:10.128850958 +1100 +@@ -1,5 +1,10 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import org.bukkit.entity.Player; ++import org.bukkit.event.inventory.FurnaceExtractEvent; ++// CraftBukkit end ++ + public class SlotFurnaceResult extends Slot { + + private EntityHuman a; +@@ -49,6 +54,17 @@ + + i = j; + } ++ ++ // CraftBukkit start - fire FurnaceExtractEvent ++ Player player = (Player) a.getBukkitEntity(); ++ TileEntityFurnace furnace = ((TileEntityFurnace) this.inventory); ++ org.bukkit.block.Block block = a.world.getWorld().getBlockAt(furnace.position.getX(), furnace.position.getY(), furnace.position.getZ()); ++ ++ FurnaceExtractEvent event = new FurnaceExtractEvent(player, block, org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(itemstack.getItem()), itemstack.count, i); ++ a.world.getServer().getPluginManager().callEvent(event); ++ ++ i = event.getExpToDrop(); ++ // CraftBukkit end + + while (i > 0) { + j = EntityExperienceOrb.getOrbValue(i); diff --git a/paper-server/nms-patches/SpawnerCreature.patch b/paper-server/nms-patches/SpawnerCreature.patch new file mode 100644 index 0000000000..968281733c --- /dev/null +++ b/paper-server/nms-patches/SpawnerCreature.patch @@ -0,0 +1,109 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/SpawnerCreature.java 2014-11-27 08:59:46.893421001 +1100 ++++ src/main/java/net/minecraft/server/SpawnerCreature.java 2014-11-27 08:42:10.164850887 +1100 +@@ -6,10 +6,16 @@ + import java.util.Random; + import java.util.Set; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.util.LongHash; ++import org.bukkit.craftbukkit.util.LongHashSet; ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; ++// CraftBukkit end ++ + public final class SpawnerCreature { + + private static final int a = (int) Math.pow(17.0D, 2.0D); +- private final Set b = Sets.newHashSet(); ++ private final LongHashSet b = new LongHashSet(); + + public SpawnerCreature() {} + +@@ -36,14 +42,18 @@ + for (int i1 = -b0; i1 <= b0; ++i1) { + for (k = -b0; k <= b0; ++k) { + boolean flag3 = i1 == -b0 || i1 == b0 || k == -b0 || k == b0; +- ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i1 + l, k + j); ++ // ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i1 + l, k + j); + +- if (!this.b.contains(chunkcoordintpair)) { ++ // CraftBukkit start - use LongHash and LongHashSet ++ long chunkCoords = LongHash.toLong(i1 + l, k + j); ++ ++ if (!this.b.contains(chunkCoords)) { + ++i; +- if (!flag3 && worldserver.af().isInBounds(chunkcoordintpair)) { +- this.b.add(chunkcoordintpair); ++ if (!flag3 && worldserver.af().isInBounds(chunkCoords)) { ++ this.b.add(chunkCoords); + } + } ++ // CraftBukkit end + } + } + } +@@ -57,18 +67,41 @@ + + for (int k1 = 0; k1 < j; ++k1) { + EnumCreatureType enumcreaturetype = aenumcreaturetype[k1]; ++ ++ // CraftBukkit start - Use per-world spawn limits ++ int limit = enumcreaturetype.b(); ++ switch (enumcreaturetype) { ++ case MONSTER: ++ limit = worldserver.getWorld().getMonsterSpawnLimit(); ++ break; ++ case CREATURE: ++ limit = worldserver.getWorld().getAnimalSpawnLimit(); ++ break; ++ case WATER_CREATURE: ++ limit = worldserver.getWorld().getWaterAnimalSpawnLimit(); ++ break; ++ case AMBIENT: ++ limit = worldserver.getWorld().getAmbientSpawnLimit(); ++ break; ++ } ++ ++ if (limit == 0) { ++ continue; ++ } ++ // CraftBukkit end + + if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2)) { + k = worldserver.a(enumcreaturetype.a()); +- int l1 = enumcreaturetype.b() * i / SpawnerCreature.a; ++ int l1 = limit * i / a; // CraftBukkit - use per-world limits + + if (k <= l1) { + Iterator iterator1 = this.b.iterator(); + + label115: + while (iterator1.hasNext()) { +- ChunkCoordIntPair chunkcoordintpair1 = (ChunkCoordIntPair) iterator1.next(); +- BlockPosition blockposition1 = getRandomPosition(worldserver, chunkcoordintpair1.x, chunkcoordintpair1.z); ++ // CraftBukkit start = use LongHash and LongObjectHashMap ++ long key = ((Long) iterator1.next()).longValue(); ++ BlockPosition blockposition1 = getRandomPosition(worldserver, LongHash.msw(key), LongHash.lsw(key)); + int i2 = blockposition1.getX(); + int j2 = blockposition1.getY(); + int k2 = blockposition1.getZ(); +@@ -120,7 +153,7 @@ + groupdataentity = entityinsentient.prepare(worldserver.E(new BlockPosition(entityinsentient)), groupdataentity); + if (entityinsentient.canSpawn()) { + ++l2; +- worldserver.addEntity(entityinsentient); ++ worldserver.addEntity(entityinsentient, SpawnReason.NATURAL); // CraftBukkit - Added a reason for spawning this creature + } + + if (l2 >= entityinsentient.bU()) { +@@ -214,8 +247,10 @@ + } + + entityinsentient.setPositionRotation((double) ((float) j1 + 0.5F), (double) blockposition.getY(), (double) ((float) k1 + 0.5F), random.nextFloat() * 360.0F, 0.0F); +- world.addEntity(entityinsentient); ++ // CraftBukkit start - Added a reason for spawning this creature, moved entityinsentient.prepare(groupdataentity) up + groupdataentity = entityinsentient.prepare(world.E(new BlockPosition(entityinsentient)), groupdataentity); ++ world.addEntity(entityinsentient, SpawnReason.CHUNK_GEN); ++ // CraftBukkit end + flag = true; + } + diff --git a/paper-server/nms-patches/StatisticManager.patch b/paper-server/nms-patches/StatisticManager.patch new file mode 100644 index 0000000000..5b9486b3f7 --- /dev/null +++ b/paper-server/nms-patches/StatisticManager.patch @@ -0,0 +1,15 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/StatisticManager.java 2014-11-27 08:59:46.893421001 +1100 ++++ src/main/java/net/minecraft/server/StatisticManager.java 2014-11-27 08:42:10.172850872 +1100 +@@ -19,6 +19,12 @@ + + public void b(EntityHuman entityhuman, Statistic statistic, int i) { + if (!statistic.d() || this.b((Achievement) statistic)) { ++ // CraftBukkit start - fire Statistic events ++ org.bukkit.event.Cancellable cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.handleStatisticsIncrease(entityhuman, statistic, this.getStatisticValue(statistic), i); ++ if (cancellable != null && cancellable.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.setStatistic(entityhuman, statistic, this.getStatisticValue(statistic) + i); + } + } diff --git a/paper-server/nms-patches/SwitchHelperLogVariant.patch b/paper-server/nms-patches/SwitchHelperLogVariant.patch new file mode 100644 index 0000000000..e6b38cc5f3 --- /dev/null +++ b/paper-server/nms-patches/SwitchHelperLogVariant.patch @@ -0,0 +1,9 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/SwitchHelperLogVariant.java 2014-11-27 08:59:46.897420984 +1100 ++++ src/main/java/net/minecraft/server/SwitchHelperLogVariant.java 2014-11-27 08:42:10.084851043 +1100 +@@ -1,5 +1,6 @@ + package net.minecraft.server; + ++// CraftBukkit - imported for visibility + class SwitchHelperLogVariant { + + static final int[] a = new int[EnumLogVariant.values().length]; diff --git a/paper-server/nms-patches/ThreadCommandReader.patch b/paper-server/nms-patches/ThreadCommandReader.patch new file mode 100644 index 0000000000..87bf341a32 --- /dev/null +++ b/paper-server/nms-patches/ThreadCommandReader.patch @@ -0,0 +1,43 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ThreadCommandReader.java 2014-11-27 08:59:46.897420984 +1100 ++++ src/main/java/net/minecraft/server/ThreadCommandReader.java 2014-11-27 08:42:10.084851043 +1100 +@@ -4,6 +4,8 @@ + import java.io.IOException; + import java.io.InputStreamReader; + ++import static org.bukkit.craftbukkit.Main.*; // CraftBukkit ++ + class ThreadCommandReader extends Thread { + + final DedicatedServer server; +@@ -14,13 +16,28 @@ + } + + public void run() { +- BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in)); ++ // CraftBukkit start ++ if (!useConsole) { ++ return; ++ } ++ // CraftBukkit end ++ ++ jline.console.ConsoleReader bufferedreader = this.server.reader; // CraftBukkit + + String s; + + try { +- while (!this.server.isStopped() && this.server.isRunning() && (s = bufferedreader.readLine()) != null) { +- this.server.issueCommand(s, this.server); ++ // CraftBukkit start - JLine disabling compatibility ++ while (!this.server.isStopped() && this.server.isRunning()) { ++ if (useJline) { ++ s = bufferedreader.readLine(">", null); ++ } else { ++ s = bufferedreader.readLine(); ++ } ++ if (s != null && s.trim().length() > 0) { // Trim to filter lines which are just spaces ++ this.server.issueCommand(s, this.server); ++ } ++ // CraftBukkit end + } + } catch (IOException ioexception) { + DedicatedServer.aR().error("Exception handling console input", ioexception); diff --git a/paper-server/nms-patches/ThreadPlayerLookupUUID.patch b/paper-server/nms-patches/ThreadPlayerLookupUUID.patch new file mode 100644 index 0000000000..d073269099 --- /dev/null +++ b/paper-server/nms-patches/ThreadPlayerLookupUUID.patch @@ -0,0 +1,72 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/ThreadPlayerLookupUUID.java 2014-11-27 08:59:46.901420966 +1100 ++++ src/main/java/net/minecraft/server/ThreadPlayerLookupUUID.java 2014-11-27 08:42:10.164850887 +1100 +@@ -5,6 +5,12 @@ + import java.math.BigInteger; + import java.util.UUID; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.util.Waitable; ++import org.bukkit.event.player.AsyncPlayerPreLoginEvent; ++import org.bukkit.event.player.PlayerPreLoginEvent; ++// CraftBukkit end ++ + class ThreadPlayerLookupUUID extends Thread { + + final LoginListener a; +@@ -22,6 +28,44 @@ + + LoginListener.a(this.a, LoginListener.a(this.a).aB().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s)); + if (LoginListener.b(this.a) != null) { ++ // CraftBukkit start - fire PlayerPreLoginEvent ++ if (!this.a.networkManager.g()) { ++ return; ++ } ++ ++ String playerName = LoginListener.a(this.a).getName(); ++ java.net.InetAddress address = ((java.net.InetSocketAddress) a.networkManager.getSocketAddress()).getAddress(); ++ java.util.UUID uniqueId = LoginListener.b(this.a).getId(); ++ final org.bukkit.craftbukkit.CraftServer server = LoginListener.a(this.a).server; ++ ++ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId); ++ server.getPluginManager().callEvent(asyncEvent); ++ ++ if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) { ++ final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId); ++ if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED) { ++ event.disallow(asyncEvent.getResult(), asyncEvent.getKickMessage()); ++ } ++ Waitable waitable = new Waitable() { ++ @Override ++ protected PlayerPreLoginEvent.Result evaluate() { ++ server.getPluginManager().callEvent(event); ++ return event.getResult(); ++ }}; ++ ++ LoginListener.a(this.a).processQueue.add(waitable); ++ if (waitable.get() != PlayerPreLoginEvent.Result.ALLOWED) { ++ this.a.disconnect(event.getKickMessage()); ++ return; ++ } ++ } else { ++ if (asyncEvent.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { ++ this.a.disconnect(asyncEvent.getKickMessage()); ++ return; ++ } ++ } ++ // CraftBukkit end ++ + LoginListener.e().info("UUID of player " + LoginListener.b(this.a).getName() + " is " + LoginListener.b(this.a).getId()); + LoginListener.a(this.a, EnumProtocolState.READY_TO_ACCEPT); + } else if (LoginListener.a(this.a).S()) { +@@ -41,6 +85,11 @@ + this.a.disconnect("Authentication servers are down. Please try again later, sorry!"); + LoginListener.e().error("Couldn\'t verify username because servers are unavailable"); + } ++ // CraftBukkit start - catch all exceptions ++ } catch (Exception exception) { ++ this.a.disconnect("Failed to verify username!"); ++ LoginListener.a(this.a).server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + LoginListener.a(this.a).getName(), exception); ++ // CraftBukkit end + } + + } diff --git a/paper-server/nms-patches/TileEntity.patch b/paper-server/nms-patches/TileEntity.patch new file mode 100644 index 0000000000..dd76aea170 --- /dev/null +++ b/paper-server/nms-patches/TileEntity.patch @@ -0,0 +1,24 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntity.java 2014-11-27 08:59:46.913420913 +1100 ++++ src/main/java/net/minecraft/server/TileEntity.java 2014-11-27 08:42:10.148850918 +1100 +@@ -6,6 +6,8 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++import org.bukkit.inventory.InventoryHolder; // CraftBukkit ++ + public abstract class TileEntity { + + private static final Logger a = LogManager.getLogger(); +@@ -182,4 +184,12 @@ + a(TileEntityFlowerPot.class, "FlowerPot"); + a(TileEntityBanner.class, "Banner"); + } ++ ++ // CraftBukkit start - add method ++ public InventoryHolder getOwner() { ++ org.bukkit.block.BlockState state = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()).getState(); ++ if (state instanceof InventoryHolder) return (InventoryHolder) state; ++ return null; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/TileEntityBeacon.patch b/paper-server/nms-patches/TileEntityBeacon.patch new file mode 100644 index 0000000000..a5179536c2 --- /dev/null +++ b/paper-server/nms-patches/TileEntityBeacon.patch @@ -0,0 +1,54 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityBeacon.java 2014-11-27 08:59:46.901420966 +1100 ++++ src/main/java/net/minecraft/server/TileEntityBeacon.java 2014-11-27 08:42:10.152850911 +1100 +@@ -5,6 +5,11 @@ + import java.util.Iterator; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class TileEntityBeacon extends TileEntityContainer implements IUpdatePlayerListBox, IInventory { + + public static final MobEffectList[][] a = new MobEffectList[][] { { MobEffectList.FASTER_MOVEMENT, MobEffectList.FASTER_DIG}, { MobEffectList.RESISTANCE, MobEffectList.JUMP}, { MobEffectList.INCREASE_DAMAGE}, { MobEffectList.REGENERATION}}; +@@ -15,6 +20,30 @@ + private int l; + private ItemStack inventorySlot; + private String n; ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return new ItemStack[] { this.inventorySlot }; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public TileEntityBeacon() {} + +@@ -182,7 +211,7 @@ + } + + public int getSize() { +- return 1; ++ return maxStack; // CraftBukkit + } + + public ItemStack getItem(int i) { diff --git a/paper-server/nms-patches/TileEntityBrewingStand.patch b/paper-server/nms-patches/TileEntityBrewingStand.patch new file mode 100644 index 0000000000..80e791ada7 --- /dev/null +++ b/paper-server/nms-patches/TileEntityBrewingStand.patch @@ -0,0 +1,94 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityBrewingStand.java 2014-11-27 08:59:46.901420966 +1100 ++++ src/main/java/net/minecraft/server/TileEntityBrewingStand.java 2014-11-27 08:42:10.132850949 +1100 +@@ -3,6 +3,12 @@ + import java.util.Arrays; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.event.inventory.BrewEvent; ++// CraftBukkit end ++ + public class TileEntityBrewingStand extends TileEntityContainer implements IUpdatePlayerListBox, IWorldInventory { + + private static final int[] a = new int[] { 3}; +@@ -12,8 +18,35 @@ + private boolean[] i; + private Item j; + private String k; ++ private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field + + public TileEntityBrewingStand() {} ++ ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = 64; ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public String getName() { + return this.hasCustomName() ? this.k : "container.brewing"; +@@ -32,9 +65,14 @@ + } + + public void c() { ++ // CraftBukkit start - Use wall time instead of ticks for brewing ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ this.lastTick = MinecraftServer.currentTick; ++ + if (this.brewTime > 0) { +- --this.brewTime; +- if (this.brewTime == 0) { ++ this.brewTime -= elapsedTicks; ++ if (this.brewTime <= 0) { // == -> <= ++ // CraftBukkit end + this.o(); + this.update(); + } else if (!this.n()) { +@@ -109,6 +147,16 @@ + private void o() { + if (this.n()) { + ItemStack itemstack = this.items[3]; ++ ++ // CraftBukkit start ++ if (getOwner() != null) { ++ BrewEvent event = new BrewEvent(world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), (org.bukkit.inventory.BrewerInventory) this.getOwner().getInventory()); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + + for (int i = 0; i < 3; ++i) { + if (this.items[i] != null && this.items[i].getItem() == Items.POTION) { +@@ -221,7 +269,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return this.maxStack; // CraftBukkit + } + + public boolean a(EntityHuman entityhuman) { diff --git a/paper-server/nms-patches/TileEntityChest.patch b/paper-server/nms-patches/TileEntityChest.patch new file mode 100644 index 0000000000..52d98548f9 --- /dev/null +++ b/paper-server/nms-patches/TileEntityChest.patch @@ -0,0 +1,104 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityChest.java 2014-11-27 08:59:46.905420949 +1100 ++++ src/main/java/net/minecraft/server/TileEntityChest.java 2014-11-27 08:42:10.168850880 +1100 +@@ -3,6 +3,11 @@ + import java.util.Iterator; + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class TileEntityChest extends TileEntityContainer implements IUpdatePlayerListBox, IInventory { + + private ItemStack[] items = new ItemStack[27]; +@@ -19,6 +24,31 @@ + private String p; + + public TileEntityChest() {} ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public int getSize() { + return 27; +@@ -125,10 +155,11 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public boolean a(EntityHuman entityhuman) { ++ if (this.world == null) return true; // CraftBukkit + return this.world.getTileEntity(this.position) != this ? false : entityhuman.e((double) this.position.getX() + 0.5D, (double) this.position.getY() + 0.5D, (double) this.position.getZ() + 0.5D) <= 64.0D; + } + +@@ -304,9 +335,22 @@ + if (this.l < 0) { + this.l = 0; + } ++ ++ int oldPower = Math.max(0, Math.min(15, this.l)); // CraftBukkit - Get power before new viewer is added + + ++this.l; ++ if (this.world == null) return; // CraftBukkit + this.world.playBlockAction(this.position, this.w(), 1, this.l); ++ ++ // CraftBukkit start - Call redstone event ++ if (this.w() == Blocks.TRAPPED_CHEST) { ++ int newPower = Math.max(0, Math.min(15, this.l)); ++ ++ if (oldPower != newPower) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, position.getX(), position.getY(), position.getZ(), oldPower, newPower); ++ } ++ } ++ // CraftBukkit end + this.world.applyPhysics(this.position, this.w()); + this.world.applyPhysics(this.position.down(), this.w()); + } +@@ -315,8 +359,21 @@ + + public void closeContainer(EntityHuman entityhuman) { + if (!entityhuman.v() && this.w() instanceof BlockChest) { ++ int oldPower = Math.max(0, Math.min(15, this.l)); // CraftBukkit - Get power before new viewer is added ++ + --this.l; ++ if (this.world == null) return; // CraftBukkit + this.world.playBlockAction(this.position, this.w(), 1, this.l); ++ ++ // CraftBukkit start - Call redstone event ++ if (this.w() == Blocks.TRAPPED_CHEST) { ++ int newPower = Math.max(0, Math.min(15, this.l)); ++ ++ if (oldPower != newPower) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(world, position.getX(), position.getY(), position.getZ(), oldPower, newPower); ++ } ++ } ++ // CraftBukkit end + this.world.applyPhysics(this.position, this.w()); + this.world.applyPhysics(this.position.down(), this.w()); + } diff --git a/paper-server/nms-patches/TileEntityCommandListener.patch b/paper-server/nms-patches/TileEntityCommandListener.patch new file mode 100644 index 0000000000..92b43a413b --- /dev/null +++ b/paper-server/nms-patches/TileEntityCommandListener.patch @@ -0,0 +1,10 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityCommandListener.java 2014-11-27 08:59:46.905420949 +1100 ++++ src/main/java/net/minecraft/server/TileEntityCommandListener.java 2014-11-27 08:42:10.132850949 +1100 +@@ -6,6 +6,7 @@ + + TileEntityCommandListener(TileEntityCommand tileentitycommand) { + this.a = tileentitycommand; ++ sender = new org.bukkit.craftbukkit.command.CraftBlockCommandSender(this); // CraftBukkit - add sender + } + + public BlockPosition getChunkCoordinates() { diff --git a/paper-server/nms-patches/TileEntityDispenser.patch b/paper-server/nms-patches/TileEntityDispenser.patch new file mode 100644 index 0000000000..918eb349ae --- /dev/null +++ b/paper-server/nms-patches/TileEntityDispenser.patch @@ -0,0 +1,63 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityDispenser.java 2014-11-27 08:59:46.905420949 +1100 ++++ src/main/java/net/minecraft/server/TileEntityDispenser.java 2014-11-27 08:42:10.116850981 +1100 +@@ -2,11 +2,43 @@ + + import java.util.Random; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++// CraftBukkit end ++ + public class TileEntityDispenser extends TileEntityContainer implements IInventory { + + private static final Random f = new Random(); + private ItemStack[] items = new ItemStack[9]; + protected String a; ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public TileEntityDispenser() {} + +@@ -58,6 +90,7 @@ + + for (int k = 0; k < this.items.length; ++k) { + if (this.items[k] != null && TileEntityDispenser.f.nextInt(j++) == 0) { ++ if (this.items[k].count == 0) continue; // CraftBukkit + i = k; + } + } +@@ -140,7 +173,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public boolean a(EntityHuman entityhuman) { diff --git a/paper-server/nms-patches/TileEntityFurnace.patch b/paper-server/nms-patches/TileEntityFurnace.patch new file mode 100644 index 0000000000..911664c52c --- /dev/null +++ b/paper-server/nms-patches/TileEntityFurnace.patch @@ -0,0 +1,183 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityFurnace.java 2014-11-27 08:59:46.909420931 +1100 ++++ src/main/java/net/minecraft/server/TileEntityFurnace.java 2014-11-27 08:42:10.156850903 +1100 +@@ -1,5 +1,15 @@ + package net.minecraft.server; + ++// CraftBukkit start ++import java.util.List; ++ ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.event.inventory.FurnaceBurnEvent; ++import org.bukkit.event.inventory.FurnaceSmeltEvent; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++// CraftBukkit end ++ + public class TileEntityFurnace extends TileEntityContainer implements IUpdatePlayerListBox, IWorldInventory { + + private static final int[] a = new int[] { 0}; +@@ -11,6 +21,32 @@ + public int cookTime; + private int cookTimeTotal; + private String m; ++ ++ // CraftBukkit start - add fields and methods ++ private int lastTick = MinecraftServer.currentTick; ++ private int maxStack = MAX_STACK; ++ public List transaction = new java.util.ArrayList(); ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public TileEntityFurnace() {} + +@@ -132,7 +168,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public boolean isBurning() { +@@ -142,9 +178,27 @@ + public void c() { + boolean flag = this.isBurning(); + boolean flag1 = false; ++ ++ // CraftBukkit start - Use wall time instead of ticks for cooking ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ this.lastTick = MinecraftServer.currentTick; ++ ++ // CraftBukkit - moved from below ++ if (this.isBurning() && this.canBurn()) { ++ this.cookTime += elapsedTicks; ++ if (this.cookTime >= this.cookTimeTotal) { ++ this.cookTime = 0; ++ this.cookTimeTotal = this.a(this.items[0]); ++ this.burn(); ++ flag1 = true; ++ } ++ } else { ++ this.cookTime = 0; ++ } ++ // CraftBukkit end + + if (this.isBurning()) { +- --this.burnTime; ++ this.burnTime -= elapsedTicks; // CraftBukkit - use elapsedTicks in place of constant + } + + if (!this.world.isStatic) { +@@ -153,9 +207,21 @@ + this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.cookTimeTotal); + } + } else { +- if (!this.isBurning() && this.canBurn()) { +- this.ticksForCurrentFuel = this.burnTime = fuelTime(this.items[1]); +- if (this.isBurning()) { ++ // CraftBukkit start - Handle multiple elapsed ticks ++ if (this.burnTime <= 0 && this.canBurn()) { // CraftBukkit - == to <= ++ CraftItemStack fuel = CraftItemStack.asCraftMirror(this.items[1]); ++ ++ FurnaceBurnEvent furnaceBurnEvent = new FurnaceBurnEvent(this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), fuel, fuelTime(this.items[1])); ++ this.world.getServer().getPluginManager().callEvent(furnaceBurnEvent); ++ ++ if (furnaceBurnEvent.isCancelled()) { ++ return; ++ } ++ ++ this.ticksForCurrentFuel = furnaceBurnEvent.getBurnTime(); ++ this.burnTime += this.ticksForCurrentFuel; ++ if (this.burnTime > 0 && furnaceBurnEvent.isBurning()) { ++ // CraftBukkit end + flag1 = true; + if (this.items[1] != null) { + --this.items[1].count; +@@ -167,7 +233,8 @@ + } + } + } +- ++ ++ /* CraftBukkit start - Moved up + if (this.isBurning() && this.canBurn()) { + ++this.cookTime; + if (this.cookTime == this.cookTimeTotal) { +@@ -179,6 +246,7 @@ + } else { + this.cookTime = 0; + } ++ */ + } + + if (flag != this.isBurning()) { +@@ -202,20 +270,48 @@ + return false; + } else { + ItemStack itemstack = RecipesFurnace.getInstance().getResult(this.items[0]); +- +- return itemstack == null ? false : (this.items[2] == null ? true : (!this.items[2].doMaterialsMatch(itemstack) ? false : (this.items[2].count < this.getMaxStackSize() && this.items[2].count < this.items[2].getMaxStackSize() ? true : this.items[2].count < itemstack.getMaxStackSize()))); ++ // CraftBukkit - consider resultant count instead of current count ++ return itemstack == null ? false : (this.items[2] == null ? true : (!this.items[2].doMaterialsMatch(itemstack) ? false : (this.items[2].count + itemstack.count <= this.getMaxStackSize() && this.items[2].count < this.items[2].getMaxStackSize() ? true : this.items[2].count + itemstack.count <= itemstack.getMaxStackSize()))); ++ + } + } + + public void burn() { + if (this.canBurn()) { + ItemStack itemstack = RecipesFurnace.getInstance().getResult(this.items[0]); ++ ++ // CraftBukkit start - fire FurnaceSmeltEvent ++ CraftItemStack source = CraftItemStack.asCraftMirror(this.items[0]); ++ org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack); + ++ FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), source, result); ++ this.world.getServer().getPluginManager().callEvent(furnaceSmeltEvent); ++ ++ if (furnaceSmeltEvent.isCancelled()) { ++ return; ++ } ++ ++ result = furnaceSmeltEvent.getResult(); ++ itemstack = CraftItemStack.asNMSCopy(result); ++ ++ if (itemstack != null) { ++ if (this.items[2] == null) { ++ this.items[2] = itemstack; ++ } else if (CraftItemStack.asCraftMirror(this.items[2]).isSimilar(result)) { ++ this.items[2].count += itemstack.count; ++ } else { ++ return; ++ } ++ } ++ ++ /* + if (this.items[2] == null) { + this.items[2] = itemstack.cloneItemStack(); + } else if (this.items[2].getItem() == itemstack.getItem()) { + ++this.items[2].count; + } ++ */ ++ // CraftBukkit end + + if (this.items[0].getItem() == Item.getItemOf(Blocks.SPONGE) && this.items[0].getData() == 1 && this.items[1] != null && this.items[1].getItem() == Items.BUCKET) { + this.items[1] = new ItemStack(Items.WATER_BUCKET); diff --git a/paper-server/nms-patches/TileEntityHopper.patch b/paper-server/nms-patches/TileEntityHopper.patch new file mode 100644 index 0000000000..a8f1dc5740 --- /dev/null +++ b/paper-server/nms-patches/TileEntityHopper.patch @@ -0,0 +1,154 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityHopper.java 2014-11-27 08:59:46.909420931 +1100 ++++ src/main/java/net/minecraft/server/TileEntityHopper.java 2014-11-27 08:42:10.132850949 +1100 +@@ -2,11 +2,45 @@ + + import java.util.List; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.event.inventory.InventoryMoveItemEvent; ++import org.bukkit.event.inventory.InventoryPickupItemEvent; ++import org.bukkit.inventory.Inventory; ++// CraftBukkit end ++ + public class TileEntityHopper extends TileEntityContainer implements IHopper, IUpdatePlayerListBox { + + private ItemStack[] items = new ItemStack[5]; + private String f; + private int g = -1; ++ ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public ItemStack[] getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ // CraftBukkit end + + public TileEntityHopper() {} + +@@ -119,7 +153,7 @@ + } + + public int getMaxStackSize() { +- return 64; ++ return maxStack; // CraftBukkit + } + + public boolean a(EntityHuman entityhuman) { +@@ -215,10 +249,35 @@ + for (int i = 0; i < this.getSize(); ++i) { + if (this.getItem(i) != null) { + ItemStack itemstack = this.getItem(i).cloneItemStack(); +- ItemStack itemstack1 = addItem(iinventory, this.splitStack(i, 1), enumdirection); ++ // ItemStack itemstack1 = addItem(iinventory, this.splitStack(i, 1), enumdirection); ++ ++ // CraftBukkit start - Call event when pushing items into other inventories ++ CraftItemStack oitemstack = CraftItemStack.asCraftMirror(this.splitStack(i, 1)); ++ ++ Inventory destinationInventory; ++ // Have to special case large chests as they work oddly ++ if (iinventory instanceof InventoryLargeChest) { ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory); ++ } else { ++ destinationInventory = iinventory.getOwner().getInventory(); ++ } ++ ++ InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); ++ this.getWorld().getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ this.setItem(i, itemstack); ++ this.d(8); // Delay hopper checks ++ return false; ++ } ++ ItemStack itemstack1 = addItem(iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); + + if (itemstack1 == null || itemstack1.count == 0) { +- iinventory.update(); ++ if (event.getItem().equals(oitemstack)) { ++ iinventory.update(); ++ } else { ++ this.setItem(i, itemstack); ++ } ++ // CraftBukkit end + return true; + } + +@@ -325,10 +384,41 @@ + + if (itemstack != null && b(iinventory, itemstack, i, enumdirection)) { + ItemStack itemstack1 = itemstack.cloneItemStack(); +- ItemStack itemstack2 = addItem(ihopper, iinventory.splitStack(i, 1), (EnumDirection) null); ++ // ItemStack itemstack2 = addItem(ihopper, iinventory.splitStack(i, 1), (EnumDirection) null); ++ // CraftBukkit start - Call event on collection of items from inventories into the hopper ++ CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.splitStack(i, 1)); ++ ++ Inventory sourceInventory; ++ // Have to special case large chests as they work oddly ++ if (iinventory instanceof InventoryLargeChest) { ++ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory); ++ } else { ++ sourceInventory = iinventory.getOwner().getInventory(); ++ } ++ ++ InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false); ++ ++ ihopper.getWorld().getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ iinventory.setItem(i, itemstack1); ++ ++ if (ihopper instanceof TileEntityHopper) { ++ ((TileEntityHopper) ihopper).d(8); // Delay hopper checks ++ } else if (ihopper instanceof EntityMinecartHopper) { ++ ((EntityMinecartHopper) ihopper).l(4); // Delay hopper minecart checks ++ } ++ ++ return false; ++ } ++ ItemStack itemstack2 = addItem(ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); + + if (itemstack2 == null || itemstack2.count == 0) { +- iinventory.update(); ++ if (event.getItem().equals(oitemstack)) { ++ iinventory.update(); ++ } else { ++ iinventory.setItem(i, itemstack1); ++ } ++ // CraftBukkit end + return true; + } + +@@ -344,6 +434,14 @@ + if (entityitem == null) { + return false; + } else { ++ // CraftBukkit start ++ InventoryPickupItemEvent event = new InventoryPickupItemEvent(iinventory.getOwner().getInventory(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); ++ entityitem.world.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end ++ + ItemStack itemstack = entityitem.getItemStack().cloneItemStack(); + ItemStack itemstack1 = addItem(iinventory, itemstack, (EnumDirection) null); + diff --git a/paper-server/nms-patches/TileEntityNote.patch b/paper-server/nms-patches/TileEntityNote.patch new file mode 100644 index 0000000000..fd9a329bb9 --- /dev/null +++ b/paper-server/nms-patches/TileEntityNote.patch @@ -0,0 +1,16 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityNote.java 2014-11-27 08:59:46.913420913 +1100 ++++ src/main/java/net/minecraft/server/TileEntityNote.java 2014-11-27 08:42:10.172850872 +1100 +@@ -44,7 +44,12 @@ + b0 = 4; + } + +- world.playBlockAction(blockposition, Blocks.NOTEBLOCK, b0, this.note); ++ // CraftBukkit start ++ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(this.world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), b0, this.note); ++ if (!event.isCancelled()) { ++ world.playBlockAction(blockposition, Blocks.NOTEBLOCK, event.getInstrument().getType(), event.getNote().getId()); ++ } ++ // CraftBukkit end + } + } + } diff --git a/paper-server/nms-patches/TileEntityPiston.patch b/paper-server/nms-patches/TileEntityPiston.patch new file mode 100644 index 0000000000..0c1fa1d0d6 --- /dev/null +++ b/paper-server/nms-patches/TileEntityPiston.patch @@ -0,0 +1,10 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityPiston.java 2014-11-27 08:59:46.917420896 +1100 ++++ src/main/java/net/minecraft/server/TileEntityPiston.java 2014-11-27 08:42:10.152850911 +1100 +@@ -104,6 +104,7 @@ + } + + public void c() { ++ if (this.world == null) return; // CraftBukkit + this.j = this.i; + if (this.j >= 1.0F) { + this.a(1.0F, 0.25F); diff --git a/paper-server/nms-patches/TileEntityRecordPlayer.patch b/paper-server/nms-patches/TileEntityRecordPlayer.patch new file mode 100644 index 0000000000..068fc0b296 --- /dev/null +++ b/paper-server/nms-patches/TileEntityRecordPlayer.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntityRecordPlayer.java 2014-11-27 08:59:46.917420896 +1100 ++++ src/main/java/net/minecraft/server/TileEntityRecordPlayer.java 2014-11-27 08:42:10.164850887 +1100 +@@ -29,6 +29,11 @@ + } + + public void setRecord(ItemStack itemstack) { ++ // CraftBukkit start - There can only be one ++ if (itemstack != null) { ++ itemstack.count = 1; ++ } ++ // CraftBukkit end + this.record = itemstack; + this.update(); + } diff --git a/paper-server/nms-patches/TileEntitySkull.patch b/paper-server/nms-patches/TileEntitySkull.patch new file mode 100644 index 0000000000..1504054f29 --- /dev/null +++ b/paper-server/nms-patches/TileEntitySkull.patch @@ -0,0 +1,13 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/TileEntitySkull.java 2014-11-27 08:59:46.917420896 +1100 ++++ src/main/java/net/minecraft/server/TileEntitySkull.java 2014-11-27 08:42:10.168850880 +1100 +@@ -105,4 +105,10 @@ + public void setRotation(int i) { + this.rotation = i; + } ++ ++ // CraftBukkit start - add method ++ public int getRotation() { ++ return this.rotation; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/Village.patch b/paper-server/nms-patches/Village.patch new file mode 100644 index 0000000000..9b58e72473 --- /dev/null +++ b/paper-server/nms-patches/Village.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/Village.java 2014-11-27 08:59:46.921420877 +1100 ++++ src/main/java/net/minecraft/server/Village.java 2014-11-27 08:42:10.104851005 +1100 +@@ -60,7 +60,7 @@ + EntityIronGolem entityirongolem = new EntityIronGolem(this.a); + + entityirongolem.setPosition(vec3d.a, vec3d.b, vec3d.c); +- this.a.addEntity(entityirongolem); ++ this.a.addEntity(entityirongolem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE); // CraftBukkit + ++this.l; + } + } diff --git a/paper-server/nms-patches/VillageSiege.patch b/paper-server/nms-patches/VillageSiege.patch new file mode 100644 index 0000000000..f6da3f1009 --- /dev/null +++ b/paper-server/nms-patches/VillageSiege.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/VillageSiege.java 2014-11-27 08:59:46.921420877 +1100 ++++ src/main/java/net/minecraft/server/VillageSiege.java 2014-11-27 08:42:10.100851012 +1100 +@@ -140,7 +140,7 @@ + } + + entityzombie.setPositionRotation(vec3d.a, vec3d.b, vec3d.c, this.a.random.nextFloat() * 360.0F, 0.0F); +- this.a.addEntity(entityzombie); ++ this.a.addEntity(entityzombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_INVASION); // CraftBukkit + BlockPosition blockposition = this.f.a(); + + entityzombie.a(blockposition, this.f.b()); diff --git a/paper-server/nms-patches/World.patch b/paper-server/nms-patches/World.patch new file mode 100644 index 0000000000..03912ea05a --- /dev/null +++ b/paper-server/nms-patches/World.patch @@ -0,0 +1,560 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/World.java 2014-11-27 08:59:46.933420825 +1100 ++++ src/main/java/net/minecraft/server/World.java 2014-11-27 08:42:10.132850949 +1100 +@@ -13,6 +13,22 @@ + import java.util.UUID; + import java.util.concurrent.Callable; + ++// CraftBukkit start ++import org.bukkit.Bukkit; ++import org.bukkit.block.BlockState; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.craftbukkit.util.LongHashSet; ++import org.bukkit.generator.ChunkGenerator; ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.event.block.BlockCanBuildEvent; ++import org.bukkit.event.block.BlockPhysicsEvent; ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; ++import org.bukkit.event.weather.WeatherChangeEvent; ++import org.bukkit.event.weather.ThunderChangeEvent; ++// CraftBukkit end ++ + public abstract class World implements IBlockAccess { + + protected boolean e; +@@ -47,7 +63,8 @@ + private final Calendar J = Calendar.getInstance(); + public Scoreboard scoreboard = new Scoreboard(); + public final boolean isStatic; +- protected Set chunkTickList = Sets.newHashSet(); ++ // CraftBukkit - longhashset ++ protected LongHashSet chunkTickList = new LongHashSet(); + private int K; + public boolean allowMonsters; + public boolean allowAnimals; +@@ -55,7 +72,39 @@ + private final WorldBorder M; + int[] H; + +- protected World(IDataManager idatamanager, WorldData worlddata, WorldProvider worldprovider, MethodProfiler methodprofiler, boolean flag) { ++ // CraftBukkit start Added the following ++ private final CraftWorld world; ++ public boolean pvpMode; ++ public boolean keepSpawnInMemory = true; ++ public ChunkGenerator generator; ++ ++ public boolean captureBlockStates = false; ++ public boolean captureTreeGeneration = false; ++ public ArrayList capturedBlockStates= new ArrayList(); ++ public long ticksPerAnimalSpawns; ++ public long ticksPerMonsterSpawns; ++ public boolean populating; ++ private int tickPosition; ++ ++ public CraftWorld getWorld() { ++ return this.world; ++ } ++ ++ public CraftServer getServer() { ++ return (CraftServer) Bukkit.getServer(); ++ } ++ ++ public Chunk getChunkIfLoaded(int x, int z) { ++ return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z); ++ } ++ ++ protected World(IDataManager idatamanager, WorldData worlddata, WorldProvider worldprovider, MethodProfiler methodprofiler, boolean flag, ChunkGenerator gen, org.bukkit.World.Environment env) { ++ this.generator = gen; ++ this.world = new CraftWorld((WorldServer) this, gen, env); ++ this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit ++ this.ticksPerMonsterSpawns = this.getServer().getTicksPerMonsterSpawns(); // CraftBukkit ++ // CraftBukkit end ++ + this.K = this.random.nextInt(12000); + this.allowMonsters = true; + this.allowAnimals = true; +@@ -66,6 +115,8 @@ + this.worldProvider = worldprovider; + this.isStatic = flag; + this.M = worldprovider.getWorldBorder(); ++ ++ this.getServer().addWorld(this.world); // CraftBukkit + } + + public World b() { +@@ -184,6 +235,27 @@ + } + + public boolean setTypeAndData(BlockPosition blockposition, IBlockData iblockdata, int i) { ++ // CraftBukkit start - tree generation ++ if (this.captureTreeGeneration) { ++ BlockState blockstate = null; ++ Iterator it = capturedBlockStates.iterator(); ++ while (it.hasNext()) { ++ BlockState previous = it.next(); ++ if (previous.getX() == blockposition.getX() && previous.getY() == blockposition.getY() && previous.getZ() == blockposition.getZ()) { ++ blockstate = previous; ++ it.remove(); ++ break; ++ } ++ } ++ if (blockstate == null) { ++ blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), i); ++ } ++ blockstate.setTypeId(CraftMagicNumbers.getId(iblockdata.getBlock())); ++ blockstate.setRawData((byte) iblockdata.getBlock().toLegacyData(iblockdata)); ++ this.capturedBlockStates.add(blockstate); ++ return true; ++ } ++ // CraftBukkit end + if (!this.isValidLocation(blockposition)) { + return false; + } else if (!this.isStatic && this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) { +@@ -191,9 +263,23 @@ + } else { + Chunk chunk = this.getChunkAtWorldCoords(blockposition); + Block block = iblockdata.getBlock(); ++ ++ // CraftBukkit start - capture blockstates ++ BlockState blockstate = null; ++ if (this.captureBlockStates) { ++ blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), i); ++ this.capturedBlockStates.add(blockstate); ++ } ++ // CraftBukkit end ++ + IBlockData iblockdata1 = chunk.a(blockposition, iblockdata); + + if (iblockdata1 == null) { ++ // CraftBukkit start - remove blockstate if failed ++ if (!this.captureBlockStates) { ++ this.capturedBlockStates.remove(blockstate); ++ } ++ // CraftBukkit end + return false; + } else { + Block block1 = iblockdata1.getBlock(); +@@ -204,6 +290,7 @@ + this.methodProfiler.b(); + } + ++ /* + if ((i & 2) != 0 && (!this.isStatic || (i & 4) == 0) && chunk.isReady()) { + this.notify(blockposition); + } +@@ -214,12 +301,35 @@ + this.updateAdjacentComparators(blockposition, block); + } + } ++ */ ++ ++ // CraftBukkit start ++ if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates ++ // Modularize client and physic updates ++ notifyAndUpdatePhysics(blockposition, chunk, block1, block, i); ++ } ++ // CraftBukkit end + + return true; + } + } + } + ++ // CraftBukkit start - Split off from original setTypeAndData(int i, int j, int k, Block block, int l, int i1) method in order to directly send client and physic updates ++ public void notifyAndUpdatePhysics(BlockPosition blockposition, Chunk chunk, Block oldBlock, Block newBLock, int flag) { ++ if ((flag & 2) != 0 && (chunk == null || chunk.isReady())) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement ++ this.notify(blockposition); ++ } ++ ++ if (!this.isStatic && (flag & 1) != 0) { ++ this.update(blockposition, oldBlock); ++ if (newBLock.isComplexRedstone()) { ++ this.updateAdjacentComparators(blockposition, newBLock); ++ } ++ } ++ } ++ // CraftBukkit end ++ + public boolean setAir(BlockPosition blockposition) { + return this.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 3); + } +@@ -253,6 +363,11 @@ + + public void update(BlockPosition blockposition, Block block) { + if (this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) { ++ // CraftBukkit start ++ if (populating) { ++ return; ++ } ++ // CraftBukkit end + this.applyPhysics(blockposition, block); + } + +@@ -328,6 +443,17 @@ + IBlockData iblockdata = this.getType(blockposition); + + try { ++ // CraftBukkit start ++ CraftWorld world = ((WorldServer) this).getWorld(); ++ if (world != null) { ++ BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block)); ++ this.getServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + iblockdata.getBlock().doPhysics(this, blockposition, iblockdata, block); + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.a(throwable, "Exception while updating neighbours"); +@@ -497,6 +623,17 @@ + } + + public IBlockData getType(BlockPosition blockposition) { ++ // CraftBukkit start - tree generation ++ if (captureTreeGeneration) { ++ Iterator it = capturedBlockStates.iterator(); ++ while (it.hasNext()) { ++ BlockState previous = it.next(); ++ if (previous.getX() == blockposition.getX() && previous.getY() == blockposition.getY() && previous.getZ() == blockposition.getZ()) { ++ return CraftMagicNumbers.getBlock(previous.getTypeId()).fromLegacyData(previous.getRawData()); ++ } ++ } ++ } ++ // CraftBukkit end + if (!this.isValidLocation(blockposition)) { + return Blocks.AIR.getBlockData(); + } else { +@@ -704,6 +841,13 @@ + } + + public boolean addEntity(Entity entity) { ++ // CraftBukkit start - Used for entities other than creatures ++ return addEntity(entity, SpawnReason.DEFAULT); ++ } ++ ++ public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason ++ if (entity == null) return false; ++ // CraftBukkit end + int i = MathHelper.floor(entity.locX / 16.0D); + int j = MathHelper.floor(entity.locZ / 16.0D); + boolean flag = entity.attachedToPlayer; +@@ -712,7 +856,35 @@ + flag = true; + } + ++ // CraftBukkit start ++ org.bukkit.event.Cancellable event = null; ++ if (entity instanceof EntityLiving && !(entity instanceof EntityPlayer)) { ++ boolean isAnimal = entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal || entity instanceof EntityGolem; ++ boolean isMonster = entity instanceof EntityMonster || entity instanceof EntityGhast || entity instanceof EntitySlime; ++ ++ if (spawnReason != SpawnReason.CUSTOM) { ++ if (isAnimal && !allowAnimals || isMonster && !allowMonsters) { ++ entity.dead = true; ++ return false; ++ } ++ } ++ ++ event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason); ++ } else if (entity instanceof EntityItem) { ++ event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity); ++ } else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Projectile) { ++ // Not all projectiles extend EntityProjectile, so check for Bukkit interface instead ++ event = CraftEventFactory.callProjectileLaunchEvent(entity); ++ } ++ ++ if (event != null && (event.isCancelled() || entity.dead)) { ++ entity.dead = true; ++ return false; ++ } ++ // CraftBukkit end ++ + if (!flag && !this.isChunkLoaded(i, j, true)) { ++ entity.dead = true; + return false; + } else { + if (entity instanceof EntityHuman) { +@@ -734,6 +906,7 @@ + ((IWorldAccess) this.u.get(i)).a(entity); + } + ++ entity.valid = true; // CraftBukkit + } + + protected void b(Entity entity) { +@@ -741,6 +914,7 @@ + ((IWorldAccess) this.u.get(i)).b(entity); + } + ++ entity.valid = false; // CraftBukkit + } + + public void kill(Entity entity) { +@@ -775,7 +949,15 @@ + this.getChunkAt(i, j).b(entity); + } + +- this.entityList.remove(entity); ++ // CraftBukkit start - Decrement loop variable field if we've already ticked this entity ++ int index = this.entityList.indexOf(entity); ++ if (index != -1) { ++ if (index <= this.tickPosition) { ++ this.tickPosition--; ++ } ++ this.entityList.remove(index); ++ } ++ // CraftBukkit end + this.b(entity); + } + +@@ -958,6 +1140,11 @@ + + for (i = 0; i < this.k.size(); ++i) { + entity = (Entity) this.k.get(i); ++ // CraftBukkit start - Fixed an NPE ++ if (entity == null) { ++ continue; ++ } ++ // CraftBukkit end + + try { + ++entity.ticksLived; +@@ -1001,8 +1188,10 @@ + this.g.clear(); + this.methodProfiler.c("regular"); + +- for (i = 0; i < this.entityList.size(); ++i) { +- entity = (Entity) this.entityList.get(i); ++ // CraftBukkit start - Use field for loop variable ++ for (this.tickPosition = 0; this.tickPosition < this.entityList.size(); ++this.tickPosition) { ++ entity = (Entity) this.entityList.get(this.tickPosition); ++ // CraftBukkit end + if (entity.vehicle != null) { + if (!entity.vehicle.dead && entity.vehicle.passenger == entity) { + continue; +@@ -1033,7 +1222,7 @@ + this.getChunkAt(j, k).b(entity); + } + +- this.entityList.remove(i--); ++ this.entityList.remove(this.tickPosition--); // CraftBukkit - Use field for loop variable + this.b(entity); + } + +@@ -1042,6 +1231,14 @@ + + this.methodProfiler.c("blockEntities"); + this.L = true; ++ // CraftBukkit start - From below, clean up tile entities before ticking them ++ if (!this.b.isEmpty()) { ++ this.tileEntityList.removeAll(this.b); ++ this.h.removeAll(this.b); ++ this.b.clear(); ++ } ++ // CraftBukkit end ++ + Iterator iterator = this.tileEntityList.iterator(); + + while (iterator.hasNext()) { +@@ -1073,11 +1270,13 @@ + } + + this.L = false; ++ /* CraftBukkit start - Moved up + if (!this.b.isEmpty()) { + this.tileEntityList.removeAll(this.b); + this.h.removeAll(this.b); + this.b.clear(); + } ++ */ // CraftBukkit end + + this.methodProfiler.c("pendingBlockEntities"); + if (!this.a.isEmpty()) { +@@ -1085,9 +1284,11 @@ + TileEntity tileentity1 = (TileEntity) this.a.get(l); + + if (!tileentity1.x()) { ++ /* CraftBukkit start - Order matters, moved down + if (!this.h.contains(tileentity1)) { + this.a(tileentity1); + } ++ // CraftBukkit end */ + + if (this.isLoaded(tileentity1.getPosition())) { + this.getChunkAtWorldCoords(tileentity1.getPosition()).a(tileentity1.getPosition(), tileentity1); +@@ -1141,7 +1342,10 @@ + int j = MathHelper.floor(entity.locZ); + byte b0 = 32; + +- if (!flag || this.isAreaLoaded(i - b0, 0, j - b0, i + b0, 0, j + b0, true)) { ++ // CraftBukkit start - Use neighbor cache instead of looking up ++ Chunk startingChunk = this.getChunkIfLoaded(i >> 4, j >> 4); ++ if (!flag || (startingChunk != null && startingChunk.areNeighborsLoaded(2)) /* this.isAreaLoaded(i - b0, 0, j - b0, i + b0, 0, j + b0) */) { ++ // CraftBukkit end + entity.P = entity.locX; + entity.Q = entity.locY; + entity.R = entity.locZ; +@@ -1615,7 +1819,13 @@ + --j; + this.worldData.setThunderDuration(j); + if (j <= 0) { +- this.worldData.setThundering(!this.worldData.isThundering()); ++ // CraftBukkit start ++ ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), !this.worldData.isThundering()); ++ this.getServer().getPluginManager().callEvent(thunder); ++ if (!thunder.isCancelled()) { ++ this.worldData.setThundering(!this.worldData.isThundering()); ++ } ++ // CraftBukkit end + } + } + +@@ -1639,7 +1849,14 @@ + --k; + this.worldData.setWeatherDuration(k); + if (k <= 0) { +- this.worldData.setStorm(!this.worldData.hasStorm()); ++ // CraftBukkit start ++ WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), !this.worldData.hasStorm()); ++ this.getServer().getPluginManager().callEvent(weather); ++ ++ if (!weather.isCancelled()) { ++ this.worldData.setStorm(!this.worldData.hasStorm()); ++ } ++ // CraftBukkit end + } + } + +@@ -1656,7 +1873,7 @@ + } + + protected void D() { +- this.chunkTickList.clear(); ++ // this.chunkTickList.clear(); // CraftBukkit - removed + this.methodProfiler.a("buildList"); + + int i; +@@ -1673,7 +1890,7 @@ + + for (int i1 = -l; i1 <= l; ++i1) { + for (int j1 = -l; j1 <= l; ++j1) { +- this.chunkTickList.add(new ChunkCoordIntPair(i1 + j, j1 + k)); ++ this.chunkTickList.add(org.bukkit.craftbukkit.util.LongHash.toLong(i1 + j, j1 + k)); + } + } + } +@@ -1851,7 +2068,10 @@ + } + + public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition) { +- if (!this.areChunksLoaded(blockposition, 17, false)) { ++ // CraftBukkit start - Use neighbor cache instead of looking up ++ Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); ++ if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) { ++ // CraftBukkit end + return false; + } else { + int i = 0; +@@ -2095,8 +2315,17 @@ + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); ++ // CraftBukkit start - Split out persistent check, don't apply it to special persistent mobs ++ if (entity instanceof EntityInsentient) { ++ EntityInsentient entityinsentient = (EntityInsentient) entity; ++ if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { ++ continue; ++ } ++ } + +- if ((!(entity instanceof EntityInsentient) || !((EntityInsentient) entity).isPersistent()) && oclass.isAssignableFrom(entity.getClass())) { ++ if (oclass.isAssignableFrom(entity.getClass())) { ++ // if ((!(entity instanceof EntityInsentient) || !((EntityInsentient) entity).isPersistent()) && oclass.isAssignableFrom(entity.getClass())) { ++ // CraftBukkit end + ++i; + } + } +@@ -2105,12 +2334,17 @@ + } + + public void b(Collection collection) { +- this.entityList.addAll(collection); ++ // CraftBukkit start ++ // this.entityList.addAll(collection); + Iterator iterator = collection.iterator(); + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); +- ++ if (entity == null) { ++ continue; ++ } ++ this.entityList.add(entity); ++ // CraftBukkit end + this.a(entity); + } + +@@ -2124,7 +2358,13 @@ + Block block1 = this.getType(blockposition).getBlock(); + AxisAlignedBB axisalignedbb = flag ? null : block.a(this, blockposition, block.getBlockData()); + +- return axisalignedbb != null && !this.a(axisalignedbb, entity) ? false : (block1.getMaterial() == Material.ORIENTABLE && block == Blocks.ANVIL ? true : block1.getMaterial().isReplaceable() && block.canPlace(this, blockposition, enumdirection, itemstack)); ++ // CraftBukkit start - store default return ++ boolean defaultReturn = axisalignedbb != null && !this.a(axisalignedbb, entity) ? false : (block1.getMaterial() == Material.ORIENTABLE && block == Blocks.ANVIL ? true : block1.getMaterial().isReplaceable() && block.canPlace(this, blockposition, enumdirection, itemstack)); ++ BlockCanBuildEvent event = new BlockCanBuildEvent(this.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block), defaultReturn); ++ this.getServer().getPluginManager().callEvent(event); ++ ++ return event.isBuildable(); ++ // CraftBukkit end + } + + public int getBlockPower(BlockPosition blockposition, EnumDirection enumdirection) { +@@ -2215,6 +2455,11 @@ + + for (int i = 0; i < this.players.size(); ++i) { + EntityHuman entityhuman1 = (EntityHuman) this.players.get(i); ++ // CraftBukkit start - Fixed an NPE ++ if (entityhuman1 == null || entityhuman1.dead) { ++ continue; ++ } ++ // CraftBukkit end + + if (IEntitySelector.d.apply(entityhuman1)) { + double d5 = entityhuman1.e(d0, d1, d2); +@@ -2269,7 +2514,7 @@ + return null; + } + +- public void checkSession() { ++ public void checkSession() throws ExceptionWorldConflict { // CraftBukkit - added throws + this.dataManager.checkSession(); + } + +@@ -2331,6 +2576,16 @@ + + public void everyoneSleeping() {} + ++ // CraftBukkit start ++ // Calls the method that checks to see if players are sleeping ++ // Called by CraftPlayer.setPermanentSleeping() ++ public void checkSleepStatus() { ++ if (!this.isStatic) { ++ this.everyoneSleeping(); ++ } ++ } ++ // CraftBukkit end ++ + public float h(float f) { + return (this.q + (this.r - this.q) * f) * this.j(f); + } +@@ -2538,6 +2793,6 @@ + int l = j * 16 + 8 - blockposition.getZ(); + short short0 = 128; + +- return k >= -short0 && k <= short0 && l >= -short0 && l <= short0; ++ return k >= -short0 && k <= short0 && l >= -short0 && l <= short0 || !this.keepSpawnInMemory; // CraftBukkit - Added 'this.world.keepSpawnInMemory' + } + } diff --git a/paper-server/nms-patches/WorldBorder.patch b/paper-server/nms-patches/WorldBorder.patch new file mode 100644 index 0000000000..37416ef7df --- /dev/null +++ b/paper-server/nms-patches/WorldBorder.patch @@ -0,0 +1,25 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldBorder.java 2014-11-27 08:59:46.925420860 +1100 ++++ src/main/java/net/minecraft/server/WorldBorder.java 2014-11-27 08:42:10.168850880 +1100 +@@ -32,9 +32,21 @@ + return (double) (blockposition.getX() + 1) > this.b() && (double) blockposition.getX() < this.d() && (double) (blockposition.getZ() + 1) > this.c() && (double) blockposition.getZ() < this.e(); + } + ++ // CraftBukkit start - split method + public boolean isInBounds(ChunkCoordIntPair chunkcoordintpair) { +- return (double) chunkcoordintpair.e() > this.b() && (double) chunkcoordintpair.c() < this.d() && (double) chunkcoordintpair.f() > this.c() && (double) chunkcoordintpair.d() < this.e(); ++ return isInBounds(chunkcoordintpair.x, chunkcoordintpair.z); + } ++ ++ // Inlined the getters from ChunkCoordIntPair ++ public boolean isInBounds(long chunkcoords) { ++ return isInBounds(org.bukkit.craftbukkit.util.LongHash.msw(chunkcoords), org.bukkit.craftbukkit.util.LongHash.lsw(chunkcoords)); ++ } ++ ++ // Inlined the getters from ChunkCoordIntPair ++ public boolean isInBounds(int x, int z) { ++ return (double) ((x << 4) + 15) > this.b() && (double) (x << 4) < this.d() && (double) ((z << 4) + 15) > this.c() && (double) (x << 4) < this.e(); ++ } ++ // CraftBukkit end + + public boolean a(AxisAlignedBB axisalignedbb) { + return axisalignedbb.d > this.b() && axisalignedbb.a < this.d() && axisalignedbb.f > this.c() && axisalignedbb.c < this.e(); diff --git a/paper-server/nms-patches/WorldGenGroundBush.patch b/paper-server/nms-patches/WorldGenGroundBush.patch new file mode 100644 index 0000000000..9a633c3bde --- /dev/null +++ b/paper-server/nms-patches/WorldGenGroundBush.patch @@ -0,0 +1,14 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldGenGroundBush.java 2014-11-27 08:59:46.925420860 +1100 ++++ src/main/java/net/minecraft/server/WorldGenGroundBush.java 2014-11-27 08:42:10.144850927 +1100 +@@ -46,7 +46,11 @@ + } + } + } ++ // CraftBukkit start - Return false if gen was unsuccessful ++ } else { ++ return false; + } ++ // CraftBukkit end + + return true; + } diff --git a/paper-server/nms-patches/WorldGenMegaTreeAbstract.patch b/paper-server/nms-patches/WorldGenMegaTreeAbstract.patch new file mode 100644 index 0000000000..4dcc862538 --- /dev/null +++ b/paper-server/nms-patches/WorldGenMegaTreeAbstract.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldGenMegaTreeAbstract.java 2014-11-27 08:59:46.925420860 +1100 ++++ src/main/java/net/minecraft/server/WorldGenMegaTreeAbstract.java 2014-11-27 08:42:10.140850934 +1100 +@@ -42,7 +42,7 @@ + + for (int k = -b0; k <= b0 && flag; ++k) { + for (int l = -b0; l <= b0 && flag; ++l) { +- if (blockposition.getY() + j < 0 || blockposition.getY() + j >= 256 || !this.a(world.getType(blockposition.a(k, j, l)).getBlock())) { ++ if (blockposition.getY() + j < 0 || blockposition.getY() + j >= 256 || (!this.a(world.getType(blockposition.a(k, j, l)).getBlock()) && world.getType(blockposition.a(k, j, l)).getBlock() != Blocks.SAPLING)) { // CraftBukkit - ignore our own saplings + flag = false; + } + } diff --git a/paper-server/nms-patches/WorldGenVillagePiece.patch b/paper-server/nms-patches/WorldGenVillagePiece.patch new file mode 100644 index 0000000000..ff11ea6a91 --- /dev/null +++ b/paper-server/nms-patches/WorldGenVillagePiece.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldGenVillagePiece.java 2014-11-27 08:59:46.929420842 +1100 ++++ src/main/java/net/minecraft/server/WorldGenVillagePiece.java 2014-11-27 08:42:10.144850927 +1100 +@@ -114,7 +114,7 @@ + entityvillager.setPositionRotation((double) j1 + 0.5D, (double) k1, (double) l1 + 0.5D, 0.0F, 0.0F); + entityvillager.prepare(world.E(new BlockPosition(entityvillager)), (GroupDataEntity) null); + entityvillager.setProfession(this.c(i1, entityvillager.getProfession())); +- world.addEntity(entityvillager); ++ world.addEntity(entityvillager, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - add SpawnReason + } + + } diff --git a/paper-server/nms-patches/WorldGenVillagePieces.patch b/paper-server/nms-patches/WorldGenVillagePieces.patch new file mode 100644 index 0000000000..e69de29bb2 diff --git a/paper-server/nms-patches/WorldGenWitchHut.patch b/paper-server/nms-patches/WorldGenWitchHut.patch new file mode 100644 index 0000000000..cfd76bed0f --- /dev/null +++ b/paper-server/nms-patches/WorldGenWitchHut.patch @@ -0,0 +1,11 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldGenWitchHut.java 2014-11-27 08:59:46.933420825 +1100 ++++ src/main/java/net/minecraft/server/WorldGenWitchHut.java 2014-11-27 08:42:10.152850911 +1100 +@@ -77,7 +77,7 @@ + + entitywitch.setPositionRotation((double) i1 + 0.5D, (double) j1, (double) k1 + 0.5D, 0.0F, 0.0F); + entitywitch.prepare(world.E(new BlockPosition(i1, j1, k1)), (GroupDataEntity) null); +- world.addEntity(entitywitch); ++ world.addEntity(entitywitch, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - add SpawnReason + } + } + diff --git a/paper-server/nms-patches/WorldManager.patch b/paper-server/nms-patches/WorldManager.patch new file mode 100644 index 0000000000..a7f97b030b --- /dev/null +++ b/paper-server/nms-patches/WorldManager.patch @@ -0,0 +1,28 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldManager.java 2014-11-27 08:59:46.937420807 +1100 ++++ src/main/java/net/minecraft/server/WorldManager.java 2014-11-27 08:42:10.132850949 +1100 +@@ -23,11 +23,13 @@ + } + + public void a(String s, double d0, double d1, double d2, float f, float f1) { +- this.a.getPlayerList().sendPacketNearby(d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world.worldProvider.getDimension(), new PacketPlayOutNamedSoundEffect(s, d0, d1, d2, f, f1)); ++ // CraftBukkit - this.world.dimension ++ this.a.getPlayerList().sendPacketNearby(d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world.dimension, new PacketPlayOutNamedSoundEffect(s, d0, d1, d2, f, f1)); + } + + public void a(EntityHuman entityhuman, String s, double d0, double d1, double d2, float f, float f1) { +- this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world.worldProvider.getDimension(), new PacketPlayOutNamedSoundEffect(s, d0, d1, d2, f, f1)); ++ // CraftBukkit - this.world.dimension ++ this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world.dimension, new PacketPlayOutNamedSoundEffect(s, d0, d1, d2, f, f1)); + } + + public void a(int i, int j, int k, int l, int i1, int j1) {} +@@ -41,7 +43,8 @@ + public void a(String s, BlockPosition blockposition) {} + + public void a(EntityHuman entityhuman, int i, BlockPosition blockposition, int j) { +- this.a.getPlayerList().sendPacketNearby(entityhuman, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 64.0D, this.world.worldProvider.getDimension(), new PacketPlayOutWorldEvent(i, blockposition, j, false)); ++ // CraftBukkit - this.world.dimension ++ this.a.getPlayerList().sendPacketNearby(entityhuman, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 64.0D, this.world.dimension, new PacketPlayOutWorldEvent(i, blockposition, j, false)); + } + + public void a(int i, BlockPosition blockposition, int j) { diff --git a/paper-server/nms-patches/WorldMap.patch b/paper-server/nms-patches/WorldMap.patch new file mode 100644 index 0000000000..86ba2aa672 --- /dev/null +++ b/paper-server/nms-patches/WorldMap.patch @@ -0,0 +1,95 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldMap.java 2014-11-27 08:59:46.941420790 +1100 ++++ src/main/java/net/minecraft/server/WorldMap.java 2014-11-27 08:42:10.152850911 +1100 +@@ -6,6 +6,14 @@ + import java.util.List; + import java.util.Map; + ++// CraftBukkit start ++import java.util.UUID; ++ ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.map.CraftMapView; ++// CraftBukkit end ++ + public class WorldMap extends PersistentBase { + + public int centerX; +@@ -16,9 +24,19 @@ + public List g = Lists.newArrayList(); + private Map i = Maps.newHashMap(); + public Map decorations = Maps.newLinkedHashMap(); ++ ++ // CraftBukkit start ++ public final CraftMapView mapView; ++ private CraftServer server; ++ private UUID uniqueId = null; ++ // CraftBukkit end + + public WorldMap(String s) { + super(s); ++ // CraftBukkit start ++ mapView = new CraftMapView(this); ++ server = (CraftServer) org.bukkit.Bukkit.getServer(); ++ // CraftBukkit end + } + + public void a(double d0, double d1, int i) { +@@ -31,7 +49,30 @@ + } + + public void a(NBTTagCompound nbttagcompound) { +- this.map = nbttagcompound.getByte("dimension"); ++ // CraftBukkit start ++ byte dimension = nbttagcompound.getByte("dimension"); ++ ++ if (dimension >= 10) { ++ long least = nbttagcompound.getLong("UUIDLeast"); ++ long most = nbttagcompound.getLong("UUIDMost"); ++ ++ if (least != 0L && most != 0L) { ++ this.uniqueId = new UUID(most, least); ++ ++ CraftWorld world = (CraftWorld) server.getWorld(this.uniqueId); ++ // Check if the stored world details are correct. ++ if (world == null) { ++ /* All Maps which do not have their valid world loaded are set to a dimension which hopefully won't be reached. ++ This is to prevent them being corrupted with the wrong map data. */ ++ dimension = 127; ++ } else { ++ dimension = (byte) world.getHandle().dimension; ++ } ++ } ++ } ++ ++ this.map = dimension; ++ // CraftBukkit end + this.centerX = nbttagcompound.getInt("xCenter"); + this.centerZ = nbttagcompound.getInt("zCenter"); + this.scale = nbttagcompound.getByte("scale"); +@@ -66,6 +107,25 @@ + } + + public void b(NBTTagCompound nbttagcompound) { ++ // CraftBukkit start ++ if (this.map >= 10) { ++ if (this.uniqueId == null) { ++ for (org.bukkit.World world : server.getWorlds()) { ++ CraftWorld cWorld = (CraftWorld) world; ++ if (cWorld.getHandle().dimension == this.map) { ++ this.uniqueId = cWorld.getUID(); ++ break; ++ } ++ } ++ } ++ /* Perform a second check to see if a matching world was found, this is a necessary ++ change incase Maps are forcefully unlinked from a World and lack a UID.*/ ++ if (this.uniqueId != null) { ++ nbttagcompound.setLong("UUIDLeast", this.uniqueId.getLeastSignificantBits()); ++ nbttagcompound.setLong("UUIDMost", this.uniqueId.getMostSignificantBits()); ++ } ++ } ++ // CraftBukkit end + nbttagcompound.setByte("dimension", this.map); + nbttagcompound.setInt("xCenter", this.centerX); + nbttagcompound.setInt("zCenter", this.centerZ); diff --git a/paper-server/nms-patches/WorldMapHumanTracker.patch b/paper-server/nms-patches/WorldMapHumanTracker.patch new file mode 100644 index 0000000000..627bbbfde7 --- /dev/null +++ b/paper-server/nms-patches/WorldMapHumanTracker.patch @@ -0,0 +1,31 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldMapHumanTracker.java 2014-11-27 08:59:46.937420807 +1100 ++++ src/main/java/net/minecraft/server/WorldMapHumanTracker.java 2014-11-27 08:42:10.168850880 +1100 +@@ -23,12 +23,26 @@ + } + + public Packet a(ItemStack itemstack) { ++ // CraftBukkit start ++ org.bukkit.craftbukkit.map.RenderData render = this.worldMap.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.trackee.getBukkitEntity()); // CraftBukkit ++ ++ java.util.Collection icons = new java.util.ArrayList(); ++ ++ for ( org.bukkit.map.MapCursor cursor : render.cursors) { ++ ++ if (cursor.isVisible()) { ++ icons.add(new MapIcon(cursor.getRawType(), cursor.getX(), cursor.getY(), cursor.getDirection())); ++ } ++ } ++ ++ + if (this.d) { + this.d = false; +- return new PacketPlayOutMap(itemstack.getData(), this.worldMap.scale, this.worldMap.decorations.values(), this.worldMap.colors, this.e, this.f, this.g + 1 - this.e, this.h + 1 - this.f); ++ return new PacketPlayOutMap(itemstack.getData(), this.worldMap.scale, icons, render.buffer, this.e, this.f, this.g + 1 - this.e, this.h + 1 - this.f); + } else { +- return this.i++ % 5 == 0 ? new PacketPlayOutMap(itemstack.getData(), this.worldMap.scale, this.worldMap.decorations.values(), this.worldMap.colors, 0, 0, 0, 0) : null; ++ return this.i++ % 5 == 0 ? new PacketPlayOutMap(itemstack.getData(), this.worldMap.scale, icons, render.buffer, 0, 0, 0, 0) : null; + } ++ // CraftBukkit end + } + + public void a(int i, int j) { diff --git a/paper-server/nms-patches/WorldNBTStorage.patch b/paper-server/nms-patches/WorldNBTStorage.patch new file mode 100644 index 0000000000..503af702a2 --- /dev/null +++ b/paper-server/nms-patches/WorldNBTStorage.patch @@ -0,0 +1,123 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldNBTStorage.java 2014-11-27 08:59:46.941420790 +1100 ++++ src/main/java/net/minecraft/server/WorldNBTStorage.java 2014-11-27 08:42:10.156850903 +1100 +@@ -11,6 +11,12 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.util.UUID; ++ ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++// CraftBukkit end ++ + public class WorldNBTStorage implements IDataManager, IPlayerFileData { + + private static final Logger a = LogManager.getLogger(); +@@ -19,6 +25,7 @@ + private final File dataDir; + private final long sessionId = MinecraftServer.ax(); + private final String f; ++ private UUID uuid = null; // CraftBukkit + + public WorldNBTStorage(File file, String s, boolean flag) { + this.baseDir = new File(file, s); +@@ -55,7 +62,7 @@ + return this.baseDir; + } + +- public void checkSession() { ++ public void checkSession() throws ExceptionWorldConflict { // CraftBukkit - throws ExceptionWorldConflict + try { + File file = new File(this.baseDir, "session.lock"); + DataInputStream datainputstream = new DataInputStream(new FileInputStream(file)); +@@ -202,12 +209,39 @@ + } + + if (nbttagcompound != null) { ++ // CraftBukkit start ++ if (entityhuman instanceof EntityPlayer) { ++ CraftPlayer player = (CraftPlayer) entityhuman.getBukkitEntity(); ++ // Only update first played if it is older than the one we have ++ long modified = new File(this.playerDir, entityhuman.getUniqueID().toString() + ".dat").lastModified(); ++ if (modified < player.getFirstPlayed()) { ++ player.setFirstPlayed(modified); ++ } ++ } ++ // CraftBukkit end ++ + entityhuman.f(nbttagcompound); + } + + return nbttagcompound; + } + ++ // CraftBukkit start ++ public NBTTagCompound getPlayerData(String s) { ++ try { ++ File file1 = new File(this.playerDir, s + ".dat"); ++ ++ if (file1.exists()) { ++ return NBTCompressedStreamTools.a((InputStream) (new FileInputStream(file1))); ++ } ++ } catch (Exception exception) { ++ a.warn("Failed to load player data for " + s); ++ } ++ ++ return null; ++ } ++ // CraftBukkit end ++ + public IPlayerFileData getPlayerFileData() { + return this; + } +@@ -237,4 +271,50 @@ + public String g() { + return this.f; + } ++ ++ // CraftBukkit start ++ public UUID getUUID() { ++ if (uuid != null) return uuid; ++ File file1 = new File(this.baseDir, "uid.dat"); ++ if (file1.exists()) { ++ DataInputStream dis = null; ++ try { ++ dis = new DataInputStream(new FileInputStream(file1)); ++ return uuid = new UUID(dis.readLong(), dis.readLong()); ++ } catch (IOException ex) { ++ a.warn("Failed to read " + file1 + ", generating new random UUID", ex); ++ } finally { ++ if (dis != null) { ++ try { ++ dis.close(); ++ } catch (IOException ex) { ++ // NOOP ++ } ++ } ++ } ++ } ++ uuid = UUID.randomUUID(); ++ DataOutputStream dos = null; ++ try { ++ dos = new DataOutputStream(new FileOutputStream(file1)); ++ dos.writeLong(uuid.getMostSignificantBits()); ++ dos.writeLong(uuid.getLeastSignificantBits()); ++ } catch (IOException ex) { ++ a.warn("Failed to write " + file1, ex); ++ } finally { ++ if (dos != null) { ++ try { ++ dos.close(); ++ } catch (IOException ex) { ++ // NOOP ++ } ++ } ++ } ++ return uuid; ++ } ++ ++ public File getPlayerDir() { ++ return playerDir; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/nms-patches/WorldServer.patch b/paper-server/nms-patches/WorldServer.patch new file mode 100644 index 0000000000..b1ad5607b7 --- /dev/null +++ b/paper-server/nms-patches/WorldServer.patch @@ -0,0 +1,550 @@ +--- ../work/decompile-bb26c12b/net/minecraft/server/WorldServer.java 2014-11-27 08:59:46.945420772 +1100 ++++ src/main/java/net/minecraft/server/WorldServer.java 2014-11-27 08:42:10.140850934 +1100 +@@ -16,6 +16,20 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + ++// CraftBukkit start ++import java.util.*; ++import java.util.logging.Level; ++ ++import org.bukkit.WeatherType; ++import org.bukkit.block.BlockState; ++import org.bukkit.craftbukkit.util.LongHash; ++ ++import org.bukkit.event.block.BlockFormEvent; ++import org.bukkit.event.weather.LightningStrikeEvent; ++import org.bukkit.event.weather.ThunderChangeEvent; ++import org.bukkit.event.weather.WeatherChangeEvent; ++// CraftBukkit end ++ + public class WorldServer extends World implements IAsyncTaskHandler { + + private static final Logger a = LogManager.getLogger(); +@@ -37,14 +51,21 @@ + private static final List U = Lists.newArrayList(new StructurePieceTreasure[] { new StructurePieceTreasure(Items.STICK, 0, 1, 3, 10), new StructurePieceTreasure(Item.getItemOf(Blocks.PLANKS), 0, 1, 3, 10), new StructurePieceTreasure(Item.getItemOf(Blocks.LOG), 0, 1, 3, 10), new StructurePieceTreasure(Items.STONE_AXE, 0, 1, 1, 3), new StructurePieceTreasure(Items.WOODEN_AXE, 0, 1, 1, 5), new StructurePieceTreasure(Items.STONE_PICKAXE, 0, 1, 1, 3), new StructurePieceTreasure(Items.WOODEN_PICKAXE, 0, 1, 1, 5), new StructurePieceTreasure(Items.APPLE, 0, 2, 3, 5), new StructurePieceTreasure(Items.BREAD, 0, 2, 3, 3), new StructurePieceTreasure(Item.getItemOf(Blocks.LOG2), 0, 1, 3, 10)}); + private List V = Lists.newArrayList(); + +- public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, WorldData worlddata, int i, MethodProfiler methodprofiler) { +- super(idatamanager, worlddata, WorldProvider.byDimension(i), methodprofiler, false); ++ // CraftBukkit start ++ public final int dimension; ++ ++ // Add env and gen to constructor ++ public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, WorldData worlddata, int i, MethodProfiler methodprofiler, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { ++ super(idatamanager, worlddata, WorldProvider.byDimension(env.getId()), methodprofiler, false, gen, env); ++ this.dimension = i; ++ this.pvpMode = minecraftserver.getPVP(); ++ // CraftBukkit end + this.server = minecraftserver; + this.tracker = new EntityTracker(this); + this.manager = new PlayerChunkMap(this); + this.worldProvider.a(this); + this.chunkProvider = this.k(); +- this.Q = new PortalTravelAgent(this); ++ this.Q = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit + this.B(); + this.C(); + this.af().a(minecraftserver.aG()); +@@ -86,6 +107,89 @@ + + return this; + } ++ ++ // CraftBukkit start ++ @Override ++ public TileEntity getTileEntity(BlockPosition pos) { ++ TileEntity result = super.getTileEntity(pos); ++ Block type = getType(pos).getBlock(); ++ ++ if (type == Blocks.CHEST) { ++ if (!(result instanceof TileEntityChest)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.FURNACE) { ++ if (!(result instanceof TileEntityFurnace)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.DROPPER) { ++ if (!(result instanceof TileEntityDropper)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.DISPENSER) { ++ if (!(result instanceof TileEntityDispenser)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.JUKEBOX) { ++ if (!(result instanceof TileEntityRecordPlayer)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.NOTEBLOCK) { ++ if (!(result instanceof TileEntityNote)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.MOB_SPAWNER) { ++ if (!(result instanceof TileEntityMobSpawner)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if ((type == Blocks.STANDING_SIGN) || (type == Blocks.WALL_SIGN)) { ++ if (!(result instanceof TileEntitySign)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.ENDER_CHEST) { ++ if (!(result instanceof TileEntityEnderChest)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.BREWING_STAND) { ++ if (!(result instanceof TileEntityBrewingStand)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.BEACON) { ++ if (!(result instanceof TileEntityBeacon)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } else if (type == Blocks.HOPPER) { ++ if (!(result instanceof TileEntityHopper)) { ++ result = fixTileEntity(pos, type, result); ++ } ++ } ++ ++ return result; ++ } ++ ++ private TileEntity fixTileEntity(BlockPosition pos, Block type, TileEntity found) { ++ this.getServer().getLogger().log(Level.SEVERE, "Block at {0},{1},{2} is {3} but has {4}" + ". " ++ + "Bukkit will attempt to fix this, but there may be additional damage that we cannot recover.", new Object[]{pos.getX(), pos.getY(), pos.getZ(), org.bukkit.Material.getMaterial(Block.getId(type)).toString(), found}); ++ ++ if (type instanceof IContainer) { ++ TileEntity replacement = ((IContainer) type).a(this, type.toLegacyData(this.getType(pos))); ++ replacement.world = this; ++ this.setTileEntity(pos, replacement); ++ return replacement; ++ } else { ++ this.getServer().getLogger().severe("Don't know how to fix for this type... Can't do anything! :("); ++ return found; ++ } ++ } ++ ++ private boolean canSpawn(int x, int z) { ++ if (this.generator != null) { ++ return this.generator.canSpawn(this.getWorld(), x, z); ++ } else { ++ return this.worldProvider.canSpawn(x, z); ++ } ++ } ++ // CraftBukkit end + + public void doTick() { + super.doTick(); +@@ -105,8 +209,11 @@ + } + + this.methodProfiler.a("mobSpawner"); +- if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) { +- this.R.a(this, this.allowMonsters, this.allowAnimals, this.worldData.getTime() % 400L == 0L); ++ // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals ++ long time = this.worldData.getTime(); ++ if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES && (this.allowMonsters || this.allowAnimals) && (this instanceof WorldServer && this.players.size() > 0)) { ++ this.R.a(this, this.allowMonsters && (this.ticksPerMonsterSpawns != 0 && time % this.ticksPerMonsterSpawns == 0L), this.allowAnimals && (this.ticksPerAnimalSpawns != 0 && time % this.ticksPerAnimalSpawns == 0L), this.worldData.getTime() % 400L == 0L); ++ // CraftBukkit end + } + + this.methodProfiler.c("chunkSource"); +@@ -135,6 +242,8 @@ + this.Q.a(this.getTime()); + this.methodProfiler.b(); + this.ak(); ++ ++ this.getWorld().processChunkGC(); // CraftBukkit + } + + public BiomeMeta a(EnumCreatureType enumcreaturetype, BlockPosition blockposition) { +@@ -161,7 +270,7 @@ + + if (entityhuman.v()) { + ++i; +- } else if (entityhuman.isSleeping()) { ++ } else if (entityhuman.isSleeping() || entityhuman.fauxSleeping) { // CraftBukkit + ++j; + } + } +@@ -187,26 +296,45 @@ + } + + private void ag() { +- this.worldData.setWeatherDuration(0); +- this.worldData.setStorm(false); +- this.worldData.setThunderDuration(0); +- this.worldData.setThundering(false); ++ // CraftBukkit start ++ WeatherChangeEvent weather = new WeatherChangeEvent(this.getWorld(), false); ++ this.getServer().getPluginManager().callEvent(weather); ++ ++ ThunderChangeEvent thunder = new ThunderChangeEvent(this.getWorld(), false); ++ this.getServer().getPluginManager().callEvent(thunder); ++ if (!weather.isCancelled()) { ++ this.worldData.setWeatherDuration(0); ++ this.worldData.setStorm(false); ++ } ++ if (!thunder.isCancelled()) { ++ this.worldData.setThunderDuration(0); ++ this.worldData.setThundering(false); ++ } ++ // CraftBukkit end + } + + public boolean everyoneDeeplySleeping() { + if (this.O && !this.isStatic) { + Iterator iterator = this.players.iterator(); + ++ // CraftBukkit - This allows us to assume that some people are in bed but not really, allowing time to pass in spite of AFKers ++ boolean foundActualSleepers = false; ++ + EntityHuman entityhuman; + + do { + if (!iterator.hasNext()) { +- return true; ++ return foundActualSleepers; + } + + entityhuman = (EntityHuman) iterator.next(); +- } while (!entityhuman.v() && entityhuman.isDeeplySleeping()); +- ++ // CraftBukkit start ++ if (entityhuman.isDeeplySleeping()) { ++ foundActualSleepers = true; ++ } ++ } while (!entityhuman.v() && (entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping)); ++ // CraftBukkit end ++ + return false; + } else { + return false; +@@ -227,15 +355,22 @@ + } else { + int i = 0; + int j = 0; +- +- for (Iterator iterator1 = this.chunkTickList.iterator(); iterator1.hasNext(); this.methodProfiler.b()) { +- ChunkCoordIntPair chunkcoordintpair1 = (ChunkCoordIntPair) iterator1.next(); +- int k = chunkcoordintpair1.x * 16; +- int l = chunkcoordintpair1.z * 16; +- ++ ++ // CraftBukkit start ++ //for (Iterator iterator1 = this.chunkTickList.iterator(); iterator1.hasNext(); this.methodProfiler.b()) { ++ // ChunkCoordIntPair chunkcoordintpair1 = (ChunkCoordIntPair) iterator1.next(); ++ // int k = chunkcoordintpair1.x * 16; ++ // int l = chunkcoordintpair1.z * 16; ++ for (long chunkCoord : chunkTickList.popAll()) { ++ int chunkX = LongHash.msw(chunkCoord); ++ int chunkZ = LongHash.lsw(chunkCoord); ++ int k = chunkX * 16; ++ int l = chunkZ * 16; ++ + this.methodProfiler.a("getChunk"); +- Chunk chunk = this.getChunkAt(chunkcoordintpair1.x, chunkcoordintpair1.z); +- ++ Chunk chunk = this.getChunkAt(chunkX, chunkZ); ++ // CraftBukkit end ++ + this.a(k, l, chunk); + this.methodProfiler.c("tickChunk"); + chunk.b(false); +@@ -260,11 +395,29 @@ + BlockPosition blockposition1 = blockposition.down(); + + if (this.w(blockposition1)) { +- this.setTypeUpdate(blockposition1, Blocks.ICE.getBlockData()); ++ // CraftBukkit start ++ BlockState blockState = this.getWorld().getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()).getState(); ++ blockState.setTypeId(Block.getId(Blocks.ICE)); ++ ++ BlockFormEvent iceBlockForm = new BlockFormEvent(blockState.getBlock(), blockState); ++ this.getServer().getPluginManager().callEvent(iceBlockForm); ++ if (!iceBlockForm.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } + + if (this.S() && this.f(blockposition, true)) { +- this.setTypeUpdate(blockposition, Blocks.SNOW_LAYER.getBlockData()); ++ // CraftBukkit start ++ BlockState blockState = this.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()).getState(); ++ blockState.setTypeId(Block.getId(Blocks.SNOW_LAYER)); ++ ++ BlockFormEvent snow = new BlockFormEvent(blockState.getBlock(), blockState); ++ this.getServer().getPluginManager().callEvent(snow); ++ if (!snow.isCancelled()) { ++ blockState.update(true); ++ } ++ // CraftBukkit end + } + + if (this.S() && this.getBiome(blockposition1).e()) { +@@ -376,7 +529,7 @@ + } + + public void tickEntities() { +- if (this.players.isEmpty()) { ++ if (false && this.players.isEmpty()) { // CraftBukkit - this prevents entity cleanup, other issues on servers with no players + if (this.emptyTime++ >= 1200) { + return; + } +@@ -401,7 +554,13 @@ + throw new IllegalStateException("TickNextTick list out of synch"); + } else { + if (i > 1000) { +- i = 1000; ++ // CraftBukkit start - If the server has too much to process over time, try to alleviate that ++ if (i > 20 * 1000) { ++ i = i / 20; ++ } else { ++ i = 1000; ++ } ++ // CraftBukkit end + } + + this.methodProfiler.a("cleaning"); +@@ -501,6 +660,7 @@ + return arraylist; + } + ++ /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed + public void entityJoinedWorld(Entity entity, boolean flag) { + if (!this.getSpawnAnimals() && (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal)) { + entity.die(); +@@ -511,7 +671,9 @@ + } + + super.entityJoinedWorld(entity, flag); ++ + } ++ // CraftBukkit end */ + + private boolean getSpawnNPCs() { + return this.server.getSpawnNPCs(); +@@ -523,14 +685,44 @@ + + protected IChunkProvider k() { + IChunkLoader ichunkloader = this.dataManager.createChunkLoader(this.worldProvider); ++ ++ // CraftBukkit start ++ org.bukkit.craftbukkit.generator.InternalChunkGenerator gen; ++ ++ if (this.generator != null) { ++ gen = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, this.getSeed(), this.generator); ++ } else if (this.worldProvider instanceof WorldProviderHell) { ++ gen = new org.bukkit.craftbukkit.generator.NetherChunkGenerator(this, this.getSeed()); ++ } else if (this.worldProvider instanceof WorldProviderTheEnd) { ++ gen = new org.bukkit.craftbukkit.generator.SkyLandsChunkGenerator(this, this.getSeed()); ++ } else { ++ gen = new org.bukkit.craftbukkit.generator.NormalChunkGenerator(this, this.getSeed()); ++ } + +- this.chunkProviderServer = new ChunkProviderServer(this, ichunkloader, this.worldProvider.getChunkProvider()); ++ this.chunkProviderServer = new ChunkProviderServer(this, ichunkloader, gen); ++ // CraftBukkit end + return this.chunkProviderServer; + } + + public List getTileEntities(int i, int j, int k, int l, int i1, int j1) { + ArrayList arraylist = Lists.newArrayList(); +- ++ ++ // CraftBukkit start - Get tile entities from chunks instead of world ++ for (int chunkX = (i >> 4); chunkX <= ((l - 1) >> 4); chunkX++) { ++ for (int chunkZ = (k >> 4); chunkZ <= ((j1 - 1) >> 4); chunkZ++) { ++ Chunk chunk = getChunkAt(chunkX, chunkZ); ++ if (chunk == null) { ++ continue; ++ } ++ for (Object te : chunk.tileEntities.values()) { ++ TileEntity tileentity = (TileEntity) te; ++ if ((tileentity.position.getX() >= i) && (tileentity.position.getY() >= j) && (tileentity.position.getZ() >= k) && (tileentity.position.getX() < l) && (tileentity.position.getY() < i1) && (tileentity.position.getZ() < j1)) { ++ arraylist.add(tileentity); ++ } ++ } ++ } ++ } ++ /* + for (int k1 = 0; k1 < this.h.size(); ++k1) { + TileEntity tileentity = (TileEntity) this.h.get(k1); + BlockPosition blockposition = tileentity.getPosition(); +@@ -539,6 +731,8 @@ + arraylist.add(tileentity); + } + } ++ */ ++ // CraftBukkit end + + return arraylist; + } +@@ -601,6 +795,23 @@ + int i = 0; + int j = this.worldProvider.getSeaLevel(); + int k = 0; ++ ++ // CraftBukkit start ++ if (this.generator != null) { ++ Random rand = new Random(this.getSeed()); ++ org.bukkit.Location spawn = this.generator.getFixedSpawnLocation(((WorldServer) this).getWorld(), rand); ++ ++ if (spawn != null) { ++ if (spawn.getWorld() != ((WorldServer) this).getWorld()) { ++ throw new IllegalStateException("Cannot set spawn point for " + this.worldData.getName() + " to be in another world (" + spawn.getWorld().getName() + ")"); ++ } else { ++ this.worldData.setSpawn(new BlockPosition(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ())); ++ this.isLoading = false; ++ return; ++ } ++ } ++ } ++ // CraftBukkit end + + if (blockposition != null) { + i = blockposition.getX(); +@@ -611,7 +822,7 @@ + + int l = 0; + +- while (!this.worldProvider.canSpawn(i, k)) { ++ while (!this.canSpawn(i, k)) { // CraftBukkit - use our own canSpawn + i += random.nextInt(64) - random.nextInt(64); + k += random.nextInt(64) - random.nextInt(64); + ++l; +@@ -648,7 +859,7 @@ + return this.worldProvider.h(); + } + +- public void save(boolean flag, IProgressUpdate iprogressupdate) { ++ public void save(boolean flag, IProgressUpdate iprogressupdate) throws ExceptionWorldConflict { // CraftBukkit - added throws + if (this.chunkProvider.canSave()) { + if (iprogressupdate != null) { + iprogressupdate.a("Saving level"); +@@ -660,7 +871,8 @@ + } + + this.chunkProvider.saveChunks(flag, iprogressupdate); +- List list = this.chunkProviderServer.a(); ++ // CraftBukkit - ArrayList -> Collection ++ Collection list = this.chunkProviderServer.a(); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { +@@ -680,7 +892,7 @@ + } + } + +- protected void a() { ++ protected void a() throws ExceptionWorldConflict { // CraftBukkit - added throws + this.checkSession(); + this.worldData.a(this.af().h()); + this.worldData.d(this.af().f()); +@@ -692,7 +904,11 @@ + this.worldData.b(this.af().j()); + this.worldData.e(this.af().i()); + this.dataManager.saveWorldData(this.worldData, this.server.getPlayerList().u()); +- this.worldMaps.a(); ++ // CraftBukkit start - save worldMaps once, rather than once per shared world ++ if (!(this instanceof SecondaryWorldServer)) { ++ this.worldMaps.a(); ++ } ++ // CraftBukkit end + } + + protected void a(Entity entity) { +@@ -724,8 +940,16 @@ + } + + public boolean strikeLightning(Entity entity) { ++ // CraftBukkit start ++ LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entity.getBukkitEntity()); ++ this.getServer().getPluginManager().callEvent(lightning); ++ ++ if (lightning.isCancelled()) { ++ return false; ++ } + if (super.strikeLightning(entity)) { +- this.server.getPlayerList().sendPacketNearby(entity.locX, entity.locY, entity.locZ, 512.0D, this.worldProvider.getDimension(), new PacketPlayOutSpawnEntityWeather(entity)); ++ this.server.getPlayerList().sendPacketNearby(entity.locX, entity.locY, entity.locZ, 512.0D, this.dimension, new PacketPlayOutSpawnEntityWeather(entity)); ++ // CraftBukkit end + return true; + } else { + return false; +@@ -737,10 +961,20 @@ + } + + public Explosion createExplosion(Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) { ++ // CraftBukkit start ++ Explosion explosion = super.createExplosion(entity, d0, d1, d2, f, flag, flag1); ++ ++ if (explosion.wasCanceled) { ++ return explosion; ++ } ++ ++ /* Remove + Explosion explosion = new Explosion(this, entity, d0, d1, d2, f, flag, flag1); + + explosion.a(); + explosion.a(false); ++ */ ++ // CraftBukkit end - TODO: Check if explosions are still properly implemented + if (!flag1) { + explosion.clearBlocks(); + } +@@ -786,7 +1020,8 @@ + BlockActionData blockactiondata = (BlockActionData) iterator.next(); + + if (this.a(blockactiondata)) { +- this.server.getPlayerList().sendPacketNearby((double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, this.worldProvider.getDimension(), new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.d(), blockactiondata.b(), blockactiondata.c())); ++ // CraftBukkit - this.worldProvider.dimension -> this.dimension ++ this.server.getPlayerList().sendPacketNearby((double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, this.dimension, new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.d(), blockactiondata.b(), blockactiondata.c())); + } + } + +@@ -809,6 +1044,7 @@ + boolean flag = this.S(); + + super.p(); ++ /* CraftBukkit start + if (this.o != this.p) { + this.server.getPlayerList().a(new PacketPlayOutGameStateChange(7, this.p), this.worldProvider.getDimension()); + } +@@ -827,6 +1063,16 @@ + this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(7, this.p)); + this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(8, this.r)); + } ++ // */ ++ if (flag != this.S()) { ++ // Only send weather packets to those affected ++ for (int i = 0; i < this.players.size(); ++i) { ++ if (((EntityPlayer) this.players.get(i)).world == this) { ++ ((EntityPlayer) this.players.get(i)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); ++ } ++ } ++ // CraftBukkit end ++ } + + } + +@@ -855,10 +1101,17 @@ + } + + public void a(EnumParticle enumparticle, boolean flag, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, int... aint) { ++ // CraftBukkit - visibility api support ++ sendParticles(null, enumparticle, flag, d0, d1, d2, i, d3, d4, d5, d6, aint); ++ } ++ ++ public void sendParticles(EntityPlayer sender, EnumParticle enumparticle, boolean flag, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, int... aint) { ++ // CraftBukkit end + PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(enumparticle, flag, (float) d0, (float) d1, (float) d2, (float) d3, (float) d4, (float) d5, (float) d6, i, aint); + + for (int j = 0; j < this.players.size(); ++j) { + EntityPlayer entityplayer = (EntityPlayer) this.players.get(j); ++ if (sender != null && !sender.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) continue; // CraftBukkit + BlockPosition blockposition = entityplayer.getChunkCoordinates(); + double d7 = blockposition.c(d0, d1, d2); + diff --git a/paper-server/pom.xml b/paper-server/pom.xml index 8dc82eb7e1..e2d4c7de43 100644 --- a/paper-server/pom.xml +++ b/paper-server/pom.xml @@ -4,7 +4,7 @@ org.bukkit craftbukkit jar - 1.7.10-R0.1-SNAPSHOT + 1.8-R0.1-SNAPSHOT CraftBukkit http://www.bukkit.org @@ -12,31 +12,12 @@ UTF-8 unknown 4.11 - 1.7.10 - 1_7_R4 + 1.8 + 1_8_R1 git-Bukkit- - - scm:git:git://github.com/Bukkit/CraftBukkit.git - scm:git:ssh://git@github.com/Bukkit/CraftBukkit.git - https://github.com/Bukkit/CraftBukkit - - - - - repobo-rel - repo.bukkit.org Releases - http://repo.bukkit.org/content/repositories/releases/ - - - repobo-snap - repo.bukkit.org Snapshots - http://repo.bukkit.org/content/repositories/snapshots/ - - - repobo-snap @@ -60,9 +41,9 @@ compile - org.bukkit + org.spigotmc minecraft-server - ${minecraft.version} + ${minecraft.version}-SNAPSHOT jar compile @@ -124,7 +105,7 @@ com.google.guava guava - 10.0 + 17.0 jar provided diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftArt.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftArt.java index f617e9e2ea..dd4dc541be 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftArt.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftArt.java @@ -11,7 +11,7 @@ public class CraftArt { case KEBAB: return Art.KEBAB; case AZTEC: return Art.AZTEC; case ALBAN: return Art.ALBAN; - case AZTEC2: return Art.AZTEC2; + case AZTEC_2: return Art.AZTEC2; case BOMB: return Art.BOMB; case PLANT: return Art.PLANT; case WASTELAND: return Art.WASTELAND; @@ -30,9 +30,9 @@ public class CraftArt { case FIGHTERS: return Art.FIGHTERS; case POINTER: return Art.POINTER; case PIGSCENE: return Art.PIGSCENE; - case BURNINGSKULL: return Art.BURNINGSKULL; + case BURNING_SKULL: return Art.BURNINGSKULL; case SKELETON: return Art.SKELETON; - case DONKEYKONG: return Art.DONKEYKONG; + case DONKEY_KONG: return Art.DONKEYKONG; case WITHER: return Art.WITHER; default: throw new AssertionError(art); @@ -44,7 +44,7 @@ public class CraftArt { case KEBAB: return EnumArt.KEBAB; case AZTEC: return EnumArt.AZTEC; case ALBAN: return EnumArt.ALBAN; - case AZTEC2: return EnumArt.AZTEC2; + case AZTEC2: return EnumArt.AZTEC_2; case BOMB: return EnumArt.BOMB; case PLANT: return EnumArt.PLANT; case WASTELAND: return EnumArt.WASTELAND; @@ -63,9 +63,9 @@ public class CraftArt { case FIGHTERS: return EnumArt.FIGHTERS; case POINTER: return EnumArt.POINTER; case PIGSCENE: return EnumArt.PIGSCENE; - case BURNINGSKULL: return EnumArt.BURNINGSKULL; + case BURNINGSKULL: return EnumArt.BURNING_SKULL; case SKELETON: return EnumArt.SKELETON; - case DONKEYKONG: return EnumArt.DONKEYKONG; + case DONKEYKONG: return EnumArt.DONKEY_KONG; case WITHER: return EnumArt.WITHER; default: throw new AssertionError(art); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index 99d3d40f79..0cba7fd99d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -3,12 +3,7 @@ package org.bukkit.craftbukkit; import java.lang.ref.WeakReference; import java.util.Arrays; -import net.minecraft.server.BiomeBase; -import net.minecraft.server.ChunkPosition; -import net.minecraft.server.ChunkSection; -import net.minecraft.server.EmptyChunk; -import net.minecraft.server.WorldChunkManager; -import net.minecraft.server.WorldServer; +import net.minecraft.server.*; import org.bukkit.Chunk; import org.bukkit.World; @@ -91,6 +86,7 @@ public class CraftChunk implements Chunk { Entity[] entities = new Entity[count]; for (int i = 0; i < 16; i++) { + for (Object obj : chunk.entitySlices[i].toArray()) { if (!(obj instanceof net.minecraft.server.Entity)) { continue; @@ -106,15 +102,16 @@ public class CraftChunk implements Chunk { public BlockState[] getTileEntities() { int index = 0; net.minecraft.server.Chunk chunk = getHandle(); + BlockState[] entities = new BlockState[chunk.tileEntities.size()]; for (Object obj : chunk.tileEntities.keySet().toArray()) { - if (!(obj instanceof ChunkPosition)) { + if (!(obj instanceof BlockPosition)) { continue; } - ChunkPosition position = (ChunkPosition) obj; - entities[index++] = worldServer.getWorld().getBlockAt(position.x + (chunk.locX << 4), position.y, position.z + (chunk.locZ << 4)).getState(); + BlockPosition position = (BlockPosition) obj; + entities[index++] = worldServer.getWorld().getBlockAt(position.getX() + (chunk.locX << 4), position.getY(), position.getZ() + (chunk.locZ << 4)).getState(); } return entities; } @@ -158,49 +155,40 @@ public class CraftChunk implements Chunk { boolean[] sectionEmpty = new boolean[cs.length]; for (int i = 0; i < cs.length; i++) { - if (cs[i] == null) { /* Section is empty? */ + if (cs[i] == null) { // Section is empty? sectionBlockIDs[i] = emptyBlockIDs; sectionBlockData[i] = emptyData; sectionSkyLights[i] = emptySkyLight; sectionEmitLights[i] = emptyData; sectionEmpty[i] = true; - } else { /* Not empty */ + } else { // Not empty short[] blockids = new short[4096]; - byte[] baseids = cs[i].getIdArray(); + char[] baseids = cs[i].getIdArray(); + byte[] dataValues = sectionBlockData[i] = new byte[2048]; - /* Copy base IDs */ + // Copy base IDs for (int j = 0; j < 4096; j++) { - blockids[j] = (short) (baseids[j] & 0xFF); - } - - if (cs[i].getExtendedIdArray() != null) { /* If we've got extended IDs */ - byte[] extids = cs[i].getExtendedIdArray().a; - - for (int j = 0; j < 2048; j++) { - short b = (short) (extids[j] & 0xFF); - - if (b == 0) { - continue; - } - - blockids[j<<1] |= (b & 0x0F) << 8; - blockids[(j<<1)+1] |= (b & 0xF0) << 4; + IBlockData blockData = net.minecraft.server.Block.getByCombinedId(baseids[j]); + blockids[j] = (short) net.minecraft.server.Block.getId(blockData.getBlock()); + int data = blockData.getBlock().toLegacyData(blockData); + int jj = j >> 1; + if ((j & 1) == 0) { + dataValues[jj] = (byte) ((dataValues[jj] & 0xF0) | (data & 0xF)); + } else { + dataValues[jj] = (byte) ((dataValues[jj] & 0xF) | ((data & 0xF) << 4)); } - } + } sectionBlockIDs[i] = blockids; - - /* Get block data nibbles */ - sectionBlockData[i] = new byte[2048]; - System.arraycopy(cs[i].getDataArray().a, 0, sectionBlockData[i], 0, 2048); + if (cs[i].getSkyLightArray() == null) { sectionSkyLights[i] = emptyData; } else { sectionSkyLights[i] = new byte[2048]; - System.arraycopy(cs[i].getSkyLightArray().a, 0, sectionSkyLights[i], 0, 2048); + System.arraycopy(cs[i].getSkyLightArray().a(), 0, sectionSkyLights[i], 0, 2048); } sectionEmitLights[i] = new byte[2048]; - System.arraycopy(cs[i].getEmittedLightArray().a, 0, sectionEmitLights[i], 0, 2048); + System.arraycopy(cs[i].getEmittedLightArray().a(), 0, sectionEmitLights[i], 0, 2048); } } @@ -221,7 +209,7 @@ public class CraftChunk implements Chunk { if (includeBiome) { biome = new BiomeBase[256]; for (int i = 0; i < 256; i++) { - biome[i] = chunk.getBiome(i & 0xF, i >> 4, wcm); + biome[i] = chunk.getBiome(new BlockPosition(i & 0xF, 0, i >> 4), wcm); } } @@ -257,7 +245,7 @@ public class CraftChunk implements Chunk { if (includeBiome) { biome = new BiomeBase[256]; for (int i = 0; i < 256; i++) { - biome[i] = world.getHandle().getBiome((x << 4) + (i & 0xF), (z << 4) + (i >> 4)); + biome[i] = world.getHandle().getBiome(new BlockPosition((x << 4) + (i & 0xF), 0, (z << 4) + (i >> 4))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java index 1328c175ec..8be0698476 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit; +import com.mojang.authlib.GameProfile; import java.io.File; import java.util.LinkedHashMap; import java.util.List; @@ -10,7 +11,6 @@ import net.minecraft.server.EntityPlayer; import net.minecraft.server.NBTTagCompound; import net.minecraft.server.WorldNBTStorage; -import net.minecraft.util.com.mojang.authlib.GameProfile; import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.Location; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanEntry.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanEntry.java index 7ec0006887..9540bf4fb3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanEntry.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanEntry.java @@ -1,9 +1,9 @@ package org.bukkit.craftbukkit; +import com.mojang.authlib.GameProfile; import net.minecraft.server.GameProfileBanEntry; import net.minecraft.server.GameProfileBanList; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.com.mojang.authlib.GameProfile; import java.io.IOException; import java.util.Date; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanList.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanList.java index fad6a9655d..700c9f7c2e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanList.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftProfileBanList.java @@ -8,12 +8,12 @@ import net.minecraft.server.GameProfileBanEntry; import net.minecraft.server.GameProfileBanList; import net.minecraft.server.JsonListEntry; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.com.mojang.authlib.GameProfile; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import com.google.common.collect.ImmutableSet; +import com.mojang.authlib.GameProfile; public class CraftProfileBanList implements org.bukkit.BanList { private final GameProfileBanList list; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index a666131f99..f2a78c1757 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -23,83 +23,7 @@ import java.util.regex.Pattern; import javax.imageio.ImageIO; -import net.minecraft.server.ChunkCoordinates; -import net.minecraft.server.CommandAchievement; -import net.minecraft.server.CommandBan; -import net.minecraft.server.CommandBanIp; -import net.minecraft.server.CommandBanList; -import net.minecraft.server.CommandClear; -import net.minecraft.server.CommandDeop; -import net.minecraft.server.CommandDifficulty; -import net.minecraft.server.CommandEffect; -import net.minecraft.server.CommandEnchant; -import net.minecraft.server.CommandGamemode; -import net.minecraft.server.CommandGamemodeDefault; -import net.minecraft.server.CommandGamerule; -import net.minecraft.server.CommandGive; -import net.minecraft.server.CommandHelp; -import net.minecraft.server.CommandIdleTimeout; -import net.minecraft.server.CommandKick; -import net.minecraft.server.CommandKill; -import net.minecraft.server.CommandList; -import net.minecraft.server.CommandMe; -import net.minecraft.server.CommandNetstat; -import net.minecraft.server.CommandOp; -import net.minecraft.server.CommandPardon; -import net.minecraft.server.CommandPardonIP; -import net.minecraft.server.CommandPlaySound; -import net.minecraft.server.CommandSay; -import net.minecraft.server.CommandScoreboard; -import net.minecraft.server.CommandSeed; -import net.minecraft.server.CommandSetBlock; -import net.minecraft.server.CommandSetWorldSpawn; -import net.minecraft.server.CommandSpawnpoint; -import net.minecraft.server.CommandSpreadPlayers; -import net.minecraft.server.CommandSummon; -import net.minecraft.server.CommandTell; -import net.minecraft.server.CommandTellRaw; -import net.minecraft.server.CommandTestFor; -import net.minecraft.server.CommandTestForBlock; -import net.minecraft.server.CommandTime; -import net.minecraft.server.CommandToggleDownfall; -import net.minecraft.server.CommandTp; -import net.minecraft.server.CommandWeather; -import net.minecraft.server.CommandWhitelist; -import net.minecraft.server.CommandXp; -import net.minecraft.server.Convertable; -import net.minecraft.server.ConvertProgressUpdater; -import net.minecraft.server.CraftingManager; -import net.minecraft.server.DedicatedPlayerList; -import net.minecraft.server.DedicatedServer; -import net.minecraft.server.Enchantment; -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.EntityTracker; -import net.minecraft.server.EnumDifficulty; -import net.minecraft.server.EnumGamemode; -import net.minecraft.server.ExceptionWorldConflict; -import net.minecraft.server.Items; -import net.minecraft.server.JsonListEntry; -import net.minecraft.server.PlayerList; -import net.minecraft.server.RecipesFurnace; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.MobEffectList; -import net.minecraft.server.PropertyManager; -import net.minecraft.server.ServerCommand; -import net.minecraft.server.ServerNBTManager; -import net.minecraft.server.WorldLoaderServer; -import net.minecraft.server.WorldManager; -import net.minecraft.server.WorldMap; -import net.minecraft.server.PersistentCollection; -import net.minecraft.server.WorldNBTStorage; -import net.minecraft.server.WorldServer; -import net.minecraft.server.WorldSettings; -import net.minecraft.server.WorldType; -import net.minecraft.util.com.google.common.base.Charsets; -import net.minecraft.util.com.mojang.authlib.GameProfile; -import net.minecraft.util.io.netty.buffer.ByteBuf; -import net.minecraft.util.io.netty.buffer.ByteBufOutputStream; -import net.minecraft.util.io.netty.buffer.Unpooled; -import net.minecraft.util.io.netty.handler.codec.base64.Base64; +import net.minecraft.server.*; import org.bukkit.BanList; import org.bukkit.Bukkit; @@ -139,8 +63,6 @@ import org.bukkit.craftbukkit.metadata.WorldMetadataStore; import org.bukkit.craftbukkit.potion.CraftPotionBrewer; import org.bukkit.craftbukkit.scheduler.CraftScheduler; import org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager; -import org.bukkit.craftbukkit.updater.AutoUpdater; -import org.bukkit.craftbukkit.updater.BukkitDLUpdaterService; import org.bukkit.craftbukkit.util.CraftIconCache; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.DatFileFilter; @@ -186,8 +108,16 @@ import com.avaje.ebean.config.DataSourceConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.SQLitePlatform; import com.avaje.ebeaninternal.server.lib.sql.TransactionIsolation; +import com.google.common.base.Charsets; +import com.google.common.base.Function; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import com.google.common.collect.MapMaker; +import com.mojang.authlib.GameProfile; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.base64.Base64; import jline.console.ConsoleReader; @@ -210,7 +140,6 @@ public final class CraftServer implements Server { private YamlConfiguration commandsConfiguration; private final Yaml yaml = new Yaml(new SafeConstructor()); private final Map offlinePlayers = new MapMaker().softValues().makeMap(); - private final AutoUpdater updater; private final EntityMetadataStore entityMetadata = new EntityMetadataStore(); private final PlayerMetadataStore playerMetadata = new PlayerMetadataStore(); private final WorldMetadataStore worldMetadata = new WorldMetadataStore(); @@ -244,7 +173,7 @@ public final class CraftServer implements Server { public CraftServer(MinecraftServer console, PlayerList playerList) { this.console = console; this.playerList = (DedicatedPlayerList) playerList; - this.playerView = Collections.unmodifiableList(net.minecraft.util.com.google.common.collect.Lists.transform(playerList.players, new net.minecraft.util.com.google.common.base.Function() { + this.playerView = Collections.unmodifiableList(Lists.transform(playerList.players, new Function() { @Override public CraftPlayer apply(EntityPlayer player) { return player.getBukkitEntity(); @@ -316,13 +245,6 @@ public final class CraftServer implements Server { chunkGCLoadThresh = configuration.getInt("chunk-gc.load-threshold"); loadIcon(); - updater = new AutoUpdater(new BukkitDLUpdaterService(configuration.getString("auto-updater.host")), getLogger(), configuration.getString("auto-updater.preferred-channel")); - updater.setEnabled(configuration.getBoolean("auto-updater.enabled")); - updater.setSuggestChannels(configuration.getBoolean("auto-updater.suggest-channels")); - updater.getOnBroken().addAll(configuration.getStringList("auto-updater.on-broken")); - updater.getOnUpdate().addAll(configuration.getStringList("auto-updater.on-update")); - updater.check(serverVersion); - loadPlugins(); enablePlugins(PluginLoadOrder.STARTUP); } @@ -405,49 +327,10 @@ public final class CraftServer implements Server { } private void setVanillaCommands() { - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandAchievement(), "/achievement give [player]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandBan(), "/ban [reason]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandBanIp(), "/ban-ip ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandBanList(), "/banlist [ips]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandClear(), "/clear [item] [metadata]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandGamemodeDefault(), "/defaultgamemode ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandDeop(), "/deop ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandDifficulty(), "/difficulty ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandEffect(), "/effect [seconds] [amplifier]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandEnchant(), "/enchant [enchantment level]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandGamemode(), "/gamemode [player]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandGamerule(), "/gamerule [true|false]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandGive(), "/give [amount] [metadata] [dataTag]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandHelp(), "/help [page|commandname]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandIdleTimeout(), "/setidletimeout ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandKick(), "/kick [reason]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandKill(), "/kill [playername]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandList(), "/list")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandMe(), "/me ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandOp(), "/op ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandPardon(), "/pardon ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandPardonIP(), "/pardon-ip ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandPlaySound(), "/playsound [x] [y] [z] [volume] [pitch] [minimumVolume]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSay(), "/say ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandScoreboard(), "/scoreboard")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSeed(), "/seed")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSetBlock(), "/setblock [datavalue] [oldblockHandling] [dataTag]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSetWorldSpawn(), "/setworldspawn [x] [y] [z]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSpawnpoint(), "/spawnpoint [x] [y] [z]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSpreadPlayers(), "/spreadplayers [spreadDistance] [maxRange] [respectTeams] ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandSummon(), "/summon [x] [y] [z] [dataTag]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandTp(), "/tp [player] \n/tp [player] ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandTell(), "/tell ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandTellRaw(), "/tellraw ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandTestFor(), "/testfor [dataTag]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandTestForBlock(), "/testforblock [datavalue] [dataTag]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandTime(), "/time set \n/time add ")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandToggleDownfall(), "/toggledownfall")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandWeather(), "/weather [duration in seconds]")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandWhitelist(), "/whitelist (add|remove) \n/whitelist (on|off|list|reload)")); - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandXp(), "/xp [player]\n/xp L [player]")); - // This is what is in the lang file, I swear. - commandMap.register("minecraft", new VanillaCommandWrapper(new CommandNetstat(), "/list")); + Map commands = new CommandDispatcher().getCommands(); + for (ICommand cmd : commands.values()) { + commandMap.register("minecraft", new VanillaCommandWrapper((CommandAbstract) cmd, LocaleI18n.get(cmd.getUsage(null)))); + } } private void loadPlugin(Plugin plugin) { @@ -550,7 +433,7 @@ public final class CraftServer implements Server { } public Player getPlayer(final EntityPlayer entity) { - return entity.playerConnection.getPlayer(); + return entity.getBukkitEntity(); } @Override @@ -759,12 +642,12 @@ public final class CraftServer implements Server { ((DedicatedServer) console).propertyManager = config; boolean animals = config.getBoolean("spawn-animals", console.getSpawnAnimals()); - boolean monsters = config.getBoolean("spawn-monsters", console.worlds.get(0).difficulty != EnumDifficulty.PEACEFUL); - EnumDifficulty difficulty = EnumDifficulty.getById(config.getInt("difficulty", console.worlds.get(0).difficulty.ordinal())); + boolean monsters = config.getBoolean("spawn-monsters", console.worlds.get(0).getDifficulty() != EnumDifficulty.PEACEFUL); + EnumDifficulty difficulty = EnumDifficulty.getById(config.getInt("difficulty", console.worlds.get(0).getDifficulty().ordinal())); online.value = config.getBoolean("online-mode", console.getOnlineMode()); console.setSpawnAnimals(config.getBoolean("spawn-animals", console.getSpawnAnimals())); - console.setPvP(config.getBoolean("pvp", console.getPvP())); + console.setPVP(config.getBoolean("pvp", console.getPVP())); console.setAllowFlight(config.getBoolean("allow-flight", console.getAllowFlight())); console.setMotd(config.getString("motd", console.getMotd())); monsterSpawn = configuration.getInt("spawn-limits.monsters"); @@ -790,7 +673,7 @@ public final class CraftServer implements Server { } for (WorldServer world : console.worlds) { - world.difficulty = difficulty; + world.worldData.setDifficulty(difficulty); world.setSpawnFlags(monsters, animals); if (this.getTicksPerAnimalSpawns() < 0) { world.ticksPerAnimalSpawns = 400; @@ -961,7 +844,8 @@ public final class CraftServer implements Server { } while(used); boolean hardcore = false; - WorldServer internal = new WorldServer(console, new ServerNBTManager(getWorldContainer(), name, true), name, dimension, new WorldSettings(creator.seed(), EnumGamemode.getById(getDefaultGameMode().getValue()), generateStructures, hardcore, type), console.methodProfiler, creator.environment(), generator); + WorldData worlddata = new WorldData(new WorldSettings(creator.seed(), EnumGamemode.getById(getDefaultGameMode().getValue()), generateStructures, hardcore, type), name); + WorldServer internal = (WorldServer) new WorldServer(console, new ServerNBTManager(getWorldContainer(), name, true), worlddata, dimension, console.methodProfiler, creator.environment(), generator).b(); if (!(worlds.containsKey(name.toLowerCase()))) { return null; @@ -971,7 +855,7 @@ public final class CraftServer implements Server { internal.tracker = new EntityTracker(internal); internal.addIWorldAccess(new WorldManager(console, internal)); - internal.difficulty = EnumDifficulty.EASY; + internal.worldData.setDifficulty(EnumDifficulty.EASY); internal.setSpawnFlags(true, true); console.worlds.add(internal); @@ -1001,8 +885,8 @@ public final class CraftServer implements Server { i = l; } - ChunkCoordinates chunkcoordinates = internal.getSpawn(); - internal.chunkProviderServer.getChunkAt(chunkcoordinates.x + j >> 4, chunkcoordinates.z + k >> 4); + BlockPosition chunkcoordinates = internal.getSpawn(); + internal.chunkProviderServer.getChunkAt(chunkcoordinates.getX() + j >> 4, chunkcoordinates.getZ() + k >> 4); } } } @@ -1055,7 +939,6 @@ public final class CraftServer implements Server { worlds.remove(world.getName().toLowerCase()); console.worlds.remove(console.worlds.indexOf(handle)); - return true; } @@ -1312,7 +1195,7 @@ public final class CraftServer implements Server { Validate.notNull(world, "World cannot be null"); net.minecraft.server.ItemStack stack = new net.minecraft.server.ItemStack(Items.MAP, 1, -1); - WorldMap worldmap = Items.MAP.getSavedMap(stack, ((CraftWorld) world).getHandle()); + WorldMap worldmap = Items.FILLED_MAP.getSavedMap(stack, ((CraftWorld) world).getHandle()); return worldmap.mapView; } @@ -1415,7 +1298,7 @@ public final class CraftServer implements Server { for (JsonListEntry entry : playerList.getProfileBans().getValues()) { result.add(getOfflinePlayer((GameProfile) entry.getKey())); - } + } return result; } @@ -1497,27 +1380,6 @@ public final class CraftServer implements Server { return worldMetadata; } - public void detectListNameConflict(EntityPlayer entityPlayer) { - // Collisions will make for invisible people - for (int i = 0; i < getHandle().players.size(); ++i) { - EntityPlayer testEntityPlayer = (EntityPlayer) getHandle().players.get(i); - - // We have a problem! - if (testEntityPlayer != entityPlayer && testEntityPlayer.listName.equals(entityPlayer.listName)) { - String oldName = entityPlayer.listName; - int spaceLeft = 16 - oldName.length(); - - if (spaceLeft <= 1) { // We also hit the list name length limit! - entityPlayer.listName = oldName.subSequence(0, oldName.length() - 2 - spaceLeft) + String.valueOf(System.currentTimeMillis() % 99); - } else { - entityPlayer.listName = oldName + String.valueOf(System.currentTimeMillis() % 99); - } - - return; - } - } - } - @Override public File getWorldContainer() { if (this.getServer().universe != null) { @@ -1575,16 +1437,6 @@ public final class CraftServer implements Server { return result; } - public void onPlayerJoin(Player player) { - if ((updater.isEnabled()) && (updater.getCurrent() != null) && (player.hasPermission(Server.BROADCAST_CHANNEL_ADMINISTRATIVE))) { - if ((updater.getCurrent().isBroken()) && (updater.getOnBroken().contains(AutoUpdater.WARN_OPERATORS))) { - player.sendMessage(ChatColor.DARK_RED + "The version of CraftBukkit that this server is running is known to be broken. Please consider updating to the latest version at dl.bukkit.org."); - } else if ((updater.isUpdateAvailable()) && (updater.getOnUpdate().contains(AutoUpdater.WARN_OPERATORS))) { - player.sendMessage(ChatColor.DARK_PURPLE + "The version of CraftBukkit that this server is running is out of date. Please consider updating to the latest version at dl.bukkit.org."); - } - } - } - @Override public Inventory createInventory(InventoryHolder owner, InventoryType type) { // TODO: Create the appropriate type, rather than Custom? diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftStatistic.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftStatistic.java index 24c8bf24cd..a261c77dcb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftStatistic.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftStatistic.java @@ -13,6 +13,9 @@ import com.google.common.base.CaseFormat; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; +import net.minecraft.server.Block; +import net.minecraft.server.Item; +import net.minecraft.server.MinecraftKey; public class CraftStatistic { private static final BiMap statistics; @@ -131,12 +134,19 @@ public class CraftStatistic { public static Material getMaterialFromStatistic(net.minecraft.server.Statistic statistic) { String statisticString = statistic.name; - int id; + String val = statisticString.substring(statisticString.lastIndexOf(".") + 1); + Item item = (Item) Item.REGISTRY.get(new MinecraftKey(val)); + if (item != null) { + return Material.getMaterial(Item.getId(item)); + } + Block block = (Block) Block.REGISTRY.get(new MinecraftKey(val)); + if (block != null) { + return Material.getMaterial(Block.getId(block)); + } try { - id = Integer.valueOf(statisticString.substring(statisticString.lastIndexOf(".") + 1)); + return Material.getMaterial(Integer.parseInt(val)); } catch (NumberFormatException e) { return null; } - return Material.getMaterial(id); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java index f7ca6a3f72..cae65cf86f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftTravelAgent.java @@ -1,6 +1,6 @@ package org.bukkit.craftbukkit; -import net.minecraft.server.ChunkCoordinates; +import net.minecraft.server.BlockPosition; import net.minecraft.server.PortalTravelAgent; import net.minecraft.server.WorldServer; @@ -22,6 +22,7 @@ public class CraftTravelAgent extends PortalTravelAgent implements TravelAgent { } } + @Override public Location findOrCreate(Location target) { WorldServer worldServer = ((CraftWorld) target.getWorld()).getHandle(); boolean before = worldServer.chunkProviderServer.forceChunkLoad; @@ -40,39 +41,47 @@ public class CraftTravelAgent extends PortalTravelAgent implements TravelAgent { return found; } + @Override public Location findPortal(Location location) { PortalTravelAgent pta = ((CraftWorld) location.getWorld()).getHandle().getTravelAgent(); - ChunkCoordinates found = pta.findPortal(location.getX(), location.getY(), location.getZ(), this.getSearchRadius()); - return found != null ? new Location(location.getWorld(), found.x, found.y, found.z, location.getYaw(), location.getPitch()) : null; + BlockPosition found = pta.findPortal(location.getX(), location.getY(), location.getZ(), this.getSearchRadius()); + return found != null ? new Location(location.getWorld(), found.getX(), found.getY(), found.getZ(), location.getYaw(), location.getPitch()) : null; } + @Override public boolean createPortal(Location location) { PortalTravelAgent pta = ((CraftWorld) location.getWorld()).getHandle().getTravelAgent(); return pta.createPortal(location.getX(), location.getY(), location.getZ(), this.getCreationRadius()); } + @Override public TravelAgent setSearchRadius(int radius) { this.searchRadius = radius; return this; } + @Override public int getSearchRadius() { return this.searchRadius; } + @Override public TravelAgent setCreationRadius(int radius) { this.creationRadius = radius < 2 ? 0 : radius; return this; } + @Override public int getCreationRadius() { return this.creationRadius; } + @Override public boolean getCanCreatePortal() { return this.canCreatePortal; } + @Override public void setCanCreatePortal(boolean create) { this.canCreatePortal = create; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index f4dec5bf15..f20a040636 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -86,7 +86,7 @@ public class CraftWorld implements World { } public int getBlockTypeIdAt(int x, int y, int z) { - return world.getTypeId(x, y, z); + return CraftMagicNumbers.getId(world.getType(new BlockPosition(x, y, z)).getBlock()); } public int getHighestBlockYAt(int x, int z) { @@ -94,18 +94,18 @@ public class CraftWorld implements World { loadChunk(x >> 4, z >> 4); } - return world.getHighestBlockYAt(x, z); + return world.getHighestBlockYAt(new BlockPosition(x, 0, z)).getY(); } public Location getSpawnLocation() { - ChunkCoordinates spawn = world.getSpawn(); - return new Location(this, spawn.x, spawn.y, spawn.z); + BlockPosition spawn = world.getSpawn(); + return new Location(this, spawn.getX(), spawn.getY(), spawn.getZ()); } public boolean setSpawnLocation(int x, int y, int z) { try { Location previousLocation = getSpawnLocation(); - world.worldData.setSpawn(x, y, z); + world.worldData.setSpawn(new BlockPosition(x, y, z)); // Notify anyone who's listening. SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); @@ -227,9 +227,9 @@ public class CraftWorld implements World { // This flags 65 blocks distributed across all the sections of the chunk, so that everything is sent, including biomes int height = getMaxHeight() / 16; for (int idx = 0; idx < 64; idx++) { - world.notify(px + (idx / height), ((idx % height) * 16), pz); + world.notify(new BlockPosition(px + (idx / height), ((idx % height) * 16), pz)); } - world.notify(px + 15, (height * 16) - 1, pz + 15); + world.notify(new BlockPosition(px + 15, (height * 16) - 1, pz + 15)); return true; } @@ -407,7 +407,7 @@ public class CraftWorld implements World { break; } - return gen.generate(world, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + return gen.generate(world, rand, new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); } public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { @@ -421,13 +421,14 @@ public class CraftWorld implements World { int x = blockstate.getX(); int y = blockstate.getY(); int z = blockstate.getZ(); - net.minecraft.server.Block oldBlock = world.getType(x, y, z); + BlockPosition position = new BlockPosition(x, y, z); + net.minecraft.server.Block oldBlock = world.getType(position).getBlock(); int typeId = blockstate.getTypeId(); int data = blockstate.getRawData(); int flag = ((CraftBlockState)blockstate).getFlag(); delegate.setTypeIdAndData(x, y, z, typeId, data); - net.minecraft.server.Block newBlock = world.getType(x, y, z); - world.notifyAndUpdatePhysics(x, y, z, null, oldBlock, newBlock, flag); + net.minecraft.server.Block newBlock = world.getType(position).getBlock(); + world.notifyAndUpdatePhysics(position, null, oldBlock, newBlock, flag); } world.capturedBlockStates.clear(); return true; @@ -438,7 +439,7 @@ public class CraftWorld implements World { } public TileEntity getTileEntityAt(final int x, final int y, final int z) { - return world.getTileEntity(x, y, z); + return world.getTileEntity(new BlockPosition(x, y, z)); } public String getName() { @@ -551,27 +552,27 @@ public class CraftWorld implements World { } public Biome getBiome(int x, int z) { - return CraftBlock.biomeBaseToBiome(this.world.getBiome(x, z)); + return CraftBlock.biomeBaseToBiome(this.world.getBiome(new BlockPosition(x, 0, z))); } public void setBiome(int x, int z, Biome bio) { BiomeBase bb = CraftBlock.biomeToBiomeBase(bio); - if (this.world.isLoaded(x, 0, z)) { - net.minecraft.server.Chunk chunk = this.world.getChunkAtWorldCoords(x, z); + if (this.world.isLoaded(new BlockPosition(x, 0, z))) { + net.minecraft.server.Chunk chunk = this.world.getChunkAtWorldCoords(new BlockPosition(x, 0, z)); if (chunk != null) { - byte[] biomevals = chunk.m(); + byte[] biomevals = chunk.getBiomeIndex(); biomevals[((z & 0xF) << 4) | (x & 0xF)] = (byte)bb.id; } } } public double getTemperature(int x, int z) { - return this.world.getBiome(x, z).temperature; + return this.world.getBiome(new BlockPosition(x, 0, z)).temperature; } public double getHumidity(int x, int z) { - return this.world.getBiome(x, z).humidity; + return this.world.getBiome(new BlockPosition(x, 0, z)).humidity; } public List getEntities() { @@ -704,11 +705,11 @@ public class CraftWorld implements World { } public void setDifficulty(Difficulty difficulty) { - this.getHandle().difficulty = EnumDifficulty.getById(difficulty.getValue()); + this.getHandle().worldData.setDifficulty(EnumDifficulty.getById(difficulty.getValue())); } public Difficulty getDifficulty() { - return Difficulty.getByValue(this.getHandle().difficulty.ordinal()); + return Difficulty.getByValue(this.getHandle().getDifficulty().ordinal()); } public BlockMetadataStore getBlockMetadata() { @@ -814,7 +815,7 @@ public class CraftWorld implements World { Validate.notNull(effect, "Effect cannot be null"); Validate.notNull(location.getWorld(), "World cannot be null"); int packetData = effect.getId(); - PacketPlayOutWorldEvent packet = new PacketPlayOutWorldEvent(packetData, location.getBlockX(), location.getBlockY(), location.getBlockZ(), data, false); + PacketPlayOutWorldEvent packet = new PacketPlayOutWorldEvent(packetData, new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()), data, false); int distance; radius *= radius; @@ -842,7 +843,7 @@ public class CraftWorld implements World { double y = location.getBlockY() + 0.5; double z = location.getBlockZ() + 0.5; - EntityFallingBlock entity = new EntityFallingBlock(world, x, y, z, net.minecraft.server.Block.getById(material.getId()), data); + EntityFallingBlock entity = new EntityFallingBlock(world, x, y, z, net.minecraft.server.Block.getById(material.getId()).fromLegacyData(data)); entity.ticksLived = 1; world.addEntity(entity, SpawnReason.CUSTOM); @@ -874,10 +875,11 @@ public class CraftWorld implements World { x = location.getBlockX(); y = location.getBlockY(); z = location.getBlockZ(); - int type = world.getTypeId((int) x, (int) y, (int) z); - int data = world.getData((int) x, (int) y, (int) z); + IBlockData blockData = world.getType(new BlockPosition(x, y, z)); + int type = CraftMagicNumbers.getId(blockData.getBlock()); + int data = blockData.getBlock().toLegacyData(blockData); - entity = new EntityFallingBlock(world, x + 0.5, y + 0.5, z + 0.5, net.minecraft.server.Block.getById(type), data); + entity = new EntityFallingBlock(world, x + 0.5, y + 0.5, z + 0.5, net.minecraft.server.Block.getById(type).fromLegacyData(data)); } else if (Projectile.class.isAssignableFrom(clazz)) { if (Snowball.class.isAssignableFrom(clazz)) { entity = new EntitySnowball(world, x, y, z); @@ -890,7 +892,7 @@ public class CraftWorld implements World { entity = new EntityThrownExpBottle(world); entity.setPositionRotation(x, y, z, 0, 0); } else if (EnderPearl.class.isAssignableFrom(clazz)) { - entity = new EntityEnderPearl(world); + entity = new EntityEnderPearl(world, null); entity.setPositionRotation(x, y, z, 0, 0); } else if (ThrownPotion.class.isAssignableFrom(clazz)) { entity = new EntityPotion(world, x, y, z, CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.POTION, 1))); @@ -1000,6 +1002,14 @@ public class CraftWorld implements World { if (Bat.class.isAssignableFrom(clazz)) { entity = new EntityBat(world); } + } else if (Rabbit.class.isAssignableFrom(clazz)) { + entity = new EntityRabbit(world); + } else if (Endermite.class.isAssignableFrom(clazz)) { + entity = new EntityEndermite(world); + } else if (Guardian.class.isAssignableFrom(clazz)){ + entity = new EntityGuardian(world); + } else if (ArmorStand.class.isAssignableFrom(clazz)) { + entity = new EntityArmorStand(world, x, y, z); } if (entity != null) { @@ -1017,29 +1027,29 @@ public class CraftWorld implements World { } else if (block.getRelative(BlockFace.SOUTH).getTypeId() == 0) { face = BlockFace.SOUTH; } - int dir; + EnumDirection dir; switch (face) { case SOUTH: default: - dir = 0; + dir = EnumDirection.SOUTH; break; case WEST: - dir = 1; + dir = EnumDirection.WEST; break; case NORTH: - dir = 2; + dir = EnumDirection.NORTH; break; case EAST: - dir = 3; + dir = EnumDirection.EAST; break; } if (Painting.class.isAssignableFrom(clazz)) { - entity = new EntityPainting(world, (int) x, (int) y, (int) z, dir); + entity = new EntityPainting(world, new BlockPosition((int) x, (int) y, (int) z), dir); } else if (ItemFrame.class.isAssignableFrom(clazz)) { - entity = new EntityItemFrame(world, (int) x, (int) y, (int) z, dir); + entity = new EntityItemFrame(world, new BlockPosition((int) x, (int) y, (int) z), dir); } else if (LeashHitch.class.isAssignableFrom(clazz)) { - entity = new EntityLeash(world, (int) x, (int) y, (int) z); + entity = new EntityLeash(world, new BlockPosition((int) x, (int) y, (int) z)); entity.attachedToPlayer = true; } @@ -1062,7 +1072,7 @@ public class CraftWorld implements World { if (entity != null) { if (entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare((GroupDataEntity) null); + ((EntityInsentient) entity).prepare(getHandle().E(new BlockPosition(entity)), (GroupDataEntity) null); } world.addEntity(entity, reason); @@ -1103,9 +1113,9 @@ public class CraftWorld implements World { public void setKeepSpawnInMemory(boolean keepLoaded) { world.keepSpawnInMemory = keepLoaded; // Grab the worlds spawn chunk - ChunkCoordinates chunkcoordinates = this.world.getSpawn(); - int chunkCoordX = chunkcoordinates.x >> 4; - int chunkCoordZ = chunkcoordinates.z >> 4; + BlockPosition chunkcoordinates = this.world.getSpawn(); + int chunkCoordX = chunkcoordinates.getX() >> 4; + int chunkCoordZ = chunkcoordinates.getZ() >> 4; // Cycle through the 25x25 Chunks around it to load/unload the chunks. for (int x = -12; x <= 12; x++) { for (int z = -12; z <= 12; z++) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java new file mode 100644 index 0000000000..5a76958d86 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java @@ -0,0 +1,105 @@ +package org.bukkit.craftbukkit.block; + +import java.util.ArrayList; +import java.util.List; +import net.minecraft.server.NBTTagCompound; +import net.minecraft.server.NBTTagList; +import net.minecraft.server.TileEntityBanner; +import org.bukkit.DyeColor; +import org.bukkit.block.Banner; +import org.bukkit.block.Block; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; +import org.bukkit.craftbukkit.CraftWorld; + +public class CraftBanner extends CraftBlockState implements Banner { + + private final TileEntityBanner banner; + private DyeColor base; + private List patterns = new ArrayList(); + + public CraftBanner(final Block block) { + super(block); + + CraftWorld world = (CraftWorld) block.getWorld(); + banner = (TileEntityBanner) world.getTileEntityAt(getX(), getY(), getZ()); + + base = DyeColor.getByDyeData((byte) banner.color); + + if (banner.patterns != null) { + for (int i = 0; i < banner.patterns.size(); i++) { + NBTTagCompound p = (NBTTagCompound) banner.patterns.get(i); + patterns.add(new Pattern(DyeColor.getByDyeData((byte) p.getInt("Color")), PatternType.getByIdentifier(p.getString("Pattern")))); + } + } + } + + @Override + public DyeColor getBaseColor() { + return this.base; + } + + @Override + public void setBaseColor(DyeColor color) { + this.base = color; + } + + @Override + public List getPatterns() { + return new ArrayList(patterns); + } + + @Override + public void setPatterns(List patterns) { + this.patterns = new ArrayList(patterns); + } + + @Override + public void addPattern(Pattern pattern) { + this.patterns.add(pattern); + } + + @Override + public Pattern getPattern(int i) { + return this.patterns.get(i); + } + + @Override + public Pattern removePattern(int i) { + return this.patterns.remove(i); + } + + @Override + public void setPattern(int i, Pattern pattern) { + this.patterns.set(i, pattern); + } + + @Override + public int numberOfPatterns() { + return patterns.size(); + } + + @Override + public boolean update(boolean force, boolean applyPhysics) { + boolean result = super.update(force, applyPhysics); + + if (result) { + banner.color = base.getDyeData(); + + NBTTagList newPatterns = new NBTTagList(); + + for (Pattern p : patterns) { + NBTTagCompound compound = new NBTTagCompound(); + compound.setInt("Color", p.getColor().getDyeData()); + compound.setString("Pattern", p.getPattern().getIdentifier()); + newPatterns.add(compound); + } + + banner.patterns = newPatterns; + + banner.update(); + } + + return result; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index 87d79aec14..fe5d231eb8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -5,15 +5,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import net.minecraft.server.BiomeBase; -import net.minecraft.server.BlockCocoa; -import net.minecraft.server.BlockRedstoneWire; -import net.minecraft.server.Blocks; -import net.minecraft.server.EnumSkyBlock; -import net.minecraft.server.GameProfileSerializer; -import net.minecraft.server.Item; -import net.minecraft.server.NBTTagCompound; -import net.minecraft.server.TileEntitySkull; +import net.minecraft.server.*; import org.bukkit.Chunk; import org.bukkit.Location; @@ -97,19 +89,27 @@ public class CraftBlock implements Block { } public void setData(final byte data) { - chunk.getHandle().world.setData(x, y, z, data, 3); + setData(data, 3); } public void setData(final byte data, boolean applyPhysics) { if (applyPhysics) { - chunk.getHandle().world.setData(x, y, z, data, 3); + setData(data, 3); } else { - chunk.getHandle().world.setData(x, y, z, data, 2); + setData(data, 2); } } + private void setData(final byte data, int flag) { + net.minecraft.server.World world = chunk.getHandle().getWorld(); + BlockPosition position = new BlockPosition(x, y, z); + IBlockData blockData = world.getType(position); + world.setTypeAndData(position, blockData.getBlock().fromLegacyData(data), flag); + } + public byte getData() { - return (byte) chunk.getHandle().getData(this.x & 0xF, this.y & 0xFF, this.z & 0xF); + IBlockData blockData = chunk.getHandle().getBlockData(new BlockPosition(x, y, z)); + return (byte) blockData.getBlock().toLegacyData(blockData); } public void setType(final Material type) { @@ -125,12 +125,14 @@ public class CraftBlock implements Block { } public boolean setTypeIdAndData(final int type, final byte data, final boolean applyPhysics) { + IBlockData blockData = getNMSBlock(type).fromLegacyData(data); + BlockPosition position = new BlockPosition(x, y, z); if (applyPhysics) { - return chunk.getHandle().world.setTypeAndData(x, y, z, getNMSBlock(type), data, 3); + return chunk.getHandle().getWorld().setTypeAndData(position, blockData, 3); } else { - boolean success = chunk.getHandle().world.setTypeAndData(x, y, z, getNMSBlock(type), data, 2); + boolean success = chunk.getHandle().getWorld().setTypeAndData(position, blockData, 2); if (success) { - chunk.getHandle().world.notify(x, y, z); + chunk.getHandle().getWorld().notify(position); } return success; } @@ -143,19 +145,19 @@ public class CraftBlock implements Block { @Deprecated @Override public int getTypeId() { - return CraftMagicNumbers.getId(chunk.getHandle().getType(this.x & 0xF, this.y & 0xFF, this.z & 0xF)); + return CraftMagicNumbers.getId(chunk.getHandle().getType(new BlockPosition(this.x, this.y, this.z))); } public byte getLightLevel() { - return (byte) chunk.getHandle().world.getLightLevel(this.x, this.y, this.z); + return (byte) chunk.getHandle().getWorld().getLightLevel(new BlockPosition(this.x, this.y, this.z)); } public byte getLightFromSky() { - return (byte) chunk.getHandle().getBrightness(EnumSkyBlock.SKY, this.x & 0xF, this.y & 0xFF, this.z & 0xF); + return (byte) chunk.getHandle().getBrightness(EnumSkyBlock.SKY, new BlockPosition(this.x, this.y, this.z)); } public byte getLightFromBlocks() { - return (byte) chunk.getHandle().getBrightness(EnumSkyBlock.BLOCK, this.x & 0xF, this.y & 0xFF, this.z & 0xF); + return (byte) chunk.getHandle().getBrightness(EnumSkyBlock.BLOCK, new BlockPosition(this.x, this.y, this.z)); } @@ -199,47 +201,42 @@ public class CraftBlock implements Block { return "CraftBlock{" + "chunk=" + chunk + ",x=" + x + ",y=" + y + ",z=" + z + ",type=" + getType() + ",data=" + getData() + '}'; } - /** - * Notch uses a 0-5 to mean DOWN, UP, NORTH, SOUTH, WEST, EAST - * in that order all over. This method is convenience to convert for us. - * - * @return BlockFace the BlockFace represented by this number - */ - public static BlockFace notchToBlockFace(int notch) { + public static BlockFace notchToBlockFace(EnumDirection notch) { + if (notch == null) return BlockFace.SELF; switch (notch) { - case 0: + case DOWN: return BlockFace.DOWN; - case 1: + case UP: return BlockFace.UP; - case 2: + case NORTH: return BlockFace.NORTH; - case 3: + case SOUTH: return BlockFace.SOUTH; - case 4: + case WEST: return BlockFace.WEST; - case 5: + case EAST: return BlockFace.EAST; default: return BlockFace.SELF; } } - public static int blockFaceToNotch(BlockFace face) { + public static EnumDirection blockFaceToNotch(BlockFace face) { switch (face) { case DOWN: - return 0; + return EnumDirection.DOWN; case UP: - return 1; + return EnumDirection.UP; case NORTH: - return 2; + return EnumDirection.NORTH; case SOUTH: - return 3; + return EnumDirection.SOUTH; case WEST: - return 4; + return EnumDirection.WEST; case EAST: - return 5; + return EnumDirection.EAST; default: - return 7; // Good as anything here, but technically invalid + return null; } } @@ -277,6 +274,9 @@ public class CraftBlock implements Block { return new CraftCommandBlock(this); case BEACON: return new CraftBeacon(this); + case BANNER: + case WALL_BANNER: + return new CraftBanner(this); default: return new CraftBlockState(this); } @@ -314,11 +314,11 @@ public class CraftBlock implements Block { } public boolean isBlockPowered() { - return chunk.getHandle().world.getBlockPower(x, y, z) > 0; + return chunk.getHandle().getWorld().getBlockPower(new BlockPosition(x, y, z)) > 0; } public boolean isBlockIndirectlyPowered() { - return chunk.getHandle().world.isBlockIndirectlyPowered(x, y, z); + return chunk.getHandle().getWorld().isBlockIndirectlyPowered(new BlockPosition(x, y, z)); } @Override @@ -336,11 +336,11 @@ public class CraftBlock implements Block { } public boolean isBlockFacePowered(BlockFace face) { - return chunk.getHandle().world.isBlockFacePowered(x, y, z, blockFaceToNotch(face)); + return chunk.getHandle().getWorld().isBlockFacePowered(new BlockPosition(x, y, z), blockFaceToNotch(face)); } public boolean isBlockFaceIndirectlyPowered(BlockFace face) { - int power = chunk.getHandle().world.getBlockFacePower(x, y, z, blockFaceToNotch(face)); + int power = chunk.getHandle().getWorld().getBlockFacePower(new BlockPosition(x, y, z), blockFaceToNotch(face)); Block relative = getRelative(face); if (relative.getType() == Material.REDSTONE_WIRE) { @@ -353,13 +353,13 @@ public class CraftBlock implements Block { public int getBlockPower(BlockFace face) { int power = 0; BlockRedstoneWire wire = Blocks.REDSTONE_WIRE; - net.minecraft.server.World world = chunk.getHandle().world; - if ((face == BlockFace.DOWN || face == BlockFace.SELF) && world.isBlockFacePowered(x, y - 1, z, 0)) power = wire.getPower(world, x, y - 1, z, power); - if ((face == BlockFace.UP || face == BlockFace.SELF) && world.isBlockFacePowered(x, y + 1, z, 1)) power = wire.getPower(world, x, y + 1, z, power); - if ((face == BlockFace.EAST || face == BlockFace.SELF) && world.isBlockFacePowered(x + 1, y, z, 2)) power = wire.getPower(world, x + 1, y, z, power); - if ((face == BlockFace.WEST || face == BlockFace.SELF) && world.isBlockFacePowered(x - 1, y, z, 3)) power = wire.getPower(world, x - 1, y, z, power); - if ((face == BlockFace.NORTH || face == BlockFace.SELF) && world.isBlockFacePowered(x, y, z - 1, 4)) power = wire.getPower(world, x, y, z - 1, power); - if ((face == BlockFace.SOUTH || face == BlockFace.SELF) && world.isBlockFacePowered(x, y, z + 1, 5)) power = wire.getPower(world, x, y, z - 1, power); + net.minecraft.server.World world = chunk.getHandle().getWorld(); + if ((face == BlockFace.DOWN || face == BlockFace.SELF) && world.isBlockFacePowered(new BlockPosition(x, y - 1, z), EnumDirection.DOWN)) power = wire.getPower(world, new BlockPosition(x, y - 1, z), power); + if ((face == BlockFace.UP || face == BlockFace.SELF) && world.isBlockFacePowered(new BlockPosition(x, y + 1, z), EnumDirection.UP)) power = wire.getPower(world, new BlockPosition(x, y + 1, z), power); + if ((face == BlockFace.EAST || face == BlockFace.SELF) && world.isBlockFacePowered(new BlockPosition(x + 1, y, z), EnumDirection.EAST)) power = wire.getPower(world, new BlockPosition(x + 1, y, z), power); + if ((face == BlockFace.WEST || face == BlockFace.SELF) && world.isBlockFacePowered(new BlockPosition(x - 1, y, z), EnumDirection.WEST)) power = wire.getPower(world, new BlockPosition(x - 1, y, z), power); + if ((face == BlockFace.NORTH || face == BlockFace.SELF) && world.isBlockFacePowered(new BlockPosition(x, y, z - 1), EnumDirection.NORTH)) power = wire.getPower(world, new BlockPosition(x, y, z - 1), power); + if ((face == BlockFace.SOUTH || face == BlockFace.SELF) && world.isBlockFacePowered(new BlockPosition(x, y, z + 1), EnumDirection.SOUTH)) power = wire.getPower(world, new BlockPosition(x, y, z - 1), power); return power > 0 ? power : (face == BlockFace.SELF ? isBlockIndirectlyPowered() : isBlockFaceIndirectlyPowered(face)) ? 15 : 0; } @@ -392,7 +392,7 @@ public class CraftBlock implements Block { boolean result = false; if (block != null && block != Blocks.AIR) { - block.dropNaturally(chunk.getHandle().world, x, y, z, data, 1.0F, 0); + block.dropNaturally(chunk.getHandle().getWorld(), new BlockPosition(x, y, z), block.fromLegacyData(data), 1.0F, 0); result = true; } @@ -415,14 +415,14 @@ public class CraftBlock implements Block { if (block != Blocks.AIR) { byte data = getData(); // based on nms.Block.dropNaturally - int count = block.getDropCount(0, chunk.getHandle().world.random); + int count = block.getDropCount(0, chunk.getHandle().getWorld().random); for (int i = 0; i < count; ++i) { - Item item = block.getDropType(data, chunk.getHandle().world.random, 0); + Item item = block.getDropType(block.fromLegacyData(data), chunk.getHandle().getWorld().random, 0); if (item != null) { // Skulls are special, their data is based on the tile entity if (Blocks.SKULL == block) { - net.minecraft.server.ItemStack nmsStack = new net.minecraft.server.ItemStack(item, 1, block.getDropData(chunk.getHandle().world, x, y, z)); - TileEntitySkull tileentityskull = (TileEntitySkull) chunk.getHandle().world.getTileEntity(x, y, z); + net.minecraft.server.ItemStack nmsStack = new net.minecraft.server.ItemStack(item, 1, block.getDropData(chunk.getHandle().getWorld(), new BlockPosition(x, y, z))); + TileEntitySkull tileentityskull = (TileEntitySkull) chunk.getHandle().getWorld().getTileEntity(new BlockPosition(x, y, z)); if (tileentityskull.getSkullType() == 3 && tileentityskull.getGameProfile() != null) { nmsStack.setTag(new NBTTagCompound()); @@ -435,12 +435,13 @@ public class CraftBlock implements Block { drops.add(CraftItemStack.asBukkitCopy(nmsStack)); // We don't want to drop cocoa blocks, we want to drop cocoa beans. } else if (Blocks.COCOA == block) { - int dropAmount = (BlockCocoa.c(data) >= 2 ? 3 : 1); + int age = (Integer) block.fromLegacyData(data).get(BlockCocoa.AGE); + int dropAmount = (age >= 2 ? 3 : 1); for (int j = 0; j < dropAmount; ++j) { drops.add(new ItemStack(Material.INK_SACK, 1, (short) 3)); } } else { - drops.add(new ItemStack(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(item), 1, (short) block.getDropData(data))); + drops.add(new ItemStack(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(item), 1, (short) block.getDropData(block.fromLegacyData(data)))); } } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java index 2297cc756c..9fb32a82fb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.server.BlockPosition; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.Chunk; @@ -147,7 +148,7 @@ public class CraftBlockState implements BlockState { } block.setData(getRawData(), applyPhysics); - world.getHandle().notify(x, y, z); + world.getHandle().notify(new BlockPosition(x, y, z)); return true; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java index 21f7b73261..0e5c240412 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.server.BlockPosition; import net.minecraft.server.TileEntityChest; import org.bukkit.Material; @@ -41,19 +42,19 @@ public class CraftChest extends CraftBlockState implements Chest { } if (world.getBlockTypeIdAt(x - 1, y, z) == id) { - CraftInventory left = new CraftInventory((TileEntityChest)world.getHandle().getTileEntity(x - 1, y, z)); + CraftInventory left = new CraftInventory((TileEntityChest)world.getHandle().getTileEntity(new BlockPosition(x - 1, y, z))); inventory = new CraftInventoryDoubleChest(left, inventory); } if (world.getBlockTypeIdAt(x + 1, y, z) == id) { - CraftInventory right = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(x + 1, y, z)); + CraftInventory right = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(new BlockPosition(x + 1, y, z))); inventory = new CraftInventoryDoubleChest(inventory, right); } if (world.getBlockTypeIdAt(x, y, z - 1) == id) { - CraftInventory left = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(x, y, z - 1)); + CraftInventory left = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(new BlockPosition(x, y, z - 1))); inventory = new CraftInventoryDoubleChest(left, inventory); } if (world.getBlockTypeIdAt(x, y, z + 1) == id) { - CraftInventory right = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(x, y, z + 1)); + CraftInventory right = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(new BlockPosition(x, y, z + 1))); inventory = new CraftInventoryDoubleChest(inventory, right); } return inventory; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java index 762a8e6dcd..ab6e55f408 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.block; import net.minecraft.server.BlockDispenser; +import net.minecraft.server.BlockPosition; import net.minecraft.server.Blocks; import net.minecraft.server.TileEntityDispenser; @@ -44,7 +45,7 @@ public class CraftDispenser extends CraftBlockState implements Dispenser { if (block.getType() == Material.DISPENSER) { BlockDispenser dispense = (BlockDispenser) Blocks.DISPENSER; - dispense.dispense(world.getHandle(), getX(), getY(), getZ()); + dispense.dispense(world.getHandle(), new BlockPosition(getX(), getY(), getZ())); return true; } else { return false; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java index 6b4ef8ad3a..327f47663c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.block; import net.minecraft.server.BlockDropper; +import net.minecraft.server.BlockPosition; import net.minecraft.server.Blocks; import net.minecraft.server.TileEntityDropper; @@ -32,7 +33,7 @@ public class CraftDropper extends CraftBlockState implements Dropper { if (block.getType() == Material.DROPPER) { BlockDropper drop = (BlockDropper) Blocks.DROPPER; - drop.dispense(world.getHandle(), getX(), getY(), getZ()); + drop.dispense(world.getHandle(), new BlockPosition(getX(), getY(), getZ())); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java index 761b76af09..ce744c977e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java @@ -1,9 +1,6 @@ package org.bukkit.craftbukkit.block; -import net.minecraft.server.BlockJukeBox; -import net.minecraft.server.Blocks; -import net.minecraft.server.ItemStack; -import net.minecraft.server.TileEntityRecordPlayer; +import net.minecraft.server.*; import org.bukkit.Effect; import org.bukkit.Material; import org.bukkit.block.Block; @@ -41,9 +38,13 @@ public class CraftJukebox extends CraftBlockState implements Jukebox { } jukebox.update(); if (record == Material.AIR) { - world.getHandle().setData(getX(), getY(), getZ(), 0, 3); + world.getHandle().setTypeAndData(new BlockPosition(getX(), getY(), getZ()), + Blocks.JUKEBOX.getBlockData() + .set(BlockJukeBox.HAS_RECORD, false), 3); } else { - world.getHandle().setData(getX(), getY(), getZ(), 1, 3); + world.getHandle().setTypeAndData(new BlockPosition(getX(), getY(), getZ()), + Blocks.JUKEBOX.getBlockData() + .set(BlockJukeBox.HAS_RECORD, true), 3); } world.playEffect(getLocation(), Effect.RECORD_PLAY, record.getId()); } @@ -54,7 +55,7 @@ public class CraftJukebox extends CraftBlockState implements Jukebox { public boolean eject() { boolean result = isPlaying(); - ((BlockJukeBox) Blocks.JUKEBOX).dropRecord(world.getHandle(), getX(), getY(), getZ()); + ((BlockJukeBox) Blocks.JUKEBOX).dropRecord(world.getHandle(), new BlockPosition(getX(), getY(), getZ()), null); return result; } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java index b83e33513f..79d8e6ddc9 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.server.BlockPosition; import net.minecraft.server.TileEntityNote; import org.bukkit.Instrument; @@ -41,7 +42,7 @@ public class CraftNoteBlock extends CraftBlockState implements NoteBlock { Block block = getBlock(); if (block.getType() == Material.NOTE_BLOCK) { - note.play(world.getHandle(), getX(), getY(), getZ()); + note.play(world.getHandle(), new BlockPosition(getX(), getY(), getZ())); return true; } else { return false; @@ -53,7 +54,7 @@ public class CraftNoteBlock extends CraftBlockState implements NoteBlock { Block block = getBlock(); if (block.getType() == Material.NOTE_BLOCK) { - world.getHandle().playBlockAction(getX(), getY(), getZ(), CraftMagicNumbers.getBlock(block), instrument, note); + world.getHandle().playBlockAction(new BlockPosition(getX(), getY(), getZ()), CraftMagicNumbers.getBlock(block), instrument, note); return true; } else { return false; @@ -65,7 +66,7 @@ public class CraftNoteBlock extends CraftBlockState implements NoteBlock { Block block = getBlock(); if (block.getType() == Material.NOTE_BLOCK) { - world.getHandle().playBlockAction(getX(), getY(), getZ(), CraftMagicNumbers.getBlock(block), instrument.getType(), note.getId()); + world.getHandle().playBlockAction(new BlockPosition(getX(), getY(), getZ()), CraftMagicNumbers.getBlock(block), instrument.getType(), note.getId()); return true; } else { return false; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java index 77717d5b2b..724dbd128d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java @@ -1,9 +1,12 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.server.ChatComponentText; +import net.minecraft.server.IChatBaseComponent; import net.minecraft.server.TileEntitySign; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.util.CraftChatMessage; public class CraftSign extends CraftBlockState implements Sign { private final TileEntitySign sign; @@ -15,7 +18,7 @@ public class CraftSign extends CraftBlockState implements Sign { CraftWorld world = (CraftWorld) block.getWorld(); sign = (TileEntitySign) world.getTileEntityAt(getX(), getY(), getZ()); lines = new String[sign.lines.length]; - System.arraycopy(sign.lines, 0, lines, 0, lines.length); + System.arraycopy(revertComponents(sign.lines), 0, lines, 0, lines.length); } public String[] getLines() { @@ -35,24 +38,37 @@ public class CraftSign extends CraftBlockState implements Sign { boolean result = super.update(force, applyPhysics); if (result) { - sign.lines = sanitizeLines(lines); + IChatBaseComponent[] newLines = sanitizeLines(lines); + System.arraycopy(newLines, 0, sign.lines, 0, 4); sign.update(); } return result; } - public static String[] sanitizeLines(String[] lines) { - String[] astring = new String[4]; + public static IChatBaseComponent[] sanitizeLines(String[] lines) { + IChatBaseComponent[] components = new IChatBaseComponent[4]; for (int i = 0; i < 4; i++) { if (i < lines.length && lines[i] != null) { - astring[i] = lines[i]; + components[i] = CraftChatMessage.fromString(lines[i])[0]; } else { - astring[i] = ""; + components[i] = new ChatComponentText(""); } } - return TileEntitySign.sanitizeLines(astring); + return components; + } + + public static String[] revertComponents(IChatBaseComponent[] components) { + String[] lines = new String[components.length]; + for (int i = 0; i < lines.length; i++) { + lines[i] = revertComponent(components[i]); + } + return lines; + } + + private static String revertComponent(IChatBaseComponent component) { + return CraftChatMessage.fromComponent(component); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java index dc9a587e8c..8d751c11ae 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java @@ -1,8 +1,8 @@ package org.bukkit.craftbukkit.block; +import com.mojang.authlib.GameProfile; import net.minecraft.server.MinecraftServer; import net.minecraft.server.TileEntitySkull; -import net.minecraft.util.com.mojang.authlib.GameProfile; import org.bukkit.SkullType; import org.bukkit.block.Block; @@ -24,7 +24,7 @@ public class CraftSkull extends CraftBlockState implements Skull { skull = (TileEntitySkull) world.getTileEntityAt(getX(), getY(), getZ()); profile = skull.getGameProfile(); skullType = getSkullType(skull.getSkullType()); - rotation = (byte) skull.getRotation(); + rotation = (byte) skull.rotation; } static SkullType getSkullType(int id) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/paper-server/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java index 9cf1b49332..c2d4c2e4f3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java @@ -35,17 +35,17 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider) vanillaCommand.tabComplete(getListener(sender), args); + return (List) vanillaCommand.tabComplete(getListener(sender), args, new BlockPosition(0, 0, 0)); } public final int dispatchVanillaCommandBlock(CommandBlockListenerAbstract icommandlistener, String s) { @@ -97,26 +87,35 @@ public final class VanillaCommandWrapper extends VanillaCommand { try { if (vanillaCommand.canUse(icommandlistener)) { if (i > -1) { - EntityPlayer aentityplayer[] = PlayerSelector.getPlayers(icommandlistener, as[i]); + List list = ((List)PlayerSelector.getPlayers(icommandlistener, as[i], Entity.class)); String s2 = as[i]; - EntityPlayer aentityplayer1[] = aentityplayer; - int k = aentityplayer1.length; - for (int l = 0; l < k;l++) { - EntityPlayer entityplayer = aentityplayer1[l]; - as[i] = entityplayer.getName(); + + icommandlistener.a(EnumCommandResult.AFFECTED_ENTITIES, list.size()); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + Entity entity = iterator.next(); + try { + as[i] = entity.getUniqueID().toString(); vanillaCommand.execute(icommandlistener, as); j++; - continue; - } catch (CommandException commandexception1) { - ChatMessage chatmessage4 = new ChatMessage(commandexception1.getMessage(), commandexception1.getArgs()); - chatmessage4.getChatModifier().setColor(EnumChatFormat.RED); - icommandlistener.sendMessage(chatmessage4); - } + // PAIL fake throws + if (false) throw new ExceptionUsage(null, null); + if (false) throw new CommandException(null, null); + } catch (ExceptionUsage exceptionusage) { + ChatMessage chatmessage = new ChatMessage("commands.generic.usage", new Object[] { new ChatMessage(exceptionusage.getMessage(), exceptionusage.getArgs())}); + chatmessage.getChatModifier().setColor(EnumChatFormat.RED); + icommandlistener.sendMessage(chatmessage); + } catch (CommandException commandexception) { + ChatMessage chatmessage = new ChatMessage(commandexception.getMessage(), commandexception.getArgs()); + chatmessage.getChatModifier().setColor(EnumChatFormat.RED); + icommandlistener.sendMessage(chatmessage); + } } - as[i] = s2; } else { + icommandlistener.a(EnumCommandResult.AFFECTED_ENTITIES, 1); vanillaCommand.execute(icommandlistener, as); j++; } @@ -125,6 +124,10 @@ public final class VanillaCommandWrapper extends VanillaCommand { chatmessage.getChatModifier().setColor(EnumChatFormat.RED); icommandlistener.sendMessage(chatmessage); } + // PAIL start: fix compile error + if (false) throw new ExceptionUsage(null, null); + if (false) throw new CommandException(null, null); + // PAIL end } catch (ExceptionUsage exceptionusage) { ChatMessage chatmessage1 = new ChatMessage("commands.generic.usage", new Object[] { new ChatMessage(exceptionusage.getMessage(), exceptionusage.getArgs()) }); chatmessage1.getChatModifier().setColor(EnumChatFormat.RED); @@ -139,16 +142,17 @@ public final class VanillaCommandWrapper extends VanillaCommand { icommandlistener.sendMessage(chatmessage3); if(icommandlistener instanceof TileEntityCommandListener) { TileEntityCommandListener listener = (TileEntityCommandListener) icommandlistener; - MinecraftServer.getLogger().log(Level.WARN, String.format("CommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().x, listener.getChunkCoordinates().y, listener.getChunkCoordinates().z), throwable); + MinecraftServer.getLogger().log(Level.WARN, String.format("CommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().getX(), listener.getChunkCoordinates().getY(), listener.getChunkCoordinates().getZ()), throwable); } else if (icommandlistener instanceof EntityMinecartCommandBlockListener) { EntityMinecartCommandBlockListener listener = (EntityMinecartCommandBlockListener) icommandlistener; - MinecraftServer.getLogger().log(Level.WARN, String.format("MinecartCommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().x, listener.getChunkCoordinates().y, listener.getChunkCoordinates().z), throwable); + MinecraftServer.getLogger().log(Level.WARN, String.format("MinecartCommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().getX(), listener.getChunkCoordinates().getY(), listener.getChunkCoordinates().getZ()), throwable); } else { MinecraftServer.getLogger().log(Level.WARN, String.format("Unknown CommandBlock failed to handle command"), throwable); } } finally { MinecraftServer.getServer().worldServer = prev; } + icommandlistener.a(EnumCommandResult.SUCCESS_COUNT, j); return j; } @@ -163,7 +167,7 @@ public final class VanillaCommandWrapper extends VanillaCommand { return ((EntityMinecartCommandBlock) ((CraftMinecartCommand) sender).getHandle()).getCommandBlock(); } if (sender instanceof RemoteConsoleCommandSender) { - return RemoteControlCommandListener.instance; + return RemoteControlCommandListener.getInstance(); } if (sender instanceof ConsoleCommandSender) { return ((CraftServer) sender.getServer()).getServer(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java new file mode 100644 index 0000000000..2896603e7c --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java @@ -0,0 +1,214 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityArmorStand; +import net.minecraft.server.Vector3f; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.EulerAngle; + +public class CraftArmorStand extends CraftLivingEntity implements ArmorStand { + + private static final int HAND = 0; + private static final int FEET = 1; + private static final int LEGS = 2; + private static final int CHEST = 3; + private static final int HEAD = 4; + + public CraftArmorStand(CraftServer server, EntityArmorStand entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftArmorStand"; + } + + @Override + public EntityType getType() { + return EntityType.ARMOR_STAND; + } + + @Override + public EntityArmorStand getHandle() { + return (EntityArmorStand) super.getHandle(); + } + + @Override + public ItemStack getItemInHand() { + return CraftItemStack.asBukkitCopy(getHandle().getEquipment(HAND)); + } + + @Override + public void setItemInHand(ItemStack item) { + getHandle().setEquipment(HAND, CraftItemStack.asNMSCopy(item)); + } + + @Override + public ItemStack getBoots() { + return CraftItemStack.asBukkitCopy(getHandle().getEquipment(FEET)); + } + + @Override + public void setBoots(ItemStack item) { + getHandle().setEquipment(FEET, CraftItemStack.asNMSCopy(item)); + } + + @Override + public ItemStack getLeggings() { + return CraftItemStack.asBukkitCopy(getHandle().getEquipment(LEGS)); + } + + @Override + public void setLeggings(ItemStack item) { + getHandle().setEquipment(LEGS, CraftItemStack.asNMSCopy(item)); + } + + @Override + public ItemStack getChestplate() { + return CraftItemStack.asBukkitCopy(getHandle().getEquipment(CHEST)); + } + + @Override + public void setChestplate(ItemStack item) { + getHandle().setEquipment(CHEST, CraftItemStack.asNMSCopy(item)); + } + + @Override + public ItemStack getHelmet() { + return CraftItemStack.asBukkitCopy(getHandle().getEquipment(HEAD)); + } + + @Override + public void setHelmet(ItemStack item) { + getHandle().setEquipment(HEAD, CraftItemStack.asNMSCopy(item)); + } + + @Override + public EulerAngle getBodyPose() { + return fromNMS(getHandle().bodyPose); + } + + @Override + public void setBodyPose(EulerAngle pose) { + getHandle().setBodyPose(toNMS(pose)); + } + + @Override + public EulerAngle getLeftArmPose() { + return fromNMS(getHandle().leftArmPose); + } + + @Override + public void setLeftArmPose(EulerAngle pose) { + getHandle().setLeftArmPose(toNMS(pose)); + } + + @Override + public EulerAngle getRightArmPose() { + return fromNMS(getHandle().rightArmPose); + } + + @Override + public void setRightArmPose(EulerAngle pose) { + getHandle().setRightArmPose(toNMS(pose)); + } + + @Override + public EulerAngle getLeftLegPose() { + return fromNMS(getHandle().leftLegPose); + } + + @Override + public void setLeftLegPose(EulerAngle pose) { + getHandle().setLeftLegPose(toNMS(pose)); + } + + @Override + public EulerAngle getRightLegPose() { + return fromNMS(getHandle().rightLegPose); + } + + @Override + public void setRightLegPose(EulerAngle pose) { + getHandle().setRightLegPose(toNMS(pose)); + } + + @Override + public EulerAngle getHeadPose() { + return fromNMS(getHandle().headPose); + } + + @Override + public void setHeadPose(EulerAngle pose) { + getHandle().setHeadPose(toNMS(pose)); + } + + @Override + public boolean hasBasePlate() { + return !getHandle().hasBasePlate(); + } + + @Override + public void setBasePlate(boolean basePlate) { + getHandle().setBasePlate(!basePlate); + } + + @Override + public boolean hasGravity() { + return !getHandle().hasGravity(); + } + + @Override + public void setGravity(boolean gravity) { + getHandle().setGravity(!gravity); + } + + @Override + public boolean isVisible() { + return !getHandle().isInvisible(); + } + + @Override + public void setVisible(boolean visible) { + getHandle().setInvisible(!visible); + } + + @Override + public boolean hasArms() { + return getHandle().hasArms(); + } + + @Override + public void setArms(boolean arms) { + getHandle().setArms(arms); + } + + @Override + public boolean isSmall() { + return getHandle().isSmall(); + } + + @Override + public void setSmall(boolean small) { + getHandle().setSmall(small); + } + + private static EulerAngle fromNMS(Vector3f old) { + return new EulerAngle( + Math.toRadians(old.getX()), + Math.toRadians(old.getY()), + Math.toRadians(old.getZ()) + ); + } + + private static Vector3f toNMS(EulerAngle old) { + return new Vector3f( + (float) Math.toDegrees(old.getX()), + (float) Math.toDegrees(old.getY()), + (float) Math.toDegrees(old.getZ()) + ); + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java index 4f8d47d6e5..dca8520464 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java @@ -33,7 +33,7 @@ public class CraftArrow extends AbstractProjectile implements Arrow { } public ProjectileSource getShooter() { - return getHandle().projectileSource; + return getHandle().projectileSource; } public void setShooter(ProjectileSource shooter) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java index a6c0b94e5c..09d42141fb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreature.java @@ -1,7 +1,6 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityCreature; -import net.minecraft.server.EntityLiving; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.Creature; import org.bukkit.entity.LivingEntity; @@ -14,20 +13,16 @@ public class CraftCreature extends CraftLivingEntity implements Creature { public void setTarget(LivingEntity target) { EntityCreature entity = getHandle(); if (target == null) { - entity.target = null; - entity.setGoalTarget(null); + entity.setGoalTarget(null, null, false); } else if (target instanceof CraftLivingEntity) { - entity.target = ((CraftLivingEntity) target).getHandle(); - entity.pathEntity = entity.world.findPath(entity, entity.target, 16.0F, true, false, false, true); - entity.setGoalTarget(((CraftLivingEntity) target).getHandle()); + entity.setGoalTarget(((CraftLivingEntity) target).getHandle(), null, false); } } public CraftLivingEntity getTarget() { - if (getHandle().target == null) return null; - if (!(getHandle().target instanceof EntityLiving)) return null; + if (getHandle().getGoalTarget() == null) return null; - return (CraftLivingEntity) getHandle().target.getBukkitEntity(); + return (CraftLivingEntity) getHandle().getGoalTarget().getBukkitEntity(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java index 09a03c05ed..b1bf7a46ec 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java @@ -2,6 +2,7 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityEnderman; +import net.minecraft.server.IBlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.Enderman; @@ -14,12 +15,12 @@ public class CraftEnderman extends CraftMonster implements Enderman { } public MaterialData getCarriedMaterial() { - return CraftMagicNumbers.getMaterial(getHandle().getCarried()).getNewData((byte) getHandle().getCarriedData()); + IBlockData blockData = getHandle().getCarried(); + return CraftMagicNumbers.getMaterial(blockData.getBlock()).getNewData((byte) blockData.getBlock().toLegacyData(blockData)); } public void setCarriedMaterial(MaterialData data) { - getHandle().setCarried(CraftMagicNumbers.getBlock(data.getItemTypeId())); - getHandle().setCarriedData(data.getData()); + getHandle().setCarried(CraftMagicNumbers.getBlock(data.getItemTypeId()).fromLegacyData(data.getData())); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java new file mode 100644 index 0000000000..4fd49ead9b --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java @@ -0,0 +1,23 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityEndermite; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Endermite; +import org.bukkit.entity.EntityType; + +public class CraftEndermite extends CraftMonster implements Endermite { + + public CraftEndermite(CraftServer server, EntityEndermite entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftEndermite"; + } + + @Override + public EntityType getType() { + return EntityType.ENDERMITE; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index b8a9a14888..b7e9d8fd5b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -37,6 +37,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { if (entity instanceof EntityPlayer) { return new CraftPlayer(server, (EntityPlayer) entity); } else { return new CraftHumanEntity(server, (EntityHuman) entity); } } + // Water Animals + else if (entity instanceof EntityWaterAnimal) { + if (entity instanceof EntitySquid) { return new CraftSquid(server, (EntitySquid) entity); } + else { return new CraftWaterMob(server, (EntityWaterAnimal) entity); } + } else if (entity instanceof EntityCreature) { // Animals if (entity instanceof EntityAnimal) { @@ -52,6 +57,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } else if (entity instanceof EntitySheep) { return new CraftSheep(server, (EntitySheep) entity); } else if (entity instanceof EntityHorse) { return new CraftHorse(server, (EntityHorse) entity); } + else if (entity instanceof EntityRabbit) { return new CraftRabbit(server, (EntityRabbit) entity); } else { return new CraftAnimals(server, (EntityAnimal) entity); } } // Monsters @@ -72,14 +78,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { if (entity instanceof EntityCaveSpider) { return new CraftCaveSpider(server, (EntityCaveSpider) entity); } else { return new CraftSpider(server, (EntitySpider) entity); } } + else if (entity instanceof EntityEndermite) { return new CraftEndermite(server, (EntityEndermite) entity); } + else if (entity instanceof EntityGuardian) { return new CraftGuardian(server, (EntityGuardian) entity); } else { return new CraftMonster(server, (EntityMonster) entity); } } - // Water Animals - else if (entity instanceof EntityWaterAnimal) { - if (entity instanceof EntitySquid) { return new CraftSquid(server, (EntitySquid) entity); } - else { return new CraftWaterMob(server, (EntityWaterAnimal) entity); } - } else if (entity instanceof EntityGolem) { if (entity instanceof EntitySnowman) { return new CraftSnowman(server, (EntitySnowman) entity); } else if (entity instanceof EntityIronGolem) { return new CraftIronGolem(server, (EntityIronGolem) entity); } @@ -105,6 +108,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { if (entity instanceof EntityBat) { return new CraftBat(server, (EntityBat) entity); } else { return new CraftAmbient(server, (EntityAmbient) entity); } } + else if (entity instanceof EntityArmorStand) { return new CraftArmorStand(server, (EntityArmorStand) entity); } else { return new CraftLivingEntity(server, (EntityLiving) entity); } } else if (entity instanceof EntityComplexPart) { @@ -154,7 +158,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { else if (entity instanceof EntityTNTPrimed) { return new CraftTNTPrimed(server, (EntityTNTPrimed) entity); } else if (entity instanceof EntityFireworks) { return new CraftFirework(server, (EntityFireworks) entity); } - throw new AssertionError("Unknown entity " + entity == null ? null : entity.getClass()); + throw new AssertionError("Unknown entity " + (entity == null ? null : entity.getClass())); } public Location getLocation() { @@ -224,7 +228,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { public List getNearbyEntities(double x, double y, double z) { @SuppressWarnings("unchecked") - List notchEntityList = entity.world.getEntities(entity, entity.boundingBox.grow(x, y, z)); + List notchEntityList = entity.world.getEntities(entity, entity.getBoundingBox().grow(x, y, z)); List bukkitEntityList = new java.util.ArrayList(notchEntityList.size()); for (Entity e : notchEntityList) { @@ -316,7 +320,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } public UUID getUniqueId() { - return getHandle().uniqueID; + return getHandle().getUniqueID(); } public int getTicksLived() { @@ -402,4 +406,34 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { return getHandle().vehicle.getBukkitEntity(); } + + @Override + public void setCustomName(String name) { + if (name == null) { + name = ""; + } + + getHandle().setCustomName(name); + } + + @Override + public String getCustomName() { + String name = getHandle().getCustomName(); + + if (name == null || name.length() == 0) { + return null; + } + + return name; + } + + @Override + public void setCustomNameVisible(boolean flag) { + getHandle().setCustomNameVisible(flag); + } + + @Override + public boolean isCustomNameVisible() { + return getHandle().getCustomNameVisible(); + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java index d67ddd086a..788f26ba5c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingSand.java @@ -33,11 +33,11 @@ public class CraftFallingSand extends CraftEntity implements FallingSand { } public int getBlockId() { - return CraftMagicNumbers.getId(getHandle().id); + return CraftMagicNumbers.getId(getHandle().getBlock().getBlock()); } public byte getBlockData() { - return (byte) getHandle().data; + return (byte) getHandle().getBlock().getBlock().toLegacyData(getHandle().getBlock()); } public boolean getDropItem() { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java index edb30e7c68..ecfc316bb2 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.entity; +import net.minecraft.server.BlockPosition; import net.minecraft.server.EntityFishingHook; import net.minecraft.server.EntityHuman; import net.minecraft.server.MathHelper; @@ -50,7 +51,7 @@ public class CraftFish extends AbstractProjectile implements Fish { EntityFishingHook hook = getHandle(); if (this.biteChance == -1) { - if (hook.world.isRainingAt(MathHelper.floor(hook.locX), MathHelper.floor(hook.locY) + 1, MathHelper.floor(hook.locZ))) { + if (hook.world.isRainingAt(new BlockPosition(MathHelper.floor(hook.locX), MathHelper.floor(hook.locY) + 1, MathHelper.floor(hook.locZ)))) { return 1/300.0; } return 1/500.0; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java new file mode 100644 index 0000000000..f254e809e9 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java @@ -0,0 +1,23 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityGuardian; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Guardian; + +public class CraftGuardian extends CraftMonster implements Guardian { + + public CraftGuardian(CraftServer server, EntityGuardian entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftGuardian"; + } + + @Override + public EntityType getType() { + return EntityType.GUARDIAN; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHanging.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHanging.java index e51dddbd56..3bf83db1b8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHanging.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHanging.java @@ -1,6 +1,8 @@ package org.bukkit.craftbukkit.entity; +import net.minecraft.server.BlockPosition; import net.minecraft.server.EntityHanging; +import net.minecraft.server.EnumDirection; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.CraftServer; @@ -23,30 +25,27 @@ public class CraftHanging extends CraftEntity implements Hanging { public boolean setFacingDirection(BlockFace face, boolean force) { Block block = getLocation().getBlock().getRelative(getAttachedFace()).getRelative(face.getOppositeFace()).getRelative(getFacing()); EntityHanging hanging = getHandle(); - int x = hanging.x, y = hanging.y, z = hanging.z, dir = hanging.direction; - hanging.x = block.getX(); - hanging.y = block.getY(); - hanging.z = block.getZ(); + BlockPosition old = hanging.getBlockPosition(); + EnumDirection dir = hanging.direction; + hanging.blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); switch (face) { case SOUTH: default: - getHandle().setDirection(0); + getHandle().setDirection(EnumDirection.SOUTH); break; case WEST: - getHandle().setDirection(1); + getHandle().setDirection(EnumDirection.WEST); break; case NORTH: - getHandle().setDirection(2); + getHandle().setDirection(EnumDirection.NORTH); break; case EAST: - getHandle().setDirection(3); + getHandle().setDirection(EnumDirection.EAST); break; } if (!force && !hanging.survives()) { // Revert since it doesn't fit - hanging.x = x; - hanging.y = y; - hanging.z = z; + hanging.blockPosition = old; hanging.setDirection(dir); return false; } @@ -55,14 +54,14 @@ public class CraftHanging extends CraftEntity implements Hanging { public BlockFace getFacing() { switch (this.getHandle().direction) { - case 0: + case SOUTH: default: return BlockFace.SOUTH; - case 1: + case WEST: return BlockFace.WEST; - case 2: + case NORTH: return BlockFace.NORTH; - case 3: + case EAST: return BlockFace.EAST; } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHorse.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHorse.java index 8522cad0e0..230ae9ee4b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHorse.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHorse.java @@ -107,7 +107,7 @@ public class CraftHorse extends CraftAnimals implements Horse { public void setOwner(AnimalTamer owner) { if (owner != null) { setTamed(true); - getHandle().setPathEntity(null); + getHandle().setGoalTarget(null, null, false); setOwnerUUID(owner.getUniqueId()); } else { setTamed(false); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 3d1ca3d81f..e69f417bc5 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -2,16 +2,7 @@ package org.bukkit.craftbukkit.entity; import java.util.Set; -import net.minecraft.server.Container; -import net.minecraft.server.EntityHuman; -import net.minecraft.server.EntityMinecartHopper; -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.PacketPlayInCloseWindow; -import net.minecraft.server.PacketPlayOutOpenWindow; -import net.minecraft.server.TileEntityBrewingStand; -import net.minecraft.server.TileEntityDispenser; -import net.minecraft.server.TileEntityFurnace; -import net.minecraft.server.TileEntityHopper; +import net.minecraft.server.*; import org.bukkit.GameMode; import org.bukkit.Location; @@ -194,38 +185,38 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { break; case DISPENSER: if (craftinv.getInventory() instanceof TileEntityDispenser) { - getHandle().openDispenser((TileEntityDispenser) craftinv.getInventory()); + getHandle().openTileEntity((TileEntityDispenser) craftinv.getInventory()); } else { - openCustomInventory(inventory, player, 3); + openCustomInventory(inventory, player, "minecraft:dispenser"); } break; case FURNACE: if (craftinv.getInventory() instanceof TileEntityFurnace) { - getHandle().openFurnace((TileEntityFurnace) craftinv.getInventory()); + getHandle().openTileEntity((TileEntityFurnace) craftinv.getInventory()); } else { - openCustomInventory(inventory, player, 2); + openCustomInventory(inventory, player, "minecraft:furnace"); } break; case WORKBENCH: - openCustomInventory(inventory, player, 1); + openCustomInventory(inventory, player, "minecraft:crafting_table"); break; case BREWING: if (craftinv.getInventory() instanceof TileEntityBrewingStand) { - getHandle().openBrewingStand((TileEntityBrewingStand) craftinv.getInventory()); + getHandle().openTileEntity((TileEntityBrewingStand) craftinv.getInventory()); } else { - openCustomInventory(inventory, player, 5); + openCustomInventory(inventory, player, "minecraft:brewing_stand"); } break; case ENCHANTING: - openCustomInventory(inventory, player, 4); + openCustomInventory(inventory, player, "minecraft:enchanting_table"); break; case HOPPER: if (craftinv.getInventory() instanceof TileEntityHopper) { - getHandle().openHopper((TileEntityHopper) craftinv.getInventory()); + getHandle().openTileEntity((TileEntityHopper) craftinv.getInventory()); } else if (craftinv.getInventory() instanceof EntityMinecartHopper) { - getHandle().openMinecartHopper((EntityMinecartHopper) craftinv.getInventory()); + getHandle().openTileEntity((EntityMinecartHopper) craftinv.getInventory()); } else { - openCustomInventory(inventory, player, 9); + openCustomInventory(inventory, player, "minecraft:hopper"); } break; case CREATIVE: @@ -239,7 +230,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { return getHandle().activeContainer.getBukkitView(); } - private void openCustomInventory(Inventory inventory, EntityPlayer player, int windowType) { + private void openCustomInventory(Inventory inventory, EntityPlayer player, String windowType) { if (player.playerConnection == null) return; Container container = new CraftContainer(inventory, this, player.nextContainerCounter()); @@ -249,7 +240,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { String title = container.getBukkitView().getTitle(); int size = container.getBukkitView().getTopInventory().getSize(); - player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, windowType, title, size, true)); + player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, windowType, new ChatComponentText(title), size)); getHandle().activeContainer = container; getHandle().activeContainer.addSlotListener(player); } @@ -264,7 +255,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { if (location == null) { location = getLocation(); } - getHandle().startCrafting(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + getHandle().openTileEntity(new TileEntityContainerWorkbench(getHandle().world, new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()))); if (force) { getHandle().activeContainer.checkReachable = false; } @@ -281,7 +272,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { if (location == null) { location = getLocation(); } - getHandle().startEnchanting(location.getBlockX(), location.getBlockY(), location.getBlockZ(), null); + getHandle().openTileEntity((ITileEntityContainer) getHandle().world.getTileEntity(new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()))); if (force) { getHandle().activeContainer.checkReachable = false; } @@ -311,10 +302,10 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { // Now open the window InventoryType type = inventory.getType(); - int windowType = CraftContainer.getNotchInventoryType(type); + String windowType = CraftContainer.getNotchInventoryType(type); String title = inventory.getTitle(); int size = inventory.getTopInventory().getSize(); - player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, windowType, title, size, false)); + player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, windowType, new ChatComponentText(title), size)); player.activeContainer = container; player.activeContainer.addSlotListener(player); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index add554e9b2..e31fcc1741 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -197,11 +197,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { reason = DamageSource.mobAttack(((CraftLivingEntity) source).getHandle()); } - if (entity instanceof EntityEnderDragon) { - ((EntityEnderDragon) entity).dealDamage(reason, (float) amount); - } else { - entity.damageEntity(reason, (float) amount); - } + entity.damageEntity(reason, (float) amount); } public Location getEyeLocation() { @@ -263,7 +259,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { } removePotionEffect(effect.getType()); } - getHandle().addEffect(new MobEffect(effect.getType().getId(), effect.getDuration(), effect.getAmplifier(), effect.isAmbient())); + getHandle().addEffect(new MobEffect(effect.getType().getId(), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), true)); return true; } @@ -384,47 +380,6 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { return super.teleport(location, cause); } - public void setCustomName(String name) { - if (!(getHandle() instanceof EntityInsentient)) { - return; - } - - if (name == null) { - name = ""; - } - - // Names cannot be more than 64 characters due to DataWatcher limitations - if (name.length() > 64) { - name = name.substring(0, 64); - } - - ((EntityInsentient) getHandle()).setCustomName(name); - } - - public String getCustomName() { - if (!(getHandle() instanceof EntityInsentient)) { - return null; - } - - String name = ((EntityInsentient) getHandle()).getCustomName(); - - if (name == null || name.length() == 0) { - return null; - } - - return name; - } - - public void setCustomNameVisible(boolean flag) { - if (getHandle() instanceof EntityInsentient) { - ((EntityInsentient) getHandle()).setCustomNameVisible(flag); - } - } - - public boolean isCustomNameVisible() { - return getHandle() instanceof EntityInsentient && ((EntityInsentient) getHandle()).getCustomNameVisible(); - } - public boolean isLeashed() { if (!(getHandle() instanceof EntityInsentient)) { return false; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java index 925a15f0a7..efad618f7f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java @@ -54,9 +54,7 @@ public class CraftPainting extends CraftHanging implements Painting { private void update() { WorldServer world = ((CraftWorld) getWorld()).getHandle(); EntityPainting painting = new EntityPainting(world); - painting.x = getHandle().x; - painting.y = getHandle().y; - painting.z = getHandle().z; + painting.blockPosition = getHandle().blockPosition; painting.art = getHandle().art; painting.setDirection(getHandle().direction); getHandle().die(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index bbf310b080..286a58c2f4 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1,12 +1,14 @@ package org.bukkit.craftbukkit.entity; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.MapMaker; +import com.mojang.authlib.GameProfile; +import io.netty.buffer.Unpooled; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; @@ -19,7 +21,6 @@ import java.util.logging.Logger; import net.minecraft.server.*; -import net.minecraft.util.com.mojang.authlib.GameProfile; import org.apache.commons.lang.Validate; import org.apache.commons.lang.NotImplementedException; import org.bukkit.*; @@ -53,6 +54,7 @@ import org.bukkit.event.player.PlayerRegisterChannelEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerUnregisterChannelEvent; import org.bukkit.inventory.InventoryView.Property; +import org.bukkit.map.MapCursor; import org.bukkit.map.MapView; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; @@ -174,44 +176,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public String getPlayerListName() { - return getHandle().listName; + return CraftChatMessage.fromComponent(getHandle().listName); } @Override public void setPlayerListName(String name) { - String oldName = getHandle().listName; - if (name == null) { name = getName(); } - - if (oldName.equals(name)) { - return; - } - - if (name.length() > 16) { - throw new IllegalArgumentException("Player list names can only be a maximum of 16 characters long"); - } - - // Collisions will make for invisible people - for (int i = 0; i < server.getHandle().players.size(); ++i) { - if (((EntityPlayer) server.getHandle().players.get(i)).listName.equals(name)) { - throw new IllegalArgumentException(name + " is already assigned as a player list name for someone"); - } - } - - getHandle().listName = name; - - // Change the name on the client side - PacketPlayOutPlayerInfo oldpacket = new PacketPlayOutPlayerInfo(oldName, false, 9999); - PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(name, true, getHandle().ping); - for (int i = 0; i < server.getHandle().players.size(); ++i) { - EntityPlayer entityplayer = (EntityPlayer) server.getHandle().players.get(i); - if (entityplayer.playerConnection == null) continue; - - if (entityplayer.getBukkitEntity().canSee(this)) { - entityplayer.playerConnection.sendPacket(oldpacket); - entityplayer.playerConnection.sendPacket(packet); + getHandle().listName = name.equals(getName()) ? null : CraftChatMessage.fromString(name)[0]; + for (EntityPlayer player : (List)server.getHandle().players) { + if (player.getBukkitEntity().canSee(this)) { + player.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, getHandle())); } } } @@ -248,7 +224,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (getHandle().playerConnection == null) return; // Do not directly assign here, from the packethandler we'll assign it. - getHandle().playerConnection.sendPacket(new PacketPlayOutSpawnPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + getHandle().playerConnection.sendPacket(new PacketPlayOutSpawnPosition(new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()))); } @Override @@ -343,7 +319,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (getHandle().playerConnection == null) return; int packetData = effect.getId(); - PacketPlayOutWorldEvent packet = new PacketPlayOutWorldEvent(packetData, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), data, false); + PacketPlayOutWorldEvent packet = new PacketPlayOutWorldEvent(packetData, new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()), data, false); getHandle().playerConnection.sendPacket(packet); } @@ -368,10 +344,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public void sendBlockChange(Location loc, int material, byte data) { if (getHandle().playerConnection == null) return; - PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), ((CraftWorld) loc.getWorld()).getHandle()); + PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(((CraftWorld) loc.getWorld()).getHandle(), new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); - packet.block = CraftMagicNumbers.getBlock(material); - packet.data = data; + packet.block = CraftMagicNumbers.getBlock(material).fromLegacyData(data); getHandle().playerConnection.sendPacket(packet); } @@ -390,10 +365,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { throw new IllegalArgumentException("Must have at least 4 lines"); } - // Limit to 15 chars per line and set null lines to blank - String[] astring = CraftSign.sanitizeLines(lines); + IChatBaseComponent[] components = CraftSign.sanitizeLines(lines); - getHandle().playerConnection.sendPacket(new PacketPlayOutUpdateSign(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), astring)); + getHandle().playerConnection.sendPacket(new PacketPlayOutUpdateSign(getHandle().world, new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()), components)); } @Override @@ -435,15 +409,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (getHandle().playerConnection == null) return; RenderData data = ((CraftMapView) map).render(this); - for (int x = 0; x < 128; ++x) { - byte[] bytes = new byte[131]; - bytes[1] = (byte) x; - for (int y = 0; y < 128; ++y) { - bytes[y + 3] = data.buffer[y * 128 + x]; + Collection icons = new ArrayList(); + for (MapCursor cursor : data.cursors) { + if (cursor.isVisible()) { + icons.add(new MapIcon(cursor.getRawType(), cursor.getX(), cursor.getY(), cursor.getDirection())); } - PacketPlayOutMap packet = new PacketPlayOutMap(map.getId(), bytes); - getHandle().playerConnection.sendPacket(packet); } + + PacketPlayOutMap packet = new PacketPlayOutMap(map.getId(), map.getScale().getValue(), icons, data.buffer, 0, 0, 0, 0); + getHandle().playerConnection.sendPacket(packet); } @Override @@ -455,7 +429,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } if (entity.playerConnection == null || entity.playerConnection.isDisconnected()) { - return false; + return false; } if (entity.passenger != null) { @@ -781,7 +755,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (event.isCancelled()) { return; } - + + getHandle().e((Entity) getHandle()); // RENAME getHandle().playerInteractManager.setGameMode(EnumGamemode.getById(mode.getValue())); getHandle().fallDistance = 0; getHandle().playerConnection.sendPacket(new PacketPlayOutGameStateChange(3, mode.getValue())); @@ -793,90 +768,108 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return GameMode.getByValue(getHandle().playerInteractManager.getGameMode().getId()); } + @Override public void giveExp(int exp) { getHandle().giveExp(exp); } + @Override public void giveExpLevels(int levels) { getHandle().levelDown(levels); } + @Override public float getExp() { return getHandle().exp; } + @Override public void setExp(float exp) { getHandle().exp = exp; getHandle().lastSentExp = -1; } + @Override public int getLevel() { return getHandle().expLevel; } + @Override public void setLevel(int level) { getHandle().expLevel = level; getHandle().lastSentExp = -1; } + @Override public int getTotalExperience() { return getHandle().expTotal; } + @Override public void setTotalExperience(int exp) { getHandle().expTotal = exp; } + @Override public float getExhaustion() { return getHandle().getFoodData().exhaustionLevel; } + @Override public void setExhaustion(float value) { getHandle().getFoodData().exhaustionLevel = value; } + @Override public float getSaturation() { return getHandle().getFoodData().saturationLevel; } + @Override public void setSaturation(float value) { getHandle().getFoodData().saturationLevel = value; } + @Override public int getFoodLevel() { return getHandle().getFoodData().foodLevel; } + @Override public void setFoodLevel(int value) { getHandle().getFoodData().foodLevel = value; } + @Override public Location getBedSpawnLocation() { World world = getServer().getWorld(getHandle().spawnWorld); - ChunkCoordinates bed = getHandle().getBed(); + BlockPosition bed = getHandle().getBed(); if (world != null && bed != null) { bed = EntityHuman.getBed(((CraftWorld) world).getHandle(), bed, getHandle().isRespawnForced()); if (bed != null) { - return new Location(world, bed.x, bed.y, bed.z); + return new Location(world, bed.getX(), bed.getY(), bed.getZ()); } } return null; } + @Override public void setBedSpawnLocation(Location location) { setBedSpawnLocation(location, false); } + @Override public void setBedSpawnLocation(Location location, boolean override) { if (location == null) { getHandle().setRespawnPosition(null, override); } else { - getHandle().setRespawnPosition(new ChunkCoordinates(location.getBlockX(), location.getBlockY(), location.getBlockZ()), override); + getHandle().setRespawnPosition(new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()), override); getHandle().spawnWorld = location.getWorld().getName(); } } + @Override public void hidePlayer(Player player) { Validate.notNull(player, "hidden player cannot be null"); if (getHandle().playerConnection == null) return; @@ -893,9 +886,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } //remove the hidden player from this player user list - getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(player.getPlayerListName(), false, 9999)); + getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, other)); } + @Override public void showPlayer(Player player) { Validate.notNull(player, "shown player cannot be null"); if (getHandle().playerConnection == null) return; @@ -910,17 +904,19 @@ public class CraftPlayer extends CraftHumanEntity implements Player { entry.updatePlayer(getHandle()); } - getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(player.getPlayerListName(), true, getHandle().ping)); + getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, other)); } public void removeDisconnectingPlayer(Player player) { hiddenPlayers.remove(player.getUniqueId()); } + @Override public boolean canSee(Player player) { return !hiddenPlayers.contains(player.getUniqueId()); } + @Override public Map serialize() { Map result = new LinkedHashMap(); @@ -929,6 +925,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return result; } + @Override public Player getPlayer() { return this; } @@ -955,14 +952,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return hash; } + @Override public long getFirstPlayed() { return firstPlayed; } + @Override public long getLastPlayed() { return lastPlayed; } + @Override public boolean hasPlayedBefore() { return hasPlayedBefore; } @@ -1009,36 +1009,43 @@ public class CraftPlayer extends CraftHumanEntity implements Player { data.setString("lastKnownName", handle.getName()); } + @Override public boolean beginConversation(Conversation conversation) { return conversationTracker.beginConversation(conversation); } + @Override public void abandonConversation(Conversation conversation) { conversationTracker.abandonConversation(conversation, new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller())); } + @Override public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) { conversationTracker.abandonConversation(conversation, details); } + @Override public void acceptConversationInput(String input) { conversationTracker.acceptConversationInput(input); } + @Override public boolean isConversing() { return conversationTracker.isConversing(); } + @Override public void sendPluginMessage(Plugin source, String channel, byte[] message) { StandardMessenger.validatePluginMessage(server.getMessenger(), source, channel, message); if (getHandle().playerConnection == null) return; if (channels.contains(channel)) { - PacketPlayOutCustomPayload packet = new PacketPlayOutCustomPayload(channel, message); + PacketPlayOutCustomPayload packet = new PacketPlayOutCustomPayload(channel, new PacketDataSerializer(Unpooled.wrappedBuffer(message))); getHandle().playerConnection.sendPacket(packet); } } + @Override public void setTexturePack(String url) { setResourcePack(url); } @@ -1047,7 +1054,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public void setResourcePack(String url) { Validate.notNull(url, "Resource pack URL cannot be null"); - getHandle().setResourcePack(url); + getHandle().setResourcePack(url, "null"); } public void addChannel(String channel) { @@ -1062,6 +1069,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } } + @Override public Set getListeningPluginChannels() { return ImmutableSet.copyOf(channels); } @@ -1082,7 +1090,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } } - getHandle().playerConnection.sendPacket(new PacketPlayOutCustomPayload("REGISTER", stream.toByteArray())); + getHandle().playerConnection.sendPacket(new PacketPlayOutCustomPayload("REGISTER", new PacketDataSerializer(Unpooled.wrappedBuffer(stream.toByteArray())))); } } @@ -1126,10 +1134,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { perm.clearPermissions(); } + @Override public boolean isFlying() { return getHandle().abilities.isFlying; } + @Override public void setFlying(boolean value) { if (!getAllowFlight() && value) { throw new IllegalArgumentException("Cannot make player fly if getAllowFlight() is false"); @@ -1139,10 +1149,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { getHandle().updateAbilities(); } + @Override public boolean getAllowFlight() { return getHandle().abilities.canFly; } + @Override public void setAllowFlight(boolean value) { if (isFlying() && !value) { getHandle().abilities.isFlying = false; @@ -1161,6 +1173,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } } + @Override public void setFlySpeed(float value) { validateSpeed(value); EntityPlayer player = getHandle(); @@ -1169,6 +1182,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } + @Override public void setWalkSpeed(float value) { validateSpeed(value); EntityPlayer player = getHandle(); @@ -1176,10 +1190,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { player.updateAbilities(); } + @Override public float getFlySpeed() { return getHandle().abilities.flySpeed * 2f; } + @Override public float getWalkSpeed() { return getHandle().abilities.walkSpeed * 2f; } @@ -1209,10 +1225,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { getHandle().triggerHealthUpdate(); } + @Override public CraftScoreboard getScoreboard() { return this.server.getScoreboardManager().getPlayerBoard(this); } + @Override public void setScoreboard(Scoreboard scoreboard) { Validate.notNull(scoreboard, "Scoreboard cannot be null"); PlayerConnection playerConnection = getHandle().playerConnection; @@ -1226,6 +1244,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.server.getScoreboardManager().setPlayerBoard(this, scoreboard); } + @Override public void setHealthScale(double value) { Validate.isTrue((float) value > 0F, "Must be greater than 0"); healthScale = value; @@ -1233,16 +1252,19 @@ public class CraftPlayer extends CraftHumanEntity implements Player { updateScaledHealth(); } + @Override public double getHealthScale() { return healthScale; } + @Override public void setHealthScaled(boolean scale) { if (scaledHealth != (scaledHealth = scale)) { updateScaledHealth(); } } + @Override public boolean isHealthScaled() { return scaledHealth; } @@ -1285,6 +1307,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player { break; } } - collection.add(new AttributeModifiable(getHandle().getAttributeMap(), (new AttributeRanged("generic.maxHealth", scaledHealth ? healthScale : getMaxHealth(), 0.0D, Float.MAX_VALUE)).a("Max Health").a(true))); + collection.add(new AttributeModifiable(getHandle().getAttributeMap(), (new AttributeRanged(null, "generic.maxHealth", scaledHealth ? healthScale : getMaxHealth(), 0.0D, Float.MAX_VALUE)).a("Max Health").a(true))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java new file mode 100644 index 0000000000..62fc7ef24b --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java @@ -0,0 +1,23 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityRabbit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Rabbit; + +public class CraftRabbit extends CraftAnimals implements Rabbit { + + public CraftRabbit(CraftServer server, EntityRabbit entity) { + super(server, entity); + } + + @Override + public String toString() { + return "CraftRabbit"; + } + + @Override + public EntityType getType() { + return EntityType.RABBIT; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java index 81b938a210..f7253554cb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java @@ -2,6 +2,7 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntitySheep; +import net.minecraft.server.EnumColor; import org.bukkit.DyeColor; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.EntityType; @@ -13,11 +14,11 @@ public class CraftSheep extends CraftAnimals implements Sheep { } public DyeColor getColor() { - return DyeColor.getByWoolData((byte) getHandle().getColor()); + return DyeColor.getByWoolData((byte) getHandle().getColor().getColorIndex()); } public void setColor(DyeColor color) { - getHandle().setColor(color.getWoolData()); + getHandle().setColor(EnumColor.fromColorIndex(color.getWoolData())); } public boolean isSheared() { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java index d4bf3a0e1f..ea1d10b3cc 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java @@ -54,7 +54,7 @@ public class CraftTameableAnimal extends CraftAnimals implements Tameable, Creat public void setOwner(AnimalTamer tamer) { if (tamer != null) { setTamed(true); - getHandle().setPathEntity(null); + getHandle().setGoalTarget(null, null, false); setOwnerUUID(tamer.getUniqueId()); } else { setTamed(false); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java index 398029b90c..6fe21cce71 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java @@ -3,10 +3,13 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityVillager; import org.apache.commons.lang.Validate; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftInventory; import org.bukkit.entity.EntityType; import org.bukkit.entity.Villager; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; -public class CraftVillager extends CraftAgeable implements Villager { +public class CraftVillager extends CraftAgeable implements Villager, InventoryHolder { public CraftVillager(CraftServer server, EntityVillager entity) { super(server, entity); } @@ -33,4 +36,9 @@ public class CraftVillager extends CraftAgeable implements Villager { Validate.notNull(profession); getHandle().setProfession(profession.getId()); } + + @Override + public Inventory getInventory() { + return new CraftInventory(getHandle().inventory); + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java index 39e8d89bf4..ee21d7b6e9 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWaterMob.java @@ -3,9 +3,10 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityWaterAnimal; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.WaterMob; -public class CraftWaterMob extends CraftCreature implements WaterMob { +public class CraftWaterMob extends CraftLivingEntity implements WaterMob { public CraftWaterMob(CraftServer server, EntityWaterAnimal entity) { super(server, entity); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java index 3d0e7cb5b5..55ce37c7f6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityWolf; +import net.minecraft.server.EnumColor; import org.bukkit.DyeColor; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.EntityType; @@ -30,10 +31,10 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf { } public DyeColor getCollarColor() { - return DyeColor.getByWoolData((byte) getHandle().getCollarColor()); + return DyeColor.getByWoolData((byte) getHandle().getCollarColor().getColorIndex()); } public void setCollarColor(DyeColor color) { - getHandle().setCollarColor(color.getWoolData()); + getHandle().setCollarColor(EnumColor.fromColorIndex(color.getWoolData())); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 9b10c418e1..cc1d37187a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -9,30 +9,7 @@ import java.util.Map; import com.google.common.base.Function; import com.google.common.base.Functions; -import net.minecraft.server.ChunkCoordinates; -import net.minecraft.server.Container; -import net.minecraft.server.DamageSource; -import net.minecraft.server.Entity; -import net.minecraft.server.EntityArrow; -import net.minecraft.server.EntityDamageSource; -import net.minecraft.server.EntityDamageSourceIndirect; -import net.minecraft.server.EntityEnderCrystal; -import net.minecraft.server.EntityEnderDragon; -import net.minecraft.server.EntityHuman; -import net.minecraft.server.EntityInsentient; -import net.minecraft.server.EntityItem; -import net.minecraft.server.EntityLiving; -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.EntityPotion; -import net.minecraft.server.Explosion; -import net.minecraft.server.InventoryCrafting; -import net.minecraft.server.ItemStack; -import net.minecraft.server.Items; -import net.minecraft.server.PacketPlayInCloseWindow; -import net.minecraft.server.PacketPlayOutSetSlot; -import net.minecraft.server.Slot; -import net.minecraft.server.World; -import net.minecraft.server.WorldServer; +import net.minecraft.server.*; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -97,9 +74,9 @@ public class CraftEventFactory { if (((CraftServer) Bukkit.getServer()).getHandle().getOPs().isEmpty()) return true; if (player.isOp()) return true; - ChunkCoordinates chunkcoordinates = worldServer.getSpawn(); + BlockPosition chunkcoordinates = worldServer.getSpawn(); - int distanceFromSpawn = Math.max(Math.abs(x - chunkcoordinates.x), Math.abs(z - chunkcoordinates.z)); + int distanceFromSpawn = Math.max(Math.abs(x - chunkcoordinates.getX()), Math.abs(z - chunkcoordinates.getY())); return distanceFromSpawn > spawnSize; } @@ -152,15 +129,15 @@ public class CraftEventFactory { /** * Bucket methods */ - public static PlayerBucketEmptyEvent callPlayerBucketEmptyEvent(EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemInHand) { + public static PlayerBucketEmptyEvent callPlayerBucketEmptyEvent(EntityHuman who, int clickedX, int clickedY, int clickedZ, EnumDirection clickedFace, ItemStack itemInHand) { return (PlayerBucketEmptyEvent) getPlayerBucketEvent(false, who, clickedX, clickedY, clickedZ, clickedFace, itemInHand, Items.BUCKET); } - public static PlayerBucketFillEvent callPlayerBucketFillEvent(EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemInHand, net.minecraft.server.Item bucket) { + public static PlayerBucketFillEvent callPlayerBucketFillEvent(EntityHuman who, int clickedX, int clickedY, int clickedZ, EnumDirection clickedFace, ItemStack itemInHand, net.minecraft.server.Item bucket) { return (PlayerBucketFillEvent) getPlayerBucketEvent(true, who, clickedX, clickedY, clickedZ, clickedFace, itemInHand, bucket); } - private static PlayerEvent getPlayerBucketEvent(boolean isFilling, EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemstack, net.minecraft.server.Item item) { + private static PlayerEvent getPlayerBucketEvent(boolean isFilling, EntityHuman who, int clickedX, int clickedY, int clickedZ, EnumDirection clickedFace, ItemStack itemstack, net.minecraft.server.Item item) { Player player = (who == null) ? null : (Player) who.getBukkitEntity(); CraftItemStack itemInHand = CraftItemStack.asNewCraftStack(item); Material bucket = CraftMagicNumbers.getMaterial(itemstack.getItem()); @@ -192,20 +169,24 @@ public class CraftEventFactory { if (action != Action.LEFT_CLICK_AIR && action != Action.RIGHT_CLICK_AIR) { throw new AssertionError(String.format("%s performing %s with %s", who, action, itemstack)); } - return callPlayerInteractEvent(who, action, 0, 256, 0, 0, itemstack); + return callPlayerInteractEvent(who, action, new BlockPosition(0, 256, 0), EnumDirection.SOUTH, itemstack); } - public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemstack) { + public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, BlockPosition position, EnumDirection direction, ItemStack itemstack) { + return callPlayerInteractEvent(who, action, position, direction, itemstack, false); + } + + public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, BlockPosition position, EnumDirection direction, ItemStack itemstack, boolean cancelledBlock) { Player player = (who == null) ? null : (Player) who.getBukkitEntity(); CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack); CraftWorld craftWorld = (CraftWorld) player.getWorld(); CraftServer craftServer = (CraftServer) player.getServer(); - Block blockClicked = craftWorld.getBlockAt(clickedX, clickedY, clickedZ); - BlockFace blockFace = CraftBlock.notchToBlockFace(clickedFace); + Block blockClicked = craftWorld.getBlockAt(position.getX(), position.getY(), position.getZ()); + BlockFace blockFace = CraftBlock.notchToBlockFace(direction); - if (clickedY > 255) { + if (position.getY() > 255) { blockClicked = null; switch (action) { case LEFT_CLICK_BLOCK: @@ -222,6 +203,9 @@ public class CraftEventFactory { } PlayerInteractEvent event = new PlayerInteractEvent(player, action, itemInHand, blockClicked, blockFace); + if (cancelledBlock) { + event.setUseInteractedBlock(Event.Result.DENY); + } craftServer.getPluginManager().callEvent(event); return event; @@ -415,7 +399,7 @@ public class CraftEventFactory { EntityDamageEvent event; if (damager == null) { event = new EntityDamageByBlockEvent(null, entity.getBukkitEntity(), DamageCause.BLOCK_EXPLOSION, modifiers, modifierFunctions); - } else if (entity instanceof EntityEnderDragon && ((EntityEnderDragon) entity).bC == damager) { + } else if (entity instanceof EntityEnderDragon && ((EntityEnderDragon) entity).bx == damager) { event = new EntityDamageEvent(entity.getBukkitEntity(), DamageCause.ENTITY_EXPLOSION, modifiers, modifierFunctions); } else { if (damager instanceof org.bukkit.entity.TNTPrimed) { @@ -840,7 +824,7 @@ public class CraftEventFactory { ItemStack itemInHand = player.inventory.getItem(itemInHandIndex); // If they've got the same item in their hand, it'll need to be updated. - if (itemInHand != null && itemInHand.getItem() == Items.BOOK_AND_QUILL) { + if (itemInHand != null && itemInHand.getItem() == Items.WRITABLE_BOOK) { if (!editBookEvent.isCancelled()) { CraftItemStack.setItemMeta(itemInHand, editBookEvent.getNewBookMeta()); if (editBookEvent.isSigning()) { @@ -876,6 +860,10 @@ public class CraftEventFactory { event = new PlayerAchievementAwardedEvent(player, CraftStatistic.getBukkitAchievement((net.minecraft.server.Achievement) statistic)); } else { org.bukkit.Statistic stat = CraftStatistic.getBukkitStatistic(statistic); + if (stat == null) { + System.err.println("Unhandled statistic: " + statistic); + return null; + } switch (stat) { case FALL_ONE_CM: case BOAT_ONE_CM: @@ -888,6 +876,9 @@ public class CraftEventFactory { case PLAY_ONE_TICK: case SWIM_ONE_CM: case WALK_ONE_CM: + case SPRINT_ONE_CM: + case CROUCH_ONE_CM: + case TIME_SINCE_DEATH: // Do not process event for these - too spammy return null; default: diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java index 9a46d0c72b..d47755a091 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -3,16 +3,7 @@ package org.bukkit.craftbukkit.generator; import java.util.List; import java.util.Random; -import net.minecraft.server.BiomeBase; -import net.minecraft.server.Chunk; -import net.minecraft.server.ChunkPosition; -import net.minecraft.server.ChunkSection; -import net.minecraft.server.EnumCreatureType; -import net.minecraft.server.IChunkProvider; -import net.minecraft.server.IProgressUpdate; -import net.minecraft.server.World; -import net.minecraft.server.WorldGenStronghold; -import net.minecraft.server.WorldServer; +import net.minecraft.server.*; import org.bukkit.block.Biome; import org.bukkit.generator.BlockPopulator; @@ -71,27 +62,14 @@ public class CustomChunkGenerator extends InternalChunkGenerator { if (xbtypes[sec] == null) { continue; } - byte[] secBlkID = new byte[4096]; // Allocate blk ID bytes - byte[] secExtBlkID = null; // Delay getting extended ID nibbles + char[] secBlkID = new char[4096]; // Allocate blk ID bytes short[] bdata = xbtypes[sec]; // Loop through data, 2 blocks at a time - for (int i = 0, j = 0; i < bdata.length; i += 2, j++) { - short b1 = bdata[i]; - short b2 = bdata[i + 1]; - byte extb = (byte) ((b1 >> 8) | ((b2 >> 4) & 0xF0)); - - secBlkID[i] = (byte) b1; - secBlkID[(i + 1)] = (byte) b2; - - if (extb != 0) { // If extended block ID data - if (secExtBlkID == null) { // Allocate if needed - secExtBlkID = new byte[2048]; - } - secExtBlkID[j] = extb; - } + for (int i = 0; i < bdata.length; i++) { + secBlkID[i] = (char) ((int)bdata[i] << 4); } // Build chunk section - csect[sec] = new ChunkSection(sec << 4, true, secBlkID, secExtBlkID); + csect[sec] = new ChunkSection(sec << 4, true, secBlkID); } } else { // Else check for byte-per-block section data @@ -107,7 +85,12 @@ public class CustomChunkGenerator extends InternalChunkGenerator { if (btypes[sec] == null) { continue; } - csect[sec] = new ChunkSection(sec << 4, true, btypes[sec], null); + + char[] secBlkID = new char[4096]; // Allocate block ID bytes + for (int i = 0; i < secBlkID.length; i++) { + secBlkID[i] = (char)(((int) btypes[sec][i]) << 4); + } + csect[sec] = new ChunkSection(sec << 4, true, secBlkID); } } else { // Else, fall back to pre 1.2 method @@ -124,7 +107,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator { // Loop through sections for (int sec = 0; sec < scnt; sec++) { ChunkSection cs = null; // Add sections when needed - byte[] csbytes = null; + char[] csbytes = null; for (int cy = 0; cy < 16; cy++) { int cyoff = cy | (sec << 4); @@ -140,7 +123,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator { cs = csect[sec] = new ChunkSection(sec << 4, true); csbytes = cs.getIdArray(); } - csbytes[(cy << 8) | (cz << 4) | cx] = blk; + csbytes[(cy << 8) | (cz << 4) | cx] = (char)((int)blk << 4); } } } @@ -153,7 +136,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator { } } // Set biome grid - byte[] biomeIndex = chunk.m(); + byte[] biomeIndex = chunk.getBiomeIndex(); for (int i = 0; i < biomeIndex.length; i++) { biomeIndex[i] = (byte) (biomegrid.biome[i].id & 0xFF); } @@ -163,10 +146,20 @@ public class CustomChunkGenerator extends InternalChunkGenerator { return chunk; } + @Override + public Chunk getChunkAt(BlockPosition blockPosition) { + return getChunkAt(blockPosition.getX() >> 4, blockPosition.getZ() >> 4); + } + public void getChunkAt(IChunkProvider icp, int i, int i1) { // Nothing! } + @Override + public boolean a(IChunkProvider iChunkProvider, Chunk chunk, int i, int i1) { + return false; + } + public boolean saveChunks(boolean bln, IProgressUpdate ipu) { return true; } @@ -206,14 +199,16 @@ public class CustomChunkGenerator extends InternalChunkGenerator { return generator.getDefaultPopulators(world); } - public List getMobsFor(EnumCreatureType type, int x, int y, int z) { - BiomeBase biomebase = world.getBiome(x, z); + @Override + public List getMobsFor(EnumCreatureType type, BlockPosition position) { + BiomeBase biomebase = world.getBiome(position); return biomebase == null ? null : biomebase.getMobs(type); } - public ChunkPosition findNearestMapFeature(World world, String type, int x, int y, int z) { - return "Stronghold".equals(type) && this.strongholdGen != null ? this.strongholdGen.getNearestGeneratedFeature(world, x, y, z) : null; + @Override + public BlockPosition findNearestMapFeature(World world, String type, BlockPosition position) { + return "Stronghold".equals(type) && this.strongholdGen != null ? this.strongholdGen.getNearestGeneratedFeature(world, position) : null; } public void recreateStructures(int i, int j) {} @@ -222,6 +217,11 @@ public class CustomChunkGenerator extends InternalChunkGenerator { return 0; } + @Override + public void recreateStructures(Chunk chunk, int i, int i1) { + + } + public String getName() { return "CustomChunkGenerator"; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java index ceab581644..4230bdb2a4 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/NormalChunkGenerator.java @@ -4,12 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import net.minecraft.server.Chunk; -import net.minecraft.server.ChunkPosition; -import net.minecraft.server.EnumCreatureType; -import net.minecraft.server.IChunkProvider; -import net.minecraft.server.IProgressUpdate; -import net.minecraft.server.World; +import net.minecraft.server.*; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.generator.BlockPopulator; @@ -21,66 +16,87 @@ public class NormalChunkGenerator extends InternalChunkGenerator { provider = world.worldProvider.getChunkProvider(); } + @Override public byte[] generate(org.bukkit.World world, Random random, int x, int z) { throw new UnsupportedOperationException("Not supported."); } + @Override public boolean canSpawn(org.bukkit.World world, int x, int z) { return ((CraftWorld) world).getHandle().worldProvider.canSpawn(x, z); } + @Override public List getDefaultPopulators(org.bukkit.World world) { return new ArrayList(); } + @Override public boolean isChunkLoaded(int i, int i1) { return provider.isChunkLoaded(i, i1); } + @Override public Chunk getOrCreateChunk(int i, int i1) { return provider.getOrCreateChunk(i, i1); } - public Chunk getChunkAt(int i, int i1) { - return provider.getChunkAt(i, i1); + @Override + public Chunk getChunkAt(BlockPosition blockPosition) { + return provider.getChunkAt(blockPosition); } + @Override public void getChunkAt(IChunkProvider icp, int i, int i1) { provider.getChunkAt(icp, i, i1); } + @Override + public boolean a(IChunkProvider iChunkProvider, Chunk chunk, int i, int i1) { + return provider.a(provider, chunk, i, i1); + } + + @Override public boolean saveChunks(boolean bln, IProgressUpdate ipu) { return provider.saveChunks(bln, ipu); } + @Override public boolean unloadChunks() { return provider.unloadChunks(); } + @Override public boolean canSave() { return provider.canSave(); } - public List getMobsFor(EnumCreatureType ect, int i, int i1, int i2) { - return provider.getMobsFor(ect, i, i1, i2); + @Override + public List getMobsFor(EnumCreatureType ect, BlockPosition position) { + return provider.getMobsFor(ect, position); } - public ChunkPosition findNearestMapFeature(World world, String string, int i, int i1, int i2) { - return provider.findNearestMapFeature(world, string, i, i1, i2); - } - - public void recreateStructures(int i, int j) { - provider.recreateStructures(i, j); + @Override + public BlockPosition findNearestMapFeature(World world, String string, BlockPosition position) { + return provider.findNearestMapFeature(world, string, position); } // n.m.s implementations always return 0. (The true implementation is in ChunkProviderServer) + @Override public int getLoadedChunks() { return 0; } + @Override + public void recreateStructures(Chunk chunk, int i, int i1) { + provider.recreateStructures(chunk, i, i1); + } + + @Override public String getName() { return "NormalWorldGenerator"; } + @Override public void c() {} } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java index 42568a2435..1dbc588e72 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.inventory; +import net.minecraft.server.ChatComponentText; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.HumanEntity; import org.bukkit.event.inventory.InventoryType; @@ -76,7 +77,7 @@ public class CraftContainer extends Container { cachedTitle = view.getTitle(); if (view.getPlayer() instanceof CraftPlayer) { CraftPlayer player = (CraftPlayer) view.getPlayer(); - int type = getNotchInventoryType(cachedType); + String type = getNotchInventoryType(cachedType); IInventory top = ((CraftInventory)view.getTopInventory()).getInventory(); IInventory bottom = ((CraftInventory)view.getBottomInventory()).getInventory(); this.b.clear(); @@ -85,44 +86,33 @@ public class CraftContainer extends Container { setupSlots(top, bottom); } int size = getSize(); - player.getHandle().playerConnection.sendPacket(new PacketPlayOutOpenWindow(this.windowId, type, cachedTitle, size, true)); + player.getHandle().playerConnection.sendPacket(new PacketPlayOutOpenWindow(this.windowId, type, new ChatComponentText(cachedTitle), size)); player.updateInventory(); } return true; } - public static int getNotchInventoryType(InventoryType type) { - int typeID; + public static String getNotchInventoryType(InventoryType type) { switch(type) { case WORKBENCH: - typeID = 1; - break; + return "minecraft:crafting_table"; case FURNACE: - typeID = 2; - break; + return "minecraft:furnace"; case DISPENSER: - typeID = 3; - break; + return "minecraft:dispenser"; case ENCHANTING: - typeID = 4; - break; + return "minecraft:enchanting_table"; case BREWING: - typeID = 5; - break; + return "minecraft:brewing_stand"; case BEACON: - typeID = 7; - break; + return "minecraft:beacon"; case ANVIL: - typeID = 8; - break; + return "minecraft:anvil"; case HOPPER: - typeID = 9; - break; + return "minecraft:hopper"; default: - typeID = 0; - break; + return "minecraft:chest"; } - return typeID; } private void setupSlots(IInventory top, IInventory bottom) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java index 6748465da6..7ae6f12c54 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java @@ -42,7 +42,7 @@ public class CraftInventory implements Inventory { } public String getName() { - return getInventory().getInventoryName(); + return getInventory().getName(); } public ItemStack getItem(int index) { @@ -58,7 +58,6 @@ public class CraftInventory implements Inventory { for (int i = 0; i < size; i++) { items[i] = mcItems[i] == null ? null : CraftItemStack.asCraftMirror(mcItems[i]); } - return items; } @@ -421,7 +420,7 @@ public class CraftInventory implements Inventory { } public String getTitle() { - return inventory.getInventoryName(); + return inventory.getName(); } public InventoryType getType() { @@ -437,7 +436,7 @@ public class CraftInventory implements Inventory { } else if (inventory instanceof TileEntityFurnace) { return InventoryType.FURNACE; } else if (inventory instanceof ContainerEnchantTableInventory) { - return InventoryType.ENCHANTING; + return InventoryType.ENCHANTING; } else if (inventory instanceof TileEntityBrewingStand) { return InventoryType.BREWING; } else if (inventory instanceof CraftInventoryCustom.MinecraftInventory) { @@ -449,7 +448,7 @@ public class CraftInventory implements Inventory { } else if (inventory instanceof TileEntityBeacon) { return InventoryType.BEACON; } else if (inventory instanceof ContainerAnvilInventory) { - return InventoryType.ANVIL; + return InventoryType.ANVIL; } else if (inventory instanceof IHopper) { return InventoryType.HOPPER; } else { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java index 7bbf1df5c7..e155329ef5 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java @@ -55,7 +55,7 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn for (int j = 0; j < mcItems.length; j++) { items[i + j] = CraftItemStack.asCraftMirror(mcItems[j]); } - + return items; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java index 8b8a317cea..947c4939d1 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java @@ -2,7 +2,9 @@ package org.bukkit.craftbukkit.inventory; import java.util.ArrayList; import java.util.List; +import net.minecraft.server.ChatComponentText; +import net.minecraft.server.IChatBaseComponent; import org.apache.commons.lang.Validate; import org.bukkit.craftbukkit.entity.CraftHumanEntity; import org.bukkit.entity.HumanEntity; @@ -106,10 +108,6 @@ public class CraftInventoryCustom extends CraftInventory { } } - public String getInventoryName() { - return title; - } - public int getMaxStackSize() { return maxStack; } @@ -143,21 +141,58 @@ public class CraftInventoryCustom extends CraftInventory { public InventoryType getType() { return type; } - - public void closeContainer() {} - + public InventoryHolder getOwner() { return owner; } - public void startOpen() {} - - public boolean k_() { - return false; - } - public boolean b(int i, ItemStack itemstack) { return true; } + + @Override + public void startOpen(EntityHuman entityHuman) { + + } + + @Override + public void closeContainer(EntityHuman entityHuman) { + + } + + @Override + public int getProperty(int i) { + return 0; + } + + @Override + public void b(int i, int i1) { + + } + + @Override + public int g() { + return 0; + } + + @Override + public void l() { + + } + + @Override + public String getName() { + return title; + } + + @Override + public boolean hasCustomName() { + return title != null; + } + + @Override + public IChatBaseComponent getScoreboardDisplayName() { + return new ChatComponentText(title); + } } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java index 0459f41ffa..87252cad4f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java @@ -1,5 +1,7 @@ package org.bukkit.craftbukkit.inventory; +import net.minecraft.server.ITileEntityContainer; +import net.minecraft.server.ITileInventory; import org.bukkit.block.DoubleChest; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; @@ -12,7 +14,7 @@ public class CraftInventoryDoubleChest extends CraftInventory implements DoubleC private final CraftInventory right; public CraftInventoryDoubleChest(CraftInventory left, CraftInventory right) { - super(new InventoryLargeChest("Large chest", left.getInventory(), right.getInventory())); + super(new InventoryLargeChest("Large chest", (ITileInventory) left.getInventory(), (ITileInventory) right.getInventory())); this.left = left; this.right = right; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java index fdc58f1600..068881d2de 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryEnchanting.java @@ -10,10 +10,12 @@ public class CraftInventoryEnchanting extends CraftInventory implements Enchanti super(inventory); } + @Override public void setItem(ItemStack item) { setItem(0,item); } + @Override public ItemStack getItem() { return getItem(0); } @@ -22,4 +24,14 @@ public class CraftInventoryEnchanting extends CraftInventory implements Enchanti public ContainerEnchantTableInventory getInventory() { return (ContainerEnchantTableInventory)inventory; } + + @Override + public void setSecondary(ItemStack item) { + setItem(1, item); + } + + @Override + public ItemStack getSecondary() { + return getItem(1); + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java index 1b2394def0..8dd889de61 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java @@ -81,6 +81,8 @@ public final class CraftItemFactory implements ItemFactory { return meta instanceof CraftMetaCharge ? meta : new CraftMetaCharge(meta); case ENCHANTED_BOOK: return meta instanceof CraftMetaEnchantedBook ? meta : new CraftMetaEnchantedBook(meta); + case BANNER: + return meta instanceof CraftMetaBanner ? meta : new CraftMetaBanner(meta); default: return new CraftMetaItem(meta); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 704be690c8..b49c2dca22 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -185,7 +185,7 @@ public final class CraftItemStack extends ItemStack { NBTTagList list = getEnchantmentList(handle); if (list == null) { list = new NBTTagList(); - handle.tag.set(ENCHANTMENTS.NBT, list); + handle.getTag().set(ENCHANTMENTS.NBT, list); } int size = list.size(); @@ -208,7 +208,7 @@ public final class CraftItemStack extends ItemStack { return false; } - if (item.tag == null) { + if (item.getTag() == null) { item.setTag(new NBTTagCompound()); } @@ -255,9 +255,9 @@ public final class CraftItemStack extends ItemStack { return 0; } if (size == 1) { - handle.tag.remove(ENCHANTMENTS.NBT); - if (handle.tag.isEmpty()) { - handle.tag = null; + handle.getTag().remove(ENCHANTMENTS.NBT); + if (handle.getTag().isEmpty()) { + handle.setTag(null); } return level; } @@ -269,7 +269,7 @@ public final class CraftItemStack extends ItemStack { listCopy.add(list.get(i)); } } - handle.tag.set(ENCHANTMENTS.NBT, listCopy); + handle.getTag().set(ENCHANTMENTS.NBT, listCopy); return level; } @@ -323,26 +323,28 @@ public final class CraftItemStack extends ItemStack { switch (getType(item)) { case WRITTEN_BOOK: case BOOK_AND_QUILL: - return new CraftMetaBook(item.tag); + return new CraftMetaBook(item.getTag()); case SKULL_ITEM: - return new CraftMetaSkull(item.tag); + return new CraftMetaSkull(item.getTag()); case LEATHER_HELMET: case LEATHER_CHESTPLATE: case LEATHER_LEGGINGS: case LEATHER_BOOTS: - return new CraftMetaLeatherArmor(item.tag); + return new CraftMetaLeatherArmor(item.getTag()); case POTION: - return new CraftMetaPotion(item.tag); + return new CraftMetaPotion(item.getTag()); case MAP: - return new CraftMetaMap(item.tag); + return new CraftMetaMap(item.getTag()); case FIREWORK: - return new CraftMetaFirework(item.tag); + return new CraftMetaFirework(item.getTag()); case FIREWORK_CHARGE: - return new CraftMetaCharge(item.tag); + return new CraftMetaCharge(item.getTag()); case ENCHANTED_BOOK: - return new CraftMetaEnchantedBook(item.tag); + return new CraftMetaEnchantedBook(item.getTag()); + case BANNER: + return new CraftMetaBanner(item.getTag()); default: - return new CraftMetaItem(item.tag); + return new CraftMetaItem(item.getTag()); } } @@ -361,7 +363,7 @@ public final class CraftItemStack extends ItemStack { return false; } if (CraftItemFactory.instance().equals(itemMeta, null)) { - item.tag = null; + item.setTag(null); return true; } if (!CraftItemFactory.instance().isApplicable(itemMeta, getType(item))) { @@ -397,7 +399,7 @@ public final class CraftItemStack extends ItemStack { if (!(that.getTypeId() == getTypeId() && getDurability() == that.getDurability())) { return false; } - return hasItemMeta() ? that.hasItemMeta() && handle.tag.equals(that.handle.tag) : !that.hasItemMeta(); + return hasItemMeta() ? that.hasItemMeta() && handle.getTag().equals(that.handle.getTag()) : !that.hasItemMeta(); } @Override @@ -406,6 +408,6 @@ public final class CraftItemStack extends ItemStack { } static boolean hasItemMeta(net.minecraft.server.ItemStack item) { - return !(item == null || item.tag == null || item.tag.isEmpty()); + return !(item == null || item.getTag() == null || item.getTag().isEmpty()); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java new file mode 100644 index 0000000000..d61615bfad --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java @@ -0,0 +1,196 @@ +package org.bukkit.craftbukkit.inventory; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import net.minecraft.server.NBTTagCompound; +import net.minecraft.server.NBTTagList; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; +import org.bukkit.configuration.serialization.DelegateDeserialization; +import org.bukkit.inventory.meta.BannerMeta; + +@DelegateDeserialization(CraftMetaItem.SerializableMeta.class) +public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { + + static final ItemMetaKey BASE = new ItemMetaKey("Base", "base-color"); + static final ItemMetaKey PATTERNS = new ItemMetaKey("Patterns", "patterns"); + static final ItemMetaKey COLOR = new ItemMetaKey("Color", "color"); + static final ItemMetaKey PATTERN = new ItemMetaKey("Pattern", "pattern"); + + private DyeColor base; + private List patterns = new ArrayList(); + + CraftMetaBanner(CraftMetaItem meta) { + super(meta); + + if (!(meta instanceof CraftMetaBanner)) { + return; + } + + CraftMetaBanner banner = (CraftMetaBanner) meta; + base = banner.base; + patterns = new ArrayList(banner.patterns); + } + + CraftMetaBanner(NBTTagCompound tag) { + super(tag); + + if (!tag.hasKey("BlockEntityTag")) { + return; + } + + NBTTagCompound entityTag = tag.getCompound("BlockEntityTag"); + + base = entityTag.hasKey(BASE.NBT) ? DyeColor.getByDyeData((byte) entityTag.getInt(BASE.NBT)) : null; + + if (entityTag.hasKey(PATTERNS.NBT)) { + NBTTagList patterns = entityTag.getList(PATTERNS.NBT, 10); + for (int i = 0; i < patterns.size(); i++) { + NBTTagCompound p = (NBTTagCompound) patterns.get(i); + this.patterns.add(new Pattern(DyeColor.getByDyeData((byte) p.getInt(COLOR.NBT)), PatternType.getByIdentifier(p.getString(PATTERN.NBT)))); + } + } + } + + CraftMetaBanner(Map map) { + super(map); + + base = SerializableMeta.getObject(DyeColor.class, map, BASE.BUKKIT, true); + + Iterable rawPatternList = SerializableMeta.getObject(Iterable.class, map, PATTERNS.BUKKIT, true); + if (rawPatternList == null) { + return; + } + + for (Object obj : rawPatternList) { + if (!(obj instanceof Pattern)) { + throw new IllegalArgumentException("Object in pattern list is not valid. " + obj.getClass()); + } + addPattern((Pattern) obj); + } + } + @Override + void applyToItem(NBTTagCompound tag) { + super.applyToItem(tag); + + NBTTagCompound entityTag = new NBTTagCompound(); + if (base != null) { + entityTag.setInt(BASE.NBT, base.getDyeData()); + } + + NBTTagList newPatterns = new NBTTagList(); + + for (Pattern p : patterns) { + NBTTagCompound compound = new NBTTagCompound(); + compound.setInt(COLOR.NBT, p.getColor().getDyeData()); + compound.setString(PATTERN.NBT, p.getPattern().getIdentifier()); + newPatterns.add(compound); + } + entityTag.set(PATTERNS.NBT, newPatterns); + + tag.set("BlockEntityTag", entityTag); + } + + @Override + public DyeColor getBaseColor() { + return base; + } + + @Override + public void setBaseColor(DyeColor color) { + base = color; + } + + @Override + public List getPatterns() { + return new ArrayList(patterns); + } + + @Override + public void setPatterns(List patterns) { + this.patterns = new ArrayList(patterns); + } + + @Override + public void addPattern(Pattern pattern) { + patterns.add(pattern); + } + + @Override + public Pattern getPattern(int i) { + return patterns.get(i); + } + + @Override + public Pattern removePattern(int i) { + return patterns.remove(i); + } + + @Override + public void setPattern(int i, Pattern pattern) { + patterns.set(i, pattern); + } + + @Override + public int numberOfPatterns() { + return patterns.size(); + } + + @Override + ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { + super.serialize(builder); + + builder.put(BASE.BUKKIT, base); + builder.put(PATTERNS.BUKKIT, ImmutableList.copyOf(patterns)); + + return builder; + } + + @Override + int applyHash() { + final int original; + int hash = original = super.applyHash(); + if (base != null) { + hash = 31 * hash + base.hashCode(); + } + if (!patterns.isEmpty()) { + hash = 31 * hash + patterns.hashCode(); + } + return original != hash ? CraftMetaBanner.class.hashCode() ^ hash : hash; + } + + @Override + public boolean equalsCommon(CraftMetaItem meta) { + if (!super.equalsCommon(meta)) { + return false; + } + if (meta instanceof CraftMetaBanner) { + CraftMetaBanner that = (CraftMetaBanner) meta; + + return base == that.base && patterns.equals(that.patterns); + } + return true; + } + + @Override + boolean notUncommon(CraftMetaItem meta) { + return super.notUncommon(meta) && (meta instanceof CraftMetaBanner || (patterns.isEmpty() && base == null)); + } + + + @Override + boolean isEmpty() { + return super.isEmpty() && patterns.isEmpty() && base == null; + } + + + @Override + boolean applicableTo(Material type) { + return type == Material.BANNER; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java index 1cf8fce416..9a24d2e7dd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java @@ -16,18 +16,25 @@ import org.bukkit.inventory.meta.BookMeta; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap.Builder; +import net.minecraft.server.ChatSerializer; +import net.minecraft.server.NBTTagString; +import org.bukkit.craftbukkit.util.CraftChatMessage; @DelegateDeserialization(SerializableMeta.class) class CraftMetaBook extends CraftMetaItem implements BookMeta { static final ItemMetaKey BOOK_TITLE = new ItemMetaKey("title"); static final ItemMetaKey BOOK_AUTHOR = new ItemMetaKey("author"); static final ItemMetaKey BOOK_PAGES = new ItemMetaKey("pages"); + static final ItemMetaKey RESOLVED = new ItemMetaKey("resolved"); + static final ItemMetaKey GENERATION = new ItemMetaKey("generation"); static final int MAX_PAGE_LENGTH = 256; static final int MAX_TITLE_LENGTH = 0xffff; private String title; private String author; private List pages = new ArrayList(); + private Boolean resolved; + private Integer generation; CraftMetaBook(CraftMetaItem meta) { super(meta); @@ -39,6 +46,8 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta { this.title = bookMeta.title; this.author = bookMeta.author; pages.addAll(bookMeta.pages); + this.resolved = bookMeta.resolved; + this.generation = bookMeta.generation; } CraftMetaBook(NBTTagCompound tag) { @@ -51,6 +60,14 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta { if (tag.hasKey(BOOK_AUTHOR.NBT)) { this.author = tag.getString(BOOK_AUTHOR.NBT); } + + if (tag.hasKey(RESOLVED.NBT)) { + resolved = tag.getBoolean(RESOLVED.NBT); + } + + if (tag.hasKey(GENERATION.NBT)) { + generation = tag.getInt(GENERATION.NBT); + } if (tag.hasKey(BOOK_PAGES.NBT)) { NBTTagList pages = tag.getList(BOOK_PAGES.NBT, 8); @@ -58,6 +75,9 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta { for (int i = 0; i < pages.size(); i++) { String page = pages.getString(i); + if (resolved != null && resolved) { + page = CraftChatMessage.fromComponent(ChatSerializer.a(page)); + } pageArray[i] = page; } @@ -74,6 +94,9 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta { Iterable pages = SerializableMeta.getObject(Iterable.class, map, BOOK_PAGES.BUKKIT, true); CraftMetaItem.safelyAdd(pages, this.pages, MAX_PAGE_LENGTH); + + resolved = SerializableMeta.getObject(Boolean.class, map, RESOLVED.BUKKIT, true); + generation = SerializableMeta.getObject(Integer.class, map, GENERATION.BUKKIT, true); } @Override @@ -89,7 +112,25 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta { } if (hasPages()) { - itemData.set(BOOK_PAGES.NBT, createStringList(pages)); + NBTTagList list = new NBTTagList(); + for (String page : pages) { + if (resolved != null && resolved) { + list.add(new NBTTagString( + ChatSerializer.a(CraftChatMessage.fromString(page, true)[0]) + )); + } else { + list.add(new NBTTagString(page)); + } + } + itemData.set(BOOK_PAGES.NBT, list); + } + + if (resolved != null) { + itemData.setBoolean(RESOLVED.NBT, resolved); + } + + if (generation != null) { + itemData.setInt(GENERATION.NBT, generation); } } @@ -255,6 +296,14 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta { if (hasPages()) { builder.put(BOOK_PAGES.BUKKIT, pages); } + + if (resolved != null) { + builder.put(RESOLVED.BUKKIT, resolved); + } + + if (generation != null) { + builder.put(GENERATION.BUKKIT, generation); + } return builder; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java index bff3be9dc7..6c6fde739d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java @@ -31,7 +31,7 @@ class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { setEffect(SerializableMeta.getObject(FireworkEffect.class, map, EXPLOSION.BUKKIT, true)); } - + CraftMetaCharge(NBTTagCompound tag) { super(tag); @@ -40,14 +40,17 @@ class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { } } + @Override public void setEffect(FireworkEffect effect) { this.effect = effect; } + @Override public boolean hasEffect() { return effect != null; } + @Override public FireworkEffect getEffect() { return effect; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java index d648d052b6..1d30e5e1bb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java @@ -3,9 +3,7 @@ package org.bukkit.craftbukkit.inventory; import java.util.Map; import net.minecraft.server.GameProfileSerializer; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.NBTTagCompound; -import net.minecraft.util.com.mojang.authlib.GameProfile; import org.bukkit.Material; import org.bukkit.configuration.serialization.DelegateDeserialization; @@ -13,6 +11,7 @@ import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta; import org.bukkit.inventory.meta.SkullMeta; import com.google.common.collect.ImmutableMap.Builder; +import com.mojang.authlib.GameProfile; @DelegateDeserialization(SerializableMeta.class) class CraftMetaSkull extends CraftMetaItem implements SkullMeta { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java b/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java index b5e9e31095..1c3e198113 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapCanvas.java @@ -37,7 +37,7 @@ public class CraftMapCanvas implements MapCanvas { return; if (buffer[y * 128 + x] != color) { buffer[y * 128 + x] = color; - mapView.worldMap.flagDirty(x, y, y); + mapView.worldMap.flagDirty(x, y); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java index 392dba4a50..d56a291cdb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java @@ -1,7 +1,7 @@ package org.bukkit.craftbukkit.map; import net.minecraft.server.WorldMap; -import net.minecraft.server.WorldMapDecoration; +import net.minecraft.server.MapIcon; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -41,8 +41,9 @@ public class CraftMapRenderer extends MapRenderer { continue; } - WorldMapDecoration decoration = (WorldMapDecoration) worldMap.decorations.get(key); - cursors.addCursor(decoration.locX, decoration.locY, (byte) (decoration.rotation & 15), decoration.type); + + MapIcon decoration = (MapIcon) worldMap.decorations.get(key); + cursors.addCursor(decoration.getX(), decoration.getY(), (byte) (decoration.getRotation() & 15), decoration.getType()); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/paper-server/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java index 0959a09e2e..b8bf7541f6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java @@ -32,7 +32,7 @@ import net.minecraft.server.EntitySmallFireball; import net.minecraft.server.EntitySnowball; import net.minecraft.server.EntityThrownExpBottle; import net.minecraft.server.EntityWitherSkull; -import net.minecraft.server.EnumFacing; +import net.minecraft.server.EnumDirection; import net.minecraft.server.IPosition; import net.minecraft.server.IProjectile; import net.minecraft.server.MathHelper; @@ -48,7 +48,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { @Override public Block getBlock() { - return dispenserBlock.getWorld().getWorld().getBlockAt(dispenserBlock.x, dispenserBlock.y, dispenserBlock.z); + return dispenserBlock.getWorld().getWorld().getBlockAt(dispenserBlock.getPosition().getX(), dispenserBlock.getPosition().getY(), dispenserBlock.getPosition().getZ()); } @Override @@ -60,10 +60,10 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { public T launchProjectile(Class projectile, Vector velocity) { Validate.isTrue(getBlock().getType() == Material.DISPENSER, "Block is no longer dispenser"); // Copied from BlockDispenser.dispense() - SourceBlock isourceblock = new SourceBlock(dispenserBlock.getWorld(), dispenserBlock.x, dispenserBlock.y, dispenserBlock.z); + SourceBlock isourceblock = new SourceBlock(dispenserBlock.getWorld(), dispenserBlock.getPosition()); // Copied from DispenseBehaviorProjectile IPosition iposition = BlockDispenser.a(isourceblock); - EnumFacing enumfacing = BlockDispenser.b(isourceblock.h()); + EnumDirection enumdirection = BlockDispenser.b(isourceblock.f()); net.minecraft.server.World world = dispenserBlock.getWorld(); net.minecraft.server.Entity launch = null; @@ -72,7 +72,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { } else if (Egg.class.isAssignableFrom(projectile)) { launch = new EntityEgg(world, iposition.getX(), iposition.getY(), iposition.getZ()); } else if (EnderPearl.class.isAssignableFrom(projectile)) { - launch = new EntityEnderPearl(world); + launch = new EntityEnderPearl(world, null); launch.setPosition(iposition.getX(), iposition.getY(), iposition.getZ()); } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) { launch = new EntityThrownExpBottle(world, iposition.getX(), iposition.getY(), iposition.getZ()); @@ -83,13 +83,13 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { ((EntityArrow) launch).fromPlayer = 1; ((EntityArrow) launch).projectileSource = this; } else if (Fireball.class.isAssignableFrom(projectile)) { - double d0 = iposition.getX() + (double) ((float) enumfacing.getAdjacentX() * 0.3F); - double d1 = iposition.getY() + (double) ((float) enumfacing.getAdjacentY() * 0.3F); - double d2 = iposition.getZ() + (double) ((float) enumfacing.getAdjacentZ() * 0.3F); + double d0 = iposition.getX() + (double) ((float) enumdirection.getAdjacentX() * 0.3F); + double d1 = iposition.getY() + (double) ((float) enumdirection.getAdjacentY() * 0.3F); + double d2 = iposition.getZ() + (double) ((float) enumdirection.getAdjacentZ() * 0.3F); Random random = world.random; - double d3 = random.nextGaussian() * 0.05D + (double) enumfacing.getAdjacentX(); - double d4 = random.nextGaussian() * 0.05D + (double) enumfacing.getAdjacentY(); - double d5 = random.nextGaussian() * 0.05D + (double) enumfacing.getAdjacentZ(); + double d3 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentX(); + double d4 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentY(); + double d5 = random.nextGaussian() * 0.05D + (double) enumdirection.getAdjacentZ(); if (SmallFireball.class.isAssignableFrom(projectile)) { launch = new EntitySmallFireball(world, d0, d1, d2, d3, d4, d5); @@ -129,7 +129,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { b *= 1.25F; } // Copied from DispenseBehaviorProjectile - ((IProjectile) launch).shoot((double) enumfacing.getAdjacentX(), (double) ((float) enumfacing.getAdjacentY() + 0.1F), (double) enumfacing.getAdjacentZ(), b, a); + ((IProjectile) launch).shoot((double) enumdirection.getAdjacentX(), (double) ((float) enumdirection.getAdjacentY() + 0.1F), (double) enumdirection.getAdjacentZ(), b, a); } if (velocity != null) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java index 612a52434a..7dedd0222a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java @@ -17,9 +17,6 @@ final class CraftCriteria { for (Map.Entry entry : ((Map ) IScoreboardCriteria.criteria).entrySet()) { String name = entry.getKey().toString(); IScoreboardCriteria criteria = (IScoreboardCriteria) entry.getValue(); - if (!criteria.getName().equals(name)) { - throw new AssertionError("Unexpected entry " + name + " to criteria " + criteria + "(" + criteria.getName() + ")"); - } defaults.put(name, new CraftCriteria(criteria)); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java index ad65b3f859..62bb8a362b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java @@ -97,13 +97,17 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { public void resetScores(OfflinePlayer player) throws IllegalArgumentException { Validate.notNull(player, "OfflinePlayer cannot be null"); - board.resetPlayerScores(player.getName()); + for (CraftObjective objective : objectives.values()) { + board.resetPlayerScores(player.getName(), objective.getHandle()); // PAIL: check me + } } public void resetScores(String entry) throws IllegalArgumentException { Validate.notNull(entry, "Entry cannot be null"); - board.resetPlayerScores(entry); + for (CraftObjective objective : objectives.values()) { + board.resetPlayerScores(entry, objective.getHandle()); // PAIL: check me + } } public Team getPlayerTeam(OfflinePlayer player) throws IllegalArgumentException { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/updater/ArtifactDetails.java b/paper-server/src/main/java/org/bukkit/craftbukkit/updater/ArtifactDetails.java deleted file mode 100644 index a9c5eafc94..0000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/updater/ArtifactDetails.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bukkit.craftbukkit.updater; - -import java.util.Date; - -public class ArtifactDetails { - private String brokenReason; - private boolean isBroken; - private int buildNumber; - private String htmlUrl; - private String version; - private Date created; - private FileDetails file; - private ChannelDetails channel; - - public ChannelDetails getChannel() { - return channel; - } - - public void setChannel(ChannelDetails channel) { - this.channel = channel; - } - - public boolean isIsBroken() { - return isBroken; - } - - public void setIsBroken(boolean isBroken) { - this.isBroken = isBroken; - } - - public FileDetails getFile() { - return file; - } - - public void setFile(FileDetails file) { - this.file = file; - } - - public String getBrokenReason() { - return brokenReason; - } - - public void setBrokenReason(String brokenReason) { - this.brokenReason = brokenReason; - } - - public int getBuildNumber() { - return buildNumber; - } - - public void setBuildNumber(int buildNumber) { - this.buildNumber = buildNumber; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - public String getHtmlUrl() { - return htmlUrl; - } - - public void setHtmlUrl(String htmlUrl) { - this.htmlUrl = htmlUrl; - } - - public boolean isBroken() { - return isBroken; - } - - public void setBroken(boolean isBroken) { - this.isBroken = isBroken; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public static class FileDetails { - private String url; - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - } - - public static class ChannelDetails { - private String name; - private String slug; - private int priority; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getPriority() { - return priority; - } - - public void setPriority(int priority) { - this.priority = priority; - } - - public String getSlug() { - return slug; - } - - public void setSlug(String slug) { - this.slug = slug; - } - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/updater/AutoUpdater.java b/paper-server/src/main/java/org/bukkit/craftbukkit/updater/AutoUpdater.java deleted file mode 100644 index f21301ce29..0000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/updater/AutoUpdater.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.bukkit.craftbukkit.updater; - -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -public class AutoUpdater { - public static final String WARN_CONSOLE = "warn-console"; - public static final String WARN_OPERATORS = "warn-ops"; - - private final BukkitDLUpdaterService service; - private final List onUpdate = new ArrayList(); - private final List onBroken = new ArrayList(); - private final Logger log; - private final String channel; - private boolean enabled; - private ArtifactDetails current = null; - private ArtifactDetails latest = null; - private boolean suggestChannels = true; - - public AutoUpdater(BukkitDLUpdaterService service, Logger log, String channel) { - this.service = service; - this.log = log; - this.channel = channel; - } - - public String getChannel() { - return channel; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean isEnabled) { - this.enabled = isEnabled; - } - - public boolean shouldSuggestChannels() { - return suggestChannels; - } - - public void setSuggestChannels(boolean suggestChannels) { - this.suggestChannels = suggestChannels; - } - - public List getOnBroken() { - return onBroken; - } - - public List getOnUpdate() { - return onUpdate; - } - - public boolean isUpdateAvailable() { - if ((latest == null) || (current == null) || (!isEnabled())) { - return false; - } else { - return latest.getCreated().after(current.getCreated()); - } - } - - public ArtifactDetails getCurrent() { - return current; - } - - public ArtifactDetails getLatest() { - return latest; - } - - public void check(final String currentSlug) { - if (!isEnabled()) return; - - new Thread() { - @Override - public void run() { - current = service.getArtifact(currentSlug, "information about this CraftBukkit version; perhaps you are running a custom one?"); - latest = service.getArtifact("latest-" + channel, "latest artifact information"); - - if (isUpdateAvailable()) { - if ((current.isBroken()) && (onBroken.contains(WARN_CONSOLE))) { - log.severe("----- Bukkit Auto Updater -----"); - log.severe("Your version of CraftBukkit is known to be broken. It is strongly advised that you update to a more recent version ASAP."); - log.severe("Known issues with your version:"); - - for (String line : current.getBrokenReason().split("\n")) { - log.severe("> " + line); - } - - log.severe("Newer version " + latest.getVersion() + " (build #" + latest.getBuildNumber() + ") was released on " + latest.getCreated() + "."); - log.severe("Details: " + latest.getHtmlUrl()); - log.severe("Download: " + latest.getFile().getUrl()); - log.severe("----- ------------------- -----"); - } else if (onUpdate.contains(WARN_CONSOLE)) { - log.warning("----- Bukkit Auto Updater -----"); - log.warning("Your version of CraftBukkit is out of date. Version " + latest.getVersion() + " (build #" + latest.getBuildNumber() + ") was released on " + latest.getCreated() + "."); - log.warning("Details: " + latest.getHtmlUrl()); - log.warning("Download: " + latest.getFile().getUrl()); - log.warning("----- ------------------- -----"); - } - } else if ((current != null) && (current.isBroken()) && (onBroken.contains(WARN_CONSOLE))) { - log.severe("----- Bukkit Auto Updater -----"); - log.severe("Your version of CraftBukkit is known to be broken. It is strongly advised that you update to a more recent version ASAP."); - log.severe("Known issues with your version:"); - - for (String line : current.getBrokenReason().split("\n")) { - log.severe("> " + line); - } - - log.severe("Unfortunately, there is not yet a newer version suitable for your server. We would advise you wait an hour or two, or try out a dev build."); - log.severe("----- ------------------- -----"); - } else if ((current != null) && (shouldSuggestChannels())) { - ArtifactDetails.ChannelDetails prefChan = service.getChannel(channel, "preferred channel details"); - - if ((prefChan != null) && (current.getChannel().getPriority() < prefChan.getPriority())) { - log.info("----- Bukkit Auto Updater -----"); - log.info("It appears that you're running a " + current.getChannel().getName() + ", when you've specified in bukkit.yml that you prefer to run " + prefChan.getName() + "s."); - log.info("If you would like to be kept informed about new " + current.getChannel().getName() + " releases, it is recommended that you change 'preferred-channel' in your bukkit.yml to '" + current.getChannel().getSlug() + "'."); - log.info("With that set, you will be told whenever a new version is available for download, so that you can always keep up to date and secure with the latest fixes."); - log.info("If you would like to disable this warning, simply set 'suggest-channels' to false in bukkit.yml."); - log.info("----- ------------------- -----"); - } - } - } - }.start(); - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java b/paper-server/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java deleted file mode 100644 index 0145ac36a8..0000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.bukkit.craftbukkit.updater; - -import com.google.gson.*; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Type; -import java.net.URL; -import java.net.URLConnection; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bukkit.Bukkit; - -public class BukkitDLUpdaterService { - private static final String API_PREFIX_ARTIFACT = "/api/1.0/downloads/projects/craftbukkit/view/"; - private static final String API_PREFIX_CHANNEL = "/api/1.0/downloads/channels/"; - private static final DateDeserializer dateDeserializer = new DateDeserializer(); - private final String host; - - public BukkitDLUpdaterService(String host) { - this.host = host; - } - - public ArtifactDetails getArtifact(String slug, String name) { - try { - return fetchArtifact(slug); - } catch (UnsupportedEncodingException ex) { - Bukkit.getLogger().log(Level.WARNING, "Could not get " + name + ": " + ex.getClass().getSimpleName()); - } catch (IOException ex) { - Bukkit.getLogger().log(Level.WARNING, "Could not get " + name + ": " + ex.getClass().getSimpleName()); - } - - return null; - } - - private String getUserAgent() { - return "CraftBukkit/" + BukkitDLUpdaterService.class.getPackage().getImplementationVersion() + "/" + System.getProperty("java.version"); - } - - public ArtifactDetails fetchArtifact(String slug) throws IOException { - URL url = new URL("http", host, API_PREFIX_ARTIFACT + slug + "/"); - InputStreamReader reader = null; - - try { - URLConnection connection = url.openConnection(); - connection.setRequestProperty("User-Agent", getUserAgent()); - reader = new InputStreamReader(connection.getInputStream()); - Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); - return gson.fromJson(reader, ArtifactDetails.class); - } finally { - if (reader != null) { - reader.close(); - } - } - } - - public ArtifactDetails.ChannelDetails getChannel(String slug, String name) { - try { - return fetchChannel(slug); - } catch (UnsupportedEncodingException ex) { - Bukkit.getLogger().log(Level.WARNING, "Could not get " + name + ": " + ex.getClass().getSimpleName()); - } catch (IOException ex) { - Bukkit.getLogger().log(Level.WARNING, "Could not get " + name + ": " + ex.getClass().getSimpleName()); - } - - return null; - } - - public ArtifactDetails.ChannelDetails fetchChannel(String slug) throws IOException { - URL url = new URL("http", host, API_PREFIX_CHANNEL + slug + "/"); - InputStreamReader reader = null; - - try { - URLConnection connection = url.openConnection(); - connection.setRequestProperty("User-Agent", getUserAgent()); - reader = new InputStreamReader(connection.getInputStream()); - Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); - - return gson.fromJson(reader, ArtifactDetails.ChannelDetails.class); - } finally { - if (reader != null) { - reader.close(); - } - } - } - - static class DateDeserializer implements JsonDeserializer { - private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - public Date deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException { - try { - return format.parse(je.getAsString()); - } catch (ParseException ex) { - throw new JsonParseException("Date is not formatted correctly", ex); - } - } - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java index 30f2622d99..2dbedd2d09 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.server.Block; +import net.minecraft.server.BlockPosition; +import net.minecraft.server.IBlockData; import org.bukkit.World; import org.bukkit.block.BlockState; @@ -35,6 +37,11 @@ public class BlockStateListPopulator { public void setTypeUpdate(int x, int y, int z, Block block) { this.setType(x, y, z, block); + } + + public void setTypeUpdate(BlockPosition position, IBlockData data) { + setTypeAndData(position.getX(), position.getY(), position.getZ(), data.getBlock(), data.getBlock().toLegacyData(data), 0); + } public void setType(int x, int y, int z, Block block) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java index 256f053107..58ff7d963b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java @@ -24,7 +24,7 @@ public final class CraftChatMessage { static { Builder builder = ImmutableMap.builder(); for (EnumChatFormat format : EnumChatFormat.values()) { - builder.put(Character.toLowerCase(format.getChar()), format); + builder.put(Character.toLowerCase(format.toString().charAt(1)), format); } formatMap = builder.build(); } @@ -36,7 +36,7 @@ public final class CraftChatMessage { private int currentIndex; private final String message; - private StringMessage(String message) { + private StringMessage(String message, boolean keepNewlines) { this.message = message; if (message == null) { output = new IChatBaseComponent[] { currentChatComponent }; @@ -71,7 +71,7 @@ public final class CraftChatMessage { case UNDERLINE: modifier.setUnderline(Boolean.TRUE); break; - case RANDOM: + case OBFUSCATED: modifier.setRandom(Boolean.TRUE); break; default: @@ -82,7 +82,11 @@ public final class CraftChatMessage { } break; case 2: - currentChatComponent = null; + if (keepNewlines) { + currentChatComponent.addSibling(new ChatComponentText("\n")); + } else { + currentChatComponent = null; + } break; case 3: modifier.setChatClickable(new ChatClickable(EnumClickAction.OPEN_URL, match)); @@ -119,7 +123,38 @@ public final class CraftChatMessage { } public static IChatBaseComponent[] fromString(String message) { - return new StringMessage(message).getOutput(); + return fromString(message, false); + } + + public static IChatBaseComponent[] fromString(String message, boolean keepNewlines) { + return new StringMessage(message, keepNewlines).getOutput(); + } + + public static String fromComponent(IChatBaseComponent component) { + if (component == null) return ""; + StringBuilder out = new StringBuilder(); + + for (IChatBaseComponent c : (Iterable) component) { + ChatModifier modi = c.getChatModifier(); + out.append(modi.getColor() == null ? EnumChatFormat.BLACK : modi.getColor()); + if (modi.isBold()) { + out.append(EnumChatFormat.BOLD); + } + if (modi.isItalic()) { + out.append(EnumChatFormat.ITALIC); + } + if (modi.isUnderlined()) { + out.append(EnumChatFormat.UNDERLINE); + } + if (modi.isStrikethrough()) { + out.append(EnumChatFormat.STRIKETHROUGH); + } + if (modi.isRandom()) { + out.append(EnumChatFormat.OBFUSCATED); + } + out.append(c.getText()); + } + return out.toString(); } private CraftChatMessage() { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index 52aa5d1831..b84ed46d5b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -1,12 +1,15 @@ package org.bukkit.craftbukkit.util; +import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Set; import net.minecraft.server.Block; import net.minecraft.server.Blocks; import net.minecraft.server.Item; +import net.minecraft.server.MinecraftKey; import net.minecraft.server.MojangsonParser; import net.minecraft.server.NBTTagCompound; import net.minecraft.server.StatisticList; @@ -88,12 +91,16 @@ public final class CraftMagicNumbers implements UnsafeValues { @Override public Material getMaterialFromInternalName(String name) { - return getMaterial((Item) Item.REGISTRY.get(name)); + return getMaterial((Item) Item.REGISTRY.get(new MinecraftKey(name))); } @Override public List tabCompleteInternalMaterialName(String token, List completions) { - return StringUtil.copyPartialMatches(token, Item.REGISTRY.keySet(), completions); + ArrayList results = Lists.newArrayList(); + for (MinecraftKey key : (Set)Item.REGISTRY.keySet()) { + results.add(key.toString()); + } + return StringUtil.copyPartialMatches(token, results, completions); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java index 90b2e6ac46..ae19da4d83 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java @@ -1,25 +1,25 @@ -package org.bukkit.craftbukkit.util; - -import java.util.HashSet; -import java.util.List; -import net.minecraft.server.EntityPlayer; -import net.minecraft.server.MinecraftServer; - -import org.bukkit.entity.Player; - -public class LazyPlayerSet extends LazyHashSet { - - @Override - HashSet makeReference() { - if (reference != null) { - throw new IllegalStateException("Reference already created!"); - } - List players = MinecraftServer.getServer().getPlayerList().players; - HashSet reference = new HashSet(players.size()); - for (EntityPlayer player : players) { - reference.add(player.getBukkitEntity()); - } - return reference; - } - -} +package org.bukkit.craftbukkit.util; + +import java.util.HashSet; +import java.util.List; +import net.minecraft.server.EntityPlayer; +import net.minecraft.server.MinecraftServer; + +import org.bukkit.entity.Player; + +public class LazyPlayerSet extends LazyHashSet { + + @Override + HashSet makeReference() { + if (reference != null) { + throw new IllegalStateException("Reference already created!"); + } + List players = MinecraftServer.getServer().getPlayerList().players; + HashSet reference = new HashSet(players.size()); + for (EntityPlayer player : players) { + reference.add(player.getBukkitEntity()); + } + return reference; + } + +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/MojangNameLookup.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/MojangNameLookup.java index 1db4874d6d..93a8f0bd70 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/MojangNameLookup.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/MojangNameLookup.java @@ -1,8 +1,7 @@ package org.bukkit.craftbukkit.util; -import net.minecraft.util.com.google.gson.Gson; -import net.minecraft.util.com.google.common.base.Charsets; -import net.minecraft.util.org.apache.commons.io.IOUtils; +import com.google.common.base.Charsets; +import com.google.gson.Gson; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -12,6 +11,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.UUID; +import org.apache.commons.io.IOUtils; public class MojangNameLookup { private static final Logger logger = LogManager.getFormatterLogger(MojangNameLookup.class); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java index 0bdfde6d55..772f730ffb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/TerminalConsoleWriterThread.java @@ -5,7 +5,7 @@ import java.io.OutputStream; import java.util.logging.Level; import java.util.logging.Logger; import jline.console.ConsoleReader; -import net.minecraft.util.com.mojang.util.QueueLogAppender; +import com.mojang.util.QueueLogAppender; import org.bukkit.craftbukkit.Main; public class TerminalConsoleWriterThread implements Runnable { diff --git a/paper-server/src/main/resources/configurations/bukkit.yml b/paper-server/src/main/resources/configurations/bukkit.yml index 129ac34dd3..a6c11786c7 100644 --- a/paper-server/src/main/resources/configurations/bukkit.yml +++ b/paper-server/src/main/resources/configurations/bukkit.yml @@ -37,13 +37,6 @@ ticks-per: animal-spawns: 400 monster-spawns: 1 autosave: 6000 -auto-updater: - enabled: true - on-broken: [warn-console, warn-ops] - on-update: [warn-console, warn-ops] - preferred-channel: rb - host: dl.bukkit.org - suggest-channels: true aliases: now-in-commands.yml database: username: bukkit diff --git a/paper-server/src/test/java/org/bukkit/DyeColorsTest.java b/paper-server/src/test/java/org/bukkit/DyeColorsTest.java index 0e3a7c7503..f0b889b344 100644 --- a/paper-server/src/test/java/org/bukkit/DyeColorsTest.java +++ b/paper-server/src/test/java/org/bukkit/DyeColorsTest.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.server.EntitySheep; +import net.minecraft.server.EnumColor; import net.minecraft.server.ItemDye; import org.bukkit.support.AbstractTestingBase; @@ -33,7 +34,7 @@ public class DyeColorsTest extends AbstractTestingBase { @Test public void checkColor() { Color color = dye.getColor(); - float[] nmsColorArray = EntitySheep.bp[dye.getWoolData()]; + float[] nmsColorArray = EntitySheep.a(EnumColor.fromColorIndex(dye.getWoolData())); Color nmsColor = Color.fromRGB((int) (nmsColorArray[0] * 255), (int) (nmsColorArray[1] * 255), (int) (nmsColorArray[2] * 255)); assertThat(color, is(nmsColor)); } @@ -41,7 +42,7 @@ public class DyeColorsTest extends AbstractTestingBase { @Test public void checkFireworkColor() { Color color = dye.getFireworkColor(); - int nmsColor = ItemDye.c[dye.getDyeData()]; + int nmsColor = ItemDye.a[dye.getDyeData()]; assertThat(color, is(Color.fromRGB(nmsColor))); } } diff --git a/paper-server/src/test/java/org/bukkit/PerMaterialTest.java b/paper-server/src/test/java/org/bukkit/PerMaterialTest.java index a33fcbffd8..f689cbf403 100644 --- a/paper-server/src/test/java/org/bukkit/PerMaterialTest.java +++ b/paper-server/src/test/java/org/bukkit/PerMaterialTest.java @@ -23,16 +23,18 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import com.google.common.collect.Lists; +import java.util.Map; +import net.minecraft.server.Block; import net.minecraft.server.Blocks; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @RunWith(Parameterized.class) public class PerMaterialTest extends AbstractTestingBase { - private static int[] fireValues; + private static Map fireValues; @BeforeClass public static void getFireValues() { - fireValues = Util.getInternalState(BlockFire.class, Blocks.FIRE, "a"); + fireValues = Util.getInternalState(BlockFire.class, Blocks.FIRE, "S"); } @Parameters(name= "{index}: {0}") @@ -120,7 +122,8 @@ public class PerMaterialTest extends AbstractTestingBase { @Test public void isBurnable() { if (material.isBlock()) { - assertThat(material.isBurnable(), is(fireValues[material.getId()] > 0)); + Block block = CraftMagicNumbers.getBlock(material); + assertThat(material.isBurnable(), is(fireValues.containsKey(block) && fireValues.get(block) > 0)); } else { assertFalse(material.isBurnable()); } @@ -129,7 +132,7 @@ public class PerMaterialTest extends AbstractTestingBase { @Test public void isOccluding() { if (material.isBlock()) { - assertThat(material.isOccluding(), is(CraftMagicNumbers.getBlock(material).r())); + assertThat(material.isOccluding(), is(CraftMagicNumbers.getBlock(material).isOccluding())); } else { assertFalse(material.isOccluding()); } diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java index 2331c18072..11d2906901 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java @@ -8,15 +8,19 @@ import java.util.List; import org.bukkit.Bukkit; import org.bukkit.Color; +import org.bukkit.DyeColor; import org.bukkit.FireworkEffect; import org.bukkit.Material; import org.bukkit.FireworkEffect.Type; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; import org.bukkit.craftbukkit.inventory.ItemStackTest.StackProvider; import org.bukkit.craftbukkit.inventory.ItemStackTest.StackWrapper; import org.bukkit.craftbukkit.inventory.ItemStackTest.BukkitWrapper; import org.bukkit.craftbukkit.inventory.ItemStackTest.CraftWrapper; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BannerMeta; import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.FireworkEffectMeta; @@ -25,7 +29,6 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.inventory.meta.MapMeta; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.potion.PotionEffectType; import org.bukkit.support.AbstractTestingBase; import org.junit.Test; @@ -192,6 +195,15 @@ public class ItemMetaTest extends AbstractTestingBase { cleanStack.setItemMeta(meta); return cleanStack; } + }, + new StackProvider(Material.BANNER) { + @Override ItemStack operate(ItemStack cleanStack) { + final BannerMeta meta = (BannerMeta) cleanStack.getItemMeta(); + meta.setBaseColor(DyeColor.CYAN); + meta.addPattern(new Pattern(DyeColor.WHITE, PatternType.BRICKS)); + cleanStack.setItemMeta(meta); + return cleanStack; + } } ); diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java deleted file mode 100644 index df7437c9b6..0000000000 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bukkit.craftbukkit.updater; - -import static org.junit.Assert.*; -import static org.hamcrest.Matchers.*; - -import java.io.FileNotFoundException; -import java.io.IOException; - -import org.junit.Test; - -public class BukkitDLUpdaterServiceTest { - @Test(expected=IOException.class) - public void testHostNotFound() throws IOException { - BukkitDLUpdaterService service = new BukkitDLUpdaterService("404.example.org"); - - service.fetchArtifact("rb"); - } - - @Test(expected=FileNotFoundException.class) - public void testArtifactNotFound() throws IOException { - BukkitDLUpdaterService service = new BukkitDLUpdaterService("dl.bukkit.org"); - - service.fetchArtifact("meep"); - } - - @Test - public void testArtifactExists() throws IOException { - BukkitDLUpdaterService service = new BukkitDLUpdaterService("dl.bukkit.org"); - - assertThat(service.fetchArtifact("latest-dev"), is(not(nullValue()))); - } -} diff --git a/paper-server/src/test/java/org/bukkit/support/AbstractTestingBase.java b/paper-server/src/test/java/org/bukkit/support/AbstractTestingBase.java index 7c4484f07e..b280ebe4fb 100644 --- a/paper-server/src/test/java/org/bukkit/support/AbstractTestingBase.java +++ b/paper-server/src/test/java/org/bukkit/support/AbstractTestingBase.java @@ -15,11 +15,62 @@ import org.junit.BeforeClass; * extend this class to solve it. */ public abstract class AbstractTestingBase { - public static final List INVALIDATED_MATERIALS = ImmutableList.builder().add(Material.BREWING_STAND, Material.BED_BLOCK, Material.NETHER_WARTS, Material.CAULDRON, Material.FLOWER_POT, Material.CROPS, Material.SUGAR_CANE_BLOCK, Material.CAKE_BLOCK, Material.SKULL, Material.PISTON_EXTENSION, Material.PISTON_MOVING_PIECE, Material.GLOWING_REDSTONE_ORE, Material.DIODE_BLOCK_ON, Material.PUMPKIN_STEM, Material.SIGN_POST, Material.REDSTONE_COMPARATOR_ON, Material.TRIPWIRE, Material.REDSTONE_LAMP_ON, Material.MELON_STEM, Material.REDSTONE_TORCH_OFF, Material.REDSTONE_COMPARATOR_OFF, Material.REDSTONE_WIRE, Material.WALL_SIGN, Material.DIODE_BLOCK_OFF, Material.IRON_DOOR_BLOCK, Material.WOODEN_DOOR).add(Material.LOCKED_CHEST).build(); + public static final List INVALIDATED_MATERIALS = ImmutableList.builder() + .add( + Material.BREWING_STAND, + Material.BED_BLOCK, + Material.NETHER_WARTS, + Material.CAULDRON, + Material.FLOWER_POT, + Material.CROPS, + Material.SUGAR_CANE_BLOCK, + Material.CAKE_BLOCK, + Material.SKULL, + Material.PISTON_EXTENSION, + Material.PISTON_MOVING_PIECE, + Material.GLOWING_REDSTONE_ORE, + Material.DIODE_BLOCK_ON, + Material.PUMPKIN_STEM, + Material.SIGN_POST, + Material.REDSTONE_COMPARATOR_ON, + Material.TRIPWIRE, + Material.REDSTONE_LAMP_ON, + Material.MELON_STEM, + Material.REDSTONE_TORCH_OFF, + Material.REDSTONE_COMPARATOR_OFF, + Material.REDSTONE_WIRE, + Material.WALL_SIGN, + Material.DIODE_BLOCK_OFF, + Material.IRON_DOOR_BLOCK, + Material.WOODEN_DOOR, + Material.LOCKED_CHEST, + Material.WATER, + Material.STATIONARY_WATER, + Material.LAVA, + Material.STATIONARY_LAVA, + Material.DOUBLE_STEP, + Material.DOUBLE_STEP, + Material.FIRE, + Material.PORTAL, + Material.ENDER_PORTAL, + Material.WOOD_DOUBLE_STEP, + Material.COCOA, + Material.CARROT, + Material.POTATO, + Material.STANDING_BANNER, + Material.WALL_BANNER, + Material.DAYLIGHT_DETECTOR_INVERTED, + Material.DOUBLE_STONE_SLAB2, + Material.SPRUCE_DOOR, + Material.BIRCH_DOOR, + Material.JUNGLE_DOOR, + Material.ACACIA_DOOR, + Material.DARK_OAK_DOOR + ).build(); @BeforeClass public static void setup() { - DispenserRegistry.b(); + DispenserRegistry.c(); DummyServer.setup(); DummyPotions.setup(); DummyEnchantments.setup(); diff --git a/paper-server/src/test/java/org/bukkit/support/DummyEnchantments.java b/paper-server/src/test/java/org/bukkit/support/DummyEnchantments.java index 5ed00a72b0..a0e0396bf1 100644 --- a/paper-server/src/test/java/org/bukkit/support/DummyEnchantments.java +++ b/paper-server/src/test/java/org/bukkit/support/DummyEnchantments.java @@ -4,7 +4,7 @@ import net.minecraft.server.Enchantment; public class DummyEnchantments { static { - Enchantment.byId.getClass(); + Enchantment.getNames(); org.bukkit.enchantments.Enchantment.stopAcceptingRegistrations(); }