diff --git a/patches/net/minecraft/entity/passive/EntityOcelot.java.patch b/patches/net/minecraft/entity/passive/EntityOcelot.java.patch index c7dc89c..8d029b6 100644 --- a/patches/net/minecraft/entity/passive/EntityOcelot.java.patch +++ b/patches/net/minecraft/entity/passive/EntityOcelot.java.patch @@ -8,7 +8,15 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityAgeable; -@@ -106,9 +105,10 @@ +@@ -47,6 +46,7 @@ + private static final DataParameter OCELOT_VARIANT = EntityDataManager.createKey(EntityOcelot.class, DataSerializers.VARINT); + private EntityAIAvoidEntity avoidEntity; + private EntityAITempt aiTempt; ++ public boolean spawnBonus = true; // Spigot + + public EntityOcelot(World worldIn) + { +@@ -106,9 +106,10 @@ } } @@ -21,7 +29,7 @@ } protected void applyEntityAttributes() -@@ -189,7 +189,8 @@ +@@ -189,7 +190,8 @@ { if (this.aiSit != null) { @@ -31,7 +39,7 @@ } return super.attackEntityFrom(source, amount); -@@ -222,7 +223,8 @@ +@@ -222,7 +224,8 @@ if (!this.world.isRemote) { @@ -41,7 +49,15 @@ { this.setTamedBy(player); this.setTameSkin(1 + this.world.rand.nextInt(3)); -@@ -368,7 +370,7 @@ +@@ -361,14 +364,14 @@ + { + livingdata = super.onInitialSpawn(difficulty, livingdata); + +- if (this.getTameSkin() == 0 && this.world.rand.nextInt(7) == 0) ++ if (spawnBonus && this.getTameSkin() == 0 && this.world.rand.nextInt(7) == 0) // Spigot + { + for (int i = 0; i < 2; ++i) + { EntityOcelot entityocelot = new EntityOcelot(this.world); entityocelot.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, 0.0F); entityocelot.setGrowingAge(-24000); diff --git a/patches/net/minecraft/entity/player/EntityPlayerMP.java.patch b/patches/net/minecraft/entity/player/EntityPlayerMP.java.patch index ed6459b..c7ee063 100644 --- a/patches/net/minecraft/entity/player/EntityPlayerMP.java.patch +++ b/patches/net/minecraft/entity/player/EntityPlayerMP.java.patch @@ -103,11 +103,16 @@ private boolean seenCredits; private final RecipeBookServer recipeBook = new RecipeBookServer(); private Vec3d levitationStartPos; -@@ -152,7 +170,26 @@ +@@ -152,7 +170,31 @@ public boolean isChangingQuantityOnly; public int ping; public boolean queuedEndExit; + private int viewDistance; ++ // Paper start - cancellable death event ++ public boolean queueHealthUpdatePacket = false; ++ public SPacketUpdateHealth queuedHealthUpdatePacket; ++ // Paper end ++ // CraftBukkit start + public String displayName; + public ITextComponent listName; + public org.bukkit.Location compassTarget; @@ -130,7 +135,7 @@ public EntityPlayerMP(MinecraftServer server, WorldServer worldIn, GameProfile profile, PlayerInteractionManager interactionManagerIn) { super(worldIn, profile); -@@ -188,8 +225,33 @@ +@@ -188,8 +230,33 @@ { this.setPosition(this.posX, this.posY + 1.0D, this.posZ); } @@ -164,7 +169,7 @@ public void readEntityFromNBT(NBTTagCompound compound) { super.readEntityFromNBT(compound); -@@ -218,6 +280,7 @@ +@@ -218,6 +285,7 @@ { this.recipeBook.read(compound.getCompoundTag("recipeBook")); } @@ -172,7 +177,7 @@ } public static void registerFixesPlayerMP(DataFixer p_191522_0_) -@@ -270,8 +333,34 @@ +@@ -270,8 +338,34 @@ } compound.setTag("recipeBook", this.recipeBook.write()); @@ -207,7 +212,7 @@ public void addExperienceLevel(int levels) { super.addExperienceLevel(levels); -@@ -313,6 +402,11 @@ +@@ -313,6 +407,11 @@ public void onUpdate() { @@ -219,7 +224,7 @@ this.interactionManager.updateBlockRemoving(); --this.respawnInvulnerabilityTicks; -@@ -398,7 +492,7 @@ +@@ -398,7 +497,7 @@ if (this.getHealth() != this.lastHealth || this.lastFoodLevel != this.foodStats.getFoodLevel() || this.foodStats.getSaturationLevel() == 0.0F != this.wasHungry) { @@ -228,7 +233,7 @@ this.lastHealth = this.getHealth(); this.lastFoodLevel = this.foodStats.getFoodLevel(); this.wasHungry = this.foodStats.getSaturationLevel() == 0.0F; -@@ -422,6 +516,12 @@ +@@ -422,6 +521,12 @@ this.updateScorePoints(IScoreCriteria.AIR, MathHelper.ceil((float)this.lastAirScore)); } @@ -241,7 +246,7 @@ if (this.getTotalArmorValue() != this.lastArmorScore) { this.lastArmorScore = this.getTotalArmorValue(); -@@ -450,6 +550,16 @@ +@@ -450,6 +555,16 @@ { CriteriaTriggers.LOCATION.trigger(this); } @@ -258,7 +263,7 @@ } catch (Throwable throwable) { -@@ -462,9 +572,9 @@ +@@ -462,9 +577,9 @@ private void updateScorePoints(IScoreCriteria criteria, int points) { @@ -270,19 +275,17 @@ score.setScorePoints(points); } } -@@ -474,29 +584,52 @@ +@@ -473,30 +588,64 @@ + { if (net.minecraftforge.common.ForgeHooks.onLivingDeath(this, cause)) return; boolean flag = this.world.getGameRules().getBoolean("showDeathMessages"); - this.connection.sendPacket(new SPacketCombatEvent(this.getCombatTracker(), SPacketCombatEvent.Event.ENTITY_DIED, flag)); + if (this.dead) { ++ this.connection.sendPacket(new SPacketCombatEvent(this.getCombatTracker(), SPacketCombatEvent.Event.ENTITY_DIED, flag)); // Paper - moved down for cancellable death event + return; + } + List loot = new java.util.ArrayList<>(this.inventory.getSizeInventory()); + boolean keepInventory = this.world.getGameRules().getBoolean("keepInventory") || this.isSpectator(); - -- if (flag) -- { -- Team team = this.getTeam(); ++ + if (!keepInventory) { + for (ItemStack item : this.inventory.getContents()) { + if (!item.isEmpty() && !EnchantmentHelper.hasVanishingCurse(item)) { @@ -290,22 +293,36 @@ + } + } + } - -- if (team != null && team.getDeathMessageVisibility() != Team.EnumVisible.ALWAYS) -- { -- if (team.getDeathMessageVisibility() == Team.EnumVisible.HIDE_FOR_OTHER_TEAMS) -- { -- this.mcServer.getPlayerList().sendMessageToAllTeamMembers(this, this.getCombatTracker().getDeathMessage()); ++ + ITextComponent chatmessage = this.getCombatTracker().getDeathMessage(); + + String deathmessage = chatmessage.getFormattedText(); + org.bukkit.event.entity.PlayerDeathEvent deathEvent = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory); -+ String deathMessage = deathEvent.getDeathMessage(); + ++ // Paper start - cancellable death event ++ if (deathEvent.isCancelled()) { ++ // make compatible with plugins that might have already set the health in an event listener ++ if (this.getHealth() <= 0) { ++ this.setHealth((float) deathEvent.getReviveHealth()); ++ } ++ return; ++ } + this.connection.sendPacket(new SPacketCombatEvent(this.getCombatTracker(), SPacketCombatEvent.Event.ENTITY_DIED, flag)); ++ // Paper end ++ String deathMessage = deathEvent.getDeathMessage(); + +- if (flag) +- { +- Team team = this.getTeam(); + if (deathMessage != null && deathMessage.length() > 0 && flag) { // TODO: allow plugins to override? + if (deathMessage.equals(deathmessage)) { + Team scoreboardteambase = this.getTeam(); -+ + +- if (team != null && team.getDeathMessageVisibility() != Team.EnumVisible.ALWAYS) +- { +- if (team.getDeathMessageVisibility() == Team.EnumVisible.HIDE_FOR_OTHER_TEAMS) +- { +- this.mcServer.getPlayerList().sendMessageToAllTeamMembers(this, this.getCombatTracker().getDeathMessage()); + if (scoreboardteambase != null && scoreboardteambase.getDeathMessageVisibility() != Team.EnumVisible.ALWAYS) { + if (scoreboardteambase.getDeathMessageVisibility() == Team.EnumVisible.HIDE_FOR_OTHER_TEAMS) { + this.mcServer.getPlayerList().sendMessageToAllTeamMembers(this, chatmessage); @@ -336,7 +353,7 @@ if (!this.world.getGameRules().getBoolean("keepInventory") && !this.isSpectator()) { -@@ -516,9 +649,14 @@ +@@ -516,9 +665,14 @@ } } @@ -353,7 +370,7 @@ score.incrementScore(); } -@@ -549,23 +687,28 @@ +@@ -549,23 +703,28 @@ { super.awardKillScore(p_191956_1_, p_191956_2_, p_191956_3_); this.addScore(p_191956_2_); @@ -388,7 +405,7 @@ } CriteriaTriggers.PLAYER_KILLED_ENTITY.trigger(this, p_191956_1_, p_191956_3_); -@@ -606,6 +749,43 @@ +@@ -606,6 +765,43 @@ return Lists.newArrayList(); } @@ -432,7 +449,27 @@ public boolean attackEntityFrom(DamageSource source, float amount) { if (this.isEntityInvulnerable(source)) -@@ -654,14 +834,17 @@ +@@ -641,8 +837,17 @@ + } + } + } +- +- return super.attackEntityFrom(source, amount); ++ // Paper start - cancellable death events ++ //return super.attackEntityFrom(source, amount); ++ this.queueHealthUpdatePacket = true; ++ boolean damaged = super.attackEntityFrom(source, amount); ++ this.queueHealthUpdatePacket = false; ++ if (this.queuedHealthUpdatePacket != null) { ++ this.connection.sendPacket(this.queuedHealthUpdatePacket); ++ this.queuedHealthUpdatePacket = null; ++ } ++ return damaged; ++ // Paper end + } + } + } +@@ -654,14 +859,17 @@ private boolean canPlayersAttack() { @@ -452,7 +489,7 @@ if (this.dimension == 0 && dimensionIn == -1) { -@@ -674,6 +857,7 @@ +@@ -674,6 +882,7 @@ if (this.dimension == 1 && dimensionIn == 1 && teleporter.isVanilla()) { @@ -460,18 +497,30 @@ this.world.removeEntity(this); if (!this.queuedEndExit) -@@ -692,7 +876,9 @@ +@@ -692,7 +901,21 @@ dimensionIn = 1; } - this.mcServer.getPlayerList().transferPlayerToDimension(this, dimensionIn, teleporter); + // this.mcServer.getPlayerList().transferPlayerToDimension(this, dimensionIn, teleporter); -+ PlayerTeleportEvent.TeleportCause cause = (this.dimension == 1 || dimensionIn == 1) ? PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; ++ PlayerTeleportEvent.TeleportCause cause = (this.dimension == 1 || dimensionIn == 1) ? PlayerTeleportEvent.TeleportCause.END_PORTAL : ((this.dimension == -1 || dimensionIn == -1) ? PlayerTeleportEvent.TeleportCause.NETHER_PORTAL : PlayerTeleportEvent.TeleportCause.MOD); ++ // From PlayerList.transferEntityToWorld fix mods teleport bug Start ++ World oldWorldIn = this.world; ++ double moveFactor = oldWorldIn.provider.getMovementFactor() / this.world.provider.getMovementFactor(); ++ double d0 = MathHelper.clamp(this.posX * moveFactor, this.world.getWorldBorder().minX() + 16.0D, this.world.getWorldBorder().maxX() - 16.0D); ++ double d1 = MathHelper.clamp(this.posZ * moveFactor, this.world.getWorldBorder().minZ() + 16.0D, this.world.getWorldBorder().maxZ() - 16.0D); + this.mcServer.getPlayerList().changeDimension(this, dimensionIn, cause); // check all this ++ if (cause == PlayerTeleportEvent.TeleportCause.MOD && !teleporter.isVanilla() && this.isEntityAlive()) { ++ d0 = MathHelper.clamp((int)d0, -29999872, 29999872); ++ d1 = MathHelper.clamp((int)d1, -29999872, 29999872); ++ this.setLocationAndAngles(d0, this.posY, d1, this.rotationYaw, this.rotationPitch); ++ teleporter.placeEntity(this.world, this, this.rotationYaw); ++ } ++ // End this.connection.sendPacket(new SPacketEffect(1032, BlockPos.ORIGIN, 0, false)); this.lastExperience = -1; this.lastHealth = -1.0F; -@@ -732,11 +918,11 @@ +@@ -732,11 +955,11 @@ this.openContainer.detectAndSendChanges(); } @@ -486,7 +535,7 @@ { this.addStat(StatList.SLEEP_IN_BED); Packet packet = new SPacketUseBed(this, bedLocation); -@@ -751,6 +937,7 @@ +@@ -751,6 +974,7 @@ public void wakeUpPlayer(boolean immediately, boolean updateWorldFlag, boolean setSpawn) { @@ -494,7 +543,7 @@ if (this.isPlayerSleeping()) { this.getServerWorld().getEntityTracker().sendToTrackingAndSelf(this, new SPacketAnimation(this, 2)); -@@ -844,6 +1031,12 @@ +@@ -844,6 +1068,12 @@ this.connection.sendPacket(new SPacketSignEditorOpen(signTile.getPos())); } @@ -507,7 +556,7 @@ public void getNextWindowId() { this.currentWindowId = this.currentWindowId % 100 + 1; -@@ -851,15 +1044,23 @@ +@@ -851,15 +1081,23 @@ public void displayGui(IInteractionObject guiOwner) { @@ -533,7 +582,7 @@ this.openContainer.windowId = this.currentWindowId; this.openContainer.addListener(this); net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.player.PlayerContainerEvent.Open(this, this.openContainer)); -@@ -868,6 +1069,29 @@ +@@ -868,6 +1106,29 @@ public void displayGUIChest(IInventory chestInventory) { @@ -563,7 +612,7 @@ if (chestInventory instanceof ILootContainer && ((ILootContainer)chestInventory).getLootTable() != null && this.isSpectator()) { this.sendStatusMessage((new TextComponentTranslation("container.spectatorCantOpen", new Object[0])).setStyle((new Style()).setColor(TextFormatting.RED)), true); -@@ -887,8 +1111,10 @@ +@@ -887,8 +1148,10 @@ { this.connection.sendPacket(new SPacketChat(new TextComponentTranslation("container.isLocked", new Object[] {chestInventory.getDisplayName()}), ChatType.GAME_INFO)); this.connection.sendPacket(new SPacketSoundEffect(SoundEvents.BLOCK_CHEST_LOCKED, SoundCategory.BLOCKS, this.posX, this.posY, this.posZ, 1.0F, 1.0F)); @@ -574,7 +623,7 @@ } this.getNextWindowId(); -@@ -896,12 +1122,14 @@ +@@ -896,12 +1159,14 @@ if (chestInventory instanceof IInteractionObject) { this.connection.sendPacket(new SPacketOpenWindow(this.currentWindowId, ((IInteractionObject)chestInventory).getGuiID(), chestInventory.getDisplayName(), chestInventory.getSizeInventory())); @@ -591,7 +640,7 @@ } this.openContainer.windowId = this.currentWindowId; -@@ -912,8 +1140,15 @@ +@@ -912,8 +1177,15 @@ public void displayVillagerTradeGui(IMerchant villager) { @@ -608,7 +657,7 @@ this.openContainer.windowId = this.currentWindowId; this.openContainer.addListener(this); net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.player.PlayerContainerEvent.Open(this, this.openContainer)); -@@ -933,6 +1168,13 @@ +@@ -933,6 +1205,13 @@ public void openGuiHorseInventory(AbstractHorse horse, IInventory inventoryIn) { @@ -622,20 +671,21 @@ if (this.openContainer != this.inventoryContainer) { this.closeScreen(); -@@ -940,7 +1182,8 @@ +@@ -940,7 +1219,8 @@ this.getNextWindowId(); this.connection.sendPacket(new SPacketOpenWindow(this.currentWindowId, "EntityHorse", inventoryIn.getDisplayName(), inventoryIn.getSizeInventory(), horse.getEntityId())); - this.openContainer = new ContainerHorseInventory(this.inventory, inventoryIn, horse, this); + // this.openContainer = new ContainerHorseInventory(this.inventory, inventoryIn, horse, this); -+ this.openContainer = container; ++ this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addListener(this); } -@@ -988,6 +1231,11 @@ +@@ -988,6 +1268,12 @@ { this.connection.sendPacket(new SPacketWindowItems(containerToSend.windowId, itemsList)); this.connection.sendPacket(new SPacketSetSlot(-1, -1, this.inventory.getItemStack())); ++ if (containerToSend.getBukkitView() == null) return; // Cauldron - allow vanilla mods to bypass + // CraftBukkit start - Send a Set Slot to update the crafting result slot + if (java.util.EnumSet.of(InventoryType.CRAFTING,InventoryType.WORKBENCH).contains(containerToSend.getBukkitView().getType())) { + this.connection.sendPacket(new SPacketSetSlot(containerToSend.windowId, 0, containerToSend.getSlot(0).getStack())); @@ -644,7 +694,7 @@ } public void sendWindowProperty(Container containerIn, int varToUpdate, int newValue) -@@ -1005,6 +1253,7 @@ +@@ -1005,6 +1291,7 @@ public void closeScreen() { @@ -652,7 +702,7 @@ this.connection.sendPacket(new SPacketCloseWindow(this.openContainer.windowId)); this.closeContainer(); } -@@ -1080,6 +1329,10 @@ +@@ -1080,6 +1367,10 @@ for (ResourceLocation resourcelocation : p_193102_1_) { @@ -663,7 +713,7 @@ list.add(CraftingManager.getRecipe(resourcelocation)); } -@@ -1110,8 +1363,16 @@ +@@ -1110,8 +1401,16 @@ public void setPlayerHealthUpdated() { this.lastHealth = -1.0E8F; @@ -680,7 +730,7 @@ public void sendStatusMessage(ITextComponent chatComponent, boolean actionBar) { this.connection.sendPacket(new SPacketChat(chatComponent, actionBar ? ChatType.GAME_INFO : ChatType.CHAT)); -@@ -1156,7 +1417,7 @@ +@@ -1156,7 +1455,7 @@ this.lastExperience = -1; this.lastHealth = -1.0F; this.lastFoodLevel = -1; @@ -689,7 +739,7 @@ this.entityRemoveQueue.addAll(that.entityRemoveQueue); this.seenCredits = that.seenCredits; this.enteredNetherPosition = that.enteredNetherPosition; -@@ -1246,6 +1507,18 @@ +@@ -1246,6 +1545,18 @@ public void setGameType(GameType gameType) { @@ -708,7 +758,7 @@ this.interactionManager.setGameType(gameType); this.connection.sendPacket(new SPacketChangeGameState(3, (float)gameType.getID())); -@@ -1280,34 +1553,32 @@ +@@ -1280,34 +1591,32 @@ public boolean canUseCommand(int permLevel, String commandName) { @@ -764,7 +814,7 @@ } public String getPlayerIP() -@@ -1320,6 +1591,17 @@ +@@ -1320,6 +1629,17 @@ public void handleClientSettings(CPacketClientSettings packetIn) { @@ -782,7 +832,7 @@ this.language = packetIn.getLang(); this.chatVisibility = packetIn.getChatVisibility(); this.chatColours = packetIn.isColorsEnabled(); -@@ -1327,7 +1609,7 @@ +@@ -1327,7 +1647,7 @@ this.getDataManager().set(MAIN_HAND, Byte.valueOf((byte)(packetIn.getMainHand() == EnumHandSide.LEFT ? 0 : 1))); } @@ -791,7 +841,7 @@ { return this.chatVisibility; } -@@ -1402,7 +1684,7 @@ +@@ -1402,7 +1722,7 @@ if (entity != this.spectatingEntity) { this.connection.sendPacket(new SPacketCamera(this.spectatingEntity)); @@ -800,7 +850,7 @@ } } -@@ -1434,7 +1716,8 @@ +@@ -1434,7 +1754,8 @@ @Nullable public ITextComponent getTabListDisplayName() { @@ -810,7 +860,7 @@ } public void swingArm(EnumHand hand) -@@ -1455,13 +1738,20 @@ +@@ -1455,13 +1776,20 @@ public void setElytraFlying() { @@ -834,7 +884,7 @@ } public PlayerAdvancements getAdvancements() -@@ -1474,4 +1764,145 @@ +@@ -1474,4 +1802,145 @@ { return this.enteredNetherPosition; } diff --git a/patches/net/minecraft/server/MinecraftServer.java.patch b/patches/net/minecraft/server/MinecraftServer.java.patch index 739c8e5..1c9ac64 100644 --- a/patches/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/net/minecraft/server/MinecraftServer.java.patch @@ -146,7 +146,7 @@ private String worldName; private boolean isDemo; private boolean enableBonusChest; -@@ -144,178 +151,276 @@ +@@ -144,178 +151,273 @@ private final GameProfileRepository profileRepo; private final PlayerProfileCache profileCache; private long nanoTimeSinceStatusRefresh; @@ -399,7 +399,7 @@ + Item item = entry.getValue(); + if(!key.getResourceDomain().equals("minecraft")) { + String materialName = key.toString().toUpperCase().replaceAll("(:|\\s)", "_").replaceAll("\\W", ""); -+ Material material = Material.addMaterial(EnumHelper.addEnum(Material.class, materialName, new Class[]{Integer.TYPE, Integer.TYPE}, new Object[]{Item.getIdFromItem(item), item.getItemStackLimit()})); ++ Material material = Material.addMaterial(Item.getIdFromItem(item), item.getItemStackLimit(), materialName); + if(MagmaConfig.instance.debugPrintBukkitMatterials.getValues()){ + if (material != null) { + MinecraftServer.LOGGER.info(String.format("Injected new Forge item material %s with ID %d.", material.name(), material.getId())); @@ -412,16 +412,13 @@ - else - { - this.worlds[i] = (WorldServer)(new WorldServer(this, isavehandler, worldinfo, j, this.profiler)).init(); -+ for (Material material : Material.values()) { -+ if (material.getId() < 256) -+ Material.addBlockMaterial(material); - } ++ + for (Map.Entry entry : ForgeRegistries.BLOCKS.getEntries()) { + ResourceLocation key = entry.getKey(); + Block block = entry.getValue(); + if(!key.getResourceDomain().equals("minecraft")) { + String materialName = key.toString().toUpperCase().replaceAll("(:|\\s)", "_").replaceAll("\\W", ""); -+ Material material = Material.addBlockMaterial(EnumHelper.addEnum(Material.class, materialName, new Class[]{Integer.TYPE}, new Object[]{Block.getIdFromBlock(block)})); ++ Material material = Material.addMaterial(Block.getIdFromBlock(block), materialName); + if(MagmaConfig.instance.debugPrintBukkitMatterials.getValues()) { + if (material != null) { + MinecraftServer.LOGGER.info(String.format("Injected new Forge block material %s with ID %d.", material.name(), material.getId())); @@ -430,7 +427,7 @@ + } + } + } -+ } + } + Map NAME_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "NAME_MAP"); + Map ID_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "ID_MAP"); @@ -520,7 +517,7 @@ int i = 16; int j = 4; int k = 192; -@@ -323,45 +428,51 @@ +@@ -323,45 +425,51 @@ int i1 = 0; this.setUserMessage("menu.generatingTerrain"); int j1 = 0; @@ -599,7 +596,7 @@ } } -@@ -379,73 +490,79 @@ +@@ -379,73 +487,79 @@ public abstract boolean shouldBroadcastConsoleToOps(); @@ -711,7 +708,7 @@ { if (worldserver1 != null) { -@@ -453,159 +570,215 @@ +@@ -453,159 +567,215 @@ worldserver1.flush(); } } @@ -1001,7 +998,7 @@ BufferedImage bufferedimage = ImageIO.read(file1); Validate.validState(bufferedimage.getWidth() == 64, "Must be 64 pixels wide"); Validate.validState(bufferedimage.getHeight() == 64, "Must be 64 pixels high"); -@@ -613,52 +786,42 @@ +@@ -613,52 +783,42 @@ ByteBuf bytebuf1 = Base64.encode(bytebuf); response.setFavicon("data:image/png;base64," + bytebuf1.toString(StandardCharsets.UTF_8)); bytebuf1.release(); // Forge: fix MC-122085 @@ -1064,7 +1061,7 @@ this.startProfiling = false; this.profiler.profilingEnabled = true; this.profiler.clearProfiling(); -@@ -667,16 +830,15 @@ +@@ -667,16 +827,15 @@ this.profiler.startSection("root"); this.updateTimeLightAndEntities(); @@ -1086,7 +1083,7 @@ } Collections.shuffle(Arrays.asList(agameprofile)); -@@ -684,7 +846,7 @@ +@@ -684,7 +843,7 @@ this.statusResponse.invalidateJson(); } @@ -1095,7 +1092,7 @@ { this.profiler.startSection("save"); this.playerList.saveAllPlayerData(); -@@ -697,95 +859,100 @@ +@@ -697,95 +856,100 @@ this.profiler.endSection(); this.profiler.startSection("snooper"); @@ -1244,7 +1241,7 @@ this.profiler.endStartSection("connection"); this.getNetworkSystem().networkTick(); this.profiler.endStartSection("players"); -@@ -794,33 +961,30 @@ +@@ -794,33 +958,30 @@ this.getFunctionManager().update(); this.profiler.endStartSection("tickables"); @@ -1286,7 +1283,7 @@ LOGGER.warn(msg); } -@@ -835,53 +999,51 @@ +@@ -835,53 +996,51 @@ return ret; } @@ -1364,7 +1361,7 @@ } }); } -@@ -889,145 +1051,115 @@ +@@ -889,145 +1048,115 @@ return report; } @@ -1554,7 +1551,7 @@ worldserver1.getWorldInfo().setDifficulty(difficulty); worldserver1.setAllowedSpawnTypes(this.allowSpawnMonsters(), this.canSpawnAnimals); } -@@ -1035,80 +1167,75 @@ +@@ -1035,80 +1164,75 @@ } } @@ -1664,7 +1661,7 @@ ++l; } } -@@ -1117,228 +1244,186 @@ +@@ -1117,228 +1241,186 @@ playerSnooper.addClientStat("worlds", Integer.valueOf(l)); } @@ -1941,7 +1938,7 @@ return entity; } } -@@ -1347,316 +1432,212 @@ +@@ -1347,316 +1429,212 @@ return null; } diff --git a/patches/net/minecraftforge/fml/common/registry/EntityRegistry.java.patch b/patches/net/minecraftforge/fml/common/registry/EntityRegistry.java.patch index ba3bf14..ba0101a 100644 --- a/patches/net/minecraftforge/fml/common/registry/EntityRegistry.java.patch +++ b/patches/net/minecraftforge/fml/common/registry/EntityRegistry.java.patch @@ -36,7 +36,7 @@ } private void doModEntityRegistration(ResourceLocation registryName, Class entityClass, String entityName, int id, Object mod, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates) -@@ -385,4 +393,23 @@ +@@ -385,4 +393,30 @@ this.entityClassRegistrations.put(entity, registration); this.entityRegistrations.put(registration.container, registration); } @@ -59,4 +59,11 @@ + entityTypeMap.put(entityClass, entityName); + entityClassMap.put(entityName, entityClass); + } ++ ++ // Magma ++ public static String getCustomEntityTypeName(Class entityClass) ++ { ++ return entityTypeMap.get(entityClass); ++ } ++ // Cauldron end } diff --git a/src/main/java/com/destroystokyo/paper/PaperMCConfig.java b/src/main/java/com/destroystokyo/paper/PaperMCConfig.java new file mode 100644 index 0000000..d7dab55 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/PaperMCConfig.java @@ -0,0 +1,318 @@ +package com.destroystokyo.paper; + +import com.google.common.base.Strings; +import com.google.common.base.Throwables; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.regex.Pattern; + +public class PaperMCConfig { + + private static File CONFIG_FILE; + private static final String HEADER = "This is the main configuration file for Paper.\n" + + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n" + + "with caution, and make sure you know what each option does before configuring.\n" + + "\n" + + "If you need help with the configuration or have any questions related to Paper,\n" + + "join us in our IRC channel.\n" + + "\n" + + "IRC: #paper @ irc.spi.gt ( http://irc.spi.gt/iris/?channels=paper )\n" + + "Wiki: https://paper.readthedocs.org/ \n" + + "Paper Forums: https://aquifermc.org/ \n"; + /*========================================================================*/ + public static YamlConfiguration config; + static int version; + static Map commands; + private static boolean verbose; + /*========================================================================*/ + private static boolean metricsStarted; + + public static void init(File configFile) { + CONFIG_FILE = configFile; + config = new YamlConfiguration(); + try { + config.load(CONFIG_FILE); + } catch (IOException ex) { + } catch (InvalidConfigurationException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Could not load paper.yml, please correct your syntax errors", ex); + throw Throwables.propagate(ex); + } + config.options().header(HEADER); + config.options().copyDefaults(true); + verbose = getBoolean("verbose", false); + + commands = new HashMap(); + + version = getInt("config-version", 13); + set("config-version", 13); + readConfig(PaperMCConfig.class, null); + } + + protected static void logError(String s) { + Bukkit.getLogger().severe(s); + } + + protected static void log(String s) { + if (verbose) { + Bukkit.getLogger().info(s); + } + } + + static void readConfig(Class clazz, Object instance) { + for (Method method : clazz.getDeclaredMethods()) { + if (Modifier.isPrivate(method.getModifiers())) { + if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { + try { + method.setAccessible(true); + method.invoke(instance); + } catch (InvocationTargetException ex) { + throw Throwables.propagate(ex.getCause()); + } catch (Exception ex) { + Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); + } + } + } + } + + try { + config.save(CONFIG_FILE); + } catch (IOException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex); + } + } + + private static final Pattern SPACE = Pattern.compile(" "); + private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]"); + + public static int getSeconds(String str) { + str = SPACE.matcher(str).replaceAll(""); + final char unit = str.charAt(str.length() - 1); + str = NOT_NUMERIC.matcher(str).replaceAll(""); + double num; + try { + num = Double.parseDouble(str); + } catch (Exception e) { + num = 0D; + } + switch (unit) { + case 'd': + num *= (double) 60 * 60 * 24; + break; + case 'h': + num *= (double) 60 * 60; + break; + case 'm': + num *= (double) 60; + break; + default: + case 's': + break; + } + return (int) num; + } + + protected static String timeSummary(int seconds) { + String time = ""; + + if (seconds > 60 * 60 * 24) { + time += TimeUnit.SECONDS.toDays(seconds) + "d"; + seconds %= 60 * 60 * 24; + } + + if (seconds > 60 * 60) { + time += TimeUnit.SECONDS.toHours(seconds) + "h"; + seconds %= 60 * 60; + } + + if (seconds > 0) { + time += TimeUnit.SECONDS.toMinutes(seconds) + "m"; + } + return time; + } + + private static void set(String path, Object val) { + config.set(path, val); + } + + private static boolean getBoolean(String path, boolean def) { + config.addDefault(path, def); + return config.getBoolean(path, config.getBoolean(path)); + } + + private static double getDouble(String path, double def) { + config.addDefault(path, def); + return config.getDouble(path, config.getDouble(path)); + } + + private static float getFloat(String path, float def) { + // TODO: Figure out why getFloat() always returns the default value. + return (float) getDouble(path, (double) def); + } + + private static int getInt(String path, int def) { + config.addDefault(path, def); + return config.getInt(path, config.getInt(path)); + } + + private static List getList(String path, T def) { + config.addDefault(path, def); + return (List) config.getList(path, config.getList(path)); + } + + private static String getString(String path, String def) { + config.addDefault(path, def); + return config.getString(path, config.getString(path)); + } + + public static int minChunkLoadThreads = 2; + + private static void chunkLoadThreads() { + minChunkLoadThreads = Math.min(6, getInt("settings.min-chunk-load-threads", 2)); // Keep people from doing stupid things with max of 6 + } + + public static boolean enableFileIOThreadSleep; + + private static void enableFileIOThreadSleep() { + enableFileIOThreadSleep = getBoolean("settings.sleep-between-chunk-saves", false); + if (enableFileIOThreadSleep) { + Bukkit.getLogger().info("Enabled sleeping between chunk saves, beware of memory issues"); + } + } + + public static boolean loadPermsBeforePlugins = true; + + private static void loadPermsBeforePlugins() { + loadPermsBeforePlugins = getBoolean("settings.load-permissions-yml-before-plugins", true); + } + + public static int regionFileCacheSize = 256; + + private static void regionFileCacheSize() { + regionFileCacheSize = getInt("settings.region-file-cache-size", 256); + } + + public static boolean enablePlayerCollisions = true; + + private static void enablePlayerCollisions() { + enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true); + } + + public static boolean saveEmptyScoreboardTeams = false; + + private static void saveEmptyScoreboardTeams() { + saveEmptyScoreboardTeams = getBoolean("settings.save-empty-scoreboard-teams", false); + } + + public static boolean bungeeOnlineMode = true; + + private static void bungeeOnlineMode() { + bungeeOnlineMode = getBoolean("settings.bungee-online-mode", true); + } + + public static int packetInSpamThreshold = 300; + + private static void packetInSpamThreshold() { + if (version < 11) { + int oldValue = getInt("settings.play-in-use-item-spam-threshold", 300); + set("settings.incoming-packet-spam-threshold", oldValue); + } + packetInSpamThreshold = getInt("settings.incoming-packet-spam-threshold", 300); + } + + public static String flyingKickPlayerMessage = "Flying is not enabled on this server"; + public static String flyingKickVehicleMessage = "Flying is not enabled on this server"; + + private static void flyingKickMessages() { + flyingKickPlayerMessage = getString("messages.kick.flying-player", flyingKickPlayerMessage); + flyingKickVehicleMessage = getString("messages.kick.flying-vehicle", flyingKickVehicleMessage); + } + + public static int playerAutoSaveRate = -1; + public static int maxPlayerAutoSavePerTick = 10; + + private static void playerAutoSaveRate() { + playerAutoSaveRate = getInt("settings.player-auto-save-rate", -1); + maxPlayerAutoSavePerTick = getInt("settings.max-player-auto-save-per-tick", -1); + if (maxPlayerAutoSavePerTick == -1) { // -1 Automatic / "Recommended" + // 10 should be safe for everyone unless your mass spamming player auto save + maxPlayerAutoSavePerTick = (playerAutoSaveRate == -1 || playerAutoSaveRate > 100) ? 10 : 20; + } + } + + public static boolean removeInvalidStatistics = false; + + private static void removeInvalidStatistics() { + if (version < 12) { + boolean oldValue = getBoolean("remove-invalid-statistics", false); + set("settings.remove-invalid-statistics", oldValue); + } + removeInvalidStatistics = getBoolean("settings.remove-invalid-statistics", false); + } + + public static boolean suggestPlayersWhenNullTabCompletions = true; + + private static void suggestPlayersWhenNull() { + suggestPlayersWhenNullTabCompletions = getBoolean("settings.suggest-player-names-when-null-tab-completions", suggestPlayersWhenNullTabCompletions); + } + + public static String authenticationServersDownKickMessage = ""; // empty = use translatable message + + private static void authenticationServersDownKickMessage() { + authenticationServersDownKickMessage = Strings.emptyToNull(getString("messages.kick.authentication-servers-down", authenticationServersDownKickMessage)); + } + + public static boolean savePlayerData = true; + + private static void savePlayerData() { + savePlayerData = getBoolean("settings.save-player-data", savePlayerData); + if (!savePlayerData) { + Bukkit.getLogger().log(Level.WARNING, "Player Data Saving is currently disabled. Any changes to your players data, " + + "such as inventories, experience points, advancements and the like will not be saved when they log out."); + } + } + + public static boolean useAlternativeLuckFormula = false; + + private static void useAlternativeLuckFormula() { + useAlternativeLuckFormula = getBoolean("settings.use-alternative-luck-formula", false); + if (useAlternativeLuckFormula) { + Bukkit.getLogger().log(Level.INFO, "Using Aikar's Alternative Luck Formula to apply Luck attribute to all loot pool calculations. See https://luckformula.emc.gs"); + } + } + + public static int tabSpamIncrement = 10; + public static int tabSpamLimit = 500; + + private static void tabSpamLimiters() { + tabSpamIncrement = getInt("settings.spam-limiter.tab-spam-increment", tabSpamIncrement); + tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit); + } + + + public static int maxBookPageSize = 2560; + public static double maxBookTotalSizeMultiplier = 0.98D; + + private static void maxBookSize() { + maxBookPageSize = getInt("settings.book-size.page-max", maxBookPageSize); + maxBookTotalSizeMultiplier = getDouble("settings.book-size.total-multiplier", maxBookTotalSizeMultiplier); + if (maxBookPageSize == 1024 && maxBookTotalSizeMultiplier == 0.90D) { + config.set("settings.book-size.page-max", 2560); + config.set("settings.book-size.total-multiplier", 0.98D); + maxBookPageSize = 2560; + maxBookTotalSizeMultiplier = 0.98D; + } + } +} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index b978e42..f29692c 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -78,7 +78,7 @@ public static Server getServer() { */ public static void setServer(Server server) { if (Bukkit.server != null) { - throw new UnsupportedOperationException("Cannot redefine singleton Server"); + Bukkit.server = server; } Bukkit.server = server; @@ -277,8 +277,8 @@ public static void reloadWhitelist() { /** * Broadcast a message to all players. *

- * This is the same as calling {@link #broadcast(String, - * String)} to {@link Server#BROADCAST_CHANNEL_USERS} + * This is the same as calling {@link #broadcast(java.lang.String, + * java.lang.String)} to {@link Server#BROADCAST_CHANNEL_USERS} * * @param message the message * @return the number of players @@ -369,6 +369,8 @@ public static int getTicksPerMonsterSpawns() { *

* This method may not return objects for offline players. * + * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer + * guaranteed to be unique * @param name the name to look up * @return a player if one was found, null otherwise */ @@ -379,6 +381,8 @@ public static Player getPlayer(String name) { /** * Gets the player with the exact given name, case insensitive. * + * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer + * guaranteed to be unique * @param name Exact name of the player to retrieve * @return a player object if one was found, null otherwise */ @@ -393,6 +397,8 @@ public static Player getPlayerExact(String name) { * This list is not sorted in any particular order. If an exact match is * found, the returned list will only contain a single result. * + * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer + * guaranteed to be unique * @param name the (partial) name to match * @return list of all possible players */ @@ -410,6 +416,11 @@ public static Player getPlayer(UUID id) { return server.getPlayer(id); } + @Nullable + public static UUID getPlayerUniqueId(String playerName) { + return server.getPlayerUniqueId(playerName); + } + /** * Gets the plugin manager for interfacing with plugins. * @@ -569,7 +580,7 @@ public static void savePlayers() { * Dispatches a command on this server, and executes it if found. * * @param sender the apparent sender of the command - * @param commandLine the command + arguments. Example: test abc + * @param commandLine the command arguments. Example: test abc * 123 * @return returns false if no target is found * @throws CommandException thrown when the executor for the given command @@ -712,9 +723,9 @@ public static int broadcast(String message, String permission) { * unique past a single session. * @param name the name the player to retrieve * @return an offline player - * @see #getOfflinePlayer(UUID) + * @see #getOfflinePlayer(java.util.UUID) */ - @Deprecated + public static OfflinePlayer getOfflinePlayer(String name) { return server.getOfflinePlayer(name); } diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java index 777cd5f..96735f4 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Map; +import net.minecraftforge.common.util.EnumHelper; import org.apache.commons.lang3.Validate; import org.bukkit.map.MapView; import org.bukkit.material.Bed; @@ -539,49 +540,169 @@ public enum Material { RECORD_11(2266, 1), RECORD_12(2267, 1), ; + private static Material[] byId = new Material[32676]; + private static Map BY_NAME = Maps.newHashMap(); // Magma - remove final + + static { + for (Material material : values()) { + if (byId.length > material.id) { + byId[material.id] = material; + } else { + byId = Arrays.copyOfRange(byId, 0, material.id + 2); + byId[material.id] = material; + } + BY_NAME.put(material.name(), material); + } + } private final int id; private final Constructor ctor; - private static Material[] byId = new Material[38000]; - private static Material[] byBlockId = new Material[10000]; //temp w - private final static Map BY_NAME = Maps.newHashMap(); private final int maxStack; private final short durability; - private Material(final int id) { + Material(final int id) { this(id, 64); } + // Magma end - private Material(final int id, final int stack) { + Material(final int id, final int stack) { this(id, stack, MaterialData.class); } - private Material(final int id, final int stack, final int durability) { + Material(final int id, final int stack, final int durability) { this(id, stack, durability, MaterialData.class); } - private Material(final int id, final Class data) { + Material(final int id, final Class data) { this(id, 64, data); } - private Material(final int id, final int stack, final Class data) { + Material(final int id, final int stack, final Class data) { this(id, stack, 0, data); } - private Material(final int id, final int stack, final int durability, final Class data) { + Material(final int id, final int stack, final int durability, final Class data) { this.id = id; this.durability = (short) durability; this.maxStack = stack; // try to cache the constructor for this material try { this.ctor = data.getConstructor(int.class, byte.class); - } catch (NoSuchMethodException ex) { - throw new AssertionError(ex); - } catch (SecurityException ex) { + } catch (NoSuchMethodException | SecurityException ex) { throw new AssertionError(ex); } } + /** + * Attempts to get the Material with the given ID + * + * @param id ID of the material to get + * @return Material if found, or null + * @deprecated Magic value + */ + + public static Material getMaterial(final int id) { + if (byId.length > id && id >= 0) { + return byId[id]; + } else { + return null; + } + } + + /** + * Attempts to get the Material with the given name. + *

+ * This is a normal lookup, names must be the precise name they are given + * in the enum. + * + * @param name Name of the material to get + * @return Material if found, or null + */ + public static Material getMaterial(final String name) { + return BY_NAME.get(name); + } + + /** + * Attempts to match the Material with the given name. + *

+ * This is a match lookup; names will be converted to uppercase, then + * stripped of special characters in an attempt to format it like the + * enum. + *

+ * Using this for match by ID is deprecated. + * + * @param name Name of the material to get + * @return Material if found, or null + */ + public static Material matchMaterial(final String name) { + Validate.notNull(name, "Name cannot be null"); + + Material result = null; + + try { + result = getMaterial(Integer.parseInt(name)); + } catch (NumberFormatException ex) { + } + + if (result == null) { + // Cauldron start - extract to normalizeName() + String filtered = normalizeName(name); + result = BY_NAME.get(filtered); + // Cauldron end + } + + /*/ Cauldron start - Try the ore dictionary + if (result == null) { + BukkitOreDictionary dict = net.minecraftforge.cauldron.api.Cauldron.getOreDictionary(); + OreDictionaryEntry entry = dict.getOreEntry(name); + if (entry != null) { + List items = dict.getDefinitions(entry); + if (items.size() > 0) { + // TODO check sanity on multiple item results + ItemStack item = items.get(0); + if (item.getDurability() == 0 || item.getDurability() == Short.MAX_VALUE) { + result = item.getType(); + } else { + // bad! we have an item with data! + } + } + } + } + // Cauldron end + */ + + return result; + } + + // use a normalize() function to ensure it is accessible after a round-trip + public static String normalizeName(String name) { + return name.toUpperCase(java.util.Locale.ENGLISH).replaceAll("(:|\\s)", "_").replaceAll("\\W", ""); + } + + public static Material addMaterial(int id, int limit, String name) { + if (byId[id] == null) { + String materialName = normalizeName(name); + Material material = EnumHelper.addEnum(Material.class, materialName, new Class[]{Integer.TYPE, Integer.TYPE}, new Object[]{id, limit}); + byId[id] = material; + BY_NAME.put(materialName, material); + BY_NAME.put("X" + material.id, material); + return material; + } + return null; + } + + public static Material addMaterial(int id, String name) { + if (byId[id] == null) { + String materialName = normalizeName(name); + Material material = EnumHelper.addEnum(Material.class, materialName, new Class[]{Integer.TYPE}, new Object[]{id}); + byId[id] = material; + BY_NAME.put(materialName, material); + BY_NAME.put("X" + material.id, material); + return material; + } + return null; + } + /** * Gets the item ID or block ID of this Material * @@ -652,10 +773,7 @@ public MaterialData getNewData(final byte raw) { * @return true if this material is a block */ public boolean isBlock() { - for (Material material : byBlockId) { - if (this == material) return true; - } - return false; + return id < 256; } /** @@ -701,106 +819,6 @@ public boolean isEdible() { } } - /** - * Attempts to get the Material with the given ID - * - * @param id ID of the material to get - * @return Material if found, or null - * @deprecated Magic value - */ - - public static Material getMaterial(final int id) { - if (byId.length > id && id >= 0) { - return byId[id]; - } else { - return null; - } - } - - /** - * Attempts to get the Material with the given name. - *

- * This is a normal lookup, names must be the precise name they are given - * in the enum. - * - * @param name Name of the material to get - * @return Material if found, or null - */ - public static Material getMaterial(final String name) { - return BY_NAME.get(name); - } - - /** - * Attempts to match the Material with the given name. - *

- * This is a match lookup; names will be converted to uppercase, then - * stripped of special characters in an attempt to format it like the - * enum. - *

- * Using this for match by ID is deprecated. - * - * @param name Name of the material to get - * @return Material if found, or null - */ - public static Material matchMaterial(final String name) { - Validate.notNull(name, "Name cannot be null"); - - Material result = null; - - try { - result = getMaterial(Integer.parseInt(name)); - } catch (NumberFormatException ex) {} - - if (result == null) { - String filtered = name.toUpperCase(java.util.Locale.ENGLISH); - - filtered = filtered.replaceAll("\\s+", "_").replaceAll("\\W", ""); - result = BY_NAME.get(filtered); - } - - return result; - } - - @Nullable - public static Material addMaterial(Material material) { - if (byId[material.id] == null) { - byId[material.id] = material; - BY_NAME.put(material.name().toUpperCase().replaceAll("(:|\\s)", "_").replaceAll("\\W", ""), material); - BY_NAME.put("X" + String.valueOf(material.id), material); - return material; - } - return null; - } - - @Nullable - public static Material addBlockMaterial(Material Blockmaterial) { - if (byBlockId[Blockmaterial.id] == null) { - byBlockId[Blockmaterial.id] = Blockmaterial; - return Blockmaterial; - } - return null; - } - - public static Material getBlockMaterial(final int id) { - if (byBlockId.length > id && id >= 0) { - return byBlockId[id]; - } else { - return null; - } - } - - static { - for (Material material : values()) { - if (byId.length > material.id) { - byId[material.id] = material; - } else { - byId = Arrays.copyOfRange(byId, 0, material.id + 2); - byId[material.id] = material; - } - BY_NAME.put(material.name(), material); - } - } - /** * @return True if this material represents a playable music disk. */ diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java index 372c990..f366c68 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -87,7 +87,7 @@ public interface Server extends PluginMessageRecipient { * * @return version of Bukkit */ - String getBukkitVersion(); + public String getBukkitVersion(); public Player[] _INVALID_getOnlinePlayers(); @@ -302,6 +302,8 @@ public interface Server extends PluginMessageRecipient { *

* This method may not return objects for offline players. * + * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer + * guaranteed to be unique * @param name the name to look up * @return a player if one was found, null otherwise */ @@ -310,6 +312,8 @@ public interface Server extends PluginMessageRecipient { /** * Gets the player with the exact given name, case insensitive. * + * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer + * guaranteed to be unique * @param name Exact name of the player to retrieve * @return a player object if one was found, null otherwise */ @@ -322,6 +326,8 @@ public interface Server extends PluginMessageRecipient { * This list is not sorted in any particular order. If an exact match is * found, the returned list will only contain a single result. * + * @deprecated Use {@link #getPlayer(UUID)} as player names are no longer + * guaranteed to be unique * @param name the (partial) name to match * @return list of all possible players */ @@ -333,10 +339,10 @@ public interface Server extends PluginMessageRecipient { * @param id UUID of the player to retrieve * @return a player object if one was found, null otherwise */ - Player getPlayer(UUID id); + public Player getPlayer(UUID id); @Nullable - UUID getPlayerUniqueId(String playerName); + public UUID getPlayerUniqueId(String playerName); /** * Gets the plugin manager for interfacing with plugins. @@ -419,7 +425,7 @@ public interface Server extends PluginMessageRecipient { * @return a map view if it exists, or null otherwise * @deprecated Magic value */ - @Deprecated + public MapView getMap(short id); /** @@ -465,7 +471,7 @@ public interface Server extends PluginMessageRecipient { * Dispatches a command on this server, and executes it if found. * * @param sender the apparent sender of the command - * @param commandLine the command + arguments. Example: test abc + * @param commandLine the command arguments. Example: test abc * 123 * @return returns false if no target is found * @throws CommandException thrown when the executor for the given command @@ -582,7 +588,7 @@ public interface Server extends PluginMessageRecipient { * @return an offline player * @see #getOfflinePlayer(UUID) */ - @Deprecated + public OfflinePlayer getOfflinePlayer(String name); /** @@ -929,7 +935,7 @@ public interface Server extends PluginMessageRecipient { * * @return current server TPS (1m, 5m, 15m in Paper-Server) */ - double[] getTPS(); + public double[] getTPS(); /** * Gets the active {@link CommandMap} @@ -959,48 +965,11 @@ public interface Server extends PluginMessageRecipient { * @see UnsafeValues * @return the unsafe values instance */ - @Deprecated - UnsafeValues getUnsafe(); - - // Spigot start - public class Spigot - { - - public org.bukkit.configuration.file.YamlConfiguration getConfig() - { - throw new UnsupportedOperationException( "Not supported yet." ); - } - - /** - * Sends the component to the player - * - * @param component the components to send - */ - public void broadcast(net.md_5.bungee.api.chat.BaseComponent component) { - throw new UnsupportedOperationException("Not supported yet."); - } - /** - * Sends an array of components as a single message to the player - * - * @param components the components to send - */ - public void broadcast(net.md_5.bungee.api.chat.BaseComponent... components) { - throw new UnsupportedOperationException("Not supported yet."); - } - - /** - * Restart the server. If the server administrator has not configured restarting, the server will stop. - */ - public void restart() { - throw new UnsupportedOperationException("Not supported yet."); - } - } + UnsafeValues getUnsafe(); Spigot spigot(); - // Spigot end - // Paper start - allow preventing player name suggestions by default /** * Checks if player names should be suggested when a command returns {@code null} as * their tab completion result. @@ -1008,6 +977,9 @@ public void restart() { * @return true if player names should be suggested */ boolean suggestPlayerNamesWhenNullTabCompletions(); + // Spigot end + + // Paper start - allow preventing player name suggestions by default /** * Creates a PlayerProfile for the specified uuid, with name as null @@ -1033,5 +1005,55 @@ public void restart() { * @return A PlayerProfile object */ com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name); + + // Spigot start + public class Spigot { + + @Deprecated + public org.bukkit.configuration.file.YamlConfiguration getConfig() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public org.bukkit.configuration.file.YamlConfiguration getBukkitConfig() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public org.bukkit.configuration.file.YamlConfiguration getSpigotConfig() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + public org.bukkit.configuration.file.YamlConfiguration getPaperConfig() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * Sends the component to the player + * + * @param component the components to send + */ + public void broadcast(net.md_5.bungee.api.chat.BaseComponent component) { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * Sends an array of components as a single message to the player + * + * @param components the components to send + */ + public void broadcast(net.md_5.bungee.api.chat.BaseComponent... components) { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * Restart the server. If the server administrator has not configured restarting, the server will stop. + */ + public void restart() { + throw new UnsupportedOperationException("Not supported yet."); + } + } // Paper end } diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java index dc0e221..43d11cd 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -295,7 +295,7 @@ public interface World extends PluginMessageRecipient, Metadatable { * * @deprecated This method is not guaranteed to work suitably across all client implementations. */ - @Deprecated + public boolean refreshChunk(int x, int z); /** @@ -411,7 +411,7 @@ public interface World extends PluginMessageRecipient, Metadatable { * @return A List of all Entities currently residing in this world that * match the given class/interface */ - @Deprecated + public Collection getEntitiesByClass(Class... classes); /** @@ -653,7 +653,7 @@ public interface World extends PluginMessageRecipient, Metadatable { * @param setFire Whether or not to set blocks on fire * @return false if explosion was canceled, otherwise true */ - boolean createExplosion(Location loc, float power, boolean setFire); + public boolean createExplosion(Location loc, float power, boolean setFire); // Paper start /** @@ -667,7 +667,7 @@ public interface World extends PluginMessageRecipient, Metadatable { * @param breakBlocks Whether or not to have blocks be destroyed * @return false if explosion was canceled, otherwise true */ - boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks); + public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks); /** * Creates explosion at given location with given power and optionally @@ -681,7 +681,7 @@ public interface World extends PluginMessageRecipient, Metadatable { * @param setFire Whether or not to set blocks on fire * @return false if explosion was canceled, otherwise true */ - default boolean createExplosion(Entity source, Location loc, float power, boolean setFire) { + public default boolean createExplosion(Entity source, Location loc, float power, boolean setFire) { return createExplosion(source, loc, power, setFire, true); } /** @@ -693,7 +693,7 @@ default boolean createExplosion(Entity source, Location loc, float power, boolea * @param power The power of explosion, where 4F is TNT * @return false if explosion was canceled, otherwise true */ - default boolean createExplosion(Entity source, Location loc, float power) { + public default boolean createExplosion(Entity source, Location loc, float power) { return createExplosion(source, loc, power, true, true); } /** @@ -706,7 +706,7 @@ default boolean createExplosion(Entity source, Location loc, float power) { * @param breakBlocks Whether or not to have blocks be destroyed * @return false if explosion was canceled, otherwise true */ - default boolean createExplosion(Entity source, float power, boolean setFire, boolean breakBlocks) { + public default boolean createExplosion(Entity source, float power, boolean setFire, boolean breakBlocks) { return createExplosion(source, source.getLocation(), power, setFire, breakBlocks); } /** @@ -720,7 +720,7 @@ default boolean createExplosion(Entity source, float power, boolean setFire, boo * @param setFire Whether or not to set blocks on fire * @return false if explosion was canceled, otherwise true */ - default boolean createExplosion(Entity source, float power, boolean setFire) { + public default boolean createExplosion(Entity source, float power, boolean setFire) { return createExplosion(source, source.getLocation(), power, setFire, true); } @@ -732,7 +732,7 @@ default boolean createExplosion(Entity source, float power, boolean setFire) { * @param power The power of explosion, where 4F is TNT * @return false if explosion was canceled, otherwise true */ - default boolean createExplosion(Entity source, float power) { + public default boolean createExplosion(Entity source, float power) { return createExplosion(source, source.getLocation(), power, true, true); } @@ -746,7 +746,7 @@ default boolean createExplosion(Entity source, float power) { * @param breakBlocks Whether or not to have blocks be destroyed * @return false if explosion was canceled, otherwise true */ - default boolean createExplosion(Location loc, float power, boolean setFire, boolean breakBlocks) { + public default boolean createExplosion(Location loc, float power, boolean setFire, boolean breakBlocks) { return createExplosion(loc.getX(), loc.getY(), loc.getZ(), power, setFire, breakBlocks); } // Paper end @@ -1566,6 +1566,69 @@ default boolean createExplosion(Location loc, float power, boolean setFire, bool */ public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data); + Spigot spigot(); + + /** + * Represents various map environment types that a world may be + */ + public enum Environment { + + /** + * Represents the "normal"/"surface world" map + */ + NORMAL(0), + /** + * Represents a nether based map ("hell") + */ + NETHER(-1), + /** + * Represents the "end" map + */ + THE_END(1); + + private static final Map lookup = new HashMap(); + + static { + for (Environment env : values()) { + lookup.put(env.getId(), env); + } + } + + private final int id; + + private Environment(int id) { + this.id = id; + } + + public static void registerEnvironment(Environment env) { + lookup.put(env.getId(), env); + } + + /** + * Get an environment by ID + * + * @param id The ID of the environment + * @return The environment + * @deprecated Magic value + */ + + public static Environment getEnvironment(int id) { + return lookup.get(id); + } + + /** + * Gets the dimension ID of this environment + * + * @return dimension ID + * @deprecated Magic value + */ + + public int getId() { + return id; + } + } + // Spigot end + // Spigot start public class Spigot { @@ -1581,7 +1644,7 @@ public class Spigot * It also throws when the effect requires a material or a material data * @deprecated Spigot specific API, use {@link Particle}. */ - @Deprecated + public void playEffect(Location location, Effect effect) { throw new UnsupportedOperationException( "Not supported yet." ); @@ -1610,7 +1673,7 @@ public void playEffect(Location location, Effect effect) * @param radius the radius around the location * @deprecated Spigot specific API, use {@link Particle}. */ - @Deprecated + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) { throw new UnsupportedOperationException( "Not supported yet." ); @@ -1622,12 +1685,12 @@ public void playEffect(Location location, Effect effect, int id, int data, float * @param loc The location to strike lightning * @param isSilent Whether this strike makes no sound * @return The lightning entity. - */ + */ public LightningStrike strikeLightning(Location loc, boolean isSilent) { throw new UnsupportedOperationException( "Not supported yet." ); } - + /** * Strikes lightning at the given {@link Location} without doing damage and possibly without sound * @@ -1640,66 +1703,4 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) throw new UnsupportedOperationException( "Not supported yet." ); } } - - Spigot spigot(); - // Spigot end - - /** - * Represents various map environment types that a world may be - */ - public enum Environment { - - /** - * Represents the "normal"/"surface world" map - */ - NORMAL(0), - /** - * Represents a nether based map ("hell") - */ - NETHER(-1), - /** - * Represents the "end" map - */ - THE_END(1); - - private final int id; - private static final Map lookup = new HashMap(); - - private Environment(int id) { - this.id = id; - } - - public static void registerEnvironment(Environment env){ - lookup.put(env.getId(), env); - } - - /** - * Gets the dimension ID of this environment - * - * @return dimension ID - * @deprecated Magic value - */ - @Deprecated - public int getId() { - return id; - } - - /** - * Get an environment by ID - * - * @param id The ID of the environment - * @return The environment - * @deprecated Magic value - */ - @Deprecated - public static Environment getEnvironment(int id) { - return lookup.get(id); - } - - static { - for (Environment env : values()) { - lookup.put(env.getId(), env); - } - } - } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 1a487c1..24576fa 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -24,6 +24,7 @@ import javax.annotation.Nullable; import javax.imageio.ImageIO; +import com.destroystokyo.paper.PaperMCConfig; import jline.console.ConsoleReader; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementRewards; @@ -158,6 +159,7 @@ import org.bukkit.scheduler.BukkitWorker; import org.bukkit.util.StringUtil; import org.bukkit.util.permissions.DefaultPermissions; +import org.magmafoundation.magma.Magma; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.error.MarkedYAMLException; @@ -184,7 +186,14 @@ import net.md_5.bungee.api.chat.BaseComponent; public final class CraftServer implements Server { - private final String serverName = "Magma"; + static { + ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); + CraftItemFactory.instance(); + } + + protected final MinecraftServer console; + protected final DedicatedPlayerList playerList; + private final String serverName = Magma.getName(); private final String serverVersion; private final String bukkitVersion = Versioning.getBukkitVersion(); private final Logger logger = Logger.getLogger("Minecraft"); @@ -195,53 +204,77 @@ public final class CraftServer implements Server { private final SimpleHelpMap helpMap = new SimpleHelpMap(this); private final StandardMessenger messenger = new StandardMessenger(); private final SimplePluginManager pluginManager = new SimplePluginManager(this, commandMap); - protected final MinecraftServer console; - protected final DedicatedPlayerList playerList; private final Map worlds = new LinkedHashMap(); - private YamlConfiguration configuration; - private YamlConfiguration commandsConfiguration; private final Yaml yaml = new Yaml(new SafeConstructor()); private final Map offlinePlayers = new MapMaker().weakValues().makeMap(); private final EntityMetadataStore entityMetadata = new EntityMetadataStore(); private final PlayerMetadataStore playerMetadata = new PlayerMetadataStore(); private final WorldMetadataStore worldMetadata = new WorldMetadataStore(); + private final BooleanWrapper online = new BooleanWrapper(); + private final List playerView; + private final Spigot spigot = new Spigot() { + + @Deprecated + @Override + public YamlConfiguration getConfig() + { + return org.spigotmc.SpigotConfig.config; + } + + @Override + public YamlConfiguration getBukkitConfig() + { + return configuration; + } + + @Override + public YamlConfiguration getSpigotConfig() + { + return org.spigotmc.SpigotConfig.config; + } + + @Override + public YamlConfiguration getPaperConfig() + { + return PaperMCConfig.config; + } + + @Override + public void broadcast(BaseComponent component) { + for (Player player : getOnlinePlayers()) { + player.spigot().sendMessage(component); + } + } + + @Override + public void broadcast(BaseComponent... components) { + for (Player player : getOnlinePlayers()) { + player.spigot().sendMessage(components); + } + } + }; + public int chunkGCPeriod = -1; + public int chunkGCLoadThresh = 0; + public CraftScoreboardManager scoreboardManager; + public boolean playerCommandState; + public int reloadCount; + private YamlConfiguration configuration; + private YamlConfiguration commandsConfiguration; private int monsterSpawn = -1; private int animalSpawn = -1; private int waterAnimalSpawn = -1; private int ambientSpawn = -1; - public int chunkGCPeriod = -1; - public int chunkGCLoadThresh = 0; private File container; private WarningState warningState = WarningState.DEFAULT; - private final BooleanWrapper online = new BooleanWrapper(); - public CraftScoreboardManager scoreboardManager; - public boolean playerCommandState; private boolean printSaveWarning; private CraftIconCache icon; private boolean overrideAllCommandBlockCommands = false; private boolean unrestrictedAdvancements; - private final List playerView; - public int reloadCount; - - private final class BooleanWrapper { - private boolean value = true; - } - - static { - ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); - CraftItemFactory.instance(); - } public CraftServer(MinecraftServer console, PlayerList playerList) { this.console = console; this.playerList = (DedicatedPlayerList) playerList; - this.playerView = Collections - .unmodifiableList(Lists.transform(playerList.getPlayers(), new Function() { - @Override - public CraftPlayer apply(EntityPlayerMP player) { - return player.getBukkitEntity(); - } - })); + this.playerView = Collections.unmodifiableList(Lists.transform(playerList.getPlayers(), player -> player.getBukkitEntity())); this.serverVersion = CraftServer.class.getPackage().getImplementationVersion(); online.value = console.getPropertyManager().getBooleanProperty("online-mode", true); @@ -412,8 +445,18 @@ public void disablePlugins() { private void setVanillaCommands(boolean first) { Map commands = console.getCommandManager().getCommands(); for (ICommand cmd : commands.values()) { - commandMap.register("minecraft", - new VanillaCommandWrapper((CommandBase) cmd, I18n.translateToLocal(cmd.getUsage(null)))); + // Spigot start + if (console.getCommandManager().getCommandMod().containsValue(cmd)) + continue; + VanillaCommandWrapper wrapper = new VanillaCommandWrapper((CommandBase) cmd, I18n.translateToLocal(cmd.getUsage(null))); + if (org.spigotmc.SpigotConfig.replaceCommands.contains(wrapper.getName())) { + if (first) { + commandMap.register("minecraft", wrapper); + } + } else if (!first) { + commandMap.register("minecraft", wrapper); + } + // Spigot end } } @@ -1576,6 +1619,12 @@ public List tabComplete(net.minecraft.command.ICommandSender sender, Str } public List tabCompleteCommand(Player player, String message, BlockPos pos) { + // Spigot Start + if ( (org.spigotmc.SpigotConfig.tabComplete < 0 || message.length() <= org.spigotmc.SpigotConfig.tabComplete) && !message.contains( " " ) ) + { + return ImmutableList.of(); + } + // Spigot End List completions = null; try { if (message.startsWith("/")) { @@ -1713,14 +1762,8 @@ public org.bukkit.advancement.Advancement getAdvancement(NamespacedKey key) { @Override public Iterator advancementIterator() { - return Iterators - .unmodifiableIterator(Iterators.transform(console.getAdvancementManager().getAdvancements().iterator(), - new Function() { // PAIL: rename - @Override - public org.bukkit.advancement.Advancement apply(Advancement advancement) { - return advancement.bukkit; - } - })); + // PAIL: rename + return Iterators.unmodifiableIterator(Iterators.transform(console.getAdvancementManager().getAdvancements().iterator(), advancement -> advancement.bukkit)); } @Deprecated @@ -1740,31 +1783,6 @@ public double[] getTPS() { } // Paper end - private final Spigot spigot = new Spigot() - { - - @Override - public YamlConfiguration getConfig() - { - return org.spigotmc.SpigotConfig.config; - } - - @Override - public void broadcast(BaseComponent component) { - for (Player player : getOnlinePlayers()) { - player.spigot().sendMessage(component); - } - } - - @Override - public void broadcast(BaseComponent... components) { - for (Player player : getOnlinePlayers()) { - player.spigot().sendMessage(components); - } - } - }; - - @Override public Spigot spigot() { return spigot; } @@ -1784,5 +1802,9 @@ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUI } return new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name); } + + private static final class BooleanWrapper { + private boolean value = true; + } // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 117d650..3d327d9 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -188,14 +188,81 @@ public class CraftWorld implements World { public static final int CUSTOM_DIMENSION_OFFSET = 10; - + private static final Random rand = new Random(); private final WorldServer world; - private WorldBorder worldBorder; - private Environment environment; private final CraftServer server = (CraftServer) Bukkit.getServer(); - public ChunkGenerator generator; private final List populators = new ArrayList(); private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this); + // Spigot start + private final Spigot spigot = new Spigot() { + @Override + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) { + Validate.notNull(location, "Location cannot be null"); + Validate.notNull(effect, "Effect cannot be null"); + Validate.notNull(location.getWorld(), "World cannot be null"); + Packet packet; + if (effect.getType() != Effect.Type.PARTICLE) { + int packetData = effect.getId(); + packet = new SPacketEffect(packetData, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), id, false); + } else { + net.minecraft.util.EnumParticleTypes particle = null; + int[] extra = null; + for (net.minecraft.util.EnumParticleTypes p : net.minecraft.util.EnumParticleTypes.values()) { + if (effect.getName().startsWith(p.getParticleName().replace("_", ""))) { + particle = p; + if (effect.getData() != null) { + if (effect.getData().equals(org.bukkit.Material.class)) { + extra = new int[]{id}; + } else { + extra = new int[]{(data << 12) | (id & 0xFFF)}; + } + } + break; + } + } + if (extra == null) { + extra = new int[0]; + } + packet = new SPacketParticles(particle, true, (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, speed, particleCount, extra); + } + int distance; + radius *= radius; + for (Player player : getPlayers()) { + if (((CraftPlayer) player).getHandle().connection == null) { + continue; + } + if (!location.getWorld().equals(player.getWorld())) { + continue; + } + distance = (int) player.getLocation().distanceSquared(location); + if (distance <= radius) { + ((CraftPlayer) player).getHandle().connection.sendPacket(packet); + } + } + } + + @Override + public void playEffect(Location location, Effect effect) { + CraftWorld.this.playEffect(location, effect, 0); + } + + @Override + public LightningStrike strikeLightning(Location loc, boolean isSilent) { + EntityLightningBolt lightning = new EntityLightningBolt(world, loc.getX(), loc.getY(), loc.getZ(), false, isSilent); + world.addWeatherEffect(lightning); + return new CraftLightningStrike(server, lightning); + } + + @Override + public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) { + EntityLightningBolt lightning = new EntityLightningBolt(world, loc.getX(), loc.getY(), loc.getZ(), true, isSilent); + world.addWeatherEffect(lightning); + return new CraftLightningStrike(server, lightning); + } + }; + public ChunkGenerator generator; + private WorldBorder worldBorder; + private Environment environment; private int monsterSpawn = -1; private int animalSpawn = -1; private int waterAnimalSpawn = -1; @@ -203,8 +270,6 @@ public class CraftWorld implements World { private int chunkLoadCount = 0; private int chunkGCTickCount; - private static final Random rand = new Random(); - public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) { this.world = world; this.generator = gen; @@ -216,6 +281,31 @@ public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) { } } + private static void randomLocationWithinBlock(Location loc, double xs, double ys, double zs) { + double prevX = loc.getX(); + double prevY = loc.getY(); + double prevZ = loc.getZ(); + loc.add(xs, ys, zs); + if (loc.getX() < Math.floor(prevX)) { + loc.setX(Math.floor(prevX)); + } + if (loc.getX() >= Math.ceil(prevX)) { + loc.setX(Math.ceil(prevX - 0.01)); + } + if (loc.getY() < Math.floor(prevY)) { + loc.setY(Math.floor(prevY)); + } + if (loc.getY() >= Math.ceil(prevY)) { + loc.setY(Math.ceil(prevY - 0.01)); + } + if (loc.getZ() < Math.floor(prevZ)) { + loc.setZ(Math.floor(prevZ)); + } + if (loc.getZ() >= Math.ceil(prevZ)) { + loc.setZ(Math.ceil(prevZ - 0.01)); + } + } + public Block getBlockAt(int x, int y, int z) { Chunk chunk = getChunkAt(x >> 4, z >> 4); return chunk == null ? null : chunk.getBlock(x & 0xF, y & 0xFF, z & 0xF); @@ -423,31 +513,6 @@ public Item dropItem(Location loc, ItemStack item) { return new CraftItem(world.getServer(), entity); } - private static void randomLocationWithinBlock(Location loc, double xs, double ys, double zs) { - double prevX = loc.getX(); - double prevY = loc.getY(); - double prevZ = loc.getZ(); - loc.add(xs, ys, zs); - if (loc.getX() < Math.floor(prevX)) { - loc.setX(Math.floor(prevX)); - } - if (loc.getX() >= Math.ceil(prevX)) { - loc.setX(Math.ceil(prevX - 0.01)); - } - if (loc.getY() < Math.floor(prevY)) { - loc.setY(Math.floor(prevY)); - } - if (loc.getY() >= Math.ceil(prevY)) { - loc.setY(Math.ceil(prevY - 0.01)); - } - if (loc.getZ() < Math.floor(prevZ)) { - loc.setZ(Math.floor(prevZ)); - } - if (loc.getZ() >= Math.ceil(prevZ)) { - loc.setZ(Math.ceil(prevZ - 0.01)); - } - } - public Item dropItemNaturally(Location loc, ItemStack item) { double xs = world.rand.nextFloat() * 0.7F - 0.35D; double ys = world.rand.nextFloat() * 0.7F - 0.35D; @@ -684,15 +749,13 @@ public boolean createExplosion(double x, double y, double z, float power, boolea public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks) { return !world.newExplosion(null, x, y, z, power, setFire, breakBlocks).wasCanceled; } + // Paper end // Paper start - @Override public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { return !world.newExplosion(source != null ? ((CraftEntity) source).getHandle() : null, loc.getX(), loc.getY(), loc.getZ(), power, setFire, breakBlocks).wasCanceled; } - // Paper end - @Override public boolean createExplosion(Location loc, float power) { return createExplosion(loc, power, false); } @@ -894,6 +957,7 @@ public List getPlayers() { return list; } + // Paper end // Paper start - getEntity by UUID API public Entity getEntity(UUID uuid) { @@ -901,21 +965,14 @@ public Entity getEntity(UUID uuid) { net.minecraft.entity.Entity entity = world.getEntityFromUuid(uuid); return entity == null ? null : entity.getBukkitEntity(); } - // Paper end - @Override public void save() { - // Spigot start - save(true); - } - - public void save(boolean forceSave) { this.server.checkSaveState(); try { boolean oldSave = world.disableLevelSaving; world.disableLevelSaving = false; - world.saveAllChunks(forceSave, null); + world.saveAllChunks(true, null); world.disableLevelSaving = oldSave; } catch (MinecraftException ex) { @@ -1050,7 +1107,7 @@ public FallingBlock spawnFallingBlock(Location location, org.bukkit.Material mat } public FallingBlock spawnFallingBlock(Location location, int blockId, byte blockData) throws IllegalArgumentException { - return spawnFallingBlock(location, org.bukkit.Material.getBlockMaterial(blockId), blockData); + return spawnFallingBlock(location, org.bukkit.Material.getMaterial(blockId), blockData); } @SuppressWarnings("unchecked") @@ -1300,7 +1357,7 @@ public net.minecraft.entity.Entity createEntity(Location location, Class list = (List) world.getEntitiesWithinAABB(null, bb); + List list = (List) world.getEntitiesWithinAABBExcludingEntity(null, bb); for (Iterator it = list.iterator(); !taken && it.hasNext();) { net.minecraft.entity.Entity e = it.next(); if (e instanceof EntityHanging) { @@ -1352,6 +1409,12 @@ public net.minecraft.entity.Entity createEntity(Location location, Class entityClass; private CraftEntityEquipment equipment; - public String entityName; public CraftLivingEntity(final CraftServer server, final EntityLivingBase entity) { super(server, entity); @@ -86,7 +87,8 @@ public CraftLivingEntity(final CraftServer server, final EntityLivingBase entity if (entity instanceof EntityLiving || entity instanceof EntityArmorStand) { equipment = new CraftEntityEquipment(this); } - this.entityName = EntityRegistry.entityTypeMap.get(entity.getClass()); + this.entityClass = entity.getClass(); + this.entityName = EntityRegistry.getCustomEntityTypeName(entityClass); if (entityName == null) { entityName = entity.getName(); } @@ -300,6 +302,9 @@ public void removePotionEffect(PotionEffectType type) { public Collection getActivePotionEffects() { List effects = new ArrayList(); for (net.minecraft.potion.PotionEffect handle : getHandle().getActivePotionMap().values()) { + if (PotionEffectType.getById(Potion.getIdFromPotion(handle.getPotion())) == null) { + continue; // Magma - ignore null types + } effects.add(new PotionEffect(PotionEffectType.getById(Potion.getIdFromPotion(handle.getPotion())), handle.getDuration(), handle.getAmplifier(), handle.getIsAmbient(), handle.doesShowParticles())); } return effects; @@ -388,7 +393,13 @@ public T launchProjectile(Class projectile, } public EntityType getType() { - return EntityType.UNKNOWN; + // Magma start + EntityType type = EntityType.fromName(this.entityName); + if (type != null) { + return type; + } + return EntityType.FORGE_MOD; + // Magma end } public boolean hasLineOfSight(Entity other) { @@ -490,16 +501,16 @@ public void setAI(boolean ai) { @Override public boolean hasAI() { - return (this.getHandle() instanceof EntityLiving) && !((EntityLiving) this.getHandle()).isAIDisabled(); + return (this.getHandle() instanceof EntityLiving) ? !((EntityLiving) this.getHandle()).isAIDisabled() : false; } @Override - public void setCollidable(boolean collidable) { - getHandle().collides = collidable; + public boolean isCollidable() { + return getHandle().collides; } @Override - public boolean isCollidable() { - return getHandle().collides; + public void setCollidable(boolean collidable) { + getHandle().collides = collidable; } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index a73163b..e3e08bc 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -124,6 +124,134 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private static final WeakHashMap> pluginWeakReferences = new WeakHashMap<>(); private int hash = 0; private double health = 20; + // Spigot start + private final Player.Spigot spigot = new Player.Spigot() { + + @Override + public InetSocketAddress getRawAddress() { + return (InetSocketAddress) getHandle().connection.netManager.getRawAddress(); + } + + @Override + public boolean getCollidesWithEntities() { + return CraftPlayer.this.isCollidable(); + } + + @Override + public void setCollidesWithEntities(boolean collides) { + CraftPlayer.this.setCollidable(collides); + } + + @Override + public void respawn() { + if (getHealth() <= 0 && isOnline()) { + server.getServer().getPlayerList().recreatePlayerEntity(getHandle(), 0, false); + } + } + + @Override + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) { + Validate.notNull(location, "Location cannot be null"); + Validate.notNull(effect, "Effect cannot be null"); + Validate.notNull(location.getWorld(), "World cannot be null"); + Packet packet; + if (effect.getType() != Effect.Type.PARTICLE) { + int packetData = effect.getId(); + packet = new SPacketEffect(packetData, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), id, false); + } else { + net.minecraft.util.EnumParticleTypes particle = null; + int[] extra = null; + for (net.minecraft.util.EnumParticleTypes p : net.minecraft.util.EnumParticleTypes.values()) { + if (effect.getName().startsWith(p.getParticleName().replace("_", ""))) { + particle = p; + if (effect.getData() != null) { + if (effect.getData().equals(org.bukkit.Material.class)) { + extra = new int[]{id}; + } else { + extra = new int[]{(data << 12) | (id & 0xFFF)}; + } + } + break; + } + } + if (extra == null) { + extra = new int[0]; + } + packet = new SPacketParticles(particle, true, (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, speed, particleCount, extra); + } + int distance; + radius *= radius; + if (getHandle().connection == null) { + return; + } + if (!location.getWorld().equals(getWorld())) { + return; + } + + distance = (int) getLocation().distanceSquared(location); + if (distance <= radius) { + getHandle().connection.sendPacket(packet); + } + } + + @Override + public String getLocale() { + return getHandle().language; + } + + @Override + public Set getHiddenPlayers() { + Set ret = new HashSet(); + for (UUID u : hiddenPlayers.keySet()) { + ret.add(getServer().getPlayer(u)); + } + + return java.util.Collections.unmodifiableSet(ret); + } + + @Override + public void sendMessage(BaseComponent component) { + sendMessage(new BaseComponent[]{component}); + } + + @Override + public void sendMessage(BaseComponent... components) { + if (getHandle().connection == null) { + return; + } + + SPacketChat packet = new SPacketChat(null, ChatType.CHAT); + packet.components = components; + getHandle().connection.sendPacket(packet); + } + + @Override + public void sendMessage(net.md_5.bungee.api.ChatMessageType position, BaseComponent component) { + sendMessage(position, new BaseComponent[]{component}); + } + + @Override + public void sendMessage(ChatMessageType position, BaseComponent... components) { + if (getHandle().connection == null) { + return; + } + + SPacketChat packet = new SPacketChat(null, ChatType.byId((byte) position.ordinal())); + // Action bar doesn't render colours, replace colours with legacy section symbols + if (position == net.md_5.bungee.api.ChatMessageType.ACTION_BAR) { + components = new BaseComponent[]{new net.md_5.bungee.api.chat.TextComponent(BaseComponent.toLegacyText(components))}; + } + packet.components = components; + getHandle().connection.sendPacket(packet); + } + + @Override + public int getPing() + { + return getHandle().ping; + } + }; + private boolean scaledHealth = false; private double healthScale = 20; @@ -133,6 +261,11 @@ public CraftPlayer(CraftServer server, EntityPlayerMP entity) { firstPlayed = System.currentTimeMillis(); } + @Nullable + private static WeakReference getPluginWeakReference(@Nullable Plugin plugin) { + return (plugin == null) ? null : pluginWeakReferences.computeIfAbsent(plugin, WeakReference::new); + } + public GameProfile getProfile() { return getHandle().getGameProfile(); } @@ -953,11 +1086,6 @@ public void setBedSpawnLocation(Location location, boolean override) { } } - @Nullable - private static WeakReference getPluginWeakReference(@Nullable Plugin plugin) { - return (plugin == null) ? null : pluginWeakReferences.computeIfAbsent(plugin, WeakReference::new); - } - @Override @Deprecated public void hidePlayer(Player player) { @@ -1212,6 +1340,7 @@ public void setResourcePack(String url, byte[] hash) { } public void addChannel(String channel) { + com.google.common.base.Preconditions.checkState( channels.size() < 128, "Too many channels registered" ); // Spigot if (channels.add(channel)) { server.getPluginManager().callEvent(new PlayerRegisterChannelEvent(this, channel)); } @@ -1327,6 +1456,11 @@ public int getNoDamageTicks() { } } + @Override + public float getFlySpeed() { + return getHandle().capabilities.flySpeed * 2f; + } + @Override public void setFlySpeed(float value) { validateSpeed(value); @@ -1336,6 +1470,11 @@ public void setFlySpeed(float value) { } + @Override + public float getWalkSpeed() { + return getHandle().capabilities.walkSpeed * 2f; + } + @Override public void setWalkSpeed(float value) { validateSpeed(value); @@ -1344,16 +1483,6 @@ public void setWalkSpeed(float value) { player.sendPlayerAbilities(); } - @Override - public float getFlySpeed() { - return getHandle().capabilities.flySpeed * 2f; - } - - @Override - public float getWalkSpeed() { - return getHandle().capabilities.walkSpeed * 2f; - } - private void validateSpeed(float value) { if (value < 0) { if (value < -1f) { @@ -1453,7 +1582,15 @@ public void updateScaledHealth() { } public void sendHealthUpdate() { - getHandle().connection.sendPacket(new SPacketUpdateHealth(getScaledHealth(), getHandle().getFoodStats().getFoodLevel(), getHandle().getFoodStats().getSaturationLevel())); + // Paper start - cancellable death event + //getHandle().connection.sendPacket(new SPacketUpdateHealth(getScaledHealth(), getHandle().getFoodStats().getFoodLevel(), getHandle().getFoodStats().getSaturationLevel())); + SPacketUpdateHealth packet = new SPacketUpdateHealth(getScaledHealth(), getHandle().getFoodStats().getFoodLevel(), getHandle().getFoodStats().getSaturationLevel()); + if (this.getHandle().queueHealthUpdatePacket) { + this.getHandle().queuedHealthUpdatePacket = packet; + } else { + this.getHandle().connection.sendPacket(packet); + } + // Paper end } public void injectScaledMaxHealth(Collection collection, boolean force) { @@ -1496,6 +1633,9 @@ public void sendTitle(String title, String subtitle) { @Override public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) { + if (getHandle().connection == null) { + return; + } SPacketTitle times = new SPacketTitle(fadeIn, stay, fadeOut); getHandle().connection.sendPacket(times); @@ -1603,143 +1743,6 @@ public String getLocale() { return getHandle().language; } - // Spigot start - private final Player.Spigot spigot = new Player.Spigot() - { - @Override - public InetSocketAddress getRawAddress() - { - return (InetSocketAddress) getHandle().connection.netManager.getRawAddress(); - } - - @Override - public boolean getCollidesWithEntities() { - return CraftPlayer.this.isCollidable(); - } - - @Override - public void setCollidesWithEntities(boolean collides) { - CraftPlayer.this.setCollidable(collides); - } - - public void respawn() - { - if ( getHealth() <= 0 && isOnline() ) - { - server.getServer().getPlayerList().recreatePlayerEntity( getHandle(), 0, false ); - } - } - - @Override - public void playEffect( Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius ) - { - Validate.notNull( location, "Location cannot be null" ); - Validate.notNull( effect, "Effect cannot be null" ); - Validate.notNull( location.getWorld(), "World cannot be null" ); - Packet packet; - if ( effect.getType() != Effect.Type.PARTICLE ) - { - int packetData = effect.getId(); - packet = new SPacketEffect( packetData, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ() ), id, false ); - } else - { - net.minecraft.util.EnumParticleTypes particle = null; - int[] extra = null; - for ( net.minecraft.util.EnumParticleTypes p : net.minecraft.util.EnumParticleTypes.values() ) - { - if ( effect.getName().startsWith( p.getParticleName().replace("_", "") ) ) - { - particle = p; - if ( effect.getData() != null ) - { - if ( effect.getData().equals( Material.class ) ) - { - extra = new int[]{ id }; - } else - { - extra = new int[]{ (data << 12) | (id & 0xFFF) }; - } - } - break; - } - } - if ( extra == null ) - { - extra = new int[0]; - } - packet = new SPacketParticles( particle, true, (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, speed, particleCount, extra ); - } - int distance; - radius *= radius; - if ( getHandle().connection == null ) - { - return; - } - if ( !location.getWorld().equals( getWorld() ) ) - { - return; - } - - distance = (int) getLocation().distanceSquared( location ); - if ( distance <= radius ) - { - getHandle().connection.sendPacket( packet ); - } - } - - public String getLocale() - { - return getHandle().language; - } - - public Set getHiddenPlayers() - { - Set ret = new HashSet(); - for ( UUID u : hiddenPlayers.keySet() ) - { - ret.add( getServer().getPlayer( u ) ); - } - - return java.util.Collections.unmodifiableSet( ret ); - } -@Override - public void sendMessage(BaseComponent component) { - sendMessage( new BaseComponent[] { component } ); - } - - @Override - public void sendMessage(BaseComponent... components) { - if ( getHandle().connection == null ) { - return; - } - - SPacketChat packet = new SPacketChat(null, ChatType.CHAT); - packet.components = components; - getHandle().connection.sendPacket(packet); - } - - @Override - public void sendMessage(net.md_5.bungee.api.ChatMessageType position, BaseComponent component) { - sendMessage( position, new BaseComponent[] { component } ); - } - - @Override - public void sendMessage(ChatMessageType position, BaseComponent... components) { - if ( getHandle().connection == null ) { - return; - } - - SPacketChat packet = new SPacketChat(null, ChatType.byId((byte) position.ordinal())); - // Action bar doesn't render colours, replace colours with legacy section symbols - if (position == net.md_5.bungee.api.ChatMessageType.ACTION_BAR) { - components = new BaseComponent[]{new net.md_5.bungee.api.chat.TextComponent(BaseComponent.toLegacyText(components))}; - } - packet.components = components; - getHandle().connection.sendPacket(packet); - } - }; - - @Override public Player.Spigot spigot() { return spigot; diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java index eaf8692..2d4ba22 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java @@ -51,6 +51,15 @@ public class CraftAsyncScheduler extends CraftScheduler { executor.prestartAllCoreThreads(); } + /** + * Task is not cancelled + * @param runningTask + * @return + */ + static boolean isValid(CraftTask runningTask) { + return runningTask.getPeriod() >= CraftTask.NO_REPEATING; + } + @Override public void cancelTask(int taskId) { this.management.execute(() -> this.removeTask(taskId)); @@ -116,12 +125,4 @@ public synchronized void cancelAllTasks() { cancelTasks(null); } - /** - * Task is not cancelled - * @param runningTask - * @return - */ - static boolean isValid(CraftTask runningTask) { - return runningTask.getPeriod() >= CraftTask.NO_REPEATING; - } } diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index 6ffc238..bd26c9c 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -1,96 +1,92 @@ package org.bukkit.craftbukkit.scheduler; +import org.apache.commons.lang3.Validate; +import org.bukkit.plugin.IllegalPluginAccessException; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitWorker; + import java.util.ArrayList; -import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.PriorityQueue; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; -import org.apache.commons.lang3.Validate; -import org.bukkit.plugin.IllegalPluginAccessException; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; -import org.bukkit.scheduler.BukkitWorker; - /** * The fundamental concepts for this implementation: *

  • Main thread owns {@link #head} and {@link #currentTick}, but it may be read from any thread
  • *
  • Main thread exclusively controls {@link #temp} and {@link #pending}. - * They are never to be accessed outside of the main thread; alternatives exist to prevent locking.
  • + * They are never to be accessed outside of the main thread; alternatives exist to prevent locking. *
  • {@link #head} to {@link #tail} act as a linked list/queue, with 1 consumer and infinite producers. - * Adding to the tail is atomic and very efficient; utility method is {@link #handle(CraftTask, long)} or {@link #addTask(CraftTask)}.
  • + * Adding to the tail is atomic and very efficient; utility method is {@link #handle(CraftTask, long)} or {@link #addTask(CraftTask)}. *
  • Changing the period on a task is delicate. - * Any future task needs to notify waiting threads. - * Async tasks must be synchronized to make sure that any thread that's finishing will remove itself from {@link #runners}. - * Another utility method is provided for this, {@link #cancelTask(int)}
  • + * Any future task needs to notify waiting threads. + * Async tasks must be synchronized to make sure that any thread that's finishing will remove itself from {@link #runners}. + * Another utility method is provided for this, {@link #cancelTask(int)} *
  • {@link #runners} provides a moderately up-to-date view of active tasks. - * If the linked head to tail set is read, all remaining tasks that were active at the time execution started will be located in runners.
  • + * If the linked head to tail set is read, all remaining tasks that were active at the time execution started will be located in runners. *
  • Async tasks are responsible for removing themselves from runners
  • *
  • Sync tasks are only to be removed from runners on the main thread when coupled with a removal from pending and temp.
  • *
  • Most of the design in this scheduler relies on queuing special tasks to perform any data changes on the main thread. - * When executed from inside a synchronous method, the scheduler will be updated before next execution by virtue of the frequent {@link #parsePending()} calls.
  • + * When executed from inside a synchronous method, the scheduler will be updated before next execution by virtue of the frequent {@link #parsePending()} calls. */ public class CraftScheduler implements BukkitScheduler { + //private final Executor executor = Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); // Spigot // Paper - moved to AsyncScheduler + //private CraftAsyncDebugger debugHead = new CraftAsyncDebugger(-1, null, null) {@Override StringBuilder debugTo(StringBuilder string) {return string;}}; // Paper + //private CraftAsyncDebugger debugTail = debugHead; // Paper + private static final int RECENT_TICKS; + + static { + RECENT_TICKS = 30; + } + /** - * Counter for IDs. Order doesn't matter, only uniqueness. + * Main thread logic only */ - private final AtomicInteger ids = new AtomicInteger(1); + final PriorityQueue pending = new PriorityQueue(10, // Paper + (o1, o2) -> { + int value = Long.compare(o1.getNextRun(), o2.getNextRun()); + + // If the tasks should run on the same tick they should be run FIFO + return value != 0 ? value : Integer.compare(o1.getTaskId(), o2.getTaskId()); + }); /** - * Current head of linked-list. This reference is always stale, {@link CraftTask#next} is the live reference. + * These are tasks that are currently active. It's provided for 'viewing' the current state. */ - private volatile CraftTask head = new CraftTask(); + final ConcurrentHashMap runners = new ConcurrentHashMap(); // Paper /** - * Tail of a linked-list. AtomicReference only matters when adding to queue + * Counter for IDs. Order doesn't matter, only uniqueness. */ - private final AtomicReference tail = new AtomicReference(head); + private final AtomicInteger ids = new AtomicInteger(1); /** * Main thread logic only */ - final PriorityQueue pending = new PriorityQueue(10, // Paper - new Comparator() { - public int compare(final CraftTask o1, final CraftTask o2) { - int value = Long.compare(o1.getNextRun(), o2.getNextRun()); - - // If the tasks should run on the same tick they should be run FIFO - return value != 0 ? value : Integer.compare(o1.getTaskId(), o2.getTaskId()); - } - }); + private final List temp = new ArrayList(); + // Paper start + private final CraftScheduler asyncScheduler; + private final boolean isAsyncScheduler; + volatile int currentTick = -1; // Paper /** - * Main thread logic only + * Current head of linked-list. This reference is always stale, {@link CraftTask#next} is the live reference. */ - private final List temp = new ArrayList(); + private volatile CraftTask head = new CraftTask(); /** - * These are tasks that are currently active. It's provided for 'viewing' the current state. + * Tail of a linked-list. AtomicReference only matters when adding to queue */ - final ConcurrentHashMap runners = new ConcurrentHashMap(); // Paper + private final AtomicReference tail = new AtomicReference(head); /** * The sync task that is currently running on the main thread. */ private volatile CraftTask currentTask = null; - volatile int currentTick = -1; // Paper - //private final Executor executor = Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); // Spigot // Paper - moved to AsyncScheduler - //private CraftAsyncDebugger debugHead = new CraftAsyncDebugger(-1, null, null) {@Override StringBuilder debugTo(StringBuilder string) {return string;}}; // Paper - //private CraftAsyncDebugger debugTail = debugHead; // Paper - private static final int RECENT_TICKS; - static { - RECENT_TICKS = 30; - } - - // Paper start - private final CraftScheduler asyncScheduler; - private final boolean isAsyncScheduler; public CraftScheduler() { this(false); } @@ -105,7 +101,14 @@ public CraftScheduler(boolean isAsync) { } // Paper end - @Override + private static void validate(final Plugin plugin, final Object task) { + Validate.notNull(plugin, "Plugin cannot be null"); + Validate.notNull(task, "Task cannot be null"); + if (!plugin.isEnabled()) { + throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); + } + } + public int scheduleSyncDelayedTask(final Plugin plugin, final Runnable task) { return this.scheduleSyncDelayedTask(plugin, task, 0L); } @@ -203,6 +206,7 @@ public void run() { check(CraftScheduler.this.pending); } } + private boolean check(final Iterable collection) { final Iterator tasks = collection.iterator(); while (tasks.hasNext()) { @@ -217,7 +221,8 @@ private boolean check(final Iterable collection) { } } return false; - }}); // Paper + } + }); // Paper handle(task, 0L); for (CraftTask taskPending = head.getNext(); taskPending != null; taskPending = taskPending.getNext()) { if (taskPending == task) { @@ -243,6 +248,7 @@ public void run() { check(CraftScheduler.this.pending); check(CraftScheduler.this.temp); } + void check(final Iterable collection) { final Iterator tasks = collection.iterator(); while (tasks.hasNext()) { @@ -280,19 +286,17 @@ public void cancelAllTasks() { } // Paper end final CraftTask task = new CraftTask( - new Runnable() { - public void run() { - Iterator it = CraftScheduler.this.runners.values().iterator(); - while (it.hasNext()) { - CraftTask task = it.next(); - task.cancel0(); - if (task.isSync()) { - it.remove(); - } + () -> { + Iterator it = CraftScheduler.this.runners.values().iterator(); + while (it.hasNext()) { + CraftTask task1 = it.next(); + task1.cancel0(); + if (task1.isSync()) { + it.remove(); } - CraftScheduler.this.pending.clear(); - CraftScheduler.this.temp.clear(); } + CraftScheduler.this.pending.clear(); + CraftScheduler.this.temp.clear(); }); // Paper handle(task, 0L); for (CraftTask taskPending = head.getNext(); taskPending != null; taskPending = taskPending.getNext()) { @@ -426,8 +430,8 @@ public void mainThreadHeartbeat(final int currentTick) { } catch (final Throwable throwable) { // Paper start String msg = String.format( - "Task #%s for %s generated an exception", - task.getTaskId(), + "Task #%s for %s generated an exception", + task.getTaskId(), task.getOwner().getDescription().getFullName()); task.getOwner().getLogger().log( Level.WARNING, @@ -479,14 +483,6 @@ protected CraftTask handle(final CraftTask task, final long delay) { // Paper return task; } - private static void validate(final Plugin plugin, final Object task) { - Validate.notNull(plugin, "Plugin cannot be null"); - Validate.notNull(task, "Task cannot be null"); - if (!plugin.isEnabled()) { - throw new IllegalPluginAccessException("Plugin attempted to register task while disabled"); - } - } - private int nextId() { return ids.incrementAndGet(); } @@ -506,8 +502,8 @@ void parsePending() { // Paper // We split this because of the way things are ordered for all of the async calls in CraftScheduler // (it prevents race-conditions) for (task = head; task != lastTask; task = head) { - head = task.getNext(); - task.setNext(null); + head = task.getNext(); + task.setNext(null); } this.head = lastTask; } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java index f7ebf2a..1a6e77c 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java @@ -4,8 +4,12 @@ public class CraftIconCache implements CachedServerIcon { public final String value; + @Override - public String getData() { return value; } // Paper + public String getData() { + return value; + } // Paper + public CraftIconCache(final String value) { this.value = value; } diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java index 588e604..bf53962 100644 --- a/src/main/java/org/bukkit/entity/EntityType.java +++ b/src/main/java/org/bukkit/entity/EntityType.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.Map; +import org.bukkit.craftbukkit.entity.CraftCustomEntity; import org.bukkit.entity.minecart.CommandMinecart; import org.bukkit.entity.minecart.HopperMinecart; import org.bukkit.entity.minecart.SpawnerMinecart; @@ -265,7 +266,8 @@ public enum EntityType { /** * An unknown entity without an Entity Class */ - UNKNOWN(null, null, -1, false); + UNKNOWN(null, null, -1, false), + FORGE_MOD("forge_mod", CraftCustomEntity.class, -1, false); private String name; private Class clazz; diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java index 81dc814..742ce4d 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -965,38 +965,38 @@ public interface Player extends HumanEntity, Conversable, CommandSender, Offline public void setFlying(boolean value); /** - * Sets the speed at which a client will fly. Negative values indicate - * reverse directions. + * Gets the current allowed speed that a client can fly. * - * @param value The new speed, from -1 to 1. - * @throws IllegalArgumentException If new speed is less than -1 or - * greater than 1 + * @return The current allowed speed, from -1 to 1 */ - public void setFlySpeed(float value) throws IllegalArgumentException; + public float getFlySpeed(); /** - * Sets the speed at which a client will walk. Negative values indicate + * Sets the speed at which a client will fly. Negative values indicate * reverse directions. * * @param value The new speed, from -1 to 1. * @throws IllegalArgumentException If new speed is less than -1 or * greater than 1 */ - public void setWalkSpeed(float value) throws IllegalArgumentException; + public void setFlySpeed(float value) throws IllegalArgumentException; /** - * Gets the current allowed speed that a client can fly. + * Gets the current allowed speed that a client can walk. * * @return The current allowed speed, from -1 to 1 */ - public float getFlySpeed(); + public float getWalkSpeed(); /** - * Gets the current allowed speed that a client can walk. + * Sets the speed at which a client will walk. Negative values indicate + * reverse directions. * - * @return The current allowed speed, from -1 to 1 + * @param value The new speed, from -1 to 1. + * @throws IllegalArgumentException If new speed is less than -1 or + * greater than 1 */ - public float getWalkSpeed(); + public void setWalkSpeed(float value) throws IllegalArgumentException; /** * Request that the player's client download and switch texture packs. @@ -1438,6 +1438,24 @@ public interface Player extends HumanEntity, Conversable, CommandSender, Offline */ public String getLocale(); + @Override + Spigot spigot(); + + /** + * Gets the view distance for this player + * @return the player's view distance + */ + public int getViewDistance(); + // Spigot end + + // Paper start + + /** + * Sets the view distance for this player + * @param viewDistance the player's view distance + */ + public void setViewDistance(int viewDistance); + // Spigot start public class Spigot extends Entity.Spigot { @@ -1543,22 +1561,10 @@ public void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.b public void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); } - } - - @Override - Spigot spigot(); - // Spigot end - - // Paper start - /** - * Gets the view distance for this player - * @return the player's view distance - */ - int getViewDistance(); - /** - * Sets the view distance for this player - * @param viewDistance the player's view distance - */ - void setViewDistance(int viewDistance); + public int getPing() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + } } diff --git a/src/main/java/org/bukkit/entity/Tameable.java b/src/main/java/org/bukkit/entity/Tameable.java index 98a936b..8b1b8b1 100644 --- a/src/main/java/org/bukkit/entity/Tameable.java +++ b/src/main/java/org/bukkit/entity/Tameable.java @@ -21,7 +21,7 @@ public interface Tameable extends Entity { * * @param tame true if tame */ - void setTamed(boolean tame); + public void setTamed(boolean tame); // Paper start /** @@ -29,7 +29,7 @@ public interface Tameable extends Entity { * * @return the owners UUID, or null if not owned */ - java.util.UUID getOwnerUUID(); + public java.util.UUID getOwnerUUID(); // Paper end /** diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java index f2095f6..addf21e 100644 --- a/src/main/java/org/bukkit/entity/Villager.java +++ b/src/main/java/org/bukkit/entity/Villager.java @@ -228,21 +228,19 @@ public enum Career { NITWIT(Profession.NITWIT); private static final Multimap careerMap = LinkedListMultimap.create(); + + static { + for (Career career : Career.values()) { + careerMap.put(career.profession, career); + } + } + private final Profession profession; private Career(Profession profession) { this.profession = profession; } - /** - * Get the {@link Profession} this {@link Career} belongs to. - * - * @return the {@link Profession}. - */ - public Profession getProfession() { - return profession; - } - /** * Get an immutable list of {@link Career}s that can be used with a * given {@link Profession} @@ -255,10 +253,13 @@ public static List getCareers(Profession profession) { return careerMap.containsKey(profession) ? ImmutableList.copyOf(careerMap.get(profession)) : ImmutableList.of(); } - static { - for (Career career : Career.values()) { - careerMap.put(career.profession, career); - } + /** + * Get the {@link Profession} this {@link Career} belongs to. + * + * @return the {@link Profession}. + */ + public Profession getProfession() { + return profession; } } } diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java index cf34c69..4e14d9f 100644 --- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java @@ -15,11 +15,12 @@ */ public class AsyncPlayerPreLoginEvent extends Event { private static final HandlerList handlers = new HandlerList(); - private Result result; - private String message; private final String name; private final InetAddress ipAddress; private final UUID uniqueId; + private Result result; + private String message; + private PlayerProfile profile; @Deprecated public AsyncPlayerPreLoginEvent(final String name, final InetAddress ipAddress) { @@ -30,7 +31,21 @@ public AsyncPlayerPreLoginEvent(final String name, final InetAddress ipAddress, // Paper start this(name, ipAddress, uniqueId, Bukkit.createProfile(uniqueId, name)); } - private PlayerProfile profile; + + public AsyncPlayerPreLoginEvent(final String name, final InetAddress ipAddress, final UUID uniqueId, PlayerProfile profile) { + super(true); + this.profile = profile; + // Paper end + this.result = Result.ALLOWED; + this.message = ""; + this.name = name; + this.ipAddress = ipAddress; + this.uniqueId = uniqueId; + } + + public static HandlerList getHandlerList() { + return handlers; + } /** * Gets the PlayerProfile of the player logging in @@ -48,17 +63,6 @@ public void setPlayerProfile(PlayerProfile profile) { this.profile = profile; } - public AsyncPlayerPreLoginEvent(final String name, final InetAddress ipAddress, final UUID uniqueId, PlayerProfile profile) { - super(true); - this.profile = profile; - // Paper end - this.result = Result.ALLOWED; - this.message = ""; - this.name = name; - this.ipAddress = ipAddress; - this.uniqueId = uniqueId; - } - /** * Gets the current result of the login, as an enum * @@ -68,6 +72,15 @@ public Result getLoginResult() { return result; } + /** + * Sets the new result of the login, as an enum + * + * @param result New result to set + */ + public void setLoginResult(final Result result) { + this.result = result; + } + /** * Gets the current result of the login, as an enum * @@ -81,15 +94,6 @@ public PlayerPreLoginEvent.Result getResult() { return result == null ? null : result.old(); } - /** - * Sets the new result of the login, as an enum - * - * @param result New result to set - */ - public void setLoginResult(final Result result) { - this.result = result; - } - /** * Sets the new result of the login, as an enum * @@ -188,10 +192,6 @@ public HandlerList getHandlers() { return handlers; } - public static HandlerList getHandlerList() { - return handlers; - } - /** * Basic kick reasons for communicating to plugins */ diff --git a/src/main/java/org/bukkit/plugin/EventExecutor.java b/src/main/java/org/bukkit/plugin/EventExecutor.java index b45b6c1..9fdde45 100644 --- a/src/main/java/org/bukkit/plugin/EventExecutor.java +++ b/src/main/java/org/bukkit/plugin/EventExecutor.java @@ -1,22 +1,21 @@ package org.bukkit.plugin; +import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor; +import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor; +import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator; +import com.destroystokyo.paper.event.executor.asm.ClassDefiner; +import com.google.common.base.Preconditions; import org.bukkit.event.Event; import org.bukkit.event.EventException; import org.bukkit.event.Listener; -// Paper start import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; -import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor; -import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor; -import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator; -import com.destroystokyo.paper.event.executor.asm.ClassDefiner; -import com.google.common.base.Preconditions; +// Paper start // Paper end /** @@ -33,7 +32,6 @@ public Class computeIfAbsent(Method key, Function eventClass) try { EventExecutor asmExecutor = executorClass.newInstance(); // Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception) - return new EventExecutor() { - @Override - public void execute(Listener listener, Event event) throws EventException { - if (!eventClass.isInstance(event)) return; - try { - asmExecutor.execute(listener, event); - } catch (Exception e) { - throw new EventException(e); - } + return (listener, event) -> { + if (!eventClass.isInstance(event)) return; + try { + asmExecutor.execute(listener, event); + } catch (Exception e) { + throw new EventException(e); } }; } catch (InstantiationException | IllegalAccessException e) { diff --git a/src/main/java/org/bukkit/plugin/PluginLoader.java b/src/main/java/org/bukkit/plugin/PluginLoader.java index 8fa8166..5d9e1a0 100644 --- a/src/main/java/org/bukkit/plugin/PluginLoader.java +++ b/src/main/java/org/bukkit/plugin/PluginLoader.java @@ -72,7 +72,7 @@ public interface PluginLoader { * * @param plugin Plugin to disable */ - void disablePlugin(Plugin plugin); + public void disablePlugin(Plugin plugin); // Paper start - close Classloader on disable /** @@ -84,7 +84,7 @@ public interface PluginLoader { * @param closeClassloader if the classloader for the Plugin should be closed */ // provide default to allow other PluginLoader implementations to work - default void disablePlugin(Plugin plugin, boolean closeClassloader) { + default public void disablePlugin(Plugin plugin, boolean closeClassloader) { disablePlugin(plugin); } // Paper end - close Classloader on disable diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java index 7d05b26..9d529f8 100644 --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java @@ -78,7 +78,7 @@ public Plugin loadPlugin(File file) throws InvalidPluginException { } else if (dataFolder.isDirectory() && oldDataFolder.isDirectory()) { server.getLogger().warning(String.format( "While loading %s (%s) found old-data folder: `%s' next to the new one `%s'", - description.getFullName(), + description.getName(), file, oldDataFolder, dataFolder @@ -89,7 +89,7 @@ public Plugin loadPlugin(File file) throws InvalidPluginException { } server.getLogger().log(Level.INFO, String.format( "While loading %s (%s) renamed data folder: `%s' to `%s'", - description.getFullName(), + description.getName(), file, oldDataFolder, dataFolder @@ -100,7 +100,7 @@ public Plugin loadPlugin(File file) throws InvalidPluginException { throw new InvalidPluginException(String.format( "Projected datafolder: `%s' for %s (%s) exists and is not a directory", dataFolder, - description.getFullName(), + description.getName(), file )); } @@ -166,9 +166,7 @@ public PluginDescriptionFile getPluginDescription(File file) throws InvalidDescr return new PluginDescriptionFile(stream); - } catch (IOException ex) { - throw new InvalidDescriptionException(ex); - } catch (YAMLException ex) { + } catch (IOException | YAMLException ex) { throw new InvalidDescriptionException(ex); } finally { if (jar != null) {