This commit releases the BinaryOperation and UnaryOperation interfaces
of the `formula` package from their `java.util.function` supertypes and
redeclares the previously inherited functions directly in the operation
interfaces, but also reifies them by explicitly using primitive doubles
instead of generics and wrapper classes. Doing so does not change the
functionality or any other code at all, but it makes the interfaces much
"stronger", since they no longer need to consider `null` values, which
they didn't actually take into account anyway. This fixes a warning in
Visual Studio Code (not sure how to get the same warning in IntelliJ)
about the operator registrations in the default formula environment
factory method being unsafe.
This commit adds a second job to the build workflow that runs after the
build job has completed. The job creates a GitHub Releases _draft_ that
needs to be manually published in order to be publicly available.
The job runs if, and only if, the following conditions are met:
- The build job has completed _successfully_, i.e. if the Gradle `build`
task fails, the draft job doesn't run.
- The `push` event that triggered the workflow happened on the `master`
branch, i.e. releases will never be created from temporary branches.
- The commit message of the most recent commit in the `push` event that
triggered the workflow starts with `"Release "`, i.e. there must be a
commit that explicitly tries to "release" a build.
- The version string does _not_ end with `-SNAPSHOT`, i.e. development
builds will not be released.
All of these conditions act as safeguards, so we don't end up releasing
something we don't want to release, but they also prevent bloating the
Releases page with a bunch of useless drafts.
The job uses the `version` output variable from the build job that was
introduced in a recent commit to extract release notes using the script
that was also introduced recently, as well as for the name of the _tag_
to create when the release is published.
Note that the `GITHUB_TOKEN` environment variable is required to be set
when we want to use the GitHub CLI in a workflow [1]. The job also has
an explicit `contents: write` permission, which is required for creating
releases from GitHub Actions.
This commit makes the build workflow output the version string as found
in the `version` property in `build.gradle.kts`. The version string will
be necessary further down the pipeline when we need to extract release
notes and create tags.
There are many ways to extract the version string:
- Use `grep` to grab it from `build.gradle.kts` directly. This is pretty
brittle, since we don't really know for sure if the structure of the
file will change in the future.
- Create a Gradle task in `build.gradle.kts` that prints the version
string. This is probably the most direct approach we could take, but
such a hyper-specific task feels like a code smell. It also requires
running Gradle again, which is a bit slow.
- Use the built-in `properties` task in Gradle to print the `version`
property and `grep` it. We avoid changing `build.gradle.kts`, which is
a plus, but we still have to actually run Gradle.
- Parse the filename of the resulting jar-file in `build/libs/`, since
it now contains the version string. This is also brittle, because we
don't know if we're gonna continue to append the version string to the
jar-file, and depending so much on it being there is a little scary.
- Extract `plugin.yml` from the resulting jar-file and `grep` it. This
is perhaps a little crude, but it is much faster than running Gradle,
and as a bonus, we get a bit closer to "what's inside the jar-file",
which should give us a bit more confidence that any given release is
actually the version it claims to be.
It may seem like a small thing to invest so much text on, but from an
automation standpoint, it is much easier to be confident in automations
with predictable and robust mechanisms for deriving input variables.
Introduces a crude Python script that can extract release notes from the
changelog for a given version and convert it to one of three different
output formats:
- `github` for GitHub Releases. This is just the Markdown itself, but
with the very first line (the version) removed, because the version is
also the title of the release itself.
- `spigot` for Spigot Resources. This is the BBCode format used on the
forums and in the resource descriptions.
- `curse` for CurseForge File Uploads. Curse uses a so-called "WYSIWYG"
format that's really just HTML underneath.
The formats for Spigot and CurseForge are straightforward to convert to
as long as we only use simple text formatting, bullet lists, and links,
but that is really all the changelog should consist of anyway.
While this script already makes the release process quite a bit easier
on its own, the end goal is to _automate_ releases as much as possible,
and to do that, we need to be able to extract release notes, and we need
to be able to do it from GitHub Actions, which is quite a bit simpler if
we don't use third-party libraries.
Publishing releases on GitHub is almost trivial, while CurseForge is
pretty easy, and Hangar should be very doable as well. Spigot, on the
other hand, is stuck in the dark ages, so we must continue to upload
files manually there.
According to the documentation, by not specifying anything in the `push`
event, GitHub Actions will run the workflow for both branches and tags,
but by specifying `branches` alone, it will _only_ run the workflow for
branches and _not_ tags [1].
We want to build on pushes to _all_ branches so we can give folks a jar
to try out for feature requests and bug fixes. We don't want to build on
tags, however, because they don't provide any value in the current build
pipeline. If the version was derived from Git tags, it could make sense
to build on tags, but that's not where we are.
As for the `**` glob pattern instead of just `*`, the documentation says
that the latter does not match forward slashes [2], and while our naming
convention for branches doesn't use slashes right now, there's no reason
that they shouldn't be viable later down the road.
---
[1] https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushbranchestagsbranches-ignoretags-ignore
[2] https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
Removes the "archive version" override for the `shadowJar` task in the
build file, resulting in a jar-file that contains the current version
number in the filename. It's mostly a convenience tradeoff; either we
can see the version directly in the filename and avoid assumptions, or
we can easily overwrite an existing jar-file with a new one.
Also updates the upload step of the build workflow to a glob pattern so
we grab the file regardless of the version.
This commit converts the project from Maven to Gradle by removing the
old Maven-related files such as `pom.xml` and the Maven Wrapper, and
replacing them with their Gradle counterparts (more or less).
Comparing the artifacts from Maven and Gradle indicates no significant
differences in the resulting jar-files, and a quick test of the plugin
shows that things are still working as expected.
Bits of `build.gradle.kts` may need a bit of a tune-up later down the
road, e.g. the test sources "hack" put in place. It may be cleaner to
omit this hack and just suck up having to repeat dependencies, but in
that case, it might be better to embrace the "libs" file instead of
having to repeat dependencies in full.
Note that this commit changes the caching mechanism used in the GitHub
Actions build workflow, opting for the one built into `setup-java`.
This setting allows server owners to allow arena monsters to teleport
around _while inside the region_. They still can't teleport out of the
region.
Taken at face value, this should just be the default behavior. However,
due to arena regions being boxes, any non-box shaped arena will need a
region that covers more than the physical arena structure, which means
mobs like Endermen will be able to teleport into possibly unreachable
areas of the physical structure. So we have to make do with a setting.
Closes#762
The idea behind the previous implementation worked, but it was a tad bit
confusing. This commit refactors the activation logic by simply removing
it entirely. The "activation" part of the logic is now derived from the
wave number (if 0, it means we haven't _really_ started yet), instead of
relying on the spawn thread to toggle the flag on and off. This kind of
dependency inversion (spawn thread -> listener, listener -> "phase") is
a pretty decent (albeit super tiny) step towards cleaning up the whole
session system, so I call that a victory in and of itself!
Using the new `mobarena.admin.errors` permission, this commit provides
server owners with a way to make the infamous Spigot health error much
more visible by sending the error message to any "admins" online when
the error occurs.
Closes#764
Introduces a new permission for "admins" that can be used to increase
visibility of errors caught by the plugin. Server owners may not want
_all_ online players to see these types of messages, so the permission
gives error handlers a way to filter the list of online players before
sending the error message.
Introduces the concept of a _saved item_; an in-game item that has been
captured in a YAML file via Bukkit's item serialization mechanism. These
items can be referenced in the config-file in all places that any other
normal item can be used, assuming the ThingManager is in charge of the
parsing. This should help bridge the gap between class chests and the
config-file by allowing any Bukkit serializable item stack to be stored
and referenced as if MobArena's item syntax directly supported it.
Three new setup commands are introduced to help manage the items, such
that they can be created, deleted, and loaded (for "editing" purposes).
The commands are somewhat rough around the edges and may need a little
bit of polish going forward.
Together with the new inventory referencing Things, this functionality
should help provide most of the flexibility people have been missing
from the item syntax for about a decade... Hell, it's about time.
Closes#212
Adds three new Thing types that can be used to reference items in chests
(or any block-based InventoryHolder):
- InventoryIndexThing looks up an item by index/slot in an inventory.
- InventoryGroupThing groups all non-null/non-air items in an inventory
into a ThingGroup.
- InventoryRangeThing groups all non-null/non-air items in a given range
of an inventory into a ThingGroup.
The new Thing types aim to bridge a gap between the class chests and the
rest of the Thing-based parts of the config-file. The goal is two-fold:
allow for more in-game configuration so access to the config-file isn't
_quite_ as crucial, and propagate the item-wise feature completeness of
class chests to other parts of the plugin.
While class chests are low configuration and a bit "all or nothing", the
inventory Thing types require manually punching in the coords for chests
and possibly indices/ranges for items. This means that the initial setup
could be a bit unwieldy, and highly volatile wave setups are definitely
not a good fit. If the wave setup is mostly pre-defined, it is fairly
easy to tweak upgrade waves and rewards in the same way class chests are
tweaked.
As for item-wise feature completeness, the inventory Thing types share
the same "if Bukkit can copy it, it will work" rule of thumb as class
chests do, which means items with metadata such as custom names, lore,
or even NBTs, should just work. This could remove the need to employ
other plugins.
By no means can this solution be considered "optimal", but it it _does_
enable some long-requested features.
Closes#456
Since Minecraft 1.20, players can edit signs by right-clicking on them,
and that poses a problem for the sign-centric portions of the plugin,
such as class selection signs and the various types of arena signs.
This commit refactors the PlayerInteractEvent handler in ArenaListener
in order to break open the possibility of handling non-lobby players as
well. We're a little more strict with lobby players, and we still want
to handle class sign clicks and iron block clicks here. For players who
aren't in the lobby, we're really just blocking the event according to
the regular protection rules (block is inside region, protect is on, and
arena is not in edit mode).
It also blanket cancels events in the HandlesSignClicks event handler,
because there is no meaningful way to edit an arena sign, since their
contents come from the template file and not from what is written on
them by the sign renderer.
Ideally, we'd refactor some of this event handler logic, because it's a
lot easier to take care of the individual responsibilities in separate
event handlers.
Fixes#765
It boggles the mind that this tiny little class has worked as intended
since 2011 (!!), and all of a sudden, signs no longer retain their text
in the repair procedure...
By calling the somewhat arbitrary `update()` method on the sign after
setting the contents, the sign appears to correctly update again.
Fixes#772
I had no idea this class existed, but it seems like it's actually never
been used for anything, since the commit that introduced it didn't even
use it either.
Introduces a couple of tests for the FormulaManager test suite in order
to cover all the methods the class exposes. This means it is no longer
necessary to suppress the "unused" warnings.
It's not clear why this variation in the auto-ready logic exists, and
the commit history doesn't seem to have any clues either. Perhaps the
actual readying up logic was incompatible with auto-ready at some point,
but at this point in time it doesn't seem like this is necessary at all,
and it appears to be causing a bug with the MobArenaStats extension.
By simply calling the player ready procedure regardless of the status of
the auto start timer, MobArena fires the arena player ready event that
MobArenaStats depends on for some of its pre-session bookkeeping. It
could be argued that MobArenaStats should be more robust, but we would
much rather fix the root problem than slack on the otherwise fairly
sound strictness of the MobArenaStats data model.
Fixes#746
Makes the boss entity the source of the obsidian bomb explosion, which
then makes the damage event listener handle the explosion damage as if
the boss is the damager, which means the `monster-infight` flag should
be respected.
Fixes#759
Makes the sheep entity the source of the explosion that's created when
it triggers close to a player. This, in turn, makes the damage event
listener handle the explosion damage as if the sheep is the damager,
which means it will respect the `monster-infight` flag.
Fixes#758
This new spawn reason was introduced somewhere between 1.18 and 1.18.1,
and unfortunately it is a breaking change, so we have to employ it for
MobArena to properly allow and register vexes (again...), but we also
have to maintain a variation of the old logic so we don't break support
for older server versions.
Fixes#719
This time around we're trying to keep the API version bumped for the
sake of not leaving the people who actually keep their servers updated
behind. It does present some potential backwards compatibility issues
when we do employ new API, but we'll just have to be mindful of _how_ we
go about doing so...
The previous name was really just a way to try to "prettify" the whole
thing, but the badge in the README is a little wonky compared to other
projects, so we're just gonna go with "build" for now for consistency.
When a player with pets dies in the arena, we want their pets to be
removed. One could probably argue that the pets _should_ be able to
stick around, but the original intent was for them to be removed
alongside their owner.
Fixes#721
Removes the first `_` in the `_SHULKER_BOX` matching to ensure that normal shulker boxes with ID `SHULKER_BOX` are removed from My Items as well.
Co-authored-by: Andreas Troelsen <garbagemule@gmail.com>
This new setting allows changing the fuse time for auto-ignited TNT,
which is normally a hardcoded 80 ticks in Minecraft. Note the somewhat
weak safeguarding without any sort of error message - with great power
comes great responsibility...
Closes#715
Now that MobArena sets the TNTPrimed source on auto-ignited TNT, the
"planter" logic becomes _somewhat_ obsolete. This is due to the fact
that manually ignited TNT blocks produce a TNTPrimed entity with the
source property set to the player that ignited the block.
Because the "planter" logic in the BlockIgniteEvent handler didn't
actually work, this change shouldn't actually do anything in that
regard. That is, a TNT block ignited by a player would still have that
player as its source regardless of who the planter was, because the
procedure that would have otherwise set the planter of the TNTPrimed
entity never ran.
Turns out igniting TNT _doesn't_ fire a BlockIgniteEvent but rather an
ExplosionPrimeEvent, which means this code has never actually been of
any use. This code block was likely dead on arrival and has been dead
for almost 9 years. Wonderful...
The proper handling here would be to listen for the PlayerInteractEvent
and detect flint and steel interactions with TNT blocks. This is super
cumbersome, however, because the event handler would have to listen on
the MONITOR priority to ensure that nothing changes down the line. What
we are _actually_ need to do is remove the TNT block from the arena's
block set when it is ignited, but since this hasn't worked for almost a
decade, we're not really in a hurry to fix it now. It just makes for a
slightly slower (but negligible) cleanup procedure most of the time.
This property makes TNT explosions look more "real" to other plugins who
may be consuming events from MobArena's sessions. It also gives way to a
potential rework of the "planter" logic that currently makes use of the
Bukkit Metadata API.
Closes#718
Changes the behavior of the ArenaListener's teleport event handler such
that it _ignores_ teleport attempts instead of _rejecting_ them when the
player in question has the `mobarena.admin.teleport` permission. Because
the global listener's event handler only ever checks the permission if
at least one per-arena listener has _rejected_ the teleport attempt, and
none of them have explicitly _allowed_ it, the change means that it will
never check the permission, because its internal `allow` flag will never
change to `false`. Thus, the check can be safely removed from the global
listener's logic.
When the response is to ignore instead of reject, the message that would
have otherwise been sent to the player is skipped. This fixes#702.
It is perhaps tempting to move the permission check up into the section
of sanity checks in the global listener, but this is very specifically
avoided to allow MobArena to _uncancel_ teleport events that have been
cancelled by other plugins, but that MobArena might need to go through.
Please see afcc526a71 for more info.
This is technically not necessary when pets are simple entities like
wolves and zombies, because these types of pets will never target and
thus attack other players in the arena. However, projectile entities
such as Blazes and Ghasts may hit players in the line of fire, and so
any such damage should be cancelled.
Fixes#712
Introduces a new arena setting that changes the "emptiness check" for
`clear-wave-before-next`, `clear-wave-before-boss`, and the final wave
check, allowing for a customizable _leeway_.
By default, the leeway is 0, which means the monster set has to be
completely empty for the checks to pass. With a value of 2, the set
may contain up to two monsters for the checks to pass, and so on.
The leeway should help alleviate some of the issues some people have
with their arena sessions when monsters "disappear" behind terrain or
end up in hard-to-reach areas. This is by no means a real "solution"
to the underlying problem, since the build-up of monsters in longer
sessions will just result in the issue being pushed to later waves.
We'll see if the setting leaves any additional customization to be
desired and perhaps defer any such requests to the Sessions Rework.
Closes#706
Sets the player fall-distance to 0 before performing a player teleport
during "move player" steps. This should cancel out the any fall damage
that may have built up before the teleport was initiated.
Fixes#698
Co-authored-by: Andreas Troelsen <garbagemule@gmail.com>
It turns out that, according to the Spigot API, flaming arrows actually
_change_ TNT blocks to air before/instead of igniting them. While this
is a little counter-intuitive, the fix seems to revolve around allowing
the change to happen if the changed block is TNT and the "changer" is an
arrow.
Allowing the change event to happen means "foreign" primed TNT entities
will spawn, which makes it necessary to clean them up during the session
cleanup phase in ArenaImpl.
Fixes#696
It's not clear if this change actually solves the underlying issue,
because it has not been tested in a controlled environment. However,
considering the EntityExplodeEvent constructor, which doesn't take a
cancel state value, and the `HIGHEST` priority setting of MobArena's
event handler, the issue is realistic, and this change very likely
solves the issue.
Fixes#704