Introduces the concept of an Announcer, which is invoked whenever the
`announce` methods on the Arena interface are invoked. Previously, all
announcements would simply be sent to the arena's Messenger, but this
new feature allows us to move them up into titles to help declutter the
somewhat overloaded chat box.
By default, to help people discover the new feature, the announcer type
is `title`, but it is possible to switch back to `chat` for the original
behavior.
Closes#272
This commit introduces a quality-of-life feature for spreading players
out during the warp to the arena floor. The feature is configured via
the new per-arena setting `arena-warp-offset`. When the value is greater
than 0.01, MobArena will add a random number of units between 0 and the
offset value to the X and Z axes in either direction. For example, if
the value is set to 3, players will be teleported to a random location
in a 3x3 square centered on the arena warp, rather than directly to the
arena warp itself.
Closes#371
Certain class chest items are cloned before they are made unbreakable,
but not all. This commit changes that, so all items in the input array
are cloned prior to setting the unbreakable flag on them. The items that
were previously cloned specifically no longer need to be, since they are
included in the initial cloning.
Fixes#637
Plugins like Multiverse and EssentialsX have features that override the
world spawn location for players respawning both with and without bed
locations. If MobArena catches the PlayerRespawnEvent too early, these
plugins will likely overwrite the respawn location set for players that
respawn after dying in an arena session.
Because MobArena is a minigame and its respawn manipulation logic only
runs for respawning arena players, it is perfectly reasonable for it to
get the final say in where these players should respawn. It would have
been nice to just use `HIGH`, but that is what EssentialsX runs at, so
we gotta go higher than that.
This commit forgoes some of the work done in the join/leave refactoring
of commit b1c6b61827.
The intent behind the original commit was to make the join/leave process
a very strictly defined set of steps that would work atomically to try
to ensure a stable, predictable process. As a result, the idea of making
spectators out of respawning players meant first kicking them out of the
arena and then re-joining as spectators, as if they had manually typed
`/ma leave` followed by `/ma spec`.
However, on some multi-world setups, this process causes people to get
thrown around a bit, which makes for a poor user experience. This commit
changes the behavior when `spectate-on-death: true` such that the player
isn't kicked, but is instead added to the spectator player pool when
they respawn. If the flag is false, players will still get sent to the
spectator area for one tick and then immediately kicked out as if they
had manually typed `/ma leave`. This does create a little bit of jumping
around, but because there is only one world change (as there would be
anyway), it is deemed acceptable at this point in time.
Closes#508
This commit changes the way Equippable wrappers are created, such that
they more closely match the way class chest armor pieces are "guessed".
That is, instead of looking directly at the Material value of the given
item, we instead look at the name _suffix_, i.e. the part after the last
underscore in the name, e.g. `BOOTS` in `IRON_BOOTS`.
The neat thing about this approach is that it is compatible with future
items that follow the same naming convention, such as Netherite armor
pieces.
The downside is that it is stringly typed and not particularly "pretty",
and if the naming convention breaks or new items are introduced (such as
the elytra), we will have to make modifications anyway.
Fixes#636
The vanilla behavior for most mobs is that they just stop minding their
targets' business if aggro is lost. The same applies to guardians and
elder guardians.
To prevent the pace of gameplay from stagnating, MobArena compensates
for target loss by helping the mobs find a new target. The issue with
this in terms of guardians is that breaking line of sight is the only
way - besides killing it very quickly - to avoid taking damage from a
guardian due to its lock-on laser attack. This means that guardians and
elder guardians need to be excluded from the retargeting logic to make
sense in an arena setting.
This commit introduces a new EnumSet of EntityTypes to exclude from the
retargeting logic. It is not a particularly pretty solution, especially
not since ArenaListener is such a huge class already, but it does make
it easier to add more mobs later down the road, and it does a slightly
better job at giving way to a config setting at some point.
For the Mobs Rework, a per-monster flag like `auto-retarget` or similar
might be a much better solution, so it's possible to have encounters
like a small batch of guardians that _don't_ lose their targets but have
very little health, so the "race against time"-aspect can exist, but in
a much more configurable way.
Fixes#601
This commit fixes the per-arena config setting `soft-restore`. Due to
commit 92c4ce1a8b, the soft restore logic
won't run on BlockBreakEvents, because to reach that specific part of
the event handler, the `protect` flag has to be set to `true`. However,
due to an early return in the soft restore logic if the `protect` flag
_is_ set to `true`, it is effectively impossible for it to run.
The fact that this functionality has been broken for over 6 years (!)
with almost no reports of it is perhaps a testament to how little it is
being used in the wild.
The integration only works reliably with the `clear-wave-` settings set
to `true`, because it relies on there being only one "current" wave.
This is a fundamental issue with the way sessions run right now, and is
another good example of why the Sessions Rework is necessary.
It is possible to achieve the exact same functionality by just making a
couple of Upgrade Waves before and after the waves that need to have
limited skill sets (thanks Lucy). With just a couple of quality-of-life
features like wave "triggers", it's possible to make things just the way
they were with the integration, but by using some more general building
blocks.
Closes#609
Catches ConfigError and prints its message rather than letting it bubble
up to the command handler as an uncaught exception. This means that
instead of seeing "An internal error occurred...", command senders now
see the underlying error message, as well as a short message telling
them to fix the error in the config-file and reload.
Closes#599
This commit fixes the `player-time-in-arena` per-arena setting by switching to `toUpperCase()` on the string value, which means that the values can actually result in something meaningful, rather than always throwing an exception.
The feature was broken in commit b1c6b61827, and it appears to be the only such instance to sneak through.
Fixes#621
Co-authored-by: Bobcat00 <Bobcat00@users.noreply.github.com>
Co-authored-by: Chew <chew@chew.pw>
This commit completely reworks the Root Target ability implementation by
replacing the repeated teleportation code with potion effects.
The old implementation relied on teleporting the target every tick for a
given duration, but because teleporting also involves pitch and yaw, the
result was a constant "snapping back in place" experience.
The new implementation works by applying the following potion effects
with a very large amplification:
- Slowness, to prevent the player from moving out of place.
- Slow falling, to negate fall damage.
- Negative jump boost, to prevent the player from jumping around.
Note that the jump boost uses a _negative_ amplification to make it have
the inverse effect, i.e. a much worse jump ability. It is still possible
to jump an arguably negligible amount away from the root location.
Fixes#490
Makes the class chest armor guessing logic pair `"ELYTRA"` up with the
chest piece slot. This specific matching works, because there are no
underscores in the `"ELYTRA"` item name.
Fixes#616
If someone spins up MobArena with a really old config-file or simply
removes the `pet-items` section, the plugin throws an NPE. This commit
fixes that by allowing the section to not exist.
It might be a good idea to log some helpful information, but let's wait
and see if this isn't good enough.
Fixes#606, closes#608.
Thanks Chew!
This commit changes how the ArenaRegion `intersects()` method works:
- The implicit null checks in the `setup` and `lobbySetup` flags have been replaced with actual null checks inside the auxiliary `intersects()` function. Not only does this make the auxiliary method more robust for potential future use, it also helps tidy up the code a bit. So neat!
- The semantics have changed, since `setup` depends on more than just the `p1` and `p2` points. This fixes an (unreported) bug where the check would report a false negative in case an overlapping arena region was defined, but e.g. the arena warp was missing.
- Instead of only checking arena vs. arena and lobby vs. lobby, we now also check arena vs. lobby and lobby vs. arena. That is, if the arena region is defined, we check it against both the arena region and lobby region of the other ArenaRegion (if they are defined). Same deal with the lobby region. This should ensure that no combination of overlaps pass through the check.
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