Something the log4j ConsoleAppender does makes the console work correctly
on Windows. After trying to pull pieces of it out and run them manually
I decided to just put the appender back. We now once again start with the
ConsoleAppender then remove it immediately after starting.
WorldMapCollection stores scoreboard, map (item), structure, and
village information. Scoreboards are explicitly handled globally,
while villages and structures are erroneously shared.
This commit separates the WorldMapCollections to not be shared among
custom worlds. Maps are special-cased to maintain the previous shared
behavior.
This change will print a warning when a plugin induces a forced save. A
player or console forcing a save (via a command) is ignored for purposes
of printing a warning.
When Minecraft first introduced an auto-save feature, we
were taken by surprise by how much of an impact it actually had on the performance
of the server. After investigating the potential causes of the significant
slow-downs we saw at the time, we came to the conclusion that it was a
combination of the auto-save interval being incredibly frequent and
servers already having an auto-save solution that was conflicting with the
newly added built-in one.
Since we noticed that most servers already had their own auto-save
solution, we decided to completely disable the built in auto-save by
default. In hindsight, however, we were so happy that we discovered and
squashed the cause of the performance issues that we forgot to consider
the future and, as a result, some servers have unfortunately been caught
by surprise when they ran their servers without any auto-save plugins.
Without the auto-save plugin conflict, however, Minecraft's default save
interval of 45 seconds is not suitable for the types of servers that run
Bukkit, to the point where it was negatively impacting performance. As
such, we've decided to re-enable the built in auto-save at an interval of
5 minutes for newly created servers.
The WorldMapCollection object for SecondaryWorldServers(Nether, End) is
shared with the main world, so saving it again for each SecondaryWorldServer
is redundant.
This commit removes the redundant call by checking if the WorldServer is an
instanceof SecondaryWorldServer before invoking worldMaps.a().
The recent Minecraft update rendered the
e20e50f85083dc53cb5456254bcf5781ef750daa fix incorrect by adding a
compound name to the base tag in some code. This fix changes all uses
of tag changes to explicitly use a name.
When a "uid.dat" file is corrupt (empty or <16 bytes), WorldNBTStorage
will silently fail to read and return null. Non-null behavior is
expected everywhere that this value is used.
This change will force a random UUID when the previous UUID cannot be
read, and getUUID to no longer silently ignore read/write exceptions.
This change adds the location and a more specific message to the
IllegalArgumentException that gets thrown when a hanging entity is being
spawned in a location that it cannot survive.
Opening a hopper inventory created by Server.createInventory will
currently have no effect as proper handling code is missing in
CraftEntityHuman for hopper inventories that aren't associated with a tile
entity or minecart. Initialization logic for hoppers is also missing from
CraftContainer, which is necessary for the opening of custom hopper
inventories.
This commit fixes the two aforementioned by adding proper handling to
CraftHumanEntity for opening inventories not associated with a tile
entity, and by adding initialization logic for hoppers to CraftContainer.
Previously fires spawned by lightning strikes were in the wrong locations.
This introduced the possibility of having blocks replaced when they should
not be.
EntityLightning now uses the correct locations as defined to spawn the
fires when needed.
When an entity is being moved as the passenger of an entity from one
entity to another, a VehicleExitEvent is fired, but it is assumed that the
current entity is a Vehicle. However, entities can be passengers of more than
just Vehicles, which causes a ClassCastException to be thrown.
This commit fixes the issue by checking that the current entity's vehicle's
bukkitEntity is an instance of Vehicle before casting it to Vehicle.
Prior to this change when a plugin called Player.hasLineOfSite() the
method would always return false because EntityHuman does not extend
EntityInsentient. This commit changes that by explicitly checking for
line of sight between two entities and returning that value.
This commit removes chat wrapping. It is no longer needed, as clients
properly render lines with line breaks.
This commit also changes an outgoing chat message to use the vanilla
behavior for indicating a client cannot chat with commands-only setting.
If a plugin generates an exception when returning a world generator, the
server will crash. This change adds a try-catch block to keep the server
from crashing on plugin defined world generators.
Custom inventories currently do not validate the titles provided. Null values
cause NPEs when writing packets. Values longer than 32 characters
disconnect clients.
This change throws and IllegalArgumentException for null titles or titles
longer than 32 characters.
The unleash event is only called for animals that are sitting - ones that
receive no movement vector. This adds the missing event call for
non-sitting animals.
When only considering trackers from player perspective, attach entity
packet could be sent before a packet for a respective vehicle is in view
and will, in turn, be ignored.
This adds another notification when the vehicle comes into view to cover
all cases.
A method has been added to Player which allows the server to send a sound string to the client. Assuming the client has the specified sound, it will be played. This is needed by the implementation of the /playsound command.
Items that cause entities to change state, including tags, chest, and
leashes, do not update the client properly following the firing of
PlayerInteractEntityEvent. This change makes the item checks occur
before the event fires, to concur with the client's assumptions.
This commit implements the ability to set the scale of hearts that the
client renders. When the Packet44UpdateAttributes packet is sent, the
max health attribute is replaced with a scaled version, to preserve the
scaled health illusion clientside.
In order to accurately display the scaled health for players, a true
health is stored within CraftPlayer, and the datawatcher now stores the
scaled health. The getHealth() method for players still returns their
true health.
Changed setHealth() within EntityLiving to appropriately handle health
for instances of EntityPlayer. Inlined a call to
setHealth(getMaxHealth()) within the EntityLiving constructor to work
around CraftEntity instantiation.
Additionally fixes the health values sent when eating food within
FoodMetaData and ItemFood, which previously sent the unscaled health;
this commit alters them to send the properly scaled health.
Additionally fixes BUKKIT-4535, BUKKIT-4536, and BUKKIT-4127
This changes livingEntity.addPotionEffect(PotionEffect, boolean) to
construct the MobEffect using the constructor that includes the ambient
setting as supplied by the PotionEffect
This also changes livingEntity.getActivePotionEffects() to construct the
PotionEffects using the ambient setting supplied by the MobEffects.
This change makes it so that EntityHuman#setPassengerOf(Entity) invokes
its parent method when leaving vehicles so that VehicleExitEvent is fired
for players leaving vehicles.
This change also fixes BUKKIT-2110, making it so VehicleExitEvent
correctly handles cancellation. The implementation of VehicleExitEvent
completely ignored the cancellation state of the event, making it so that
cancelling the event had no effect. Cancelling a VehicleExitEvent now
causes the entity to remain inside of the vehicle, with no visual stutter.
API has been added to interface with Horses and to modify their inventories. Horse entities will now be recognized with the type EntityType.HORSE, and will no longer be UNKNOWN.
HorseJumpEvent, EntityDamageEvent, and EntityTameEvent are all correctly fired for horses.
This commit fixes BUKKIT-4393.
Cancelling InventoryDragEvent causes the placed items to be lost. This is
because the cursor is set to the result prior to the event taking place,
so the items are removed from the cursor. When the event is cancelled, the
items removed from the cursor aren't placed in the inventory, and are just
lost.
This change sets the cursor back to the original cursor when the event is
cancelled.
Cancelling an InventoryClickEvent for a single click causes the click not
to be processed by the clicked inventory. The server then doesn't
correctly identify their second click as being a double click, causing an
inconsistency between what the Player believes the inventory to be and
what the server believes the inventory to be.
This change forces an updateInventory call whenever an InventoryClickEvent
whose action is NOTHING is cancelled. Both clicks are considered
PICKUP_ALL, so updating the inventory after the second click fixes any
inconsistencies that could arise between the client and the server.
Currently, the method used for calculating the damage of zombies is scaled
to their health, but it uses the default max health rather than the real
max health value. If zombies have more health than the default max health
value, the amount of damage they deal becomes negative.
This is caused by EntityZombie.getMaxHealth() returning a hardcoded value of
20, which is the vanilla max health for zombies. Rather than using this value
when calculating zombie damage, the call is changed to instead use
((CraftLivingEntity) this.bukkitEntity).getMaxHealth(). This uses the true
maximum health of the Entity. "this.maxHealth" could be used instead of the
aforementioned method, however that creates a very unclear diff, and a
confusing change.
When a Player drops an ItemStack while in creative mode by placing it outside
of their inventory window, the slot number in the packet is -1. The check
that was added to avoid throwing InventoryCreativeEvent excessively didn't
take this into account, and would cause an ArrayIndexOutOfBoundsException to
be thrown when attempting to get the slot specified by the packet.
This change shorts the invocation of player.defaultContainer.getSlot(
packet107setcreativeslot.b) to only occur if the slot id is within the range
of the Inventory. This prevents attempting to get the slot from a location
that is actually outside of the Inventory.
This commit brings the InventoryClickEvent up to date with the new Minecraft
changes in 1.5.
InventoryDragEvent (thanks to @YLivay for his PR) is added to represent the
new "dragging" or "painting" functionality, where if you hold an itemstack and
click-drag over several slots, the items will be split evenly (left click) or
1 each (right click).
The ClickType enum is used to represent what the client did to trigger the
event.
The InventoryAction enum is reserved for future expansion, but will be used to
indicate the approximate result of the action.
Additionally, handling of creative inventory editing is improved with the new
InventoryCreativeEvent, and handling of numberkey presses is also improved
within InventoryClickEvent and CraftItemEvent.
Also, cancelling a creative click now displays properly on the client.
Adresses BUKKIT-3692, BUKKIT-4035, BUKKIT-3859 (new 1.5 events),
BUKKIT-2659, BUKKIT-3043, BUKKIT-2659, and BUKKIT-2897 (creative click events).
We only go through event creation and calling when dispensing filled buckets
if the bucket is able to place its liquid. However, the check for this is
incorrect so the event is not called when a block liquids can destroy is
in front of the dispenser. This commit fixes the check to match the checks
vanilla does when actually using the bucket.
The CraftBlock class is setting bit 0x4 of the update flag when bit 0x2
should in fact be set here. Bit 0x2 means "do updates"; bit 0x4 means
"don't do updates if the world is static, even when bit 0x2 is set".
Minecraft 1.5.2 changed mob spawning by ignoring persistent mobs from the
mob count. In CraftBukkit all mobs that previously used a separate hard
coded persistence system were ported to instead use this one. This causes
all animals to be persistent by default and thus never be counted. To
correct this issue we consider if the mob would be considered persistent
in the hard coded system as well when deciding if a mob should count.
Currently there are several cases where a player will have their inventory
screen closed client side but we will not call an event. To correct this
we call the event when the server is the cause of the inventory closing
instead of just when the client is the cause. We also ensure the server is
closing the inventory reliably so we get the events. Additionally this
commit also calls the event when a player disconnects which will handle
kicks, quits, and server shutdown.
As an optimization we don't do any movement processing on entities that
have not moved. However, players in minecarts trigger this condition when
the minecart is moving on its own. This causes issues with things that rely
on player collision like tripwires. To correct this and any future related
issues we always handle movement for passengers and their vehicles even
if one of the two hasn't moved since they are linked.
When converting things in Minecraft to use wall time instead of ticks I
realized we'd run into integer division rounding issues and could have
updates that end up counting as zero ticks. To compensate for this the
code ensures we always process at least one tick. However, every time we
end up with zero ticks the next time we have an extra tick due to rounding
the other way with the leftovers. This means we are going far too fast and
should not have this at least one tick logic at all.
On top of this some potions rely on the number of ticks they run and not
just the amount of time they last and so potions were put back to running
with ticks entirely.
If a chunk has somehow managed to save with arrays that are not 4096
entries long when reading them again we will get exceptions. Checking the
array length and resizing if needed is cheap so we should do this to help
avoid crashing servers due to this error.
When a chunk is being loaded the server checks to ensure the chunk's idea
of where it is located matches where it was located in the region file. If
these two values do not match the chunk's idea of its position is updated
and the chunk is reloaded. In vanilla minecraft this loading involves the
chunk's tile entities as well. With the change to loading player chunks
asynchronously we split loading tile entities to a separate step that takes
place after this check. Because of this tile entities are loaded with
invalid locations that result in trying to fetch block data from negative
or too large positions in the chunk's internal block storage arrays.
Because loading the tile entities is not thread safe we cannot return to
vanilla behavior here. Instead when we detect a misplaced chunk we just
edit the NBT data for the chunk to relocate the tile entities. This results
in them moving correctly with the chunk without having to actually load
them first.
If a hopper is unable to perform any action during a tick it attempts to do
so every tick from then on. Once it is able to do so it then sets a delay
before attempting to do something again. To avoid excessive CPU usage for
hoppers sitting idle we now apply this delay regardless of the success of
the action.
When using the new feature in 1.5 to drop the item in any highlighted slot,
the anvil result slot does not apply the full anvil calculation that picking
up the item does, including the experience calculation.
Currently furnace smelting and the item pickup delay timer use wall time
(aka actual time passed) to emulate a constant tick rate so run at the
same speed regardless of the server's actual tick rate. There are several
other places this makes sense so this commit converts them.
The item despawn timer is converted so now always takes 5 minutes. Users
know this 5 minute number well so keeping this constant helps to avoid
confusion. This also helps alleviate lag because if a large number of item
drops is the reason your server is running slowly having them stay around
longer just means your server is slow longer.
Potion brewing and the zombie villager conversion timer are now constant.
These match the furnace criteria of being useful for hiding lag and not
having a detrimental effect on gameplay.
Potion effects are now also using wall time. The client is told about effect
times in ticks and displays this information to the user as minutes and
seconds assuming a solid 20 ticks per second. The server does have
code for updating the client with the current time remaining to help
avoid skew due to differing tick rates but making this a constant makes
sense due to this display.
Add a check to avoid doing movement work if an entity doesn't move. This
usually will not ever happen in the current server but is useful when it
does and will be more useful in the future.
Only process mob on mob (non-player) collisions every other tick. Players
tend to pack a lot of mobs into a small space (sheep farm, mob grinder, etc)
so they do a lot of work processing collisions. To help alleviate some of
this we only run these calculations every other tick. This has no visible
effect on the client but can be a huge win on the server depending on
circumstances.
Use generic entity inWater checking for squids. Squids have their own logic
currently for determining if they are in water. This check is almost
identical to the generic entity checking which is run anyway. To avoid
doing duplicate work we just remove the squid version. This does not
have any noticeable effect on gameplay since the checks are so similar.
Use HashSet for tile entities instead of ArrayList. Using an ArrayList for
storing tile entities in a world means we have very expensive inserts and
removes that aren't at the end of the array due to the array copy this
causes. This is most noticeable during chunk unload when a large number of
tile entities are removed from the world at once. Using a HashSet here uses
a little more memory but is O(1) for all operations so removes this
bottleneck.
When a player comes into range of an entity in a vehicle they will often be
sent the spawn packet for the rider before receiving one for the vehicle.
This causes the attachment packet to fail client side because it attempts
to attach the rider to a vehicle that doesn't exist on the client. To
correct this we account for both possible orderings and send the
attachment packet appropriately.
Vanilla also sends an new attach packet every 60 ticks even if the vehicle
has not changed. As this packet is a toggle this resulting in players
teleporting around randomly. Since we handle attachments properly now we
simply revert this section to use the 1.4 logic.
When looking up tile entities for a chunk to send to a player we currently
loop through every tile entity in the world checking if it is within the
bounds of the relevant chunk. Instead of doing this we can just use the
tile entities list stored in the chunk to avoid this costly searching.
As a further optimization, we also modify the generic range-based lookup
to use chunks as well. For most lookups this will give a smaller search
pool which will result in faster lookups.
Thanks to @mikeprimm for the idea and most of the implementation.
In certain scenarios a boat can be killed multiple ways in a single tick.
Due to improper guards this can cause the death code to run multiple times
creating item drops. To correct this we insert the appropriate death check.
Two connection status checks were added to setting a scoreboard for a
player. The first checks to see if a player has logged in yet, which
implicates the ability to receive packets. The second checks to affirm
that the CraftPlayer reference is still to a logged in player; setting
it while not logged in would maintain a stale player reference in the
scoreboard manager.
The method's return value was being incorrectly calculated from the
perspective of this.canHurt(that), where it's actually used from the
this.canBeHurtBy(that) perspective.
The method getTeam gets the team from name of, as opposed to getting the
team a player belongs to.
This also addresses BUKKIT-4002 and partially BUKKIT-4044
When a world is created using our API, it does not use secondary world
server and will maintain a reference to its own scoreboard. In vanilla,
this is not an issue as there is only ever one world.
Similarly to maps, an overwrite to the scoreboard reference has been
added for when another world has been created.
This should also address BUKKIT-3982 and BUKKIT-3985
In commit 7710efc5f9 we corrected the handling of large chests as the
destination for hoppers moving items but did not apply the same fix for
large chests being the source or for droppers. This commit updates these
to have the same fix.
This implementation facilitates the correspondence of the Bukkit Scoreboard
API to the internal minecraft implementation.
When the first scoreboard is loaded, the scoreboard manager will be created.
It uses the newly added WeakCollection for handling plugin scoreboard
references to update the respective objectives. When a scoreboard contains no
more active references, it should be garbage collected.
An active reference can be held by a still registered objective, team, and
transitively a score for a still registered objective. An internal reference
will also be kept if a player's specific scoreboard has been set, and will
remain persistent until that player logs out.
A player's specific scoreboard becomes the scoreboard used when determining
team structure for the player's attacking damage and the player's vision.
This class is designed to be an invisible layer between a normal collection,
and one that silently loses entries because they are only weakly referencable.
Some operations have additional overhead to be semantically correct, but it
maintains the equals contract for all entries, as opposed to identity.
It does not support the equals or hash code method as it cannot easily have
the transitive and commutative properties.
This adds calls to BlockRedstoneEvent for the new daylight sensor and
trapped chest blocks. Note that the redstone level for trapped chests
cannot be modified, as it is based on the number of players currently
viewing the chest's inventory.
When an array of an inventory's contents is requested, we loop through the contents of the NMS inventory's ItemStacks in order to return Bukkit ItemStacks that can be used through the API. However, the NMS ItemStack can, in some cases, be larger than the physical size of the inventory. Using the size of the NMS array as a limit on the loop that follows can result in an ArrayIndexOutOfBoundsException because the Bukkit array's length is the actual size of the inventory, and thus will be smaller.
With this commit we use the smaller of the two arrays' length as the limit in the loop, thus eliminating the possibility that the smaller array will be asked for an index higher than its length.
When a block placement happens we currently update physics on the
attempted placement and update again if the placement is cancelled.
To correct the first one we simply set the block without applying
physics. To correct the second we have to add a new method to
BlockState that lets us update without applying physics and use
this method method when putting the block back.
Without this check, any non-null reference to a plugin is considered
'valid' for registering a task in the scheduler. This is obviously
unintentional behavior and has been changed to throw an
IllegalPluginAccessException. It is now consistent with the
SimplePluginManager event registration contract.
This in affect also addresses BUKKIT-3950 for uninitialized plugin
references (ones without a description).
Large chests work in a different fashion as they are a combination of
two other inventories. This causes their getOwner method to always return
null as their is no correct return. To compensate for this for the hopper
events we special case them to use their CraftBukkit counterpart that has
the information we need for the event.
When a splash potion has no applicable effects we currently do not call
PotionSplashEvent. This means plugins are unable to make custom
potions with reliable splash handling as they have to relicate the
functionality themselves.
With this commit we simply make the event fire regardless of the effects
on the potion.
When cloning an item, all references are copied to the new item. For
collections, this makes internal changes become visible in both the old and
new items.
In CraftMetaItem, clone was not making copies of the appropriate collections
and has been fixed for non-null values.
In CraftMetaEnchantedBook and CraftMetaPotion, clone was using possible empty
collection references and has been changed to explicitly null-check instead.
I should try to compile before I say "this change is okay".
I should try to compile before I say "this change is okay".
I should try to compile before I say "this change is okay".
I should try to compile before I say "this change is okay".
for i in range(100)
This causes the server to generate PrepareItemEnchantEvent even in the
case that an item is already enchanted or otherwise would normally not
be enchantable.
The client resets all formatting after a color code is received, but currently the ANSI codes do not, and so the console does not accurately reflect the appearance of the formatted text. Instead, the ANSI color codes are now set to reset all text attributes.
Currently when dealing with physical interactions with pressure plates
and tripwires we immediately block their activation as soon as a single
entity involved has their event cancelled. We also fire events whenever
an entity intersects the block a wooden button is in even if they aren't
actually pressing it. To correct this we move the button interaction to
the correct place and modify all three to only block the activation if
every entity is blocked from using them instead of just one of them.
CraftServer methods that implement the Server interface will throw an
IllegalArgumentException if a method cannot operate on a null input
and given a null pointer.
This causes methods to fail early and identify that a plugin is
responsible for passing in an invalid argument. This will only
change the exception thrown, if there originally was a thrown
exception. This helps with hunting down legitimate problems
with CraftBukkit.
If the server changes the weather it will set the per-player weather
variable and future changes will not apply. We should only set this
variable when a plugin is requesting per-player weather and not when
the server it doing it.
We used to fall Item.filterData() for this but that method is meant for
converting item data to block data during placement and does the wrong
thing for this case. Instead we just see if the item should have data and
if not set it to zero. We also have to filter wool data explicitly because
clients crash when given invalid wool data.
In Minecraft 1.5 saplings do not grow with a single use of bonemeal anymore.
Our code assumes they will and only takes away bonemeal from the player
when the tree grows successfully (not cancelled by a plugin). Instead we
now always remove a bonemeal even if a plugin is the reason a tree didn't
grow as this matches the vanilla logic more closely.