This commit fixes an issue with the new `intersects()` method on ArenaRegion. Instead of blindly assuming that the region points `p1` and `p2` are set when the method is called, we first make sure both regions are properly set.
Fixes#590
This commit introduces an `intersects()` method on ArenaRegion that
allows us to check whether two regions intersect.
The new method is employed in ArenaMasterImpl during arena load. If an
arena's region intersects with any other arena's region (in the same
world), we print a warning to the server log.
Fixes#367
This commit introduces a null check in the ConfigUtils `parseLocation`
method. If the world of a location string does not exist, the method now
throws an IllegalArgumentException, which allows callers to fail more
gracefully instead of having to resort to null checks.
Additionally, the parsing of exit warps, leaderboards, or linked class
chests is wrapped in try-catch statements that re-throw ConfigErrors
for better error reporting.
Fixes#421
This commit removes the old version checker that used the DBO resource
page and replaces it with a custom checker that uses the "legacy" Spigot
resource API. The Spigot API is much more lightweight and doesn't
require any sort of parsing.
The new version checker uses a simple cache, keeping version checks
fresh for up to one hour, reducing the need to go fishing on every op
login. The cache resets on restarts, though, but this is acceptable.
Note that no attempt has been made to ensure correctness on multiple,
consecutive invocations when the cache is stale. If a cache refresh is
initiated, all update checks invoked before the cache refresh has ended
will behave as if no update is available. This is acceptable, because
update checks are non-essential, the time frame is extremely narrow, and
the most common result of an update check is "no updates available",
since the amount of update checks made is vastly greater than the amount
of updates released.
Since the actual execution of these commands use the regular player name
instead of the display name, the tab completion is useless if it doesn't
also use the regular player name.
Fixes#589
This commit is a complete rewrite of the target event handling logic in
the ArenaListener class.
Instead of the complex, inconsistent code structure with too many line
breaks between control flow branches, we just have a thin logic wrapper
that delegates the event handling to smaller, more focused functions
that handle arena pets, arena monsters, and foreign entities on their
own.
A couple of auxiliary methods are introduced to try to limit the amount
of warnings produced by checking set membership with `contains()` when
the entity/target is an Entity and the collection is a sub type.
Fixes#572
This commit removes a condition in ArenaImpl#canJoin(Player) that checks to see if the arena's WaveManager has any recurrent waves.
Removing this condition is safe, because the WaveManager already makes sure to have a "catch all" default wave at hand for when no wave definitions match a given wave number. As such, the condition in ArenaImpl is completely unnecessary, and was in fact the root cause of a bug.
Fixes#566
Due to the package structure and location of MASpawnThread, SpawnsPets doesn't need to be opened up for this to work.
This change opens up for quite a few different upgrade strategies, since pet items obtained outside of Upgrade Waves are transformed as well. It is technically a breaking change, because it breaks the invariant that "after arena start, no items are transformed to pets". However, since pet items are customizable, it is possible to just change the `bone` to `sponge` in the config-file if bones carry some sort of implicit meaning in an existing setup.
Closes#524
It doesn't seem like there was any real reason to leave out potion effects as upgrades in Upgrade Waves previously, so they were likely just forgotten in the Things API overhaul.
Closes#565
This is a bit of an overhaul of how CreatureSpawnEvent is handled:
- Events happening outside the arena region are still ignored, as are armor stands placed in edit mode.
- Otherwise, if the arena isn't running, we blanket reject all entities.
- Player-mode iron golems and snowmen are still allowed.
- Anything that isn't spawned by a plugin is rejected, _unless_ it is a Vex spawned with "default" spawn reason, which is what the Evoker summon spell uses.
In the end we have a "custom" spawn reason inside the arena region while it's running, which is perfectly "legal". And because of the unfortunate use of Creature (instead of Mob) in MACreature, Slimes and Magma Cubes still need to be handled separately here.
Fixes#564
When a player takes damage from a hostile mob, the player's class pets will have their target set to that mob. This means that even zombies can function as "real" pets!
This commit removes the `auto-respawn` arena setting and the logic associated with it.
MobArena's hacky implementation of auto-respawning is buggy and discouraged. To get true auto-respawn functionality we'd have to move to the Spigot API instead of the Bukkit API.
This commit adds custom names to class pets in the form `<player name>'s pet`. This should help players more easily distinguish between pets and hostile mobs.
This commit changes the pet parsing and handling such that it is a lot more dynamic. Rather than limiting pets to wolves and ocelots, any living entity is now a potential pet. This means that we can do away with the logic that specifically targets the Wolf and Ocelot interfaces and instead work with the more general Tameable interface. As a result, the discrepancies between Minecraft 1.13 and 1.14 in this regard are largely irrelevant, because server owners can just specify which entity they want to spawn given which item in their config-files.
MonsterManager's two Wolf- and Ocelot-specific addPet() methods are replaced with a generic addPet() method that takes an owner (Player) and a pet (Entity). This is technically a breaking API change, but MonsterManager is an internal component that is very unlikely to be used outside of MobArena.
The `global-settings` node in the config-file can no longer be forced into strict compliance via ConfigUtils, because the `pet-items` node is now dynamic rather than static.
The default `pet-items` node in the config-file no longer has `ocelot` in there to avoid confusion on 1.14. It now only contains `wolf` and people will have to add their own ocelot/cat in if they haven't added it already.
Fixes#563
This commit changes how SitPets determines if a nearby entity is "pet material". Instead of assuming that wolves and ocelots are tameable, we check for the Tameable interface. This means that we get rid of the "concrete" types, Wolf and Ocelot, and also fixes a bug on Minecraft 1.14 servers where ocelots are no longer tameable, but cats are. It also kinda catches parrots, but they will not sit if they are flying or perching on the player's shoulder when joining.
Because ocelots are no longer tameable in 1.14, they shouldn't cause trouble here, but because they are tameable in 1.13, we need to rely on the Tameable interface to maintain both backwards and forwards compatibility.
Fixes#548 (kind of - no more exceptions thrown, but the pet ocelots from SuperLuckyBlock may misbehave, however that is a different issue).
This commit adds support for basic tab completion for most of the commands that take arguments. Some completions are somewhat intelligent, e.g. `/ma join` which only lists enabled and "functional" arenas that the given player is permitted to use. Others are just kinda dumb, e.g. `/ma enable` which indiscriminately lists all arenas.
Closes#405
This commit changes how the final "catch all" works for incoming monster damage. Instead of checking if the damager entity is a LivingEntity, we check if it is a monster of the arena and then proceed as normal.
Note that this change may make it possible for monsters in the arena to take damage from non-arena entities. The so-called "catch all" doesn't really catch everything, but it does catch the infighting that it was designed to catch.
One "not thought of" damage source is that of player-made golems, so coincidentally, this commit fixes#550.
This commit adds support for altering the data portion of a potion item by prefixing either `long_` or `strong_` to get extended duration or level II versions of the given potion, respectively.
Closes#520
getById() is deprecated, and while this does break existing functionality, it is a good kind of breakage because it forces people over to the name-based IDs, which they will eventually be happier with.
Partial fix for #406
Similar to the previous commit about leaderboards, this commit fixes the crash caused by using the MaterialData API on Minecraft 1.14 servers.
Fixes#546
This commit fixes a bug on Minecraft 1.14 servers where leaderboards would cause a NullPointerException due to the MaterialData API being broken. Instead, we now use the new BlockData API, and everything is back to normal.
Fixes#536
This commit changes how the unbreakable setting works by just assuming that everything that is "damageable" (implements the Damageable interface) needs to be set as unbreakable. This means that the entire weapons/armor collection in ArenaClass is obsolete, and all of the checking is contained in ArenaImpl.
Fixes#544
This commit changes the SetHealth step such that it uses the player's own value for max health rather than the generic base value. As a result, players who join holding items that lower their max health will be missing health as soon as they join the lobby. But because food levels are maxed and locked, the health will quickly regenerate.
Unfortunately, players who join with a higher health value than the base max health value will have their health capped to the base max health value on the way out of the arena. This was also the case before this commit, but it is worth mentioning again for completeness.
These odd side effects are currently "necessary" because the effects of items that change max health values for players don't take immediate effect in the same tick as they are added/removed, so because MobArena's join sequence is synchronous, we can't feasibly "get it right".
Fixes#545
There is no reason why food should be a thing in the lobby or spectator area. This commit effectively disables it for players in those places/states, while retaining the in-arena conditional logic based on the config-file setting.
Fixes#514
The whitelisting approach works well for the legacy builds, because the
version landscape doesn't change with those. However, the main build on
the master branch will not run on a server version other than 1.13, so
come 1.14, MobArena will be broken.
This commit fixes this problem by changing to a blacklisting approach
for the main build on the master branch. Checking for versions that the
build *can't* run on brings back MobArena's old resilience to version
changes on the Minecraft side of things.
The previous hardcoded value of `20.0` works in most cases, but if a server uses a base health higher than 20, players don't get a full heal. Worse, if the base health is lower than 20, MobArena crashes when it tries to set the health to 20, which is now out of range.
This commit introduces the Attribute enum to MobArena's code base and uses it to get the base value for player max health. This should fix the aforementioned issues.
Fixes#513
Instead of explicitly ALLOW'ing a teleport if a player has the permission, we let the teleport handler logic run its course. If an arena explicitly REJECTs the teleport, we need to cancel the event, but the permission now overrides that behavior. This means that only in the case of an impending event cancellation, the permission kicks in.
This is important, because the permission is supposed to override the decision to cancel, rather than drive the decision to uncancel. With this change, MobArena never uncancels something it wouldn't have uncancelled otherwise, meaning it won't interfere with teleports outside of its own context, and thus won't interfere with other plugins.
Fixes#515, closes#516
Thanks to @minoneer for the bug report and pull request that this code
was based upon!
Spigot is at it again with another breaking change to the API where the
JavaDocs have been retrofitted to match the new, ancient way of writing
software.
The addItem and removeItem methods originally just added or removed
whatever they could when called, and returned a map of items that failed
due to lack of space/items. Now, with the breaking API change, these
methods actually *mutate their arguments* - a practice that has been
heavily discouraged for decades in modern software development, and
something you usually only see in C these days. This change, like many
others in the same vein, show the complete recklessness, incompetence,
and lack of awareness from an otherwise talented team of developers.
Hopefully, they will continue to hone their skills so that we can
eventually have a stable API again.
From a purist standpoint, the flySpeed tag should never be messed with
in MobArena, because simply turning off flight should be enough. It is
likely that the flySpeed tag was originally included to cull "cheaters"
who somehow managed to activate flight in the arena anyway, but this
isn't really MobArena's responsibility and can very probably be handled
by other means of cheat prevention in WorldGuard regions or the like.
By not touching the flySpeed tag, it makes it much easier for server
owners to recover from crashes where the leave steps aren't executed,
leaving players "locked in the air" when they try to fly.
Closes#509 since this "fix" was the reason that feature request was made.
Note that this doesn't make the arguments for commands case insensitive. Each command is still responsible for lowercasing their arguments if it makes sense for them to do so.
This closes#446.
Lowercasing the enchantment string before feeding it to the Bukkit API makes the enchantments a little more "copy/paste proof" when grabbing the uppercased names from the JavaDocs/Minecraft wiki.
Spectating is possible both during and before/after arena sessions. This means that an early return from the entity damage cancellation logic when the arena isn't running is going to allow damage to go through to spectators of non-running arenas, which means they can die. By simply removing the early return (and placing it in the one branch that actually requires it explicitly), spectators should no longer be able to take damage.
This fixes#502.
This changes how unbreakable items work in MobArena. It removes the legacy "repair logic" and replaces it with the item meta unbreakable flag. This approach should work all the same, except now if weapons and armor in class chests have special durability values, these are preserved in the cloning.
This should make MobArena compatible with plugins that depend on special durability values, such as QualityArmory.
This commit changes how MASpawnThread is started. Instead of simply scheduling a task and letting it run whenever, we now explicitly tell it to stop when the arena ends. This matters, because if the scheduled task does not get cancelled, it will run at the scheduled time. MASpawnThread's run() method has an early return to stop whenever the arena isn't running, but with unlucky timing, it's possible to start a new arena session before the task runs again, meaning the same MASpawnThread keeps scheduling itself on the previous scheduling loop.
Instead of this whacky approach, we now specifically have MASpawnThread track its own BukkitTask. Upon arena start, we instantiate a new MASpawnThread and call its start() method, which in turn schedules itself and stores a reference to the associated BukkitTask. Upon arena end, we call the MASpawnThread's stop() method, which explicitly calls the BukkitTask's cancel() method, effectively stopping/unscheduling the task.
This fixes the (very) long-standing "double wave spawner" bug that we haven't been able to reproduce for so long. Hooray!
This setting was removed a long time ago, likely by "happy mistake" in a larger refactoring.
When enabled, players are granted any collected experience during the arena session as a reward when they die or reach the final wave of the arena. Note that deliberately leaving the arena is not included here, because "leaving" an arena is a highly ambiguous and conditional concept at the time of this commit. Figuring out when and how the experience reward should be added is complicated, and unless someone puts in a request for it, I think it's enough that the "legitimate" reasons for getting the experience (honorable death and reaching the final wave) are covered.
Closes#485
It turns out that experience in Minecraft is split out on a couple of different variables, and they are only loosely coupled.
Total experience, level, and level progress are three completely different variables that can be manipulated individually. This means that while 10 experience points from level 0 should bring you up to level 1 with a third of the experience bar full (level 0 to 1 takes 7 points, level 1 to 2 takes 9 points), simply setting the total points value to 10 won't automatically level you up. Using the Player#giveExp(int) method will, however, work this way.
This commit adds an event handler for the PlayerArmorStandManipulateEvent and cancels it if the arena protection is on, we aren't in edit mode, and the region contains the armor stand. The same logic applies to the armor stand damage event.
This commit re-implements and rearranges a lot of the logic in the main plugin class. It also removes the ConfigCommand class and moves its functionality into the CommandHandler to allow for reloads to be a bit more special than normal commands.
In the refactoring of the main class, the startup logic is broken up into two phases, setup and (re)load:
- In the setup phase, we create the data folder, and the command handler, config serializer(s), plugin integrations, boss abilities, the global event listener, and metrics are initialized. The ArenaMaster is instantiated, but it isn't initialized. These are things that need to be set up just once and don't change on reloads.
- In the (re)load phase, the config-file is loaded from disk, the global messenger is instantiated, the arena master is initialized (loads settings, classes, and arenas), the announcements file is loaded from disk along with the sign data/templates. These are things that we want to be reloadable.
If anything goes wrong during these phases, we store the exception thrown. This puts MobArena into a state where it prints the exception message to anyone who types a non-reload MobArena command to bring attention to the error so it can be fixed.
This commit changes how the ThingParser is used throughout the code base. Instead of blindly filtering out null values, we're now throwing a new InvalidThingInputString exception. This exception is caught in an outer scope that has more context. The exception is then unwrapped and rethrown as a ConfigError with the additional context. In the outermost scope of (re)loading the config-file, the ConfigError is caught and printed, and then (re)loading stops gracefully.
We still need a proper way to handle loads/reloads consistently to get rid of the default command usage message, but this is a good step towards better usability in the face of user errors.
Fixes#478