127 Commits

Author SHA1 Message Date
0f6c29a203 Bumps version to snapshot for jenkins
All checks were successful
EpicKnarvik97/Stargate/pipeline/head This commit looks good
2025-09-14 01:38:05 +02:00
1eeefa4593 Adds distribution management to pom
All checks were successful
EpicKnarvik97/Stargate/pipeline/head This commit looks good
2025-09-14 01:21:56 +02:00
8c4d492e07 Adds back the Jenkins file
Some checks failed
EpicKnarvik97/Stargate/pipeline/head There was a failure building this commit
2025-09-14 01:08:26 +02:00
407b22fba0 Ignores cancelled block events 2025-09-14 00:55:01 +02:00
bcde89dec4 Updates dependencies, and removes some redundant code 2025-09-14 00:15:19 +02:00
fe8200813f Updates KnarLib, uses improved formatting and removes redundant code 2025-09-13 23:57:05 +02:00
d80907b5fb Adds better default permissions
- Adds three new permission groups for easier setup
- Sets better default permissions
- Updates and prettifies some documentation
- Renames the silent portal option to quiet
2025-07-30 18:58:42 +02:00
e971bd2cf5 Fixes Stargate verification 2025-07-27 20:26:25 +02:00
a861591fec Cleanup and maintenance
Updates Spigot version
Removes MockBukkit and related tests, as it makes updating a hassle
Bumps API version to 1.20
Removes legacy sign updating
2025-07-26 20:21:35 +02:00
932dae0182 Fix #389
Tested on Purpur Version: 1.21.5-2430-603c755 (MC: 1.21.5)
2025-05-10 18:14:18 +02:00
Pheotis
779a8265f5 Preparing for a release. 2024-11-10 18:26:41 -05:00
864eaac940 Removes unnecessary hashmap copying 2024-11-08 18:45:10 +01:00
7dd01995ed Fixes dependency relocations to remove all warnings
Removes unused adventure-platform-bukkit dependency
Explicitly includes bstats-base
Adds and fixes filters and relocations
2024-11-08 16:50:14 +01:00
966fed331f Optimizes portal entrance lookup 2024-11-08 16:09:28 +01:00
534ada874d Implement equalsand hashCode methods for material specifiers 2024-10-09 18:00:45 +02:00
bd12ec138b Revert "Fix validate portals check" 4377a9418f 2024-10-09 17:59:44 +02:00
4377a9418f Fix validate portals check 2024-09-22 21:25:04 +02:00
Pheotis
72258f659d Preparing for a release. 2024-06-01 14:21:18 -04:00
0a4295e8a9 Merge branch 'legacy' of https://github.com/stargate-rewritten/Stargate-Bukkit into legacy 2024-06-01 20:13:33 +02:00
f77ead15c4 Uses optional legacy method when getting sign lines 2024-06-01 20:13:20 +02:00
Pheotis
eb34d998f9 Getting ready for a release. 2024-05-28 20:48:18 -04:00
2c98103db0 Adds missing return statement. 2024-05-17 20:33:56 +02:00
85928a23a3 Merge branch 'legacy' of https://github.com/stargate-rewritten/Stargate-Bukkit into legacy 2024-05-17 20:30:42 +02:00
97643d8ce0 Adds condition to require exactly one exit point
Note that Legacy didn't have a check because the actual exits were calculated based on the bottom opening blocks in order to center a leaving player. A warning would instead be displayed upon teleportation when a player tried to teleport to a Stargate with no exit.
2024-05-17 20:30:27 +02:00
Pheotis
314995aa14 Merge pull request #337 from stargate-rewritten/legacy-localisation-update
Manual import of crowdin localisations to legacy.
2024-05-13 15:34:43 -04:00
905aec8101 Makes the duplicate dynmap marker creation warning into a debug message 2024-05-13 20:56:54 +02:00
4c024e7536 Updates configuration-related language lists 2024-05-13 19:01:51 +02:00
Pheotis
7a71d5b8c7 Fixed! 2024-05-13 11:30:56 -04:00
Pheotis
c86fa2120a Manually backported rewrite's crowdin. 2024-05-13 11:21:31 -04:00
0bcf65b2f1 Adds geyser and floodgate soft depends 2024-04-28 11:34:45 +02:00
36792d4ddf Removes applyStartupFixes, and adds controlUpdateDelay
Now, all updating of Stargates' control blocks happens through a queue. The amount of ticks between each time the queue is polled from is configurable using controlUpdateDelay
2024-04-23 18:35:41 +02:00
50e7586942 Updates Vault and KnarLib 2024-04-22 15:05:16 +02:00
9db73b7bae Adds an option for disabling startup fixes
Also fixes configuration default values not being used when the option is missing from the configuration file.
2024-04-21 23:10:26 +02:00
6287a5e492 Only fetches name from UUID if necessary
Also fixes some minor warnings
2024-04-21 16:13:57 +02:00
484d4f4cf1 Caches result of getOfflinePlayer in PortalOwner 2024-04-21 15:31:13 +02:00
29bae9d793 Adds more debug output during post load tasks 2024-04-20 19:08:11 +02:00
420e4fc185 Optimizes sign updating 2024-04-20 18:35:31 +02:00
58373f7d0f Adds some conditions to the portals updated during loading 2024-04-20 18:17:41 +02:00
ca52f58129 Fixes a class type problem when spawning a new vehicle 2024-03-19 14:51:55 +01:00
be6e7ec87b Checks the Floodgate API in addition to the Geyser API 2024-03-19 14:28:17 +01:00
Pheotis
5b825b5037 Bump version 2024-03-06 20:44:21 -05:00
209ae91d9b Reverts MockBukkit update, and removes inconsistent JUnit version 2024-03-06 15:24:28 +01:00
dfeeaf6999 Adds proper geyser checking 2024-03-06 14:59:09 +01:00
184cb38cbb Updates MockBukkit, and fixes some test-related issues
Fixes JUnit 5's After being used instead of AfterEach
Fixes a potential NullPointerException when tearing down GateLayoutTest
2024-03-06 14:25:45 +01:00
74708914f3 Expands hit-box for END_GATEWAY for players with Bedrock names (WIP) 2024-03-06 14:02:28 +01:00
c2ab3dd8b2 Fixes the problem with Dynmap disabling Stargate 2024-03-06 13:57:31 +01:00
2746e4f8ee Merge pull request #336 from stargate-rewritten/legacy-improvements
Legacy improvements
2024-02-22 03:49:17 +01:00
c03b3fc6b0 Removes some redundancy in createPortal 2024-02-20 22:48:36 +01:00
9abf60bb31 Reduces some code complexity 2024-02-20 20:48:29 +01:00
cde20e35d5 Uses matcher.find instead of matcher.matches
Also removes some code smells
2024-02-20 19:45:41 +01:00
9abf6db27a Alters the RegEx for replacing the plugin folder path 2024-02-20 19:29:27 +01:00
ee9bc21099 Fixes some code style issues, and attempts to fix test failures 2024-02-20 18:54:04 +01:00
e57aa4097c Adds a Message enum to avoid string keys 2024-02-20 16:18:38 +01:00
a9e5855194 Improves button and material customization
Allows specifying a comma-separated list of materials and tags for a portal's button, open-material, closed-material and border blocks. A random value is used if more than one material is available.0
Uses the supplied button if any, instead of enforcing the specified button material.
Always protects the button against block breaking.
Fixes an incorrect permission result in the previous commit, which caused players stargate access to be inverted.
2024-02-20 15:15:52 +01:00
b4a6ce1a77 Adds nullability annotations among other things
Adds nullability annotations for all methods
Fixes some nullability problems and inconsistencies
Gets rid of RelativeBlockVector's inner class
Changes RelativeBlockVector to a record
Simplifies FromTheEndTeleportation's storage, and makes it into a minimal record
Removes the putStringInList method
Gets rid of some primitive list usage
Fixes some incorrect method accessibility
Removes some redundancy in PortalOption
2024-02-20 12:43:01 +01:00
894a692e7b Fix #334 2024-02-19 22:22:09 +01:00
9154074a18 Removes a TODO that's already completed 2024-02-17 18:26:26 +01:00
c560063c06 Fixes incorrect formatting and unused imports 2024-02-17 18:22:27 +01:00
a4d4864bdd Checks markerAPIInitialized during dynmap initialization 2024-01-20 16:11:07 +01:00
d975666154 Fix failed tests 2024-01-07 18:36:54 +01:00
95058e86a6 Merge branch 'legacy' of https://github.com/stargate-rewritten/Stargate-Bukkit into legacy 2024-01-07 18:27:54 +01:00
Pheotis
8d6b233a8f Preparing for legacy release. 2024-01-07 12:13:39 -05:00
e20ddb52ef Update about.md 2023-12-29 16:55:41 +01:00
f657816533 Modify the about command 2023-12-29 12:43:58 +01:00
f37a196dd9 sg debug -> sg 2023-12-28 17:28:59 +01:00
44aadcd225 Implement the debug command 2023-12-28 17:25:13 +01:00
Thorinwasher
7cfec1190e Merge pull request #304 from furplag/legacy
fix exception occur when invalid yaw ( negative value ) given .
2023-12-28 17:11:26 +01:00
furplag
30cba7051c Update DirectionHelper.java
fix exception occur when invalid yaw ( negative value ) given .
2023-12-28 13:18:04 +09:00
e85f133bc2 Uses depositPlayer for negative economy transactions 2023-08-11 14:42:37 +02:00
0dfbcb0b54 Merge branch 'legacy' of https://github.com/stargate-rewritten/Stargate-Bukkit into legacy 2023-06-27 13:47:46 +02:00
3fcae6ca45 Tries to fix a stack trace when Dynmap fails to disable itself 2023-06-27 13:47:35 +02:00
Pheotis
902fc0aa4e Updated readme to prep for minor release. 2023-06-17 09:28:12 -04:00
3e8bfbe5f6 Bumped version 2023-06-17 15:26:49 +02:00
6b6e9d007e Fixes compatibility for pre-1.20 spigot 2023-06-17 14:37:05 +02:00
Pheotis
ef2238a535 Update README.md 2023-06-07 16:56:12 -04:00
27fba221d6 Adds per-sign color settings for the new signs 2023-06-07 22:25:41 +02:00
1c06cf2188 Updates depreciated sign API calls 2023-06-07 18:35:22 +02:00
Pheotis
22f4cb78f6 Bumped Version 2023-06-01 19:24:37 -04:00
Pheotis
732cabd040 Update readme for release bump 2023-06-01 19:24:20 -04:00
9d48374d28 Possibly fixes #296 2023-05-31 17:13:13 +02:00
Pheotis
6f88eecb41 Update changelog and bumps version.
(Preparing for minor release)
2023-05-21 08:21:33 -04:00
0d073a7dad Fixes #291 2023-05-21 10:58:42 +02:00
cbc9e85314 Fixes some formatting again 2023-04-21 17:56:10 +02:00
Pheotis
b3428877ba Cleaned up Config & Updated Changelog 2023-04-21 11:49:27 -04:00
Pheotis
30a5efdadf Bumped version, added changelog, fixed readme . 2023-04-21 10:17:08 -04:00
53126beba3 Adds author to StargateYamlConfiguration 2023-04-21 16:15:03 +02:00
4f7bab8a1a Merge pull request #288 from stargate-rewritten/legacy-config-migration
Legacy config migration
2023-04-21 13:11:56 +00:00
9a215a7c11 Attempts to make SonarCloud happier 2023-04-21 15:10:20 +02:00
e07adacf73 Reduces the complexity of convertYAMLMappingsToComments 2023-04-21 14:53:23 +02:00
05fadfa558 Removes stack trace printing 2023-04-21 14:03:33 +02:00
fab067c94b Fixes #287 2023-04-21 13:56:18 +02:00
45f3bcc415 Improves logging a bit 2023-04-21 13:41:42 +02:00
50015c2912 Adds graceful shutdown for CraftBukkit #286 2023-04-21 12:53:43 +02:00
486149fa01 Improves performance of StargateYamlConfiguration a bit 2023-04-20 18:44:46 +02:00
9d981f2cc6 Fixes a crash caused by StargateYamlConfiguration 2023-04-20 16:02:57 +02:00
aa480faef2 Improves behavior if the config cannot be loaded 2023-04-19 23:13:02 +02:00
24b62ec749 Attempts to properly comment migrated config values
Note that for some reason, YamlConfiguration cannot load the output created by StargateYamlConfiguration causing a major crash
2023-04-19 22:17:29 +02:00
032a4df4d7 Overrides saving 2023-04-19 20:51:35 +02:00
c3752db99b Adds a custom configuration to retain comments 2023-04-19 20:03:23 +02:00
17bb27d553 Merge branch 'legacy' of https://github.com/stargate-rewritten/Stargate-Bukkit into legacy 2023-04-19 19:00:07 +02:00
6737a4f789 Adds the missing taxAccounts option 2023-04-19 19:00:02 +02:00
Pheotis
b0b31e04fc Removed some potentially confusing abbreviations 2023-04-19 12:40:22 -04:00
2074904aef Improves configuration comments 2023-04-19 18:34:37 +02:00
421e0b17e2 Updates the resource id for the update checker
This change makes the update checker look at https://www.spigotmc.org/resources/stargate.109355/ for updates, instead of the legacy with incorrect version numbering: https://www.spigotmc.org/resources/stargate-old.87978/
2023-04-19 11:06:52 +00:00
Pheotis
e6c92f9322 Fixed maven shade to handle bstats and knarlib. 2023-03-25 17:02:55 -04:00
bd947d5c94 Merge branch 'temp-legacy' of https://github.com/stargate-rewritten/Stargate-Bukkit into temp-legacy 2023-03-25 02:57:38 +01:00
7e46fa413e Relocates BStats, but KnarLib is not properly shaded 2023-03-25 02:57:23 +01:00
Pheotis
77fec1d5de Fixed a mismatch re the increased character limit. 2023-03-24 21:51:09 -04:00
Pheotis
24890a4b5d Fixed a text oversight. 2023-03-24 21:48:50 -04:00
Pheotis
3834ef04d4 Updated the readme to reflect the merger. 2023-03-24 21:45:55 -04:00
a20a1c2f00 Renames the I-flag to the Q-flag 2023-03-25 02:18:28 +01:00
472aeda2f8 Implements BStats statistics 2023-03-25 02:18:05 +01:00
c1720e05a0 Adds a wool gate amongst other things
Adds the wool gate type from legacy
Adds some missing material tag-related code
Updates the URL for update checking
2023-03-25 01:54:43 +01:00
91d855312d Changes the E flag to a V flag for rewrite consistency 2023-03-24 23:52:18 +01:00
10a16000c6 Removes unused frameTypes variable 2023-03-24 23:46:21 +01:00
454bac6f14 Implements support for character tags 2023-03-24 23:44:17 +01:00
f8cddea188 Adds one missing legacy config conversion 2023-03-24 22:48:37 +01:00
06271a356e Updates Vault repository 2023-03-24 21:57:06 +01:00
79bf297513 Updates some dependencies 2023-03-24 21:47:41 +01:00
36f09d5b29 Updates website URL to a shortcut 2023-03-24 21:29:13 +01:00
5a2766c4c6 Updates website URL 2023-03-24 20:58:18 +01:00
b63bd19db0 Sets the Spigot API version to 1.16 2023-03-24 20:56:34 +01:00
2bdcc0da8d Merge remote-tracking branch 'origin/temp-legacy' into temp-legacy
# Conflicts:
#	pom.xml
2023-03-24 20:50:28 +01:00
1f4aeefad1 Bumps version and removes Jenkinsfile
Bumps version to 0.11.5.0-SNAPSHOT for consistency
2023-03-24 20:47:31 +01:00
Pheotis
12a2d4eb71 Merged temp-legacy's versioning with legacy's
This is now a major version ahead of SGR's legacy.
2023-03-24 15:45:15 -04:00
Pheotis
69ae5ea3de Merge remote-tracking branch 'knarvik/master' into temp-legacy 2023-03-24 15:37:03 -04:00
Michael Smith
4bdcd9992b Fix repository URL 2022-03-25 23:48:40 -07:00
121 changed files with 4525 additions and 3650 deletions

4
.gitignore vendored
View File

@@ -1,2 +1,6 @@
target/ target/
.idea/ .idea/
*.secret
*.db
nbactions.xml
stargate.iml

674
LICENSE
View File

@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

911
README.md

File diff suppressed because it is too large Load Diff

121
pom.xml
View File

@@ -4,7 +4,7 @@
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>Stargate</artifactId> <artifactId>Stargate</artifactId>
<version>0.9.4.3-SNAPSHOT</version> <version>0.11.5.12-SNAPSHOT</version>
<licenses> <licenses>
<license> <license>
@@ -28,8 +28,8 @@
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url> <url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository> </repository>
<repository> <repository>
<id>vault-repo</id> <id>jitpack.io</id>
<url>https://nexus.hc.to/content/repositories/pub_releases</url> <url>https://jitpack.io</url>
</repository> </repository>
<repository> <repository>
<id>dynmap</id> <id>dynmap</id>
@@ -39,7 +39,16 @@
<id>papermc</id> <id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url> <url>https://repo.papermc.io/repository/maven-public/</url>
</repository> </repository>
<repository>
<id>minebench-repo</id>
<url>https://repo.minebench.de/</url>
</repository>
<repository>
<id>opencollab-snapshot</id>
<url>https://repo.opencollab.dev/main/</url>
</repository>
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<repository> <repository>
<id>knarcraft-repo</id> <id>knarcraft-repo</id>
@@ -55,51 +64,68 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.19.3-R0.1-SNAPSHOT</version> <version>1.21.8-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.milkbowl.vault</groupId> <groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId> <artifactId>VaultAPI</artifactId>
<version>1.7</version> <version>1.7.1</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.18</artifactId>
<version>2.85.2</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jetbrains</groupId> <groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId> <artifactId>annotations</artifactId>
<version>23.0.0</version> <version>26.0.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>us.dynmap</groupId> <groupId>us.dynmap</groupId>
<artifactId>dynmap-api</artifactId> <artifactId>dynmap-api</artifactId>
<version>3.1-beta-2</version> <version>3.5</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>knarlib</artifactId> <artifactId>knarlib</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.2.18</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-base</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>de.themoep</groupId>
<artifactId>minedown</artifactId>
<version>1.7.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.geysermc.geyser</groupId>
<artifactId>api</artifactId>
<version>2.2.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>api</artifactId>
<version>2.2.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -116,7 +142,8 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version> <version>3.4.1</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -125,7 +152,37 @@
</goals> </goals>
<configuration> <configuration>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>net.knarcraft.stargate.lib.metrics</shadedPattern>
</relocation>
<relocation>
<pattern>net.knarcraft.knarlib</pattern>
<shadedPattern>net.knarcraft.stargate.lib.knarlib</shadedPattern>
</relocation>
<relocation>
<pattern>de.themoep</pattern>
<shadedPattern>net.knarcraft.stargate.lib.minedown</shadedPattern>
</relocation>
<relocation>
<pattern>org.jetbrains.annotations</pattern>
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
</relocation>
</relocations>
<filters> <filters>
<filter>
<artifact>de.themoep:minedown</artifact>
<includes>
<include>de/themoep/minedown/**</include>
</includes>
</filter>
<filter>
<artifact>org.bstats</artifact>
<includes>
<include>org/bstats/**</include>
</includes>
</filter>
<filter> <filter>
<artifact>net.knarcraft:knarlib</artifact> <artifact>net.knarcraft:knarlib</artifact>
<includes> <includes>
@@ -133,10 +190,10 @@
</includes> </includes>
</filter> </filter>
<filter> <filter>
<excludes> <artifact>org.jetbrains:annotations</artifact>
<exclude>*.MF</exclude> <includes>
<exclude>*.yml</exclude> <include>org/jetbrains/annotations/**</include>
</excludes> </includes>
</filter> </filter>
</filters> </filters>
</configuration> </configuration>

View File

@@ -1,180 +0,0 @@
package net.knarcraft.stargate;
import org.bukkit.Axis;
import org.bukkit.block.BlockFace;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* A class for performing rotational operations on vectors
*
* @author Kristian Knarvik
*/
@SuppressWarnings("unused")
public class SimpleVectorOperation {
private static final Map<BlockFace, Double> rotationAngles = new HashMap<>();
private static final Map<BlockFace, Vector> rotationAxes = new HashMap<>();
private static final Map<BlockFace, Axis> normalAxes = new HashMap<>();
private static final BlockFace defaultDirection = BlockFace.SOUTH;
private static final Axis defaultVerticalAxis = Axis.Y;
private final Axis normalAxis;
private boolean flipZAxis = false;
private final BlockFace facing;
/**
* Instantiates a vector operation to rotate vectors in the direction of a sign face
*
* @param signFace <p>The sign face of a gate's sign</p>
*/
public SimpleVectorOperation(BlockFace signFace) {
if (normalAxes.isEmpty()) {
initializeIrisNormalAxes();
initializeOperations();
}
this.facing = signFace;
this.normalAxis = normalAxes.get(signFace);
}
/**
* Gets the block face of a sign given upon instantiation
*
* @return <p>The block face of a sign given upon instantiation</p>
*/
public BlockFace getFacing() {
return facing;
}
/**
* Gets the normal axis orthogonal to the opening plane
*
* <p>Said another way, get the axis going directly towards or away from a stargate's entrance.</p>
*
* @return <p>The normal axis orthogonal to the opening plane</p>
*/
public Axis getNormalAxis() {
return normalAxis;
}
/**
* Sets whether to flip the Z- axis
*
* @param flipZAxis <p>Whether to flip the z-axis</p>
*/
public void setFlipZAxis(boolean flipZAxis) {
this.flipZAxis = flipZAxis;
}
/**
* Performs an operation from the real space to the vector space
*
* @param vector <p>The vector to perform the operation on</p>
* @return vector <p>A new vector with the operation applied</p>
*/
public Vector performToAbstractSpaceOperation(@NotNull Vector vector) {
Vector clone = vector.clone();
clone.rotateAroundAxis(rotationAxes.get(facing), rotationAngles.get(facing));
if (flipZAxis) {
clone.setZ(-clone.getZ());
}
return clone;
}
/**
* Performs an operation from the vector space to the real space
*
* @param vector <p>The vector to perform the inverse operation on</p>
* @return vector <p>A new vector with the operation applied</p>
*/
public Vector performToRealSpaceOperation(@NotNull Vector vector) {
Vector clone = vector.clone();
if (flipZAxis) {
clone.setZ(-clone.getZ());
}
return clone.rotateAroundAxis(rotationAxes.get(facing), -rotationAngles.get(facing));
}
/**
* Performs an operation from the vector space to the real space
*
* @param vector <p>The vector to perform the inverse operation on</p>
* @return vector <p>A new vector with the operation applied</p>
*/
public BlockVector performToRealSpaceOperation(@NotNull BlockVector vector) {
return performToRealSpaceOperation((Vector) vector).toBlockVector();
}
/**
* Initializes the operations used for rotating to each block-face
*/
private static void initializeOperations() {
Map<Axis, Vector> axisVectors = new HashMap<>();
axisVectors.put(Axis.Y, new Vector(0, 1, 0));
axisVectors.put(Axis.X, new Vector(1, 0, 0));
axisVectors.put(Axis.Z, new Vector(0, 0, 1));
//Use the cross product to find the correct axis
for (BlockFace face : normalAxes.keySet()) {
Vector crossProduct = face.getDirection().crossProduct(defaultDirection.getDirection());
if (face == defaultDirection || face == defaultDirection.getOppositeFace()) {
rotationAxes.put(face, axisVectors.get(defaultVerticalAxis));
} else if (Math.abs(crossProduct.getZ()) > 0) {
rotationAxes.put(face, axisVectors.get(Axis.Z));
} else if (Math.abs(crossProduct.getY()) > 0) {
rotationAxes.put(face, axisVectors.get(Axis.Y));
} else {
rotationAxes.put(face, axisVectors.get(Axis.X));
}
}
calculateRotations();
}
/**
* Calculates the required rotations based on the default rotation
*/
private static void calculateRotations() {
double halfRotation = Math.PI;
double quarterRotation = halfRotation / 2;
Vector defaultDirectionVector = defaultDirection.getDirection();
boolean defaultDirectionPositive = defaultDirectionVector.getX() + defaultDirectionVector.getY() +
defaultDirectionVector.getZ() > 0;
for (BlockFace blockFace : normalAxes.keySet()) {
if (defaultDirection == blockFace) {
//The default direction requires no rotation
rotationAngles.put(blockFace, 0d);
} else if (defaultDirection.getOppositeFace() == blockFace) {
//The opposite direction requires a half rotation
rotationAngles.put(blockFace, halfRotation);
} else {
//All the other used directions require a quarter rotation
Vector faceDirectionVector = blockFace.getDirection();
boolean faceDirectionPositive = faceDirectionVector.getX() + faceDirectionVector.getY() +
faceDirectionVector.getZ() > 0;
double rotation = defaultDirectionPositive && faceDirectionPositive ? quarterRotation : -quarterRotation;
rotationAngles.put(blockFace, rotation);
}
}
}
/**
* Initializes the iris normal axes corresponding to each block face
*/
private static void initializeIrisNormalAxes() {
normalAxes.put(BlockFace.EAST, Axis.Z);
normalAxes.put(BlockFace.WEST, Axis.Z);
normalAxes.put(BlockFace.NORTH, Axis.X);
normalAxes.put(BlockFace.SOUTH, Axis.X);
normalAxes.put(BlockFace.UP, Axis.Y);
normalAxes.put(BlockFace.DOWN, Axis.Y);
}
}

View File

@@ -1,14 +1,20 @@
package net.knarcraft.stargate; package net.knarcraft.stargate;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.Translator;
import net.knarcraft.knarlib.plugin.ConfigCommentPlugin;
import net.knarcraft.knarlib.util.ConfigHelper;
import net.knarcraft.knarlib.util.UpdateChecker; import net.knarcraft.knarlib.util.UpdateChecker;
import net.knarcraft.stargate.command.CommandStarGate; import net.knarcraft.stargate.command.CommandStarGate;
import net.knarcraft.stargate.command.StarGateTabCompleter; import net.knarcraft.stargate.command.StarGateTabCompleter;
import net.knarcraft.stargate.config.EconomyConfig; import net.knarcraft.stargate.config.EconomyConfig;
import net.knarcraft.stargate.config.MessageSender; import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.config.StargateConfig; import net.knarcraft.stargate.config.StargateConfig;
import net.knarcraft.stargate.config.StargateGateConfig; import net.knarcraft.stargate.config.StargateGateConfig;
import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.ChunkUnloadRequest; import net.knarcraft.stargate.container.ChunkUnloadRequest;
import net.knarcraft.stargate.container.ControlBlockUpdateRequest;
import net.knarcraft.stargate.listener.BlockEventListener; import net.knarcraft.stargate.listener.BlockEventListener;
import net.knarcraft.stargate.listener.EntityEventListener; import net.knarcraft.stargate.listener.EntityEventListener;
import net.knarcraft.stargate.listener.EntitySpawnListener; import net.knarcraft.stargate.listener.EntitySpawnListener;
@@ -22,15 +28,16 @@ import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.thread.BlockChangeThread; import net.knarcraft.stargate.thread.BlockChangeThread;
import net.knarcraft.stargate.thread.ChunkUnloadThread; import net.knarcraft.stargate.thread.ChunkUnloadThread;
import net.knarcraft.stargate.thread.ControlBlocksUpdateThread;
import net.knarcraft.stargate.thread.StarGateThread; import net.knarcraft.stargate.thread.StarGateThread;
import org.bukkit.Server; import net.knarcraft.stargate.utility.BStatsHelper;
import org.bukkit.command.PluginCommand; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.util.LinkedList; import java.util.LinkedList;
@@ -45,7 +52,7 @@ Copyright (C) 2011 Shaun (sturmeh)
Copyright (C) 2011 Dinnerbone Copyright (C) 2011 Dinnerbone
Copyright (C) 2011-2013 Steven "Drakia" Scott <Contact@TheDgtl.net> Copyright (C) 2011-2013 Steven "Drakia" Scott <Contact@TheDgtl.net>
Copyright (C) 2015-2020 Michael Smith (PseudoKnight) Copyright (C) 2015-2020 Michael Smith (PseudoKnight)
Copyright (C) 2021-2022 Kristian Knarvik (EpicKnarvik97) Copyright (C) 2021-2025 Kristian Knarvik (EpicKnarvik97)
The following license notice applies to all source and resource files in the Stargate project: The following license notice applies to all source and resource files in the Stargate project:
@@ -67,9 +74,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* The main class of the Stargate plugin * The main class of the Stargate plugin
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Stargate extends JavaPlugin { public class Stargate extends ConfigCommentPlugin {
private static final Queue<BlockChangeRequest> blockChangeRequestQueue = new LinkedList<>(); private static final String CONFIG_FILE_NAME = "config.yml";
private static final Queue<BlockChangeRequest> controlBlockUpdateRequestQueue = new LinkedList<>();
private static final Queue<ControlBlockUpdateRequest> CONTROL_BLOCK_UPDATE_REQUEST_QUEUE = new LinkedList<>();
private static final Queue<ChunkUnloadRequest> chunkUnloadQueue = new PriorityQueue<>(); private static final Queue<ChunkUnloadRequest> chunkUnloadQueue = new PriorityQueue<>();
private static Logger logger; private static Logger logger;
@@ -105,7 +114,7 @@ public class Stargate extends JavaPlugin {
* *
* @param version <p>The version of the new update available</p> * @param version <p>The version of the new update available</p>
*/ */
public static void setUpdateAvailable(String version) { public static void setUpdateAvailable(@NotNull String version) {
updateAvailable = version; updateAvailable = version;
} }
@@ -114,6 +123,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The version number if an update is available. Null otherwise</p> * @return <p>The version number if an update is available. Null otherwise</p>
*/ */
@Nullable
public static String getUpdateAvailable() { public static String getUpdateAvailable() {
return updateAvailable; return updateAvailable;
} }
@@ -123,6 +133,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>An instance of this plugin, or null if not instantiated</p> * @return <p>An instance of this plugin, or null if not instantiated</p>
*/ */
@NotNull
public static Stargate getInstance() { public static Stargate getInstance() {
return stargate; return stargate;
} }
@@ -132,28 +143,41 @@ public class Stargate extends JavaPlugin {
* *
* @param request <p>The request to add</p> * @param request <p>The request to add</p>
*/ */
public static void addBlockChangeRequest(BlockChangeRequest request) { public static void addControlBlockUpdateRequest(@Nullable BlockChangeRequest request) {
if (request != null) { if (request != null) {
blockChangeRequestQueue.add(request); controlBlockUpdateRequestQueue.add(request);
} }
} }
/** /**
* Gets the queue containing block change requests * Gets the queue containing control block update requests
* *
* @return <p>A block change request queue</p> * @return <p>A control block update request queue</p>
*/ */
public static Queue<BlockChangeRequest> getBlockChangeRequestQueue() { @NotNull
return blockChangeRequestQueue; public static Queue<BlockChangeRequest> getControlBlockUpdateRequestQueue() {
return controlBlockUpdateRequestQueue;
} }
/** /**
* Gets the sender for sending messages to players * Adds a control block update request to the request queue
* *
* @return <p>The sender for sending messages to players</p> * @param request <p>The request to add</p>
*/ */
public static MessageSender getMessageSender() { public static void addControlBlockUpdateRequest(@Nullable ControlBlockUpdateRequest request) {
return stargateConfig.getMessageSender(); if (request != null) {
CONTROL_BLOCK_UPDATE_REQUEST_QUEUE.add(request);
}
}
/**
* Gets the queue containing button update requests
*
* @return <p>A button update request queue</p>
*/
@NotNull
public static Queue<ControlBlockUpdateRequest> getButtonUpdateRequestQueue() {
return CONTROL_BLOCK_UPDATE_REQUEST_QUEUE;
} }
/** /**
@@ -161,6 +185,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The object containing gate configuration values</p> * @return <p>The object containing gate configuration values</p>
*/ */
@NotNull
public static StargateGateConfig getGateConfig() { public static StargateGateConfig getGateConfig() {
return stargateConfig.getStargateGateConfig(); return stargateConfig.getStargateGateConfig();
} }
@@ -170,6 +195,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>This plugin's version</p> * @return <p>This plugin's version</p>
*/ */
@NotNull
public static String getPluginVersion() { public static String getPluginVersion() {
return pluginVersion; return pluginVersion;
} }
@@ -179,6 +205,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The logger</p> * @return <p>The logger</p>
*/ */
@NotNull
public static Logger getConsoleLogger() { public static Logger getConsoleLogger() {
return logger; return logger;
} }
@@ -199,8 +226,8 @@ public class Stargate extends JavaPlugin {
* @param route <p>The class name/route where something happened</p> * @param route <p>The class name/route where something happened</p>
* @param message <p>A message describing what happened</p> * @param message <p>A message describing what happened</p>
*/ */
public static void debug(String route, String message) { public static void debug(@NotNull String route, @NotNull String message) {
if (stargateConfig == null || stargateConfig.isDebuggingEnabled()) { if (stargateConfig == null || stargateConfig.isNotLoaded() || stargateConfig.isDebuggingEnabled()) {
logger.info("[Stargate::" + route + "] " + message); logger.info("[Stargate::" + route + "] " + message);
} else { } else {
logger.log(Level.FINEST, "[Stargate::" + route + "] " + message); logger.log(Level.FINEST, "[Stargate::" + route + "] " + message);
@@ -212,8 +239,8 @@ public class Stargate extends JavaPlugin {
* *
* @param message <p>The message to log</p> * @param message <p>The message to log</p>
*/ */
public static void logInfo(String message) { public static void logInfo(@NotNull String message) {
logger.info(getBackupString("prefix") + message); log(Level.INFO, message);
} }
/** /**
@@ -221,7 +248,7 @@ public class Stargate extends JavaPlugin {
* *
* @param message <p>The message to log</p> * @param message <p>The message to log</p>
*/ */
public static void logSevere(String message) { public static void logSevere(@NotNull String message) {
log(Level.SEVERE, message); log(Level.SEVERE, message);
} }
@@ -230,7 +257,7 @@ public class Stargate extends JavaPlugin {
* *
* @param message <p>The message to log</p> * @param message <p>The message to log</p>
*/ */
public static void logWarning(String message) { public static void logWarning(@NotNull String message) {
log(Level.WARNING, message); log(Level.WARNING, message);
} }
@@ -240,8 +267,11 @@ public class Stargate extends JavaPlugin {
* @param severity <p>The severity of the event triggering the message</p> * @param severity <p>The severity of the event triggering the message</p>
* @param message <p>The message to log</p> * @param message <p>The message to log</p>
*/ */
private static void log(Level severity, String message) { private static void log(@NotNull Level severity, @NotNull String message) {
logger.log(severity, getBackupString("prefix") + message); if (logger == null) {
logger = Bukkit.getLogger();
}
logger.log(severity, message);
} }
/** /**
@@ -251,6 +281,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The folder for storing the portal database</p> * @return <p>The folder for storing the portal database</p>
*/ */
@NotNull
public static String getPortalFolder() { public static String getPortalFolder() {
return stargateConfig.getPortalFolder(); return stargateConfig.getPortalFolder();
} }
@@ -262,6 +293,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The folder storing gate files</p> * @return <p>The folder storing gate files</p>
*/ */
@NotNull
public static String getGateFolder() { public static String getGateFolder() {
return stargateConfig.getGateFolder(); return stargateConfig.getGateFolder();
} }
@@ -271,51 +303,27 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The default network</p> * @return <p>The default network</p>
*/ */
@NotNull
public static String getDefaultNetwork() { public static String getDefaultNetwork() {
return stargateConfig.getStargateGateConfig().getDefaultPortalNetwork(); return stargateConfig.getStargateGateConfig().getDefaultPortalNetwork();
} }
/** /**
* Gets a translated string given its string key * Gets a backup string given its message key
*
* <p>The name/key is the string before the equals sign in the language files</p>
*
* @param name <p>The name/key of the string to get</p>
* @return <p>The full translated string</p>
*/
public static String getString(String name) {
return stargateConfig.getLanguageLoader().getString(name);
}
/**
* Gets a backup string given its string key
*
* <p>The name/key is the string before the equals sign in the language files</p>
* *
* @param name <p>The name/key of the string to get</p> * @param name <p>The name/key of the string to get</p>
* @return <p>The full string in the backup language (English)</p> * @return <p>The full string in the backup language (English)</p>
*/ */
public static String getBackupString(String name) { public static @NotNull String getBackupString(@NotNull Message name) {
return stargateConfig.getLanguageLoader().getBackupString(name); return stargateConfig.getLanguageLoader().getBackupString(name);
} }
/**
* Replaces a variable in a string
*
* @param input <p>The input containing the variables</p>
* @param search <p>The variable to replace</p>
* @param value <p>The replacement value</p>
* @return <p>The input string with the search replaced with value</p>
*/
public static String replaceVars(String input, String search, String value) {
return input.replace(search, value);
}
/** /**
* Gets this plugin's plugin manager * Gets this plugin's plugin manager
* *
* @return <p>A plugin manager</p> * @return <p>A plugin manager</p>
*/ */
@NotNull
public static PluginManager getPluginManager() { public static PluginManager getPluginManager() {
return pluginManager; return pluginManager;
} }
@@ -325,6 +333,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The object containing economy config values</p> * @return <p>The object containing economy config values</p>
*/ */
@NotNull
public static EconomyConfig getEconomyConfig() { public static EconomyConfig getEconomyConfig() {
return stargateConfig.getEconomyConfig(); return stargateConfig.getEconomyConfig();
} }
@@ -333,24 +342,34 @@ public class Stargate extends JavaPlugin {
public void onDisable() { public void onDisable() {
PortalHandler.closeAllPortals(); PortalHandler.closeAllPortals();
PortalRegistry.clearPortals(); PortalRegistry.clearPortals();
stargateConfig.clearManagedWorlds(); if (stargateConfig != null) {
stargateConfig.clearManagedWorlds();
}
getServer().getScheduler().cancelTasks(this); getServer().getScheduler().cancelTasks(this);
} }
@Override @Override
public void onEnable() { public void onEnable() {
Stargate.stargate = this;
Stargate.logger = getLogger();
ConfigHelper.saveDefaults(this);
PluginDescriptionFile pluginDescriptionFile = this.getDescription(); PluginDescriptionFile pluginDescriptionFile = this.getDescription();
pluginManager = getServer().getPluginManager(); pluginManager = getServer().getPluginManager();
FileConfiguration newConfig = this.getConfig();
this.saveDefaultConfig();
newConfig.options().copyDefaults(true);
logger = Logger.getLogger("Minecraft"); // Set temporary string formatter before strings are loaded
Server server = getServer(); SGFormatBuilder.setStringFormatter(new StringFormatter(this.getDescription().getName(), new Translator()));
stargate = this;
stargateConfig = new StargateConfig(logger); try {
stargateConfig.finishSetup(); stargateConfig = new StargateConfig(logger);
stargateConfig.finishSetup();
} catch (NoClassDefFoundError exception) {
logSevere("Could not properly load. Class not found: " +
exception.getMessage() + "\nThis is probably because you are using CraftBukkit, or other outdated" +
"Minecraft server software. Minecraft server software based on Spigot or Paper is required. Paper" +
" is recommended, and can be downloaded at: https://papermc.io/downloads/paper");
this.onDisable();
return;
}
pluginVersion = pluginDescriptionFile.getVersion(); pluginVersion = pluginDescriptionFile.getVersion();
@@ -362,11 +381,13 @@ public class Stargate extends JavaPlugin {
//Run necessary threads //Run necessary threads
runThreads(); runThreads();
this.registerCommands(); registerCommand("stargate", new CommandStarGate(this), new StarGateTabCompleter());
//Check for any available updates //Check for any available updates
UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=97784", UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=109355",
Stargate::getPluginVersion, Stargate::setUpdateAvailable); Stargate::getPluginVersion, Stargate::setUpdateAvailable);
BStatsHelper.initialize(this);
} }
/** /**
@@ -376,6 +397,8 @@ public class Stargate extends JavaPlugin {
BukkitScheduler scheduler = getServer().getScheduler(); BukkitScheduler scheduler = getServer().getScheduler();
scheduler.runTaskTimer(this, new StarGateThread(), 0L, 100L); scheduler.runTaskTimer(this, new StarGateThread(), 0L, 100L);
scheduler.runTaskTimer(this, new BlockChangeThread(), 0L, 1L); scheduler.runTaskTimer(this, new BlockChangeThread(), 0L, 1L);
scheduler.runTaskTimer(this, new ControlBlocksUpdateThread(), 0L,
getStargateConfig().getStargateGateConfig().controlUpdateDelay());
scheduler.runTaskTimer(this, new ChunkUnloadThread(), 0L, 100L); scheduler.runTaskTimer(this, new ChunkUnloadThread(), 0L, 100L);
} }
@@ -395,22 +418,12 @@ public class Stargate extends JavaPlugin {
pluginManager.registerEvents(new EntitySpawnListener(), this); pluginManager.registerEvents(new EntitySpawnListener(), this);
} }
/**
* Registers a command for this plugin
*/
private void registerCommands() {
PluginCommand stargateCommand = this.getCommand("stargate");
if (stargateCommand != null) {
stargateCommand.setExecutor(new CommandStarGate());
stargateCommand.setTabCompleter(new StarGateTabCompleter());
}
}
/** /**
* Gets the chunk unload queue containing chunks to unload * Gets the chunk unload queue containing chunks to unload
* *
* @return <p>The chunk unload queue</p> * @return <p>The chunk unload queue</p>
*/ */
@NotNull
public static Queue<ChunkUnloadRequest> getChunkUnloadQueue() { public static Queue<ChunkUnloadRequest> getChunkUnloadQueue() {
return chunkUnloadQueue; return chunkUnloadQueue;
} }
@@ -420,7 +433,7 @@ public class Stargate extends JavaPlugin {
* *
* @param request <p>The new chunk unload request to add</p> * @param request <p>The new chunk unload request to add</p>
*/ */
public static void addChunkUnloadRequest(ChunkUnloadRequest request) { public static void addChunkUnloadRequest(@NotNull ChunkUnloadRequest request) {
chunkUnloadQueue.removeIf((item) -> item.getChunkToUnload().equals(request.getChunkToUnload())); chunkUnloadQueue.removeIf((item) -> item.getChunkToUnload().equals(request.getChunkToUnload()));
chunkUnloadQueue.add(request); chunkUnloadQueue.add(request);
} }
@@ -430,6 +443,7 @@ public class Stargate extends JavaPlugin {
* *
* @return <p>The stargate configuration</p> * @return <p>The stargate configuration</p>
*/ */
@NotNull
public static StargateConfig getStargateConfig() { public static StargateConfig getStargateConfig() {
return stargateConfig; return stargateConfig;
} }

View File

@@ -1,12 +1,20 @@
package net.knarcraft.stargate.command; package net.knarcraft.stargate.command;
import de.themoep.minedown.MineDown;
import net.knarcraft.knarlib.util.FileHelper;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/** /**
* This command represents the plugin's about command * This command represents the plugin's about command
*/ */
@@ -18,11 +26,19 @@ public class CommandAbout implements CommandExecutor {
ChatColor textColor = ChatColor.GOLD; ChatColor textColor = ChatColor.GOLD;
ChatColor highlightColor = ChatColor.GREEN; ChatColor highlightColor = ChatColor.GREEN;
commandSender.sendMessage(textColor + "Stargate Plugin originally created by " + highlightColor +
"Drakia" + textColor + ", and revived by " + highlightColor + "EpicKnarvik97");
commandSender.sendMessage(textColor + "Go to " + highlightColor + try (InputStream inputStream = FileHelper.getInputStreamForInternalFile("/messages/about.md")) {
"https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository"); if (inputStream != null) {
String author = Stargate.getStargateConfig().getLanguageLoader().getString("author"); List<String> lines = FileHelper.readLines(FileHelper.getBufferedReaderFromInputStream(inputStream));
String aboutMessageString = String.join("\n", lines);
BaseComponent[] component = MineDown.parse(aboutMessageString);
commandSender.spigot().sendMessage(component);
}
} catch (IOException ioException) {
commandSender.sendMessage("Internal error");
}
String author = Stargate.getStargateConfig().getLanguageLoader().getString(Message.AUTHOR);
if (!author.isEmpty()) { if (!author.isEmpty()) {
commandSender.sendMessage(textColor + "Language created by " + highlightColor + author); commandSender.sendMessage(textColor + "Language created by " + highlightColor + author);
} }

View File

@@ -4,7 +4,9 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption; import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.ConfigTag; import net.knarcraft.stargate.config.ConfigTag;
import net.knarcraft.stargate.config.DynmapManager; import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.OptionDataType; import net.knarcraft.stargate.config.OptionDataType;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.PortalSignDrawer; import net.knarcraft.stargate.portal.PortalSignDrawer;
@@ -16,6 +18,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -30,7 +33,7 @@ public class CommandConfig implements CommandExecutor {
@NotNull String[] args) { @NotNull String[] args) {
if (commandSender instanceof Player player) { if (commandSender instanceof Player player) {
if (!player.hasPermission("stargate.admin.config")) { if (!player.hasPermission("stargate.admin.config")) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied"); new SGFormatBuilder("Permission Denied").error(commandSender);
return true; return true;
} }
} }
@@ -65,7 +68,8 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender <p>The command sender that changed the value</p> * @param commandSender <p>The command sender that changed the value</p>
* @param value <p>The new value of the config option</p> * @param value <p>The new value of the config option</p>
*/ */
private void updateConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) { private void updateConfigValue(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender,
@NotNull String value) {
FileConfiguration configuration = Stargate.getInstance().getConfig(); FileConfiguration configuration = Stargate.getInstance().getConfig();
//Validate any sign colors //Validate any sign colors
@@ -119,7 +123,8 @@ public class CommandConfig implements CommandExecutor {
* @param value <p>The new value of the config option</p> * @param value <p>The new value of the config option</p>
* @param configuration <p>The configuration file to save to</p> * @param configuration <p>The configuration file to save to</p>
*/ */
private void updateBooleanConfigValue(ConfigOption selectedOption, String value, FileConfiguration configuration) { private void updateBooleanConfigValue(@NotNull ConfigOption selectedOption, @NotNull String value,
@NotNull FileConfiguration configuration) {
boolean newValue = Boolean.parseBoolean(value); boolean newValue = Boolean.parseBoolean(value);
if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) { if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) {
Stargate.getStargateConfig().startStopBungeeListener(newValue); Stargate.getStargateConfig().startStopBungeeListener(newValue);
@@ -135,7 +140,8 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender <p>The command sender that changed the value</p> * @param commandSender <p>The command sender that changed the value</p>
* @param value <p>The new value of the config option</p> * @param value <p>The new value of the config option</p>
*/ */
private void updateStringConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) { private void updateStringConfigValue(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender,
@NotNull String value) {
if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER || if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER ||
selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) { selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) {
if (value.contains("../") || value.contains("..\\")) { if (value.contains("../") || value.contains("..\\")) {
@@ -161,13 +167,13 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender <p>The command sender that changed the value</p> * @param commandSender <p>The command sender that changed the value</p>
* @param arguments <p>The arguments for the new config option</p> * @param arguments <p>The arguments for the new config option</p>
*/ */
private void updateListConfigValue(ConfigOption selectedOption, CommandSender commandSender, String[] arguments) { private void updateListConfigValue(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender,
@NotNull String[] arguments) {
FileConfiguration configuration = Stargate.getInstance().getConfig(); FileConfiguration configuration = Stargate.getInstance().getConfig();
if (selectedOption == ConfigOption.PER_SIGN_COLORS) { if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
if (arguments.length < 4) { if (arguments.length < 4) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "Usage: /sg config perSignColors " + new SGFormatBuilder("Usage: /sg config perSignColors <SIGN_TYPE> <MAIN_COLOR> <HIGHLIGHTING_COLOR>").error(commandSender);
"<SIGN_TYPE> <MAIN_COLOR> <HIGHLIGHTING_COLOR>");
return; return;
} }
@@ -190,22 +196,24 @@ public class CommandConfig implements CommandExecutor {
* @param arguments <p>The arguments given by the user</p> * @param arguments <p>The arguments given by the user</p>
* @return <p>The per-sign color string to update with, or null if the input was invalid</p> * @return <p>The per-sign color string to update with, or null if the input was invalid</p>
*/ */
private String parsePerSignColorInput(CommandSender commandSender, String[] arguments) { @Nullable
private String parsePerSignColorInput(@NotNull CommandSender commandSender, @NotNull String[] arguments) {
//Make sure the sign type is an actual sign //Make sure the sign type is an actual sign
if (Material.matchMaterial(arguments[1] + "_SIGN") == null) { if (Material.matchMaterial(arguments[1] + "_SIGN") == null) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "The given sign type is invalid"); new SGFormatBuilder("The given sign type is invalid").error(commandSender);
return null; return null;
} }
String colorString = arguments[1] + ":"; String colorString = arguments[1] + ":";
//Validate the colors given by the user //Validate the colors given by the user
String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color is invalid!"}; String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color " +
"is invalid!"};
String[] newColors = new String[2]; String[] newColors = new String[2];
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (validatePerSignColor(arguments[i + 2])) { if (validatePerSignColor(arguments[i + 2])) {
newColors[i] = arguments[i + 2]; newColors[i] = arguments[i + 2];
} else { } else {
Stargate.getMessageSender().sendErrorMessage(commandSender, errorMessage[i]); new SGFormatBuilder(errorMessage[i]).error(commandSender);
return null; return null;
} }
} }
@@ -220,9 +228,11 @@ public class CommandConfig implements CommandExecutor {
* @param colorString <p>The new color string to replace any previous value with</p> * @param colorString <p>The new color string to replace any previous value with</p>
* @param configuration <p>The file configuration to update with the new per-sign colors</p> * @param configuration <p>The file configuration to update with the new per-sign colors</p>
*/ */
private void updatePerSignColors(String signType, String colorString, FileConfiguration configuration) { private void updatePerSignColors(@NotNull String signType, @NotNull String colorString,
@NotNull FileConfiguration configuration) {
List<String> newColorStrings = new ArrayList<>(); List<String> newColorStrings = new ArrayList<>();
List<?> oldColors = (List<?>) Stargate.getStargateConfig().getConfigOptionsReference().get(ConfigOption.PER_SIGN_COLORS); List<?> oldColors = (List<?>) Stargate.getStargateConfig().getConfigOptionsReference().get(
ConfigOption.PER_SIGN_COLORS);
for (Object object : oldColors) { for (Object object : oldColors) {
newColorStrings.add(String.valueOf(object)); newColorStrings.add(String.valueOf(object));
} }
@@ -239,7 +249,7 @@ public class CommandConfig implements CommandExecutor {
* @param color <p>The color chosen by the user</p> * @param color <p>The color chosen by the user</p>
* @return <p>True if the given color is valid</p> * @return <p>True if the given color is valid</p>
*/ */
private boolean validatePerSignColor(String color) { private boolean validatePerSignColor(@NotNull String color) {
ChatColor newHighlightColor = parseColor(color); ChatColor newHighlightColor = parseColor(color);
return newHighlightColor != null || color.equalsIgnoreCase("default") || return newHighlightColor != null || color.equalsIgnoreCase("default") ||
color.equalsIgnoreCase("inverted"); color.equalsIgnoreCase("inverted");
@@ -251,11 +261,11 @@ public class CommandConfig implements CommandExecutor {
* @param selectedOption <p>The config option that was changed</p> * @param selectedOption <p>The config option that was changed</p>
* @param commandSender <p>The command sender that executed the config command</p> * @param commandSender <p>The command sender that executed the config command</p>
*/ */
private void saveAndReload(ConfigOption selectedOption, CommandSender commandSender) { private void saveAndReload(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender) {
//Save the config file and reload if necessary //Save the config file and reload if necessary
Stargate.getInstance().saveConfig(); Stargate.getInstance().saveConfig();
Stargate.getMessageSender().sendSuccessMessage(commandSender, "Config updated"); new SGFormatBuilder("Config updated").success(commandSender);
//Reload whatever is necessary //Reload whatever is necessary
reloadIfNecessary(commandSender, selectedOption); reloadIfNecessary(commandSender, selectedOption);
@@ -268,7 +278,8 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender <p>The command sender to alert if the color is invalid</p> * @param commandSender <p>The command sender to alert if the color is invalid</p>
* @param value <p>The new option value</p> * @param value <p>The new option value</p>
*/ */
private boolean registerColor(ConfigOption selectedOption, String value, CommandSender commandSender) { private boolean registerColor(@NotNull ConfigOption selectedOption, @NotNull String value,
@NotNull CommandSender commandSender) {
ChatColor parsedColor = parseColor(value); ChatColor parsedColor = parseColor(value);
if (parsedColor == null) { if (parsedColor == null) {
commandSender.sendMessage(ChatColor.RED + "Invalid color given"); commandSender.sendMessage(ChatColor.RED + "Invalid color given");
@@ -291,7 +302,8 @@ public class CommandConfig implements CommandExecutor {
* @param value <p>The value to parse</p> * @param value <p>The value to parse</p>
* @return <p>The parsed color or null</p> * @return <p>The parsed color or null</p>
*/ */
private ChatColor parseColor(String value) { @Nullable
private ChatColor parseColor(@NotNull String value) {
try { try {
return ChatColor.of(value.toUpperCase()); return ChatColor.of(value.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ignored) { } catch (IllegalArgumentException | NullPointerException ignored) {
@@ -307,7 +319,9 @@ public class CommandConfig implements CommandExecutor {
* @param value <p>The value given</p> * @param value <p>The value given</p>
* @return <p>An integer, or null if it was invalid</p> * @return <p>An integer, or null if it was invalid</p>
*/ */
private Integer getInteger(CommandSender commandSender, ConfigOption selectedOption, String value) { @Nullable
private Integer getInteger(@NotNull CommandSender commandSender, @NotNull ConfigOption selectedOption,
@NotNull String value) {
try { try {
int intValue = Integer.parseInt(value); int intValue = Integer.parseInt(value);
@@ -331,7 +345,9 @@ public class CommandConfig implements CommandExecutor {
* @param value <p>The value given</p> * @param value <p>The value given</p>
* @return <p>A double, or null if it was invalid</p> * @return <p>A double, or null if it was invalid</p>
*/ */
private Double getDouble(CommandSender commandSender, ConfigOption selectedOption, String value) { @Nullable
private Double getDouble(@NotNull CommandSender commandSender, @NotNull ConfigOption selectedOption,
@NotNull String value) {
try { try {
double doubleValue = Double.parseDouble(value); double doubleValue = Double.parseDouble(value);
@@ -353,7 +369,7 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender <p>The command sender initiating the reload</p> * @param commandSender <p>The command sender initiating the reload</p>
* @param configOption <p>The changed config option</p> * @param configOption <p>The changed config option</p>
*/ */
private void reloadIfNecessary(CommandSender commandSender, ConfigOption configOption) { private void reloadIfNecessary(@NotNull CommandSender commandSender, @NotNull ConfigOption configOption) {
if (ConfigTag.requiresFullReload(configOption)) { if (ConfigTag.requiresFullReload(configOption)) {
//Reload everything //Reload everything
Stargate.getStargateConfig().reload(commandSender); Stargate.getStargateConfig().reload(commandSender);
@@ -391,7 +407,7 @@ public class CommandConfig implements CommandExecutor {
* @param sender <p>The command sender that sent the command</p> * @param sender <p>The command sender that sent the command</p>
* @param option <p>The config option to print information about</p> * @param option <p>The config option to print information about</p>
*/ */
private void printConfigOptionValue(CommandSender sender, ConfigOption option) { private void printConfigOptionValue(@NotNull CommandSender sender, @NotNull ConfigOption option) {
Object value = Stargate.getStargateConfig().getConfigOptions().get(option); Object value = Stargate.getStargateConfig().getConfigOptions().get(option);
sender.sendMessage(getOptionDescription(option)); sender.sendMessage(getOptionDescription(option));
sender.sendMessage(ChatColor.GREEN + "Current value: " + ChatColor.GOLD + value); sender.sendMessage(ChatColor.GREEN + "Current value: " + ChatColor.GOLD + value);
@@ -402,8 +418,8 @@ public class CommandConfig implements CommandExecutor {
* *
* @param sender <p>The command sender to display the config list to</p> * @param sender <p>The command sender to display the config list to</p>
*/ */
private void displayConfigValues(CommandSender sender) { private void displayConfigValues(@NotNull CommandSender sender) {
sender.sendMessage(ChatColor.GREEN + Stargate.getBackupString("prefix") + ChatColor.GOLD + sender.sendMessage(ChatColor.GREEN + Stargate.getBackupString(Message.PREFIX) + ChatColor.GOLD +
"Config values:"); "Config values:");
for (ConfigOption option : ConfigOption.values()) { for (ConfigOption option : ConfigOption.values()) {
sender.sendMessage(getOptionDescription(option)); sender.sendMessage(getOptionDescription(option));
@@ -416,7 +432,8 @@ public class CommandConfig implements CommandExecutor {
* @param option <p>The option to describe</p> * @param option <p>The option to describe</p>
* @return <p>A string describing the config option</p> * @return <p>A string describing the config option</p>
*/ */
private String getOptionDescription(ConfigOption option) { @NotNull
private String getOptionDescription(@NotNull ConfigOption option) {
Object defaultValue = option.getDefaultValue(); Object defaultValue = option.getDefaultValue();
String stringValue = String.valueOf(defaultValue); String stringValue = String.valueOf(defaultValue);
if (option.getDataType() == OptionDataType.STRING_LIST) { if (option.getDataType() == OptionDataType.STRING_LIST) {

View File

@@ -1,6 +1,7 @@
package net.knarcraft.stargate.command; package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.SGFormatBuilder;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -17,7 +18,7 @@ public class CommandReload implements CommandExecutor {
@NotNull String[] args) { @NotNull String[] args) {
if (commandSender instanceof Player player) { if (commandSender instanceof Player player) {
if (!player.hasPermission("stargate.admin.reload")) { if (!player.hasPermission("stargate.admin.reload")) {
Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied"); new SGFormatBuilder("Permission Denied").error(commandSender);
return true; return true;
} }
} }

View File

@@ -1,10 +1,11 @@
package net.knarcraft.stargate.command; package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Arrays;
@@ -16,6 +17,11 @@ import java.util.Arrays;
* the plugin itself, not commands for functions of the plugin.</p> * the plugin itself, not commands for functions of the plugin.</p>
*/ */
public class CommandStarGate implements CommandExecutor { public class CommandStarGate implements CommandExecutor {
private final Plugin stargate;
public CommandStarGate(Plugin stargate) {
this.stargate = stargate;
}
@Override @Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@@ -31,8 +37,8 @@ public class CommandStarGate implements CommandExecutor {
} }
return false; return false;
} else { } else {
commandSender.sendMessage(ChatColor.GOLD + "Stargate version " + commandSender.sendMessage(ChatColor.GREEN + "Stargate version " + ChatColor.GOLD + stargate.getDescription().getVersion()
ChatColor.GREEN + Stargate.getPluginVersion()); + ChatColor.GREEN + " running on " + ChatColor.GOLD + Bukkit.getServer().getVersion());
return true; return true;
} }
} }

View File

@@ -61,25 +61,26 @@ public class ConfigTabCompleter implements TabCompleter {
* @param typedText <p>The beginning of the typed text, for filtering matching results</p> * @param typedText <p>The beginning of the typed text, for filtering matching results</p>
* @return <p>Some or all of the valid values for the option</p> * @return <p>Some or all of the valid values for the option</p>
*/ */
private List<String> getPossibleOptionValues(ConfigOption selectedOption, String typedText) { @Nullable
private List<String> getPossibleOptionValues(@NotNull ConfigOption selectedOption,
@NotNull String typedText) {
switch (selectedOption) { switch (selectedOption) {
case LANGUAGE: case LANGUAGE -> {
//Return available languages //Return available languages
return filterMatchingStartsWith(languages, typedText); return filterMatchingStartsWith(languages, typedText);
case GATE_FOLDER: }
case PORTAL_FOLDER: case GATE_FOLDER, PORTAL_FOLDER, DEFAULT_GATE_NETWORK -> {
case DEFAULT_GATE_NETWORK:
//Just return the default value as most values should be possible //Just return the default value as most values should be possible
if (typedText.trim().isEmpty()) { if (typedText.trim().isEmpty()) {
return putStringInList((String) selectedOption.getDefaultValue()); return List.of((String) selectedOption.getDefaultValue());
} else { } else {
return new ArrayList<>(); return new ArrayList<>();
} }
case MAIN_SIGN_COLOR: }
case HIGHLIGHT_SIGN_COLOR: case MAIN_SIGN_COLOR, HIGHLIGHT_SIGN_COLOR, FREE_GATES_COLOR -> {
case FREE_GATES_COLOR:
//Return all colors //Return all colors
return filterMatchingStartsWith(chatColors, typedText); return filterMatchingStartsWith(chatColors, typedText);
}
} }
//If the config value is a boolean, show the two boolean values //If the config value is a boolean, show the two boolean values
@@ -114,11 +115,13 @@ public class ConfigTabCompleter implements TabCompleter {
* @param args <p>The arguments given by the user</p> * @param args <p>The arguments given by the user</p>
* @return <p>Some or all of the valid values for the option</p> * @return <p>Some or all of the valid values for the option</p>
*/ */
private List<String> getPossibleStringListOptionValues(ConfigOption selectedOption, String[] args) { @NotNull
private List<String> getPossibleStringListOptionValues(@NotNull ConfigOption selectedOption,
@NotNull String[] args) {
if (selectedOption == ConfigOption.PER_SIGN_COLORS) { if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
return getPerSignColorCompletion(args); return getPerSignColorCompletion(args);
} else { } else {
return null; return new ArrayList<>();
} }
} }
@@ -128,7 +131,8 @@ public class ConfigTabCompleter implements TabCompleter {
* @param args <p>The arguments given by the user</p> * @param args <p>The arguments given by the user</p>
* @return <p>The options to give the user</p> * @return <p>The options to give the user</p>
*/ */
private List<String> getPerSignColorCompletion(String[] args) { @NotNull
private List<String> getPerSignColorCompletion(@NotNull String[] args) {
if (args.length < 3) { if (args.length < 3) {
return filterMatchingStartsWith(signTypes, args[1]); return filterMatchingStartsWith(signTypes, args[1]);
} else if (args.length < 4) { } else if (args.length < 4) {
@@ -139,18 +143,6 @@ public class ConfigTabCompleter implements TabCompleter {
return new ArrayList<>(); return new ArrayList<>();
} }
/**
* Puts a single string value into a string list
*
* @param value <p>The string to make into a list</p>
* @return <p>A list containing the string value</p>
*/
private List<String> putStringInList(String value) {
List<String> list = new ArrayList<>();
list.add(value);
return list;
}
/** /**
* Initializes all lists of auto-completable values * Initializes all lists of auto-completable values
*/ */
@@ -200,6 +192,7 @@ public class ConfigTabCompleter implements TabCompleter {
* *
* @return <p>The available chat colors</p> * @return <p>The available chat colors</p>
*/ */
@NotNull
private List<ChatColor> getChatColors() { private List<ChatColor> getChatColors() {
List<ChatColor> chatColors = new ArrayList<>(); List<ChatColor> chatColors = new ArrayList<>();
char[] colors = new char[]{'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; char[] colors = new char[]{'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
@@ -216,6 +209,7 @@ public class ConfigTabCompleter implements TabCompleter {
*/ */
private void initializeLanguages() { private void initializeLanguages() {
languages = new ArrayList<>(); languages = new ArrayList<>();
languages.add("cs");
languages.add("de"); languages.add("de");
languages.add("en"); languages.add("en");
languages.add("es"); languages.add("es");
@@ -223,12 +217,15 @@ public class ConfigTabCompleter implements TabCompleter {
languages.add("hu"); languages.add("hu");
languages.add("it"); languages.add("it");
languages.add("ja"); languages.add("ja");
languages.add("nb-no"); languages.add("nb");
languages.add("nl"); languages.add("nl");
languages.add("nn-no"); languages.add("nn");
languages.add("pt-br"); languages.add("pt");
languages.add("ru"); languages.add("ru");
languages.add("zh_cn"); languages.add("sv");
languages.add("tr");
languages.add("uk");
languages.add("zh");
//TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom //TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom
// language files // language files
} }

View File

@@ -17,8 +17,9 @@ import java.util.List;
public class StarGateTabCompleter implements TabCompleter { public class StarGateTabCompleter implements TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @Nullable
@NotNull String s, @NotNull String[] args) { public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) {
if (args.length == 1) { if (args.length == 1) {
List<String> commands = getAvailableCommands(commandSender); List<String> commands = getAvailableCommands(commandSender);
List<String> matchingCommands = new ArrayList<>(); List<String> matchingCommands = new ArrayList<>();
@@ -42,7 +43,8 @@ public class StarGateTabCompleter implements TabCompleter {
* @param commandSender <p>The command sender to get available commands for</p> * @param commandSender <p>The command sender to get available commands for</p>
* @return <p>The commands available to the command sender</p> * @return <p>The commands available to the command sender</p>
*/ */
private List<String> getAvailableCommands(CommandSender commandSender) { @NotNull
private List<String> getAvailableCommands(@NotNull CommandSender commandSender) {
List<String> commands = new ArrayList<>(); List<String> commands = new ArrayList<>();
commands.add("about"); commands.add("about");
if (!(commandSender instanceof Player player) || player.hasPermission("stargate.admin.reload")) { if (!(commandSender instanceof Player player) || player.hasPermission("stargate.admin.reload")) {

View File

@@ -1,5 +1,8 @@
package net.knarcraft.stargate.config; package net.knarcraft.stargate.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* A ConfigOption represents one of the available config options * A ConfigOption represents one of the available config options
*/ */
@@ -55,7 +58,8 @@ public enum ConfigOption {
*/ */
PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{ PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{
"'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'", "'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'",
"'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'"}), "'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'",
"'BAMBOO:default,default'", "'CHERRY:default,default'"}),
/** /**
* Whether to destroy portals when any blocks are broken by explosions * Whether to destroy portals when any blocks are broken by explosions
@@ -150,6 +154,11 @@ public enum ConfigOption {
CHARGE_FREE_DESTINATION("economy.chargeFreeDestination", CHARGE_FREE_DESTINATION("economy.chargeFreeDestination",
"Whether to require payment if the destination is free, but the entrance stargate is not", true), "Whether to require payment if the destination is free, but the entrance stargate is not", true),
/**
* The account to transfer all paid fees to
*/
TAX_ACCOUNT("economy.taxAccount", "The UUID of the account all fees are paid to (except for money to the Stargate owner)", ""),
/** /**
* Whether to mark free gates with a different color * Whether to mark free gates with a different color
*/ */
@@ -189,7 +198,14 @@ public enum ConfigOption {
* Whether to hide Dynmap icons by default * Whether to hide Dynmap icons by default
*/ */
DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault", DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault",
"Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true); "Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true),
/**
* The amount of ticks to wait when processing the Stargate control update queue
*/
CONTROL_UPDATE_QUEUE_DELAY("gates.integrity.controlUpdateDelay",
"The delay between each time a Stargate's controls are updated after startup", 3),
;
private final String configNode; private final String configNode;
private final String description; private final String description;
@@ -203,7 +219,7 @@ public enum ConfigOption {
* @param description <p>The description of what this config option does</p> * @param description <p>The description of what this config option does</p>
* @param defaultValue <p>The default value of this config option</p> * @param defaultValue <p>The default value of this config option</p>
*/ */
ConfigOption(String configNode, String description, Object defaultValue) { ConfigOption(@NotNull String configNode, @NotNull String description, @NotNull Object defaultValue) {
this.configNode = configNode; this.configNode = configNode;
this.description = description; this.description = description;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
@@ -229,7 +245,7 @@ public enum ConfigOption {
* @param name <p>The name of the config option to get</p> * @param name <p>The name of the config option to get</p>
* @return <p>The corresponding config option, or null if the name is invalid</p> * @return <p>The corresponding config option, or null if the name is invalid</p>
*/ */
public static ConfigOption getByName(String name) { public static @Nullable ConfigOption getByName(@NotNull String name) {
for (ConfigOption option : ConfigOption.values()) { for (ConfigOption option : ConfigOption.values()) {
if (option.getName().equalsIgnoreCase(name)) { if (option.getName().equalsIgnoreCase(name)) {
return option; return option;
@@ -243,7 +259,7 @@ public enum ConfigOption {
* *
* @return <p>The name of this config option</p> * @return <p>The name of this config option</p>
*/ */
public String getName() { public @NotNull String getName() {
if (!this.configNode.contains(".")) { if (!this.configNode.contains(".")) {
return this.configNode; return this.configNode;
} }
@@ -256,7 +272,7 @@ public enum ConfigOption {
* *
* @return <p>The data type used</p> * @return <p>The data type used</p>
*/ */
public OptionDataType getDataType() { public @NotNull OptionDataType getDataType() {
return this.dataType; return this.dataType;
} }
@@ -265,7 +281,7 @@ public enum ConfigOption {
* *
* @return <p>This config option's config node</p> * @return <p>This config option's config node</p>
*/ */
public String getConfigNode() { public @NotNull String getConfigNode() {
return this.configNode; return this.configNode;
} }
@@ -274,7 +290,7 @@ public enum ConfigOption {
* *
* @return <p>The description of this config option</p> * @return <p>The description of this config option</p>
*/ */
public String getDescription() { public @NotNull String getDescription() {
return this.description; return this.description;
} }
@@ -283,7 +299,7 @@ public enum ConfigOption {
* *
* @return <p>This config option's default value</p> * @return <p>This config option's default value</p>
*/ */
public Object getDefaultValue() { public @NotNull Object getDefaultValue() {
return this.defaultValue; return this.defaultValue;
} }

View File

@@ -1,25 +1,38 @@
package net.knarcraft.stargate.config; package net.knarcraft.stargate.config;
import java.util.Arrays; import org.jetbrains.annotations.NotNull;
import java.util.Set;
/** /**
* A config tag groups config values by a property * A config tag groups config values by a property
*/ */
public enum ConfigTag { public enum ConfigTag {
COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, /**
ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}), * Color-related configuration options
FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}), */
DYNMAP(new ConfigOption[]{ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN}); COLOR(Set.of(ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, ConfigOption.HIGHLIGHT_SIGN_COLOR,
ConfigOption.PER_SIGN_COLORS)),
private final ConfigOption[] taggedOptions; /**
* Folder-altering configuration options
*/
FOLDER(Set.of(ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER)),
/**
* Dynmap-related configuration options
*/
DYNMAP(Set.of(ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN));
private final Set<ConfigOption> taggedOptions;
/** /**
* Instantiates a new config tag * Instantiates a new config tag
* *
* @param taggedOptions <p>The config options included in this tag</p> * @param taggedOptions <p>The config options included in this tag</p>
*/ */
ConfigTag(ConfigOption[] taggedOptions) { ConfigTag(@NotNull Set<ConfigOption> taggedOptions) {
this.taggedOptions = taggedOptions; this.taggedOptions = taggedOptions;
} }
@@ -29,8 +42,8 @@ public enum ConfigTag {
* @param option <p>The config option to check</p> * @param option <p>The config option to check</p>
* @return <p>True of the config option is tagged</p> * @return <p>True of the config option is tagged</p>
*/ */
public boolean isTagged(ConfigOption option) { public boolean isTagged(@NotNull ConfigOption option) {
return Arrays.stream(taggedOptions).anyMatch((item) -> item == option); return taggedOptions.contains(option);
} }
/** /**
@@ -39,7 +52,7 @@ public enum ConfigTag {
* @param configOption <p>The config option to check</p> * @param configOption <p>The config option to check</p>
* @return <p>True if changing the config option requires a "reload of colors" to take effect</p> * @return <p>True if changing the config option requires a "reload of colors" to take effect</p>
*/ */
public static boolean requiresColorReload(ConfigOption configOption) { public static boolean requiresColorReload(@NotNull ConfigOption configOption) {
return (COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR); return (COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR);
} }
@@ -49,7 +62,7 @@ public enum ConfigTag {
* @param option <p>The config option to check</p> * @param option <p>The config option to check</p>
* @return <p>True if changing the config option requires a full reload to take effect</p> * @return <p>True if changing the config option requires a full reload to take effect</p>
*/ */
public static boolean requiresFullReload(ConfigOption option) { public static boolean requiresFullReload(@NotNull ConfigOption option) {
return FOLDER.isTagged(option); return FOLDER.isTagged(option);
} }
@@ -59,7 +72,7 @@ public enum ConfigTag {
* @param configOption <p>The config option to check</p> * @param configOption <p>The config option to check</p>
* @return <p>True if changing the config option requires a reload of all dynmap markers</p> * @return <p>True if changing the config option requires a reload of all dynmap markers</p>
*/ */
public static boolean requiresDynmapReload(ConfigOption configOption) { public static boolean requiresDynmapReload(@NotNull ConfigOption configOption) {
return DYNMAP.isTagged(configOption); return DYNMAP.isTagged(configOption);
} }
@@ -69,7 +82,7 @@ public enum ConfigTag {
* @param option <p>The config option to check</p> * @param option <p>The config option to check</p>
* @return <p>True if changing the config option requires a portal reload to take effect</p> * @return <p>True if changing the config option requires a portal reload to take effect</p>
*/ */
public static boolean requiresPortalReload(ConfigOption option) { public static boolean requiresPortalReload(@NotNull ConfigOption option) {
return COLOR.isTagged(option) || FOLDER.isTagged(option) || option == ConfigOption.VERIFY_PORTALS; return COLOR.isTagged(option) || FOLDER.isTagged(option) || option == ConfigOption.VERIFY_PORTALS;
} }
@@ -79,7 +92,7 @@ public enum ConfigTag {
* @param option <p>The config option to check</p> * @param option <p>The config option to check</p>
* @return <p>True if the language loader requires a reload</p> * @return <p>True if the language loader requires a reload</p>
*/ */
public static boolean requiresLanguageReload(ConfigOption option) { public static boolean requiresLanguageReload(@NotNull ConfigOption option) {
return option == ConfigOption.LANGUAGE; return option == ConfigOption.LANGUAGE;
} }
@@ -89,7 +102,7 @@ public enum ConfigTag {
* @param option <p>The config option to check</p> * @param option <p>The config option to check</p>
* @return <p>True if economy requires a reload</p> * @return <p>True if economy requires a reload</p>
*/ */
public static boolean requiresEconomyReload(ConfigOption option) { public static boolean requiresEconomyReload(@NotNull ConfigOption option) {
return option == ConfigOption.USE_ECONOMY; return option == ConfigOption.USE_ECONOMY;
} }

View File

@@ -1,6 +1,7 @@
package net.knarcraft.stargate.config; package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.portal.PortalRegistry;
import org.bukkit.Location; import org.bukkit.Location;
@@ -10,6 +11,8 @@ import org.dynmap.markers.GenericMarker;
import org.dynmap.markers.Marker; import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon; import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet; import org.dynmap.markers.MarkerSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* A manager for dealing with everything Dynmap * A manager for dealing with everything Dynmap
@@ -27,9 +30,10 @@ public final class DynmapManager {
* Initializes the dynmap manager * Initializes the dynmap manager
* *
* @param dynmapAPI <p>A reference</p> * @param dynmapAPI <p>A reference</p>
* @throws NullPointerException <p>If dynmap has an invalid state</p>
*/ */
public static void initialize(DynmapAPI dynmapAPI) { public static void initialize(@Nullable DynmapAPI dynmapAPI) throws NullPointerException {
if (dynmapAPI == null || dynmapAPI.getMarkerAPI() == null) { if (dynmapAPI == null || !dynmapAPI.markerAPIInitialized() || dynmapAPI.getMarkerAPI() == null) {
markerSet = null; markerSet = null;
portalIcon = null; portalIcon = null;
} else { } else {
@@ -66,7 +70,7 @@ public final class DynmapManager {
* *
* @param portal <p>The portal to add a marker for</p> * @param portal <p>The portal to add a marker for</p>
*/ */
public static void addPortalMarker(Portal portal) { public static void addPortalMarker(@NotNull Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) { if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return; return;
} }
@@ -75,8 +79,22 @@ public final class DynmapManager {
return; return;
} }
Location location = portal.getBlockAt(portal.getGate().getLayout().getExit()); Location location;
Marker marker = markerSet.createMarker(getPortalMarkerId(portal), portal.getName(), world.getName(), @Nullable RelativeBlockVector exit = portal.getGate().getLayout().getExit();
if (exit == null) {
location = portal.getTopLeft();
} else {
location = portal.getBlockAt(exit);
}
String markerId = getPortalMarkerId(portal);
if (markerSet.findMarker(markerId) != null) {
Stargate.debug("DynmapManager::addPortalMarker", "Skipped marker creation, as the portal " +
"marker " + markerId + " already exists");
return;
}
Marker marker = markerSet.createMarker(markerId, portal.getName(), world.getName(),
location.getX(), location.getY(), location.getZ(), portalIcon, false); location.getX(), location.getY(), location.getZ(), portalIcon, false);
if (marker == null) { if (marker == null) {
Stargate.logWarning(String.format( Stargate.logWarning(String.format(
@@ -86,7 +104,7 @@ public final class DynmapManager {
Portal name: %s Portal name: %s
Portal world: %s Portal world: %s
Portal location: %s,%s,%s""", Portal location: %s,%s,%s""",
getPortalMarkerId(portal), portal.getName(), world.getName(), location.getX(), location.getY(), markerId, portal.getName(), world.getName(), location.getX(), location.getY(),
location.getZ())); location.getZ()));
return; return;
} }
@@ -111,7 +129,7 @@ public final class DynmapManager {
* *
* @param portal <p>The portal to remove the marker for</p> * @param portal <p>The portal to remove the marker for</p>
*/ */
public static void removePortalMarker(Portal portal) { public static void removePortalMarker(@NotNull Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) { if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return; return;
} }
@@ -121,13 +139,21 @@ public final class DynmapManager {
} }
} }
/**
* Disables Dynmap integration
*/
public static void disable() {
markerSet = null;
portalIcon = null;
}
/** /**
* Gets the id used for the given portal's marker * Gets the id used for the given portal's marker
* *
* @param portal <p>The portal to get a marker id for</p> * @param portal <p>The portal to get a marker id for</p>
* @return <p></p> * @return <p></p>
*/ */
private static String getPortalMarkerId(Portal portal) { private static String getPortalMarkerId(@NotNull Portal portal) {
return portal.getNetwork() + "-:-" + portal.getName(); return portal.getNetwork() + "-:-" + portal.getName();
} }

View File

@@ -11,6 +11,8 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager; import org.bukkit.plugin.ServicesManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map; import java.util.Map;
@@ -29,7 +31,7 @@ public final class EconomyConfig {
* *
* @param configOptions <p>The loaded config options to read</p> * @param configOptions <p>The loaded config options to read</p>
*/ */
public EconomyConfig(Map<ConfigOption, Object> configOptions) { public EconomyConfig(@NotNull Map<ConfigOption, Object> configOptions) {
this.configOptions = configOptions; this.configOptions = configOptions;
try { try {
String freeColor = (String) configOptions.get(ConfigOption.FREE_GATES_COLOR); String freeColor = (String) configOptions.get(ConfigOption.FREE_GATES_COLOR);
@@ -62,6 +64,7 @@ public final class EconomyConfig {
* *
* @return <p>An economy object, or null if economy is disabled or not initialized</p> * @return <p>An economy object, or null if economy is disabled or not initialized</p>
*/ */
@Nullable
public Economy getEconomy() { public Economy getEconomy() {
return economy; return economy;
} }
@@ -71,6 +74,7 @@ public final class EconomyConfig {
* *
* @return <p>An instance of the Vault plugin, or null if Vault is not loaded</p> * @return <p>An instance of the Vault plugin, or null if Vault is not loaded</p>
*/ */
@Nullable
public Plugin getVault() { public Plugin getVault() {
return vault; return vault;
} }
@@ -132,6 +136,16 @@ public final class EconomyConfig {
return (Integer) configOptions.get(ConfigOption.DESTROY_COST); return (Integer) configOptions.get(ConfigOption.DESTROY_COST);
} }
/**
* Gets the account all taxes are paid to
*
* @return <p>The account all taxes are paid to</p>
*/
@Nullable
public String getTaxAccount() {
return (String) configOptions.get(ConfigOption.TAX_ACCOUNT);
}
/** /**
* Checks whether the given player can afford the given fee * Checks whether the given player can afford the given fee
* *
@@ -149,6 +163,7 @@ public final class EconomyConfig {
* @param amount <p>The amount to display</p> * @param amount <p>The amount to display</p>
* @return <p>A formatted text string describing the amount</p> * @return <p>A formatted text string describing the amount</p>
*/ */
@NotNull
public String format(int amount) { public String format(int amount) {
if (isEconomyEnabled()) { if (isEconomyEnabled()) {
return economy.format(amount); return economy.format(amount);
@@ -163,7 +178,7 @@ public final class EconomyConfig {
* @param pluginManager <p>The plugin manager to get plugins from</p> * @param pluginManager <p>The plugin manager to get plugins from</p>
* @return <p>True if economy was enabled</p> * @return <p>True if economy was enabled</p>
*/ */
public boolean setupEconomy(PluginManager pluginManager) { public boolean setupEconomy(@NotNull PluginManager pluginManager) {
if (!isEconomyEnabled()) { if (!isEconomyEnabled()) {
return false; return false;
} }
@@ -177,10 +192,10 @@ public final class EconomyConfig {
this.vault = vault; this.vault = vault;
return true; return true;
} else { } else {
Stargate.logInfo(Stargate.getString("ecoLoadError")); Stargate.logInfo(new SGFormatBuilder(Message.ECONOMY_LOAD_ERROR).toString());
} }
} else { } else {
Stargate.logInfo(Stargate.getString("vaultLoadError")); Stargate.logInfo(new SGFormatBuilder(Message.VAULT_LOAD_ERROR).toString());
} }
configOptions.put(ConfigOption.USE_ECONOMY, false); configOptions.put(ConfigOption.USE_ECONOMY, false);
return false; return false;
@@ -202,7 +217,7 @@ public final class EconomyConfig {
* @param gate <p>The gate type used</p> * @param gate <p>The gate type used</p>
* @return <p>The cost of creating the gate</p> * @return <p>The cost of creating the gate</p>
*/ */
public int getCreateCost(Player player, Gate gate) { public int getCreateCost(@NotNull Player player, @NotNull Gate gate) {
if (isFree(player, "create")) { if (isFree(player, "create")) {
return 0; return 0;
} else { } else {
@@ -217,7 +232,7 @@ public final class EconomyConfig {
* @param gate <p>The gate type used</p> * @param gate <p>The gate type used</p>
* @return <p>The cost of destroying the gate</p> * @return <p>The cost of destroying the gate</p>
*/ */
public int getDestroyCost(Player player, Gate gate) { public int getDestroyCost(@NotNull Player player, @NotNull Gate gate) {
if (isFree(player, "destroy")) { if (isFree(player, "destroy")) {
return 0; return 0;
} else { } else {
@@ -232,7 +247,7 @@ public final class EconomyConfig {
* @param permissionNode <p>The free.permissionNode necessary to allow free gate {action}</p> * @param permissionNode <p>The free.permissionNode necessary to allow free gate {action}</p>
* @return <p></p> * @return <p></p>
*/ */
private boolean isFree(Player player, String permissionNode) { private boolean isFree(@NotNull Player player, @NotNull String permissionNode) {
return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode); return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode);
} }

View File

@@ -3,15 +3,16 @@ package net.knarcraft.stargate.config;
import net.knarcraft.knarlib.property.ColorConversion; import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.FileHelper; import net.knarcraft.knarlib.util.FileHelper;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* This class is responsible for loading all strings which are translated into several languages * This class is responsible for loading all strings which are translated into several languages
@@ -19,9 +20,9 @@ import java.util.Set;
public final class LanguageLoader { public final class LanguageLoader {
private final String languageFolder; private final String languageFolder;
private final Map<String, String> loadedBackupStrings; private final Map<Message, String> loadedBackupStrings;
private String chosenLanguage; private String chosenLanguage;
private Map<String, String> loadedStringTranslations; private Map<Message, String> loadedStringTranslations;
/** /**
* Instantiates a new language loader * Instantiates a new language loader
@@ -30,7 +31,7 @@ public final class LanguageLoader {
* *
* @param languageFolder <p>The folder containing the language files</p> * @param languageFolder <p>The folder containing the language files</p>
*/ */
public LanguageLoader(String languageFolder) { public LanguageLoader(@NotNull String languageFolder) {
this.languageFolder = languageFolder; this.languageFolder = languageFolder;
File testFile = new File(languageFolder, "en.txt"); File testFile = new File(languageFolder, "en.txt");
if (!testFile.exists()) { if (!testFile.exists()) {
@@ -45,7 +46,7 @@ public final class LanguageLoader {
loadedBackupStrings = load("en", inputStream); loadedBackupStrings = load("en", inputStream);
} else { } else {
loadedBackupStrings = null; loadedBackupStrings = null;
Stargate.getConsoleLogger().severe("[stargate] Error loading backup language. " + Stargate.logSevere("Error loading backup language. " +
"There may be missing text in-game"); "There may be missing text in-game");
} }
} }
@@ -60,32 +61,34 @@ public final class LanguageLoader {
} }
/** /**
* Gets the string to display given its name/key * Gets the string to display given its message key
* *
* @param name <p>The name/key of the string to display</p> * @param message <p>The message to display</p>
* @return <p>The string in the user's preferred language</p> * @return <p>The message in the user's preferred language</p>
*/ */
public String getString(String name) { @NotNull
public String getString(@NotNull Message message) {
String value = null; String value = null;
if (loadedStringTranslations != null) { if (loadedStringTranslations != null) {
value = loadedStringTranslations.get(name); value = loadedStringTranslations.get(message);
} }
if (value == null) { if (value == null) {
value = getBackupString(name); value = getBackupString(message);
} }
return value; return value;
} }
/** /**
* Gets the string to display given its name/key * Gets the string to display given its message key
* *
* @param name <p>The name/key of the string to display</p> * @param message <p>The message to display</p>
* @return <p>The string in the backup language (English)</p> * @return <p>The string in the backup language (English)</p>
*/ */
public String getBackupString(String name) { @NotNull
public String getBackupString(@NotNull Message message) {
String value = null; String value = null;
if (loadedBackupStrings != null) { if (loadedBackupStrings != null) {
value = loadedBackupStrings.get(name); value = loadedBackupStrings.get(message);
} }
if (value == null) { if (value == null) {
return ""; return "";
@@ -98,7 +101,7 @@ public final class LanguageLoader {
* *
* @param chosenLanguage <p>The new plugin language</p> * @param chosenLanguage <p>The new plugin language</p>
*/ */
public void setChosenLanguage(String chosenLanguage) { public void setChosenLanguage(@NotNull String chosenLanguage) {
this.chosenLanguage = chosenLanguage; this.chosenLanguage = chosenLanguage;
} }
@@ -107,21 +110,21 @@ public final class LanguageLoader {
* *
* @param language <p>The language to update</p> * @param language <p>The language to update</p>
*/ */
private void updateLanguage(String language) { private void updateLanguage(@NotNull String language) {
Map<String, String> currentLanguageValues = load(language); Map<Message, String> currentLanguageValues = load(language);
InputStream inputStream = getClass().getResourceAsStream("/lang/" + language + ".txt"); InputStream inputStream = FileHelper.getInputStreamForInternalFile("/lang/" + language + ".txt");
if (inputStream == null) { if (inputStream == null) {
Stargate.logInfo(String.format("The language %s is not available. Falling back to english, You can add a " + Stargate.logInfo(String.format("Unable to find internal language file for %s. This will normally not " +
"custom language by creating a new text file in the lang directory.", language)); "cause any problems, except newly added translatable strings won't be automatically added", language));
Stargate.debug("LanguageLoader::updateLanguage", String.format("Unable to load /lang/%s.txt", language)); Stargate.debug("LanguageLoader::updateLanguage", String.format("Unable to load /lang/%s.txt", language));
return; return;
} }
try { try {
readChangedLanguageStrings(inputStream, language, currentLanguageValues); readChangedLanguageStrings(inputStream, language, currentLanguageValues);
} catch (IOException ex) { } catch (IOException exception) {
ex.printStackTrace(); Stargate.logSevere("Unable to read language strings! Message: " + exception.getMessage());
} }
} }
@@ -133,12 +136,12 @@ public final class LanguageLoader {
* @param currentLanguageValues <p>The current values of the loaded/processed language</p> * @param currentLanguageValues <p>The current values of the loaded/processed language</p>
* @throws IOException <p>if unable to read a language file</p> * @throws IOException <p>if unable to read a language file</p>
*/ */
private void readChangedLanguageStrings(InputStream inputStream, String language, Map<String, private void readChangedLanguageStrings(@NotNull InputStream inputStream, @NotNull String language,
String> currentLanguageValues) throws IOException { @Nullable Map<Message, String> currentLanguageValues) throws IOException {
//Get language values //Get language values
BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream); BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
Map<String, String> internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader, "=", Map<Message, String> internalLanguageValues = fromStringMap(FileHelper.readKeyValuePairs(bufferedReader,
ColorConversion.NORMAL); "=", ColorConversion.NORMAL));
//If currentLanguageValues is null; the chosen language has not been used before //If currentLanguageValues is null; the chosen language has not been used before
if (currentLanguageValues == null) { if (currentLanguageValues == null) {
@@ -149,11 +152,14 @@ public final class LanguageLoader {
//If a key is not found in the language file, add the one in the internal file. Must update the external file //If a key is not found in the language file, add the one in the internal file. Must update the external file
if (!internalLanguageValues.keySet().equals(currentLanguageValues.keySet())) { if (!internalLanguageValues.keySet().equals(currentLanguageValues.keySet())) {
Map<String, String> newLanguageValues = new HashMap<>(); Map<Message, String> newLanguageValues = new EnumMap<>(Message.class);
boolean updateNecessary = false; boolean updateNecessary = false;
for (String key : internalLanguageValues.keySet()) { for (Map.Entry<Message, String> entry : internalLanguageValues.entrySet()) {
Message key = entry.getKey();
String value = entry.getValue();
if (currentLanguageValues.get(key) == null) { if (currentLanguageValues.get(key) == null) {
newLanguageValues.put(key, internalLanguageValues.get(key)); newLanguageValues.put(key, value);
//Found at least one value in the internal file not in the external file. Need to update //Found at least one value in the internal file not in the external file. Need to update
updateNecessary = true; updateNecessary = true;
} else { } else {
@@ -177,20 +183,20 @@ public final class LanguageLoader {
* @param customLanguageStrings <p>Any custom language strings not recognized</p> * @param customLanguageStrings <p>Any custom language strings not recognized</p>
* @throws IOException <p>If unable to write to the language file</p> * @throws IOException <p>If unable to write to the language file</p>
*/ */
private void updateLanguageFile(String language, Map<String, String> languageStrings, private void updateLanguageFile(@NotNull String language, @NotNull Map<Message, String> languageStrings,
Map<String, String> customLanguageStrings) throws IOException { @Nullable Map<Message, String> customLanguageStrings) throws IOException {
BufferedWriter bufferedWriter = FileHelper.getBufferedWriterFromString(languageFolder + language + ".txt"); BufferedWriter bufferedWriter = FileHelper.getBufferedWriterFromString(languageFolder + language + ".txt");
//Output normal Language data //Output normal Language data
for (String key : languageStrings.keySet()) { for (Map.Entry<Message, String> entry : languageStrings.entrySet()) {
bufferedWriter.write(key + "=" + languageStrings.get(key)); bufferedWriter.write(entry.getKey() + "=" + entry.getValue());
bufferedWriter.newLine(); bufferedWriter.newLine();
} }
bufferedWriter.newLine(); bufferedWriter.newLine();
//Output any custom language strings the user had //Output any custom language strings the user had
if (customLanguageStrings != null) { if (customLanguageStrings != null) {
for (String key : customLanguageStrings.keySet()) { for (Map.Entry<Message, String> entry : customLanguageStrings.entrySet()) {
bufferedWriter.write(key + "=" + customLanguageStrings.get(key)); bufferedWriter.write(entry.getKey() + "=" + entry.getValue());
bufferedWriter.newLine(); bufferedWriter.newLine();
} }
} }
@@ -203,7 +209,8 @@ public final class LanguageLoader {
* @param lang <p>The language to load</p> * @param lang <p>The language to load</p>
* @return <p>A mapping between loaded string indexes and the strings to display</p> * @return <p>A mapping between loaded string indexes and the strings to display</p>
*/ */
private Map<String, String> load(String lang) { @Nullable
private Map<Message, String> load(@NotNull String lang) {
return load(lang, null); return load(lang, null);
} }
@@ -214,8 +221,8 @@ public final class LanguageLoader {
* @param inputStream <p>An optional input stream to use. Defaults to using a file input stream</p> * @param inputStream <p>An optional input stream to use. Defaults to using a file input stream</p>
* @return <p>A mapping between loaded string indexes and the strings to display</p> * @return <p>A mapping between loaded string indexes and the strings to display</p>
*/ */
private Map<String, String> load(String lang, InputStream inputStream) { @Nullable
Map<String, String> strings; private Map<Message, String> load(@NotNull String lang, @Nullable InputStream inputStream) {
BufferedReader bufferedReader; BufferedReader bufferedReader;
try { try {
if (inputStream == null) { if (inputStream == null) {
@@ -223,14 +230,13 @@ public final class LanguageLoader {
} else { } else {
bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream); bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
} }
strings = FileHelper.readKeyValuePairs(bufferedReader, "=", ColorConversion.NORMAL); return fromStringMap(FileHelper.readKeyValuePairs(bufferedReader, "=", ColorConversion.NORMAL));
} catch (Exception e) { } catch (Exception exception) {
if (Stargate.getStargateConfig().isDebuggingEnabled()) { if (Stargate.getStargateConfig().isDebuggingEnabled()) {
Stargate.getConsoleLogger().info("[Stargate] Unable to load language " + lang); Stargate.logInfo("Unable to load language " + lang);
} }
return null; return null;
} }
return strings;
} }
/** /**
@@ -238,20 +244,41 @@ public final class LanguageLoader {
*/ */
public void debug() { public void debug() {
if (loadedStringTranslations != null) { if (loadedStringTranslations != null) {
Set<String> keys = loadedStringTranslations.keySet(); for (Map.Entry<Message, String> entry : loadedStringTranslations.entrySet()) {
for (String key : keys) { Stargate.debug("LanguageLoader::Debug::loadedStringTranslations", entry.getKey() +
Stargate.debug("LanguageLoader::Debug::loadedStringTranslations", key + " => " + " => " + entry.getValue());
loadedStringTranslations.get(key));
} }
} }
if (loadedBackupStrings == null) { if (loadedBackupStrings == null) {
return; return;
} }
Set<String> keys = loadedBackupStrings.keySet();
for (String key : keys) { for (Map.Entry<Message, String> entry : loadedBackupStrings.entrySet()) {
Stargate.debug("LanguageLoader::Debug::loadedBackupStrings", key + " => " + Stargate.debug("LanguageLoader::Debug::loadedBackupStrings", entry.getKey() + " => " +
loadedBackupStrings.get(key)); entry.getValue());
} }
} }
/**
* Converts a map from string key to message into a map from message key to message
*
* @param configurationStrings <p>The map to convert</p>
* @return <p>The converted map</p>
*/
@NotNull
private Map<Message, String> fromStringMap(@NotNull Map<String, String> configurationStrings) {
Map<Message, String> output = new EnumMap<>(Message.class);
for (Map.Entry<String, String> entry : configurationStrings.entrySet()) {
Message message = Message.getFromKey(entry.getKey());
if (message == null) {
Stargate.logWarning("Found unrecognized language key " + entry.getKey());
continue;
}
output.put(message, entry.getValue());
}
return output;
}
} }

View File

@@ -0,0 +1,251 @@
package net.knarcraft.stargate.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Translated messages displayed to players
*/
public enum Message {
/**
* The prefix displayed in front of all messages shown in the chat
*/
PREFIX("prefix"),
/**
* The message displayed when a player is teleported
*/
TELEPORTED("teleportMsg"),
/**
* The message displayed when a player destroys a Stargate
*/
DESTROYED("destroyMsg"),
/**
* The message displayed when the currently selected Stargate destination is invalid
*/
INVALID_DESTINATION("invalidMsg"),
/**
* The message displayed when the destination portal is busy with another player
*/
DESTINATION_BLOCKED("blockMsg"),
/**
* The message displayed when the Stargate has no destinations available to the player
*/
NO_DESTINATION("destEmpty"),
/**
* The message displayed when a player is denied access to any action
*/
ACCESS_DENIED("denyMsg"),
/**
* The message displayed when the plugin is reloaded
*/
RELOADED("reloaded"),
/**
* The message displayed when a player has some currency deducted from their account
*/
ECONOMY_DEDUCTED("ecoDeduct"),
/**
* The message displayed when a player has some currency refunded to their account
*/
ECONOMY_REFUNDED("ecoRefund"),
/**
* The message displayed when a player obtains some currency to their account (from portal usage)
*/
ECONOMY_OBTAINED("ecoObtain"),
/**
* The message displayed when the player has an insufficient amount of currency to perform an action
*/
ECONOMY_INSUFFICIENT("ecoInFunds"),
/**
* The message displayed when economy fails to load
*/
ECONOMY_LOAD_ERROR("ecoLoadError"),
/**
* The message displayed when Vault fails to load
*/
VAULT_LOAD_ERROR("vaultLoadError"),
/**
* The message displayed when Vault successfully loads
*/
VAULT_LOADED("vaultLoaded"),
/**
* The message displayed when a Stargate is successfully created
*/
CREATED("createMsg"),
/**
* The message displayed when a player is denied from creating a Stargate on the selected network
*/
CREATION_NETWORK_DENIED("createNetDeny"),
/**
* The message displayed when a player is denied from creating a Stargate of the given gate type
*/
CREATION_GATE_DENIED("createGateDeny"),
/**
* The message displayed when a Stargate is created on the player's personal network
*/
CREATION_PERSONAL("createPersonal"),
/**
* The message displayed when the name of a Stargate is too short or too long
*/
CREATION_NAME_LENGTH("createNameLength"),
/**
* The message displayed when another Stargate on the network has the same name as the new Stargate
*/
CREATION_NAME_COLLISION("createExists"),
/**
* The message displayed when the specified network is full
*/
CREATION_NETWORK_FULL("createFull"),
/**
* The message displayed when a player is denied from creating a Stargate in the current world
*/
CREATION_WORLD_DENIED("createWorldDeny"),
/**
* The message displayed when a gate is physically conflicting with another
*/
CREATION_CONFLICT("createConflict"),
/**
* The right-click prompt displayed on Stargate signs
*/
SIGN_RIGHT_CLICK("signRightClick"),
/**
* The to use prompt displayed on Stargate signs
*/
SIGN_TO_USE("signToUse"),
/**
* The random string displayed on Stargate signs
*/
SIGN_RANDOM("signRandom"),
/**
* The disconnected string displayed on Stargate signs
*/
SIGN_DISCONNECTED("signDisconnected"),
/**
* The invalid gate string displayed on Stargate signs
*/
SIGN_INVALID("signInvalidGate"),
/**
* The message displayed if trying to create a bungee gate when bungee is disabled
*/
BUNGEE_DISABLED("bungeeDisabled"),
/**
* The message displayed when a player is denied from creating a bungee Stargate
*/
BUNGEE_CREATION_DENIED("bungeeDeny"),
/**
* The message displayed if a Stargate is missing the destination, the network or both
*/
BUNGEE_MISSING_INFO("bungeeEmpty"),
/**
* The teleportation prompt shown on bungee signs
*/
BUNGEE_SIGN("bungeeSign"),
/**
* The format of the title of the portal info shown in chat
*/
PORTAL_INFO_TITLE("portalInfoTitle"),
/**
* The format of the name of the portal info shown in chat
*/
PORTAL_INFO_NAME("portalInfoName"),
/**
* The format of the destination of the portal info shown in chat
*/
PORTAL_INFO_DESTINATION("portalInfoDestination"),
/**
* The format of the network of the portal info shown in chat
*/
PORTAL_INFO_NETWORK("portalInfoNetwork"),
/**
* The format of the server of the portal info shown in chat
*/
PORTAL_INFO_SERVER("portalInfoServer"),
/**
* The author that created the loaded translation
*/
AUTHOR("author"),
;
private final String key;
/**
* Instantiates a new message
*
* @param key <p>The key of the message in the language files</p>
*/
Message(@NotNull String key) {
this.key = key;
}
/**
* Gets the language file key for this message
*
* @return <p>This message's key</p>
*/
@NotNull
public String getKey() {
return this.key;
}
/**
* Gets the message corresponding to the given key
*
* @param key <p>The key to get a message from</p>
* @return <p>The message, or null if not found</p>
*/
@Nullable
public static Message getFromKey(@NotNull String key) {
for (Message message : Message.values()) {
if (message.getKey().equalsIgnoreCase(key)) {
return message;
}
}
return null;
}
@Override
@NotNull
public String toString() {
return this.getKey();
}
}

View File

@@ -1,61 +0,0 @@
package net.knarcraft.stargate.config;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.command.CommandSender;
/**
* The message sender is responsible sending messages to players with correct coloring and formatting
*/
public final class MessageSender {
private final LanguageLoader languageLoader;
/**
* Instantiates a new message sender
*
* @param languageLoader <p>The language loader to get translated strings from</p>
*/
public MessageSender(LanguageLoader languageLoader) {
this.languageLoader = languageLoader;
}
/**
* Sends an error message to a player
*
* @param player <p>The player to send the message to</p>
* @param message <p>The message to send</p>
*/
public void sendErrorMessage(CommandSender player, String message) {
sendMessage(player, message, true);
}
/**
* Sends a success message to a player
*
* @param player <p>The player to send the message to</p>
* @param message <p>The message to send</p>
*/
public void sendSuccessMessage(CommandSender player, String message) {
sendMessage(player, message, false);
}
/**
* Sends a message to a player
*
* @param sender <p>The player to send the message to</p>
* @param message <p>The message to send</p>
* @param error <p>Whether the message sent is an error</p>
*/
private void sendMessage(CommandSender sender, String message, boolean error) {
if (message.isEmpty()) {
return;
}
message = ChatColor.translateAlternateColorCodes('&', message);
if (error) {
sender.sendMessage(ChatColor.RED + languageLoader.getString("prefix") + ChatColor.WHITE + message);
} else {
sender.sendMessage(ChatColor.GREEN + languageLoader.getString("prefix") + ChatColor.WHITE + message);
}
}
}

View File

@@ -0,0 +1,40 @@
package net.knarcraft.stargate.config;
import net.knarcraft.knarlib.formatting.FormatBuilder;
import net.knarcraft.stargate.Stargate;
import org.jetbrains.annotations.NotNull;
/**
* A customized format builder for automatic translation of Stargate messages
*/
public class SGFormatBuilder extends FormatBuilder {
/**
* Instantiates a new format builder
*/
public SGFormatBuilder() {
super();
}
/**
* Instantiates a new format builder
*
* <p>If the input is a list, it will be joined using the default delimiter: ",".</p>
*
* @param input <p>The input to use as the initial string of this format builder</p>
* @throws IllegalStateException <p>If the string formatter has not been set, and the input is a translatable message</p>
*/
public <K> SGFormatBuilder(@NotNull K input) throws IllegalStateException {
super(input);
}
@Override
@NotNull
protected <K> String asString(@NotNull K input, @NotNull String delimiter) {
if (input instanceof Message message) {
return Stargate.getStargateConfig().getLanguageLoader().getString(message);
}
return super.asString(input, delimiter);
}
}

View File

@@ -1,7 +1,9 @@
package net.knarcraft.stargate.config; package net.knarcraft.stargate.config;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.Translator;
import net.knarcraft.knarlib.property.ColorConversion; import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.FileHelper; import net.knarcraft.knarlib.util.ConfigHelper;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.listener.BungeeCordListener; import net.knarcraft.stargate.listener.BungeeCordListener;
@@ -17,9 +19,9 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.messaging.Messenger; import org.bukkit.plugin.messaging.Messenger;
import org.dynmap.DynmapAPI; import org.dynmap.DynmapAPI;
import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@@ -27,6 +29,8 @@ import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* The stargate config is responsible for keeping track of all configuration values * The stargate config is responsible for keeping track of all configuration values
@@ -38,7 +42,6 @@ public final class StargateConfig {
private final HashSet<String> managedWorlds = new HashSet<>(); private final HashSet<String> managedWorlds = new HashSet<>();
private StargateGateConfig stargateGateConfig; private StargateGateConfig stargateGateConfig;
private MessageSender messageSender;
private final LanguageLoader languageLoader; private final LanguageLoader languageLoader;
private EconomyConfig economyConfig; private EconomyConfig economyConfig;
private final Logger logger; private final Logger logger;
@@ -47,6 +50,7 @@ public final class StargateConfig {
private String gateFolder; private String gateFolder;
private String portalFolder; private String portalFolder;
private String languageName = "en"; private String languageName = "en";
private boolean isLoaded = false;
private final Map<ConfigOption, Object> configOptions; private final Map<ConfigOption, Object> configOptions;
@@ -55,7 +59,7 @@ public final class StargateConfig {
* *
* @param logger <p>The logger to use for logging errors</p> * @param logger <p>The logger to use for logging errors</p>
*/ */
public StargateConfig(Logger logger) { public StargateConfig(@NotNull Logger logger) {
this.logger = logger; this.logger = logger;
configOptions = new HashMap<>(); configOptions = new HashMap<>();
@@ -73,6 +77,7 @@ public final class StargateConfig {
* *
* @return <p>A reference to the config options map</p> * @return <p>A reference to the config options map</p>
*/ */
@NotNull
public Map<ConfigOption, Object> getConfigOptionsReference() { public Map<ConfigOption, Object> getConfigOptionsReference() {
return configOptions; return configOptions;
} }
@@ -92,22 +97,48 @@ public final class StargateConfig {
languageLoader.setChosenLanguage(languageName); languageLoader.setChosenLanguage(languageName);
languageLoader.reload(); languageLoader.reload();
messageSender = new MessageSender(languageLoader); // Update prefix of the format builder
SGFormatBuilder.setStringFormatter(getStringFormatter());
if (isDebuggingEnabled()) { if (isDebuggingEnabled()) {
languageLoader.debug(); languageLoader.debug();
} }
this.createMissingFolders();
this.loadGates(); this.loadGates();
this.createMissingFolders();
this.loadAllPortals(); this.loadAllPortals();
//Set up vault economy if vault has been loaded //Set up vault economy if vault has been loaded
setupVaultEconomy(); setupVaultEconomy();
DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
if (dynmapAPI != null) { //Set up dynmap
DynmapManager.initialize(dynmapAPI); try {
DynmapManager.addAllPortalMarkers(); DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
if (dynmapAPI != null) {
try {
DynmapManager.initialize(dynmapAPI);
DynmapManager.addAllPortalMarkers();
} catch (NullPointerException ignored) {
logger.warning("Dynmap started in an invalid state. Check your log/console for dynmap-related " +
"problems. Dynmap integration cannot be initialized.");
}
}
} catch (NoClassDefFoundError error) {
logger.warning("Dynmap seems to be unavailable, even though its API is registered. Dynmap " +
"integration is disabled.");
DynmapManager.disable();
} }
this.isLoaded = true;
}
/**
* Gets whether this configuration has been fully loaded
*
* @return <p>True if not fully loaded</p>
*/
public boolean isNotLoaded() {
return !this.isLoaded;
} }
/** /**
@@ -115,6 +146,7 @@ public final class StargateConfig {
* *
* @return <p>The loaded config options</p> * @return <p>The loaded config options</p>
*/ */
@NotNull
public Map<ConfigOption, Object> getConfigOptions() { public Map<ConfigOption, Object> getConfigOptions() {
return new HashMap<>(configOptions); return new HashMap<>(configOptions);
} }
@@ -126,6 +158,7 @@ public final class StargateConfig {
* *
* @return <p>The open portals queue</p> * @return <p>The open portals queue</p>
*/ */
@NotNull
public Queue<Portal> getOpenPortalsQueue() { public Queue<Portal> getOpenPortalsQueue() {
return openPortalsQueue; return openPortalsQueue;
} }
@@ -137,6 +170,7 @@ public final class StargateConfig {
* *
* @return <p>The active portals queue</p> * @return <p>The active portals queue</p>
*/ */
@NotNull
public Queue<Portal> getActivePortalsQueue() { public Queue<Portal> getActivePortalsQueue() {
return activePortalsQueue; return activePortalsQueue;
} }
@@ -182,6 +216,7 @@ public final class StargateConfig {
* *
* @return <p>The object containing economy config values</p> * @return <p>The object containing economy config values</p>
*/ */
@NotNull
public EconomyConfig getEconomyConfig() { public EconomyConfig getEconomyConfig() {
return this.economyConfig; return this.economyConfig;
} }
@@ -191,16 +226,16 @@ public final class StargateConfig {
* *
* @param sender <p>The sender of the reload request</p> * @param sender <p>The sender of the reload request</p>
*/ */
public void reload(CommandSender sender) { public void reload(@NotNull CommandSender sender) {
//Unload all saved data //Unload all saved data
unload(); unload();
//Perform all block change requests to prevent mismatch if a gate's open-material changes. Changing the //Perform all block change requests to prevent mismatch if a gate's open-material changes. Changing the
// closed-material still requires a restart. // closed-material still requires a restart.
BlockChangeRequest firstElement = Stargate.getBlockChangeRequestQueue().peek(); BlockChangeRequest firstElement = Stargate.getControlBlockUpdateRequestQueue().peek();
while (firstElement != null) { while (firstElement != null) {
BlockChangeThread.pollQueue(); BlockChangeThread.pollQueue();
firstElement = Stargate.getBlockChangeRequestQueue().peek(); firstElement = Stargate.getControlBlockUpdateRequestQueue().peek();
} }
//Store the old enable bungee state in case it changes //Store the old enable bungee state in case it changes
@@ -217,7 +252,10 @@ public final class StargateConfig {
//Reload portal markers //Reload portal markers
DynmapManager.addAllPortalMarkers(); DynmapManager.addAllPortalMarkers();
messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded")); // Update prefix of the format builder
SGFormatBuilder.setStringFormatter(getStringFormatter());
new SGFormatBuilder(Message.RELOADED).error(sender);
} }
/** /**
@@ -264,6 +302,7 @@ public final class StargateConfig {
* *
* @return <p>The managed worlds</p> * @return <p>The managed worlds</p>
*/ */
@NotNull
public Set<String> getManagedWorlds() { public Set<String> getManagedWorlds() {
return new HashSet<>(managedWorlds); return new HashSet<>(managedWorlds);
} }
@@ -273,7 +312,7 @@ public final class StargateConfig {
* *
* @param worldName <p>The name of the world to manage</p> * @param worldName <p>The name of the world to manage</p>
*/ */
public void addManagedWorld(String worldName) { public void addManagedWorld(@NotNull String worldName) {
managedWorlds.add(worldName); managedWorlds.add(worldName);
} }
@@ -282,7 +321,7 @@ public final class StargateConfig {
* *
* @param worldName <p>The name of the world to stop managing</p> * @param worldName <p>The name of the world to stop managing</p>
*/ */
public void removeManagedWorld(String worldName) { public void removeManagedWorld(@NotNull String worldName) {
managedWorlds.remove(worldName); managedWorlds.remove(worldName);
} }
@@ -364,9 +403,11 @@ public final class StargateConfig {
FileConfiguration newConfig = Stargate.getInstance().getConfig(); FileConfiguration newConfig = Stargate.getInstance().getConfig();
boolean isMigrating = false; boolean isMigrating = false;
if (newConfig.getString("lang") != null || newConfig.getString("economy.freeGatesGreen") != null) { if (newConfig.getString("lang") != null || newConfig.getString("economy.taxAccount") == null) {
migrateConfig(newConfig); ConfigHelper.migrateConfig(Stargate.getInstance());
isMigrating = true; isMigrating = true;
Stargate.getInstance().reloadConfig();
newConfig = Stargate.getInstance().getConfig();
} }
//Copy missing default values if any values are missing //Copy missing default values if any values are missing
@@ -380,13 +421,10 @@ public final class StargateConfig {
//Load the option using its correct data type //Load the option using its correct data type
switch (option.getDataType()) { switch (option.getDataType()) {
case STRING_LIST -> optionValue = newConfig.getStringList(configNode); case STRING_LIST -> optionValue = newConfig.getStringList(configNode);
case STRING -> { case STRING -> optionValue = newConfig.getString(configNode, (String) option.getDefaultValue()).trim();
String value = newConfig.getString(configNode); case BOOLEAN -> optionValue = newConfig.getBoolean(configNode, (boolean) option.getDefaultValue());
optionValue = value != null ? value.trim() : ""; case INTEGER -> optionValue = newConfig.getInt(configNode, (int) option.getDefaultValue());
} case DOUBLE -> optionValue = newConfig.getDouble(configNode, (double) option.getDefaultValue());
case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
case INTEGER -> optionValue = newConfig.getInt(configNode);
case DOUBLE -> optionValue = newConfig.getDouble(configNode);
default -> throw new IllegalArgumentException("Invalid config data type encountered"); default -> throw new IllegalArgumentException("Invalid config data type encountered");
} }
configOptions.put(option, optionValue); configOptions.put(option, optionValue);
@@ -397,10 +435,24 @@ public final class StargateConfig {
//Get important folders from the config //Get important folders from the config
portalFolder = (String) configOptions.get(ConfigOption.PORTAL_FOLDER); portalFolder = (String) configOptions.get(ConfigOption.PORTAL_FOLDER);
if (portalFolder.isEmpty()) {
portalFolder = dataFolderPath + "/portals/";
} else {
portalFolder = replacePluginFolderPath(portalFolder);
}
Stargate.debug("StargateConfig::loadConfig", "Portal folder is " + portalFolder);
gateFolder = (String) configOptions.get(ConfigOption.GATE_FOLDER); gateFolder = (String) configOptions.get(ConfigOption.GATE_FOLDER);
if (gateFolder.isEmpty()) {
gateFolder = dataFolderPath + "/gates/";
} else {
gateFolder = replacePluginFolderPath(gateFolder);
}
Stargate.debug("StargateConfig::loadConfig", "Gate folder is " + gateFolder);
//If users have an outdated config, assume they also need to update their default gates //If users have an outdated config, assume they also need to update their default gates
if (isMigrating) { if (isMigrating) {
this.createMissingFolders();
GateHandler.writeDefaultGatesToFolder(gateFolder); GateHandler.writeDefaultGatesToFolder(gateFolder);
} }
@@ -413,11 +465,29 @@ public final class StargateConfig {
Stargate.getInstance().saveConfig(); Stargate.getInstance().saveConfig();
} }
/**
* Replaces "plugins/Stargate" in a folder path, and replaces it with the full path relative to the data folder
*
* @param input <p>The input string to replace in</p>
* @return <p>The replaced path, or the input if not applicable</p>
*/
@NotNull
private String replacePluginFolderPath(@NotNull String input) {
Pattern pattern = Pattern.compile("(?i)^plugins[\\\\/]Stargate");
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return dataFolderPath + matcher.replaceAll("");
} else {
return input;
}
}
/** /**
* Gets the object containing configuration values regarding gates * Gets the object containing configuration values regarding gates
* *
* @return <p>Gets the gate config</p> * @return <p>Gets the gate config</p>
*/ */
@NotNull
public StargateGateConfig getStargateGateConfig() { public StargateGateConfig getStargateGateConfig() {
return stargateGateConfig; return stargateGateConfig;
} }
@@ -430,54 +500,15 @@ public final class StargateConfig {
Stargate.logInfo(String.format("Loaded %s gate layouts", GateHandler.getGateCount())); Stargate.logInfo(String.format("Loaded %s gate layouts", GateHandler.getGateCount()));
} }
/**
* Changes all configuration values from the old name to the new name
*
* @param newConfig <p>The config to read from and write to</p>
*/
private void migrateConfig(FileConfiguration newConfig) {
//Save the old config just in case something goes wrong
try {
newConfig.save(dataFolderPath + "/config.yml.old");
} catch (IOException e) {
Stargate.debug("Stargate::migrateConfig", "Unable to save old backup and do migration");
e.printStackTrace();
return;
}
//Read all available config migrations
Map<String, String> migrationFields;
try {
migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(
FileHelper.getInputStreamForInternalFile("/config-migrations.txt")), "=",
ColorConversion.NORMAL);
} catch (IOException e) {
Stargate.debug("Stargate::migrateConfig", "Unable to load config migration file");
e.printStackTrace();
return;
}
//Replace old config names with the new ones
for (String key : migrationFields.keySet()) {
if (newConfig.contains(key)) {
String newPath = migrationFields.get(key);
Object oldValue = newConfig.get(key);
if (!newPath.trim().isEmpty()) {
newConfig.set(newPath, oldValue);
}
newConfig.set(key, null);
}
}
}
/** /**
* Loads economy from Vault * Loads economy from Vault
*/ */
private void setupVaultEconomy() { private void setupVaultEconomy() {
EconomyConfig economyConfig = getEconomyConfig(); EconomyConfig economyConfig = getEconomyConfig();
if (economyConfig.setupEconomy(Stargate.getPluginManager()) && economyConfig.getEconomy() != null) { if (economyConfig.setupEconomy(Stargate.getPluginManager()) && economyConfig.getEconomy() != null &&
economyConfig.getVault() != null) {
String vaultVersion = economyConfig.getVault().getDescription().getVersion(); String vaultVersion = economyConfig.getVault().getDescription().getVersion();
Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion)); Stargate.logInfo(new SGFormatBuilder(Message.VAULT_LOADED).replace("%version%", vaultVersion).toString());
} }
} }
@@ -497,18 +528,24 @@ public final class StargateConfig {
* Creates missing folders * Creates missing folders
*/ */
private void createMissingFolders() { private void createMissingFolders() {
File newPortalDir = new File(portalFolder); createMissingFolder(new File(gateFolder), "Unable to create gate directory");
if (!newPortalDir.exists()) { createMissingFolder(new File(portalFolder), "Unable to create portal directory");
if (!newPortalDir.mkdirs()) {
logger.severe("Unable to create portal directory");
}
}
File newFile = new File(portalFolder, Stargate.getInstance().getServer().getWorlds().get(0).getName() + File newFile = new File(portalFolder, Stargate.getInstance().getServer().getWorlds().get(0).getName() +
".db"); ".db");
if (!newFile.exists() && !newFile.getParentFile().exists()) { if (!newFile.exists() && !newFile.getParentFile().exists() && !newFile.getParentFile().mkdirs()) {
if (!newFile.getParentFile().mkdirs()) { logger.severe("Unable to create portal database folder: " + newFile.getParentFile().getPath());
logger.severe("Unable to create portal database folder: " + newFile.getParentFile().getPath()); }
} }
/**
* Creates the given folder if it's missing
*
* @param folder <p>The folder to create</p>
* @param errorMessage <p>The error message to display if unable to create the folder</p>
*/
private void createMissingFolder(File folder, String errorMessage) {
if (!folder.exists() && !folder.mkdirs()) {
logger.severe(errorMessage);
} }
} }
@@ -517,6 +554,7 @@ public final class StargateConfig {
* *
* @return <p>The portal folder</p> * @return <p>The portal folder</p>
*/ */
@NotNull
public String getPortalFolder() { public String getPortalFolder() {
return portalFolder; return portalFolder;
} }
@@ -528,26 +566,57 @@ public final class StargateConfig {
* *
* @return <p>The folder storing gate files</p> * @return <p>The folder storing gate files</p>
*/ */
@NotNull
public String getGateFolder() { public String getGateFolder() {
return gateFolder; return gateFolder;
} }
/**
* Gets the sender for sending messages to players
*
* @return <p>The sender for sending messages to players</p>
*/
public MessageSender getMessageSender() {
return messageSender;
}
/** /**
* Gets the language loader containing translated strings * Gets the language loader containing translated strings
* *
* @return <p>The language loader</p> * @return <p>The language loader</p>
*/ */
@NotNull
public LanguageLoader getLanguageLoader() { public LanguageLoader getLanguageLoader() {
return languageLoader; return languageLoader;
} }
/**
* Gets the string formatter to use
*/
@NotNull
private StringFormatter getStringFormatter() {
// In order to allow automatic customization of prefix color, parse it properly
String rawPrefix = getLanguageLoader().getString(Message.PREFIX);
String colorPattern = "(?:[&§][a-fA-F0-9klmnor]|&?#[0-9a-fA-F]{6}|§x(?:§[a-fA-F0-9]){6})*";
Pattern pattern = Pattern.compile("(" + colorPattern + "\\[" + colorPattern + ")(\\w+)(" +
colorPattern + "]" + colorPattern + ")");
return getStringFormatter(rawPrefix, pattern);
}
/**
* Gets the string formatter to use
*
* @param rawPrefix <p>The formatter prefix to parse</p>
* @param pattern <p>The pattern to use for parsing</p>
*/
private static @NotNull StringFormatter getStringFormatter(String rawPrefix, Pattern pattern) {
String prefix = rawPrefix;
String namePrefix = "[";
String nameSuffix = "]";
Matcher matcher = pattern.matcher(rawPrefix);
if (matcher.find()) {
namePrefix = matcher.group(1).trim();
prefix = matcher.group(2).trim();
nameSuffix = matcher.group(3).trim();
}
StringFormatter stringFormatter = new StringFormatter(prefix, new Translator());
stringFormatter.setColorConversion(ColorConversion.RGB);
stringFormatter.setNamePrefix(namePrefix);
stringFormatter.setNameSuffix(nameSuffix);
return stringFormatter;
}
} }

View File

@@ -6,6 +6,7 @@ import net.knarcraft.stargate.portal.PortalSignDrawer;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Material; import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -26,7 +27,7 @@ public final class StargateGateConfig {
* *
* @param configOptions <p>The loaded config options to use</p> * @param configOptions <p>The loaded config options to use</p>
*/ */
public StargateGateConfig(Map<ConfigOption, Object> configOptions) { public StargateGateConfig(@NotNull Map<ConfigOption, Object> configOptions) {
this.configOptions = configOptions; this.configOptions = configOptions;
loadGateConfig(); loadGateConfig();
} }
@@ -100,6 +101,17 @@ public final class StargateGateConfig {
return (boolean) configOptions.get(ConfigOption.HANDLE_CREATURE_TRANSPORTATION); return (boolean) configOptions.get(ConfigOption.HANDLE_CREATURE_TRANSPORTATION);
} }
/**
* Gets the delay to wait between each update of a Stargate's control block
*
* <p>This only affects the queued control updates during startup. It does not affect normal gameplay.</p>
*
* @return <p>The amount of ticks to delay control updates by</p>
*/
public int controlUpdateDelay() {
return (int) configOptions.get(ConfigOption.CONTROL_UPDATE_QUEUE_DELAY);
}
/** /**
* Gets whether vehicles containing a creature, but not a player should be handled * Gets whether vehicles containing a creature, but not a player should be handled
* *
@@ -248,8 +260,8 @@ public final class StargateGateConfig {
* @param defaultColors <p>The specified default colors</p> * @param defaultColors <p>The specified default colors</p>
* @param colorMaps <p>The list of color maps to save the resulting colors to</p> * @param colorMaps <p>The list of color maps to save the resulting colors to</p>
*/ */
private void parsePerSignColors(Object signColorSpecification, ChatColor[] defaultColors, private void parsePerSignColors(@NotNull Object signColorSpecification, @NotNull ChatColor[] defaultColors,
List<Map<Material, ChatColor>> colorMaps) { @NotNull List<Map<Material, ChatColor>> colorMaps) {
String[] specificationData = String.valueOf(signColorSpecification).split(":"); String[] specificationData = String.valueOf(signColorSpecification).split(":");
Material[] signMaterials = new Material[]{Material.matchMaterial(specificationData[0] + "_SIGN"), Material[] signMaterials = new Material[]{Material.matchMaterial(specificationData[0] + "_SIGN"),
Material.matchMaterial(specificationData[0] + "_WALL_SIGN")}; Material.matchMaterial(specificationData[0] + "_WALL_SIGN")};
@@ -280,8 +292,8 @@ public final class StargateGateConfig {
* @param signMaterials <p>The materials to load this color for</p> * @param signMaterials <p>The materials to load this color for</p>
* @param colorMaps <p>The list of color maps to save the resulting color to</p> * @param colorMaps <p>The list of color maps to save the resulting color to</p>
*/ */
private void loadPerSignColor(String[] colors, int colorIndex, ChatColor[] defaultColors, Material[] signMaterials, private void loadPerSignColor(@NotNull String[] colors, int colorIndex, @NotNull ChatColor[] defaultColors,
List<Map<Material, ChatColor>> colorMaps) { @NotNull Material[] signMaterials, @NotNull List<Map<Material, ChatColor>> colorMaps) {
ChatColor parsedColor; ChatColor parsedColor;
if (colors[colorIndex].equalsIgnoreCase("inverted")) { if (colors[colorIndex].equalsIgnoreCase("inverted")) {
//Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor //Convert from ChatColor to awt.Color to Bukkit.Color then invert and convert to ChatColor
@@ -309,18 +321,20 @@ public final class StargateGateConfig {
* *
* @param mainSignColor <p>A string representing the main sign color</p> * @param mainSignColor <p>A string representing the main sign color</p>
*/ */
private void loadPerSignColor(String mainSignColor, String highlightSignColor) { private void loadPerSignColor(@NotNull String mainSignColor, @NotNull String highlightSignColor) {
try { try {
PortalSignDrawer.setMainColor(ChatColor.of(mainSignColor.toUpperCase())); PortalSignDrawer.setMainColor(ChatColor.of(mainSignColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException exception) { } catch (IllegalArgumentException | NullPointerException exception) {
Stargate.logWarning("You have specified an invalid main sign color in your config.yml. Defaulting to BLACK"); Stargate.logWarning("You have specified an invalid main sign color in your config.yml (" + mainSignColor +
"). Defaulting to BLACK");
PortalSignDrawer.setMainColor(ChatColor.BLACK); PortalSignDrawer.setMainColor(ChatColor.BLACK);
} }
try { try {
PortalSignDrawer.setHighlightColor(ChatColor.of(highlightSignColor.toUpperCase())); PortalSignDrawer.setHighlightColor(ChatColor.of(highlightSignColor.toUpperCase()));
} catch (IllegalArgumentException | NullPointerException exception) { } catch (IllegalArgumentException | NullPointerException exception) {
Stargate.logWarning("You have specified an invalid highlighting sign color in your config.yml. Defaulting to WHITE"); Stargate.logWarning("You have specified an invalid highlighting sign color in your config.yml (" +
highlightSignColor + "). Defaulting to WHITE");
PortalSignDrawer.setHighlightColor(ChatColor.WHITE); PortalSignDrawer.setHighlightColor(ChatColor.WHITE);
} }
} }

View File

@@ -0,0 +1,49 @@
package net.knarcraft.stargate.config.material;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* A specifier for a Bukkit material
*/
public class BukkitMaterialSpecifier implements MaterialSpecifier {
private final Material material;
/**
* Instantiates a new material specifier
*
* @param material <p>The material to specify</p>
*/
public BukkitMaterialSpecifier(@NotNull Material material) {
this.material = material;
}
@Override
@NotNull
public String asString() {
return this.material.name();
}
@Override
@NotNull
public Set<Material> asMaterials() {
return Set.of(this.material);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof BukkitMaterialSpecifier bukkitMaterialSpecifier)) {
return false;
}
return this.material == bukkitMaterialSpecifier.material;
}
@Override
public int hashCode() {
return material.hashCode();
}
}

View File

@@ -0,0 +1,49 @@
package net.knarcraft.stargate.config.material;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* A specifier for a Bukkit material tag
*/
public class BukkitTagSpecifier implements MaterialSpecifier {
private final Tag<Material> tag;
/**
* Instantiates a new tag specifier
*
* @param tag <p>The tag to specify</p>
*/
public BukkitTagSpecifier(@NotNull Tag<Material> tag) {
this.tag = tag;
}
@Override
public @NotNull String asString() {
return "#" + this.tag.getKey().toString().replaceFirst("minecraft:", "");
}
@Override
public @NotNull Set<Material> asMaterials() {
return this.tag.getValues();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof BukkitTagSpecifier bukkitMaterialSpecifier)) {
return false;
}
return this.tag == bukkitMaterialSpecifier.tag;
}
@Override
public int hashCode() {
return tag.hashCode();
}
}

View File

@@ -0,0 +1,29 @@
package net.knarcraft.stargate.config.material;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* An interface describing a specifier for one or more Bukkit materials
*/
public interface MaterialSpecifier {
/**
* Gets the string representation of the material specifier
*
* <p>This is used when saving the value to a gate file</p>
*/
@NotNull
String asString();
/**
* Gets all the materials the specifier specifies
*
* <p>This is used when registering gate materials</p>
*/
@NotNull
Set<Material> asMaterials();
}

View File

@@ -2,6 +2,8 @@ package net.knarcraft.stargate.container;
import org.bukkit.Axis; import org.bukkit.Axis;
import org.bukkit.Material; import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Represents a request for changing a block into another material * Represents a request for changing a block into another material
@@ -19,7 +21,7 @@ public class BlockChangeRequest {
* @param material <p>The new material to change the block to</p> * @param material <p>The new material to change the block to</p>
* @param axis <p>The new axis to orient the block along</p> * @param axis <p>The new axis to orient the block along</p>
*/ */
public BlockChangeRequest(BlockLocation blockLocation, Material material, Axis axis) { public BlockChangeRequest(@NotNull BlockLocation blockLocation, @NotNull Material material, @Nullable Axis axis) {
this.blockLocation = blockLocation; this.blockLocation = blockLocation;
newMaterial = material; newMaterial = material;
newAxis = axis; newAxis = axis;
@@ -30,6 +32,7 @@ public class BlockChangeRequest {
* *
* @return <p>The location of the block</p> * @return <p>The location of the block</p>
*/ */
@NotNull
public BlockLocation getBlockLocation() { public BlockLocation getBlockLocation() {
return blockLocation; return blockLocation;
} }
@@ -39,6 +42,7 @@ public class BlockChangeRequest {
* *
* @return <p>The material to change the block into</p> * @return <p>The material to change the block into</p>
*/ */
@NotNull
public Material getMaterial() { public Material getMaterial() {
return newMaterial; return newMaterial;
} }
@@ -48,6 +52,7 @@ public class BlockChangeRequest {
* *
* @return <p>The axis to orient the block along</p> * @return <p>The axis to orient the block along</p>
*/ */
@Nullable
public Axis getAxis() { public Axis getAxis() {
return newAxis; return newAxis;
} }

View File

@@ -10,6 +10,8 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional; import org.bukkit.block.data.Directional;
import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.Sign;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* This class represents a block location * This class represents a block location
@@ -30,7 +32,7 @@ public class BlockLocation extends Location {
* @param y <p>The y coordinate of the block</p> * @param y <p>The y coordinate of the block</p>
* @param z <p>The z coordinate of the block</p> * @param z <p>The z coordinate of the block</p>
*/ */
public BlockLocation(World world, int x, int y, int z) { public BlockLocation(@NotNull World world, int x, int y, int z) {
super(world, x, y, z); super(world, x, y, z);
} }
@@ -39,7 +41,7 @@ public class BlockLocation extends Location {
* *
* @param block <p>The block to get the location of</p> * @param block <p>The block to get the location of</p>
*/ */
public BlockLocation(Block block) { public BlockLocation(@NotNull Block block) {
super(block.getWorld(), block.getX(), block.getY(), block.getZ()); super(block.getWorld(), block.getX(), block.getY(), block.getZ());
} }
@@ -49,7 +51,7 @@ public class BlockLocation extends Location {
* @param world <p>The world the block exists in</p> * @param world <p>The world the block exists in</p>
* @param string <p>A comma separated list of x, y and z coordinates as integers</p> * @param string <p>A comma separated list of x, y and z coordinates as integers</p>
*/ */
public BlockLocation(World world, String string) { public BlockLocation(@NotNull World world, @NotNull String string) {
super(world, Integer.parseInt(string.split(",")[0]), Integer.parseInt(string.split(",")[1]), super(world, Integer.parseInt(string.split(",")[0]), Integer.parseInt(string.split(",")[1]),
Integer.parseInt(string.split(",")[2])); Integer.parseInt(string.split(",")[2]));
} }
@@ -62,6 +64,7 @@ public class BlockLocation extends Location {
* @param z <p>The number of blocks to move in the z-direction</p> * @param z <p>The number of blocks to move in the z-direction</p>
* @return <p>A new block location</p> * @return <p>A new block location</p>
*/ */
@NotNull
public BlockLocation makeRelativeBlockLocation(int x, int y, int z) { public BlockLocation makeRelativeBlockLocation(int x, int y, int z) {
return (BlockLocation) this.clone().add(x, y, z); return (BlockLocation) this.clone().add(x, y, z);
} }
@@ -75,6 +78,7 @@ public class BlockLocation extends Location {
* @param yaw <p>The number of blocks to move in the z-direction</p> * @param yaw <p>The number of blocks to move in the z-direction</p>
* @return <p>A new location</p> * @return <p>A new location</p>
*/ */
@NotNull
public Location makeRelativeLocation(double x, double y, double z, float yaw) { public Location makeRelativeLocation(double x, double y, double z, float yaw) {
Location newLocation = this.clone(); Location newLocation = this.clone();
newLocation.setYaw(yaw); newLocation.setYaw(yaw);
@@ -89,9 +93,10 @@ public class BlockLocation extends Location {
* @param yaw <p>The yaw pointing outwards from a portal (in the relative vector's out direction)</p> * @param yaw <p>The yaw pointing outwards from a portal (in the relative vector's out direction)</p>
* @return <p>A location relative to this location</p> * @return <p>A location relative to this location</p>
*/ */
public BlockLocation getRelativeLocation(RelativeBlockVector relativeVector, double yaw) { @NotNull
Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(relativeVector.getRight(), public BlockLocation getRelativeLocation(@NotNull RelativeBlockVector relativeVector, double yaw) {
relativeVector.getDown(), relativeVector.getOut(), yaw); Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(relativeVector.right(),
relativeVector.down(), relativeVector.out(), yaw);
return makeRelativeBlockLocation(realVector.getBlockX(), realVector.getBlockY(), realVector.getBlockZ()); return makeRelativeBlockLocation(realVector.getBlockX(), realVector.getBlockY(), realVector.getBlockZ());
} }
@@ -107,6 +112,7 @@ public class BlockLocation extends Location {
* @param portalYaw <p>The yaw when looking out from the portal</p> * @param portalYaw <p>The yaw when looking out from the portal</p>
* @return A new location relative to this block location * @return A new location relative to this block location
*/ */
@NotNull
public Location getRelativeLocation(double right, double down, double out, float portalYaw) { public Location getRelativeLocation(double right, double down, double out, float portalYaw) {
Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(right, down, out, portalYaw); Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(right, down, out, portalYaw);
return makeRelativeLocation(0.5 + realVector.getBlockX(), realVector.getBlockY(), return makeRelativeLocation(0.5 + realVector.getBlockX(), realVector.getBlockY(),
@@ -118,6 +124,7 @@ public class BlockLocation extends Location {
* *
* @return <p>The block's material type</p> * @return <p>The block's material type</p>
*/ */
@NotNull
public Material getType() { public Material getType() {
return this.getBlock().getType(); return this.getBlock().getType();
} }
@@ -127,7 +134,7 @@ public class BlockLocation extends Location {
* *
* @param type <p>The block's new material type</p> * @param type <p>The block's new material type</p>
*/ */
public void setType(Material type) { public void setType(@NotNull Material type) {
this.getBlock().setType(type); this.getBlock().setType(type);
} }
@@ -136,6 +143,7 @@ public class BlockLocation extends Location {
* *
* @return <p>The location representing this block location</p> * @return <p>The location representing this block location</p>
*/ */
@NotNull
public Location getLocation() { public Location getLocation() {
return this.clone(); return this.clone();
} }
@@ -148,6 +156,7 @@ public class BlockLocation extends Location {
* *
* @return <p>This block location's parent block</p> * @return <p>This block location's parent block</p>
*/ */
@Nullable
public Block getParent() { public Block getParent() {
if (parent == null) { if (parent == null) {
findParent(); findParent();
@@ -184,6 +193,7 @@ public class BlockLocation extends Location {
} }
@Override @Override
@NotNull
public String toString() { public String toString() {
return String.valueOf(this.getBlockX()) + ',' + this.getBlockY() + ',' + this.getBlockZ(); return String.valueOf(this.getBlockX()) + ',' + this.getBlockY() + ',' + this.getBlockZ();
} }
@@ -203,7 +213,7 @@ public class BlockLocation extends Location {
} }
@Override @Override
public boolean equals(Object object) { public boolean equals(@Nullable Object object) {
if (this == object) { if (this == object) {
return true; return true;
} }

View File

@@ -17,7 +17,7 @@ public class ChunkUnloadRequest implements Comparable<ChunkUnloadRequest> {
* @param chunkToUnload <p>The chunk to request the unloading of</p> * @param chunkToUnload <p>The chunk to request the unloading of</p>
* @param timeUntilUnload <p>The time in milliseconds to wait before unloading the chunk</p> * @param timeUntilUnload <p>The time in milliseconds to wait before unloading the chunk</p>
*/ */
public ChunkUnloadRequest(Chunk chunkToUnload, Long timeUntilUnload) { public ChunkUnloadRequest(@NotNull Chunk chunkToUnload, @NotNull Long timeUntilUnload) {
this.chunkToUnload = chunkToUnload; this.chunkToUnload = chunkToUnload;
long systemNanoTime = System.nanoTime(); long systemNanoTime = System.nanoTime();
this.unloadNanoTime = systemNanoTime + (timeUntilUnload * 1000000); this.unloadNanoTime = systemNanoTime + (timeUntilUnload * 1000000);
@@ -28,6 +28,7 @@ public class ChunkUnloadRequest implements Comparable<ChunkUnloadRequest> {
* *
* @return <p>The chunk to unload</p> * @return <p>The chunk to unload</p>
*/ */
@NotNull
public Chunk getChunkToUnload() { public Chunk getChunkToUnload() {
return this.chunkToUnload; return this.chunkToUnload;
} }
@@ -37,11 +38,13 @@ public class ChunkUnloadRequest implements Comparable<ChunkUnloadRequest> {
* *
* @return <p>The system nano time denoting when the chunk is to be unloaded</p> * @return <p>The system nano time denoting when the chunk is to be unloaded</p>
*/ */
@NotNull
public Long getUnloadNanoTime() { public Long getUnloadNanoTime() {
return this.unloadNanoTime; return this.unloadNanoTime;
} }
@Override @Override
@NotNull
public String toString() { public String toString() {
return "{" + chunkToUnload + ", " + unloadNanoTime + "}"; return "{" + chunkToUnload + ", " + unloadNanoTime + "}";
} }

View File

@@ -0,0 +1,12 @@
package net.knarcraft.stargate.container;
import net.knarcraft.stargate.portal.Portal;
import org.jetbrains.annotations.NotNull;
/**
* A request for updating a portal's control blocks
*
* @param portal <p>The portal to update the control blocks for</p>
*/
public record ControlBlockUpdateRequest(@NotNull Portal portal) {
}

View File

@@ -1,60 +1,16 @@
package net.knarcraft.stargate.container; package net.knarcraft.stargate.container;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull;
/** /**
* This class represents a player teleporting from the end to the over-world using an artificial end portal * This class represents a teleportation from the end to the over-world using an artificial end portal
* *
* <p>This is necessary because a player entering an end portal in the end is a special case. Instead of being * <p>This is necessary because a player entering an end portal in the end is a special case. Instead of being
* teleported, the player is respawned. Because of this, the teleportation needs to be saved and later used to hijack * teleported, the player is respawned. Because of this, the teleportation needs to be saved and later used to hijack
* the position of where the player is to respawn.</p> * the position of where the player is to respawn.</p>
*
* @param exitPortal <p>The portal the player should exit from when arriving in the over-world</p>
*/ */
public class FromTheEndTeleportation { public record FromTheEndTeleportation(@NotNull Portal exitPortal) {
private final Player teleportingPlayer;
private final Portal exitPortal;
/**
* Instantiates a new teleportation from the end
*
* @param teleportingPlayer <p>The teleporting player</p>
* @param exitPortal <p>The portal to exit from</p>
*/
public FromTheEndTeleportation(Player teleportingPlayer, Portal exitPortal) {
this.teleportingPlayer = teleportingPlayer;
this.exitPortal = exitPortal;
}
/**
* Gets the teleporting player
*
* @return <p>The teleporting player</p>
*/
public Player getPlayer() {
return this.teleportingPlayer;
}
/**
* Gets the portal to exit from
*
* @return <p>The portal to exit from</p>
*/
public Portal getExit() {
return this.exitPortal;
}
@Override
public int hashCode() {
return teleportingPlayer.hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof FromTheEndTeleportation otherTeleportation)) {
return false;
}
return teleportingPlayer.equals(otherTeleportation.teleportingPlayer);
}
} }

View File

@@ -1,6 +1,7 @@
package net.knarcraft.stargate.container; package net.knarcraft.stargate.container;
import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* This stores a block location as a vector relative to a position * This stores a block location as a vector relative to a position
@@ -9,71 +10,48 @@ import org.bukkit.util.Vector;
* top-left block of a gate (top-left when looking at the side with the sign). The right is therefore the distance * top-left block of a gate (top-left when looking at the side with the sign). The right is therefore the distance
* from the top-left corner towards the top-right corner. Down is the distance from the top-left corner towards the * from the top-left corner towards the top-right corner. Down is the distance from the top-left corner towards the
* bottom-left corner. Out is the distance outward from the gate.</p> * bottom-left corner. Out is the distance outward from the gate.</p>
*
* <p>Relative block vectors start from a top-left corner. A yaw is used to orient a relative block vector in the
* "real world". In terms of a gate layout, the origin is 0,0. Right is towards the end of the line. Down is to the
* next line. Out is towards the observer.</p>
*
* @param right <p>The distance rightward relative to the origin</p>
* @param down <p>The distance downward relative to the origin</p>
* @param out <p>The distance outward relative to the origin</p>
*/ */
public class RelativeBlockVector { public record RelativeBlockVector(int right, int down, int out) {
private final int right;
private final int down;
private final int out;
/** /**
* A specifier for one of the relative block vector's three properties * Adds the given value to this relative block vector's "right" property
*
* @param valueToAdd <p>The value to add</p>
* @return <p>The new resulting vector</p>
*/ */
public enum Property { @NotNull
/** public RelativeBlockVector addRight(int valueToAdd) {
* Specifies the relative block vector's right property return new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
*/
RIGHT,
/**
* Specifies the relative block vector's down property
*/
DOWN,
/**
* Specifies the relative block vector's out property
*/
OUT
} }
/** /**
* Instantiates a new relative block vector * Adds the given value to this relative block vector's "down" property
* *
* <p>Relative block vectors start from a top-left corner. A yaw is used to orient a relative block vector in the * @param valueToAdd <p>The value to add</p>
* "real world". * @return <p>The new resulting vector</p>
* In terms of a gate layout, the origin is 0,0. Right is towards the end of the line. Down is to the
* next line. Out is towards the observer.</p>
*
* @param right <p>The distance rightward relative to the origin</p>
* @param down <p>The distance downward relative to the origin</p>
* @param out <p>The distance outward relative to the origin</p>
*/ */
public RelativeBlockVector(int right, int down, int out) { @NotNull
this.right = right; public RelativeBlockVector addDown(int valueToAdd) {
this.down = down; return new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
this.out = out;
} }
/** /**
* Adds a value to one of the properties of this relative block vector * Adds the given value to this relative block vector's "out" property
* *
* @param propertyToAddTo <p>The property to add to</p> * @param valueToAdd <p>The value to add</p>
* @param valueToAdd <p>The value to add to the property (negative to move in the opposite direction)</p> * @return <p>The new resulting vector</p>
* @return <p>A new relative block vector with the property altered</p>
*/ */
public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) { @NotNull
return switch (propertyToAddTo) { public RelativeBlockVector addOut(int valueToAdd) {
case RIGHT -> new RelativeBlockVector(this.right + valueToAdd, this.down, this.out); return new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
case DOWN -> new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
case OUT -> new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
};
}
/**
* Gets a relative vector in the real space representing this relative block vector
*
* @return <p>A vector representing this relative block vector</p>
*/
public Vector toVector() {
return new Vector(this.right, -this.down, this.out);
} }
/** /**
@@ -81,44 +59,19 @@ public class RelativeBlockVector {
* *
* @return <p>This vector, but inverted</p> * @return <p>This vector, but inverted</p>
*/ */
@NotNull
public RelativeBlockVector invert() { public RelativeBlockVector invert() {
return new RelativeBlockVector(-this.right, -this.down, -this.out); return new RelativeBlockVector(-this.right, -this.down, -this.out);
} }
/**
* Gets the distance to the right relative to the origin
*
* @return <p>The distance to the right relative to the origin</p>
*/
public int getRight() {
return right;
}
/**
* Gets the distance downward relative to the origin
*
* @return <p>The distance downward relative to the origin</p>
*/
public int getDown() {
return down;
}
/**
* Gets the distance outward relative to the origin
*
* @return <p>The distance outward relative to the origin</p>
*/
public int getOut() {
return out;
}
@Override @Override
@NotNull
public String toString() { public String toString() {
return String.format("(right = %d, down = %d, out = %d)", right, down, out); return String.format("(right = %d, down = %d, out = %d)", right, down, out);
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(@Nullable Object other) {
if (other == this) { if (other == this) {
return true; return true;
} }

View File

@@ -1,9 +1,11 @@
package net.knarcraft.stargate.container; package net.knarcraft.stargate.container;
import net.knarcraft.knarlib.util.ColorHelper; import net.knarcraft.knarlib.util.ColorHelper;
import net.knarcraft.stargate.utility.SignHelper;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.DyeColor; import org.bukkit.DyeColor;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.jetbrains.annotations.NotNull;
/** /**
* A class that keeps track of the sign colors for a given sign * A class that keeps track of the sign colors for a given sign
@@ -22,11 +24,11 @@ public class SignData {
* @param mainSignColor <p>The main color to use for the sign</p> * @param mainSignColor <p>The main color to use for the sign</p>
* @param highlightSignColor <p>The highlighting color to use for the sign</p> * @param highlightSignColor <p>The highlighting color to use for the sign</p>
*/ */
public SignData(Sign sign, ChatColor mainSignColor, ChatColor highlightSignColor) { public SignData(@NotNull Sign sign, @NotNull ChatColor mainSignColor, @NotNull ChatColor highlightSignColor) {
this.sign = sign; this.sign = sign;
this.mainSignColor = mainSignColor; this.mainSignColor = mainSignColor;
this.highlightSignColor = highlightSignColor; this.highlightSignColor = highlightSignColor;
this.dyedColor = sign.getColor(); this.dyedColor = SignHelper.getDye(sign);
} }
/** /**
@@ -34,6 +36,7 @@ public class SignData {
* *
* @return <p>The sign of this sign colors object</p> * @return <p>The sign of this sign colors object</p>
*/ */
@NotNull
public Sign getSign() { public Sign getSign() {
return sign; return sign;
} }
@@ -43,6 +46,7 @@ public class SignData {
* *
* @return <p>The main color of the sign</p> * @return <p>The main color of the sign</p>
*/ */
@NotNull
public ChatColor getMainSignColor() { public ChatColor getMainSignColor() {
if (dyedColor != DyeColor.BLACK) { if (dyedColor != DyeColor.BLACK) {
return ColorHelper.fromColor(dyedColor.getColor()); return ColorHelper.fromColor(dyedColor.getColor());
@@ -56,6 +60,7 @@ public class SignData {
* *
* @return <p>The highlighting color of the sign</p> * @return <p>The highlighting color of the sign</p>
*/ */
@NotNull
public ChatColor getHighlightSignColor() { public ChatColor getHighlightSignColor() {
if (dyedColor != DyeColor.BLACK) { if (dyedColor != DyeColor.BLACK) {
return ColorHelper.fromColor(ColorHelper.invert(dyedColor.getColor())); return ColorHelper.fromColor(ColorHelper.invert(dyedColor.getColor()));

View File

@@ -24,7 +24,7 @@ public class StargateAccessEvent extends StargatePlayerEvent {
* @param portal <p>The portal involved in the event</p> * @param portal <p>The portal involved in the event</p>
* @param deny <p>Whether the stargate access should be denied</p> * @param deny <p>Whether the stargate access should be denied</p>
*/ */
public StargateAccessEvent(Player player, Portal portal, boolean deny) { public StargateAccessEvent(@NotNull Player player, @NotNull Portal portal, boolean deny) {
super(portal, player); super(portal, player);
this.deny = deny; this.deny = deny;
@@ -53,6 +53,7 @@ public class StargateAccessEvent extends StargatePlayerEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -28,7 +28,8 @@ public class StargateActivateEvent extends StargatePlayerEvent {
* @param destinations <p>The destinations available to the player using the portal</p> * @param destinations <p>The destinations available to the player using the portal</p>
* @param destination <p>The currently selected destination</p> * @param destination <p>The currently selected destination</p>
*/ */
public StargateActivateEvent(Portal portal, Player player, List<String> destinations, String destination) { public StargateActivateEvent(@NotNull Portal portal, @NotNull Player player, @NotNull List<String> destinations,
@NotNull String destination) {
super(portal, player); super(portal, player);
this.destinations = destinations; this.destinations = destinations;
@@ -40,6 +41,7 @@ public class StargateActivateEvent extends StargatePlayerEvent {
* *
* @return <p>The destinations available for the portal</p> * @return <p>The destinations available for the portal</p>
*/ */
@NotNull
public List<String> getDestinations() { public List<String> getDestinations() {
return destinations; return destinations;
} }
@@ -49,7 +51,7 @@ public class StargateActivateEvent extends StargatePlayerEvent {
* *
* @param destinations <p>The new list of available destinations</p> * @param destinations <p>The new list of available destinations</p>
*/ */
public void setDestinations(List<String> destinations) { public void setDestinations(@NotNull List<String> destinations) {
this.destinations = destinations; this.destinations = destinations;
} }
@@ -58,6 +60,7 @@ public class StargateActivateEvent extends StargatePlayerEvent {
* *
* @return <p>The selected destination</p> * @return <p>The selected destination</p>
*/ */
@NotNull
public String getDestination() { public String getDestination() {
return destination; return destination;
} }
@@ -67,7 +70,7 @@ public class StargateActivateEvent extends StargatePlayerEvent {
* *
* @param destination <p>The new selected destination</p> * @param destination <p>The new selected destination</p>
*/ */
public void setDestination(String destination) { public void setDestination(@NotNull String destination) {
this.destination = destination; this.destination = destination;
} }
@@ -76,6 +79,7 @@ public class StargateActivateEvent extends StargatePlayerEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -22,7 +22,7 @@ public class StargateCloseEvent extends StargateEvent {
* @param portal <p>The portal to close</p> * @param portal <p>The portal to close</p>
* @param force <p>Whether to force the gate to close, even if set as always-on</p> * @param force <p>Whether to force the gate to close, even if set as always-on</p>
*/ */
public StargateCloseEvent(Portal portal, boolean force) { public StargateCloseEvent(@NotNull Portal portal, boolean force) {
super(portal); super(portal);
this.force = force; this.force = force;
@@ -51,6 +51,7 @@ public class StargateCloseEvent extends StargateEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -29,7 +29,8 @@ public class StargateCreateEvent extends StargatePlayerEvent {
* @param denyReason <p>The reason stargate creation was denied</p> * @param denyReason <p>The reason stargate creation was denied</p>
* @param cost <p>The cost of creating the new star gate</p> * @param cost <p>The cost of creating the new star gate</p>
*/ */
public StargateCreateEvent(Player player, Portal portal, String[] lines, boolean deny, String denyReason, int cost) { public StargateCreateEvent(@NotNull Player player, @NotNull Portal portal, @NotNull String[] lines, boolean deny,
@NotNull String denyReason, int cost) {
super(portal, player); super(portal, player);
this.lines = lines; this.lines = lines;
this.deny = deny; this.deny = deny;
@@ -44,6 +45,7 @@ public class StargateCreateEvent extends StargatePlayerEvent {
* @return <p>The text on the given line</p> * @return <p>The text on the given line</p>
* @throws IndexOutOfBoundsException <p>If given a line index less than zero or above three</p> * @throws IndexOutOfBoundsException <p>If given a line index less than zero or above three</p>
*/ */
@NotNull
public String getLine(int index) throws IndexOutOfBoundsException { public String getLine(int index) throws IndexOutOfBoundsException {
return lines[index]; return lines[index];
} }
@@ -71,6 +73,7 @@ public class StargateCreateEvent extends StargatePlayerEvent {
* *
* @return <p>The reason the stargate creation was denied</p> * @return <p>The reason the stargate creation was denied</p>
*/ */
@NotNull
public String getDenyReason() { public String getDenyReason() {
return denyReason; return denyReason;
} }
@@ -80,7 +83,7 @@ public class StargateCreateEvent extends StargatePlayerEvent {
* *
* @param denyReason <p>The new reason why the stargate creation was denied</p> * @param denyReason <p>The new reason why the stargate creation was denied</p>
*/ */
public void setDenyReason(String denyReason) { public void setDenyReason(@NotNull String denyReason) {
this.denyReason = denyReason; this.denyReason = denyReason;
} }
@@ -107,6 +110,7 @@ public class StargateCreateEvent extends StargatePlayerEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -20,7 +20,7 @@ public class StargateDeactivateEvent extends StargateEvent {
* *
* @param portal <p>The portal which was deactivated</p> * @param portal <p>The portal which was deactivated</p>
*/ */
public StargateDeactivateEvent(Portal portal) { public StargateDeactivateEvent(@NotNull Portal portal) {
super(portal); super(portal);
} }
@@ -29,6 +29,7 @@ public class StargateDeactivateEvent extends StargateEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -27,7 +27,8 @@ public class StargateDestroyEvent extends StargatePlayerEvent {
* @param denyMsg <p>The message to display if the event is denied</p> * @param denyMsg <p>The message to display if the event is denied</p>
* @param cost <p>The cost of destroying the portal</p> * @param cost <p>The cost of destroying the portal</p>
*/ */
public StargateDestroyEvent(Portal portal, Player player, boolean deny, String denyMsg, int cost) { public StargateDestroyEvent(@NotNull Portal portal, @NotNull Player player, boolean deny, @NotNull String denyMsg,
int cost) {
super(portal, player); super(portal, player);
this.deny = deny; this.deny = deny;
this.denyReason = denyMsg; this.denyReason = denyMsg;
@@ -57,6 +58,7 @@ public class StargateDestroyEvent extends StargatePlayerEvent {
* *
* @return <p>The reason the event was denied</p> * @return <p>The reason the event was denied</p>
*/ */
@NotNull
public String getDenyReason() { public String getDenyReason() {
return denyReason; return denyReason;
} }
@@ -66,7 +68,7 @@ public class StargateDestroyEvent extends StargatePlayerEvent {
* *
* @param denyReason <p>The reason the event was denied</p> * @param denyReason <p>The reason the event was denied</p>
*/ */
public void setDenyReason(String denyReason) { public void setDenyReason(@NotNull String denyReason) {
this.denyReason = denyReason; this.denyReason = denyReason;
} }
@@ -93,6 +95,7 @@ public class StargateDestroyEvent extends StargatePlayerEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -27,7 +27,8 @@ public class StargateEntityPortalEvent extends StargateEvent implements Stargate
* @param destination <p>The destination the entity should exit from</p> * @param destination <p>The destination the entity should exit from</p>
* @param exit <p>The exit location of the destination portal the entity will be teleported to</p> * @param exit <p>The exit location of the destination portal the entity will be teleported to</p>
*/ */
public StargateEntityPortalEvent(Entity travellingEntity, Portal portal, Portal destination, Location exit) { public StargateEntityPortalEvent(@NotNull Entity travellingEntity, @NotNull Portal portal,
@NotNull Portal destination, @NotNull Location exit) {
super(portal); super(portal);
this.travellingEntity = travellingEntity; this.travellingEntity = travellingEntity;
@@ -40,6 +41,7 @@ public class StargateEntityPortalEvent extends StargateEvent implements Stargate
* *
* @return <p>The non-player teleporting</p> * @return <p>The non-player teleporting</p>
*/ */
@NotNull
public Entity getEntity() { public Entity getEntity() {
return travellingEntity; return travellingEntity;
} }
@@ -49,6 +51,7 @@ public class StargateEntityPortalEvent extends StargateEvent implements Stargate
* *
* @return <p>The destination portal</p> * @return <p>The destination portal</p>
*/ */
@NotNull
public Portal getDestination() { public Portal getDestination() {
return destination; return destination;
} }
@@ -59,6 +62,7 @@ public class StargateEntityPortalEvent extends StargateEvent implements Stargate
* @return <p>Location of the exit point</p> * @return <p>Location of the exit point</p>
*/ */
@Override @Override
@NotNull
public Location getExit() { public Location getExit() {
return exit; return exit;
} }
@@ -68,7 +72,7 @@ public class StargateEntityPortalEvent extends StargateEvent implements Stargate
* *
* @param location <p>The new location of the entity's exit point</p> * @param location <p>The new location of the entity's exit point</p>
*/ */
public void setExit(Location location) { public void setExit(@NotNull Location location) {
this.exit = location; this.exit = location;
} }
@@ -77,6 +81,7 @@ public class StargateEntityPortalEvent extends StargateEvent implements Stargate
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -3,6 +3,7 @@ package net.knarcraft.stargate.event;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
/** /**
* An abstract event describing any stargate event * An abstract event describing any stargate event
@@ -18,7 +19,7 @@ public abstract class StargateEvent extends Event implements Cancellable {
* *
* @param portal <p>The portal involved in this stargate event</p> * @param portal <p>The portal involved in this stargate event</p>
*/ */
StargateEvent(Portal portal) { StargateEvent(@NotNull Portal portal) {
this.portal = portal; this.portal = portal;
this.cancelled = false; this.cancelled = false;
} }
@@ -28,6 +29,7 @@ public abstract class StargateEvent extends Event implements Cancellable {
* *
* @return <p>The portal involved in this stargate event</p> * @return <p>The portal involved in this stargate event</p>
*/ */
@NotNull
public Portal getPortal() { public Portal getPortal() {
return portal; return portal;
} }

View File

@@ -4,6 +4,7 @@ import net.knarcraft.stargate.portal.Portal;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* This event should be called whenever a player opens a stargate * This event should be called whenever a player opens a stargate
@@ -23,7 +24,7 @@ public class StargateOpenEvent extends StargatePlayerEvent {
* @param portal <p>The opened portal</p> * @param portal <p>The opened portal</p>
* @param force <p>Whether to force the portal open</p> * @param force <p>Whether to force the portal open</p>
*/ */
public StargateOpenEvent(Player player, Portal portal, boolean force) { public StargateOpenEvent(@Nullable Player player, @NotNull Portal portal, boolean force) {
super(portal, player); super(portal, player);
this.force = force; this.force = force;
@@ -52,6 +53,7 @@ public class StargateOpenEvent extends StargatePlayerEvent {
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -2,6 +2,8 @@ package net.knarcraft.stargate.event;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* An abstract event describing any stargate event where a player is involved * An abstract event describing any stargate event where a player is involved
@@ -16,7 +18,7 @@ public abstract class StargatePlayerEvent extends StargateEvent {
* *
* @param portal <p>The portal involved in this stargate event</p> * @param portal <p>The portal involved in this stargate event</p>
*/ */
StargatePlayerEvent(Portal portal, Player player) { StargatePlayerEvent(@NotNull Portal portal, @Nullable Player player) {
super(portal); super(portal);
this.player = player; this.player = player;
} }
@@ -26,6 +28,7 @@ public abstract class StargatePlayerEvent extends StargateEvent {
* *
* @return <p>The player creating the star gate</p> * @return <p>The player creating the star gate</p>
*/ */
@Nullable
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }

View File

@@ -26,7 +26,8 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent implements St
* @param destination <p>The destination the player should exit from</p> * @param destination <p>The destination the player should exit from</p>
* @param exit <p>The exit location of the destination portal the user will be teleported to</p> * @param exit <p>The exit location of the destination portal the user will be teleported to</p>
*/ */
public StargatePlayerPortalEvent(Player player, Portal portal, Portal destination, Location exit) { public StargatePlayerPortalEvent(@NotNull Player player, @NotNull Portal portal, @NotNull Portal destination,
@NotNull Location exit) {
super(portal, player); super(portal, player);
this.destination = destination; this.destination = destination;
@@ -38,6 +39,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent implements St
* *
* @return <p>The destination portal</p> * @return <p>The destination portal</p>
*/ */
@NotNull
public Portal getDestination() { public Portal getDestination() {
return destination; return destination;
} }
@@ -48,6 +50,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent implements St
* @return <p>Location of the exit point</p> * @return <p>Location of the exit point</p>
*/ */
@Override @Override
@NotNull
public Location getExit() { public Location getExit() {
return exit; return exit;
} }
@@ -57,7 +60,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent implements St
* *
* @param location <p>The new location of the player's exit point</p> * @param location <p>The new location of the player's exit point</p>
*/ */
public void setExit(Location location) { public void setExit(@NotNull Location location) {
this.exit = location; this.exit = location;
} }
@@ -66,6 +69,7 @@ public class StargatePlayerPortalEvent extends StargatePlayerEvent implements St
* *
* @return <p>A handler-list with all event handlers</p> * @return <p>A handler-list with all event handlers</p>
*/ */
@NotNull
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }

View File

@@ -2,6 +2,7 @@ package net.knarcraft.stargate.event;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.NotNull;
/** /**
* A generic teleportation event * A generic teleportation event
@@ -13,6 +14,7 @@ public interface StargateTeleportEvent extends Cancellable {
* *
* @return <p>Location of the exit point</p> * @return <p>Location of the exit point</p>
*/ */
@NotNull
Location getExit(); Location getExit();
} }

View File

@@ -1,7 +1,10 @@
package net.knarcraft.stargate.listener; package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.event.StargateDestroyEvent; import net.knarcraft.stargate.event.StargateDestroyEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalCreator; import net.knarcraft.stargate.portal.PortalCreator;
@@ -28,13 +31,13 @@ import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
/** /**
* This class is responsible for listening to relevant block events related to creating and breaking portals * This class is responsible for listening to relevant block events related to creating and breaking portals
*/ */
@SuppressWarnings("unused")
public class BlockEventListener implements Listener { public class BlockEventListener implements Listener {
/** /**
@@ -45,9 +48,9 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler @EventHandler(ignoreCancelled = true)
public void onBlockFormedByEntity(EntityBlockFormEvent event) { public void onBlockFormedByEntity(@NotNull EntityBlockFormEvent event) {
if (event.isCancelled() || (!Stargate.getGateConfig().protectEntrance() && if ((!Stargate.getGateConfig().protectEntrance() &&
!Stargate.getGateConfig().verifyPortals())) { !Stargate.getGateConfig().verifyPortals())) {
return; return;
} }
@@ -66,11 +69,8 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler @EventHandler(ignoreCancelled = true)
public void onSignChange(SignChangeEvent event) { public void onSignChange(@NotNull SignChangeEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
Block block = event.getBlock(); Block block = event.getBlock();
//Ignore normal signs //Ignore normal signs
@@ -88,23 +88,21 @@ public class BlockEventListener implements Listener {
if (portal.getOptions().hasNoSign()) { if (portal.getOptions().hasNoSign()) {
Material replaceMaterial = PortalFileHelper.decideRemovalMaterial(portal.getSignLocation(), portal); Material replaceMaterial = PortalFileHelper.decideRemovalMaterial(portal.getSignLocation(), portal);
BlockChangeRequest request = new BlockChangeRequest(portal.getSignLocation(), replaceMaterial, null); BlockChangeRequest request = new BlockChangeRequest(portal.getSignLocation(), replaceMaterial, null);
Stargate.addBlockChangeRequest(request); Stargate.addControlBlockUpdateRequest(request);
} }
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("createMsg")); new SGFormatBuilder(Message.CREATED).success(player);
Stargate.debug("onSignChange", "Initialized stargate: " + portal.getName()); Stargate.debug("onSignChange", "Initialized stargate: " + portal.getName());
Stargate.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), Stargate.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(),
portal::drawSign, 1); portal::drawSign, 1);
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(@NotNull BlockPlaceEvent event) {
if (event.isCancelled() || !Stargate.getGateConfig().protectEntrance()) { if (!Stargate.getGateConfig().protectEntrance()) {
return; return;
} }
Block block = event.getBlock(); Block block = event.getBlock();
Player player = event.getPlayer();
Portal portal = PortalHandler.getByEntrance(block); Portal portal = PortalHandler.getByEntrance(block);
if (portal != null) { if (portal != null) {
//Prevent blocks from being placed in the entrance, if protectEntrance is enabled, as breaking the block //Prevent blocks from being placed in the entrance, if protectEntrance is enabled, as breaking the block
@@ -118,11 +116,8 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(@NotNull BlockBreakEvent event) {
if (event.isCancelled()) {
return;
}
Block block = event.getBlock(); Block block = event.getBlock();
Player player = event.getPlayer(); Player player = event.getPlayer();
@@ -138,9 +133,16 @@ public class BlockEventListener implements Listener {
boolean deny = false; boolean deny = false;
String denyMessage = ""; String denyMessage = "";
// Block breaking the button from breaking the entire Stargate
if (portal.getStructure().getButton() != null && portal.getStructure().getButton().equals(
new BlockLocation(event.getBlock()))) {
event.setCancelled(true);
return;
}
//Decide if the user can destroy the portal //Decide if the user can destroy the portal
if (!PermissionHelper.canDestroyPortal(player, portal)) { if (!PermissionHelper.canDestroyPortal(player, portal)) {
denyMessage = Stargate.getString("denyMsg"); denyMessage = new SGFormatBuilder(Message.ACCESS_DENIED).toString();
deny = true; deny = true;
Stargate.logInfo(String.format("%s tried to destroy gate", player.getName())); Stargate.logInfo(String.format("%s tried to destroy gate", player.getName()));
} }
@@ -158,7 +160,7 @@ public class BlockEventListener implements Listener {
//Destroy denied //Destroy denied
if (destroyEvent.getDeny()) { if (destroyEvent.getDeny()) {
if (!destroyEvent.getDenyReason().trim().isEmpty()) { if (!destroyEvent.getDenyReason().trim().isEmpty()) {
Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason()); new SGFormatBuilder(destroyEvent.getDenyReason()).error(player);
} }
event.setCancelled(true); event.setCancelled(true);
return; return;
@@ -170,7 +172,7 @@ public class BlockEventListener implements Listener {
} }
PortalRegistry.unregisterPortal(portal, true); PortalRegistry.unregisterPortal(portal, true);
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("destroyMsg")); new SGFormatBuilder(Message.DESTROYED).success(player);
} }
/** /**
@@ -182,8 +184,8 @@ public class BlockEventListener implements Listener {
* @param event <p>The break event</p> * @param event <p>The break event</p>
* @return <p>True if the payment was successful. False if the event was cancelled</p> * @return <p>True if the payment was successful. False if the event was cancelled</p>
*/ */
private boolean handleEconomyPayment(StargateDestroyEvent destroyEvent, Player player, Portal portal, private boolean handleEconomyPayment(@NotNull StargateDestroyEvent destroyEvent, @NotNull Player player,
BlockBreakEvent event) { @NotNull Portal portal, @NotNull BlockBreakEvent event) {
int cost = destroyEvent.getCost(); int cost = destroyEvent.getCost();
if (cost != 0) { if (cost != 0) {
String portalName = portal.getName(); String portalName = portal.getName();
@@ -209,8 +211,8 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The event to check and possibly cancel</p> * @param event <p>The event to check and possibly cancel</p>
*/ */
@EventHandler @EventHandler(ignoreCancelled = true)
public void onBlockPhysics(BlockPhysicsEvent event) { public void onBlockPhysics(@NotNull BlockPhysicsEvent event) {
Block block = event.getBlock(); Block block = event.getBlock();
Portal portal = null; Portal portal = null;
@@ -229,12 +231,12 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The event to check and possibly cancel</p> * @param event <p>The event to check and possibly cancel</p>
*/ */
@EventHandler @EventHandler(ignoreCancelled = true)
public void onBlockFromTo(BlockFromToEvent event) { public void onBlockFromTo(@NotNull BlockFromToEvent event) {
Portal portal = PortalHandler.getByEntrance(event.getBlock()); Portal portal = PortalHandler.getByEntrance(event.getBlock());
if (portal != null) { if (portal != null && event.getBlock().getY() == event.getToBlock().getY()) {
event.setCancelled((event.getBlock().getY() == event.getToBlock().getY())); event.setCancelled(true);
} }
} }
@@ -243,8 +245,8 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The event to check and possibly cancel</p> * @param event <p>The event to check and possibly cancel</p>
*/ */
@EventHandler @EventHandler(ignoreCancelled = true)
public void onPistonExtend(BlockPistonExtendEvent event) { public void onPistonExtend(@NotNull BlockPistonExtendEvent event) {
cancelPistonEvent(event, event.getBlocks()); cancelPistonEvent(event, event.getBlocks());
} }
@@ -253,8 +255,8 @@ public class BlockEventListener implements Listener {
* *
* @param event <p>The event to check and possibly cancel</p> * @param event <p>The event to check and possibly cancel</p>
*/ */
@EventHandler @EventHandler(ignoreCancelled = true)
public void onPistonRetract(BlockPistonRetractEvent event) { public void onPistonRetract(@NotNull BlockPistonRetractEvent event) {
if (!event.isSticky()) { if (!event.isSticky()) {
return; return;
} }
@@ -267,7 +269,7 @@ public class BlockEventListener implements Listener {
* @param event <p>The event to cancel</p> * @param event <p>The event to cancel</p>
* @param blocks <p>The blocks included in the event</p> * @param blocks <p>The blocks included in the event</p>
*/ */
private void cancelPistonEvent(BlockPistonEvent event, List<Block> blocks) { private void cancelPistonEvent(@NotNull BlockPistonEvent event, @NotNull List<Block> blocks) {
for (Block block : blocks) { for (Block block : blocks) {
Portal portal = PortalHandler.getByBlock(block); Portal portal = PortalHandler.getByBlock(block);
if (portal != null) { if (portal != null) {

View File

@@ -12,6 +12,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityPortalEvent; import org.bukkit.event.entity.EntityPortalEvent;
import org.jetbrains.annotations.NotNull;
/** /**
* This listener listens for any relevant events on portal entities * This listener listens for any relevant events on portal entities
@@ -25,7 +26,7 @@ public class EntityEventListener implements Listener {
* @param event <p>The event to check and possibly cancel</p> * @param event <p>The event to check and possibly cancel</p>
*/ */
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onPortalEvent(EntityPortalEvent event) { public void onPortalEvent(@NotNull EntityPortalEvent event) {
if (event.isCancelled()) { if (event.isCancelled()) {
return; return;
} }
@@ -46,7 +47,7 @@ public class EntityEventListener implements Listener {
* @param event <p>The triggered explosion event</p> * @param event <p>The triggered explosion event</p>
*/ */
@EventHandler @EventHandler
public void onEntityExplode(EntityExplodeEvent event) { public void onEntityExplode(@NotNull EntityExplodeEvent event) {
if (event.isCancelled()) { if (event.isCancelled()) {
return; return;
} }

View File

@@ -5,6 +5,7 @@ import net.knarcraft.stargate.portal.PortalHandler;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
/** /**
* A listener that listens for any relevant events causing entities to spawn * A listener that listens for any relevant events causing entities to spawn
@@ -12,13 +13,12 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
public class EntitySpawnListener implements Listener { public class EntitySpawnListener implements Listener {
@EventHandler @EventHandler
public void onCreatureSpawn(CreatureSpawnEvent event) { public void onCreatureSpawn(@NotNull CreatureSpawnEvent event) {
//Prevent Zombified Piglins and other creatures form spawning at stargates //Prevent Zombified Piglins and other creatures form spawning at stargates
if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.NETHER_PORTAL) { if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.NETHER_PORTAL &&
if (PortalHandler.getByEntrance(event.getLocation()) != null) { PortalHandler.getByEntrance(event.getLocation()) != null) {
event.setCancelled(true); event.setCancelled(true);
Stargate.debug("EntitySpawnListener", "Prevented creature from spawning at Stargate"); Stargate.debug("EntitySpawnListener", "Prevented creature from spawning at Stargate");
}
} }
} }

View File

@@ -1,8 +1,10 @@
package net.knarcraft.stargate.listener; package net.knarcraft.stargate.listener;
import net.knarcraft.knarlib.formatting.FormatBuilder;
import net.knarcraft.knarlib.util.UpdateChecker; import net.knarcraft.knarlib.util.UpdateChecker;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.MessageSender; import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalActivator; import net.knarcraft.stargate.portal.PortalActivator;
@@ -35,9 +37,15 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.geyser.api.GeyserApi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* This listener listens to any player-related events related to stargates * This listener listens to any player-related events related to stargates
@@ -46,6 +54,8 @@ import java.util.Map;
public class PlayerEventListener implements Listener { public class PlayerEventListener implements Listener {
private static final Map<Player, Long> previousEventTimes = new HashMap<>(); private static final Map<Player, Long> previousEventTimes = new HashMap<>();
private boolean hasGeyser = true;
private boolean hasFloodgate = true;
/** /**
* This event handler handles detection of any player teleporting through a bungee gate * This event handler handles detection of any player teleporting through a bungee gate
@@ -53,7 +63,7 @@ public class PlayerEventListener implements Listener {
* @param event <p>The event to check for a teleporting player</p> * @param event <p>The event to check for a teleporting player</p>
*/ */
@EventHandler @EventHandler
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(@NotNull PlayerJoinEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
//Migrate player name to UUID if necessary //Migrate player name to UUID if necessary
UUIDMigrationHelper.migrateUUID(player); UUIDMigrationHelper.migrateUUID(player);
@@ -63,7 +73,7 @@ public class PlayerEventListener implements Listener {
if (availableUpdate != null && Stargate.getStargateConfig().alertAdminsAboutUpdates() && if (availableUpdate != null && Stargate.getStargateConfig().alertAdminsAboutUpdates() &&
player.hasPermission("stargate.admin")) { player.hasPermission("stargate.admin")) {
String updateMessage = UpdateChecker.getUpdateAvailableString(availableUpdate, Stargate.getPluginVersion()); String updateMessage = UpdateChecker.getUpdateAvailableString(availableUpdate, Stargate.getPluginVersion());
Stargate.getMessageSender().sendErrorMessage(player, updateMessage); new SGFormatBuilder(updateMessage).error(player);
} }
if (!Stargate.getGateConfig().enableBungee()) { if (!Stargate.getGateConfig().enableBungee()) {
@@ -73,6 +83,7 @@ public class PlayerEventListener implements Listener {
//Check if the player is waiting to be teleported to a stargate //Check if the player is waiting to be teleported to a stargate
String destination = BungeeHelper.removeFromQueue(player.getUniqueId()); String destination = BungeeHelper.removeFromQueue(player.getUniqueId());
if (destination == null) { if (destination == null) {
Stargate.debug("PlayerJoin", "No bungee request found in queue");
return; return;
} }
@@ -91,7 +102,7 @@ public class PlayerEventListener implements Listener {
* @param event <p>The player move event which was triggered</p> * @param event <p>The player move event which was triggered</p>
*/ */
@EventHandler @EventHandler
public void onPlayerMove(PlayerMoveEvent event) { public void onPlayerMove(@NotNull PlayerMoveEvent event) {
if (event.isCancelled() || event.getTo() == null) { if (event.isCancelled() || event.getTo() == null) {
return; return;
} }
@@ -108,9 +119,16 @@ public class PlayerEventListener implements Listener {
//Check an additional block away in case the portal is a bungee portal using END_PORTAL //Check an additional block away in case the portal is a bungee portal using END_PORTAL
if (entrancePortal == null) { if (entrancePortal == null) {
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation); entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
// This should never realistically be null
if (entrancePortal == null) {
return;
}
} }
Portal destination = entrancePortal.getPortalActivator().getDestination(player); Portal destination = entrancePortal.getPortalActivator().getDestination(player);
if (destination == null) {
return;
}
Entity playerVehicle = player.getVehicle(); Entity playerVehicle = player.getVehicle();
//If the player is in a vehicle, but vehicle handling is disabled, just ignore the player //If the player is in a vehicle, but vehicle handling is disabled, just ignore the player
@@ -129,8 +147,8 @@ public class PlayerEventListener implements Listener {
* @param destination <p>The destination of the entrance portal</p> * @param destination <p>The destination of the entrance portal</p>
* @param event <p>The move event causing the teleportation to trigger</p> * @param event <p>The move event causing the teleportation to trigger</p>
*/ */
private void teleportPlayer(Entity playerVehicle, Player player, Portal entrancePortal, Portal destination, private void teleportPlayer(@Nullable Entity playerVehicle, @NotNull Player player, @NotNull Portal entrancePortal,
PlayerMoveEvent event) { @NotNull Portal destination, @NotNull PlayerMoveEvent event) {
if (playerVehicle instanceof LivingEntity) { if (playerVehicle instanceof LivingEntity) {
//Make sure any horses are properly tamed //Make sure any horses are properly tamed
if (playerVehicle instanceof AbstractHorse horse && !horse.isTamed()) { if (playerVehicle instanceof AbstractHorse horse && !horse.isTamed()) {
@@ -144,8 +162,8 @@ public class PlayerEventListener implements Listener {
//Just teleport the player like normal //Just teleport the player like normal
new PlayerTeleporter(destination, player).teleportPlayer(entrancePortal, event); new PlayerTeleporter(destination, player).teleportPlayer(entrancePortal, event);
} }
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg")); new SGFormatBuilder(Message.TELEPORTED).success(player);
} }
entrancePortal.getPortalOpener().closePortal(false); entrancePortal.getPortalOpener().closePortal(false);
} }
@@ -159,22 +177,17 @@ public class PlayerEventListener implements Listener {
* @param toLocation <p>The location the player is moving to</p> * @param toLocation <p>The location the player is moving to</p>
* @return <p>True if the event is relevant</p> * @return <p>True if the event is relevant</p>
*/ */
private boolean isRelevantMoveEvent(PlayerMoveEvent event, Player player, BlockLocation fromLocation, private boolean isRelevantMoveEvent(@NotNull PlayerMoveEvent event, Player player,
BlockLocation toLocation) { @NotNull BlockLocation fromLocation, @NotNull BlockLocation toLocation) {
//Check to see if the player moved to another block //Check to see if the player moved to another block
if (fromLocation.equals(toLocation)) { if (fromLocation.equals(toLocation)) {
return false; return false;
} }
//Check if the player moved from a portal //Get the portal the player entered, if any
Portal entrancePortal = PortalHandler.getByEntrance(toLocation); Portal entrancePortal = getEnteredPortal(toLocation, player);
if (entrancePortal == null) { if (entrancePortal == null) {
//Check an additional block away for BungeeCord portals using END_PORTAL as its material return false;
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
if (entrancePortal == null || !entrancePortal.getOptions().isBungee() ||
entrancePortal.getGate().getPortalOpenBlock() != Material.END_PORTAL) {
return false;
}
} }
Portal destination = entrancePortal.getPortalActivator().getDestination(player); Portal destination = entrancePortal.getPortalActivator().getDestination(player);
@@ -191,8 +204,8 @@ public class PlayerEventListener implements Listener {
//Decide if the user should be teleported to another bungee server //Decide if the user should be teleported to another bungee server
if (entrancePortal.getOptions().isBungee()) { if (entrancePortal.getOptions().isBungee()) {
if (BungeeHelper.bungeeTeleport(player, entrancePortal, event) && !entrancePortal.getOptions().isSilent()) { if (BungeeHelper.bungeeTeleport(player, entrancePortal, event) && !entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg")); new SGFormatBuilder(Message.TELEPORTED).success(player);
} }
return false; return false;
} }
@@ -201,13 +214,87 @@ public class PlayerEventListener implements Listener {
return TeleportHelper.noLeashedCreaturesPreventTeleportation(player); return TeleportHelper.noLeashedCreaturesPreventTeleportation(player);
} }
/**
* Gets the portal a player entered
*
* @param toLocation <p>The location the player moved to</p>
* @param player <p>The player that moved</p>
* @return <p>The portal the player entered, or null if no portal was entered</p>
*/
private Portal getEnteredPortal(@NotNull BlockLocation toLocation, @NotNull Player player) {
Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
// Return if in an entrance
if (entrancePortal != null) {
return entrancePortal;
}
//Check an additional block away for special cases like BungeeCord portals using END_PORTAL as its material
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
if (entrancePortal == null) {
return null;
}
// If END_GATEWAY and END_PORTAL cannot appear, skip further checks
Set<Material> entranceMaterials = MaterialHelper.specifiersToMaterials(entrancePortal.getGate().getPortalOpenMaterials());
if (!entranceMaterials.contains(Material.END_GATEWAY) && !entranceMaterials.contains(Material.END_PORTAL)) {
return null;
}
// Get the real materials in the entrance, as END_GATEWAY or END_PORTAL may be available, but not chosen
Set<Material> materialsInEntrance = new HashSet<>();
for (BlockLocation location : entrancePortal.getStructure().getEntrances()) {
materialsInEntrance.add(location.getType());
}
// Abort if not a special case
if ((!materialsInEntrance.contains(Material.END_GATEWAY) || !isGeyserPlayer(player)) &&
(!entrancePortal.getOptions().isBungee() || !materialsInEntrance.contains(Material.END_PORTAL))) {
return null;
}
return entrancePortal;
}
/**
* Checks whether the given player is connected through Geyser
*
* @param player <p>The player to check</p>
* @return <p>True if the player is connected through Geyser</p>
*/
private boolean isGeyserPlayer(@NotNull Player player) {
// Prevent unnecessary checking for non-geyser and floodgate servers
if (!hasGeyser && !hasFloodgate) {
return false;
}
// Use Geyser API to get connection status
if (hasGeyser) {
try {
return GeyserApi.api().connectionByUuid(player.getUniqueId()) != null;
} catch (NoClassDefFoundError error1) {
hasGeyser = false;
}
}
// Use Floodgate API to get connection status
if (hasFloodgate) {
try {
return FloodgateApi.getInstance().isFloodgatePlayer(player.getUniqueId());
} catch (NoClassDefFoundError error2) {
hasFloodgate = false;
}
}
return false;
}
/** /**
* This event handler detects if a player clicks a button or a sign * This event handler detects if a player clicks a button or a sign
* *
* @param event <p>The player interact event which was triggered</p> * @param event <p>The player interact event which was triggered</p>
*/ */
@EventHandler @EventHandler
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(@NotNull PlayerInteractEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
Block block = event.getClickedBlock(); Block block = event.getClickedBlock();
@@ -216,6 +303,10 @@ public class PlayerEventListener implements Listener {
} }
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (event.getHand() == null) {
return;
}
// Handle right-click of a sign, button or other
handleRightClickBlock(event, player, block, event.getHand()); handleRightClickBlock(event, player, block, event.getHand());
} else if (event.getAction() == Action.LEFT_CLICK_BLOCK && block.getBlockData() instanceof WallSign) { } else if (event.getAction() == Action.LEFT_CLICK_BLOCK && block.getBlockData() instanceof WallSign) {
//Handle left click of a wall sign //Handle left click of a wall sign
@@ -231,25 +322,16 @@ public class PlayerEventListener implements Listener {
* @param block <p>The block that was clicked</p> * @param block <p>The block that was clicked</p>
* @param leftClick <p>Whether the player performed a left click as opposed to a right click</p> * @param leftClick <p>Whether the player performed a left click as opposed to a right click</p>
*/ */
private void handleSignClick(PlayerInteractEvent event, Player player, Block block, boolean leftClick) { private void handleSignClick(@NotNull PlayerInteractEvent event, @NotNull Player player, @NotNull Block block,
boolean leftClick) {
Portal portal = PortalHandler.getByBlock(block); Portal portal = PortalHandler.getByBlock(block);
if (portal == null) { if (portal == null) {
return; return;
} }
//Allow players with permissions to apply dye to signs //Allow players with permissions to apply dye to signs
EquipmentSlot hand = event.getHand(); if (dyeSign(event, player, portal)) {
if (hand != null && (PermissionHelper.hasPermission(player, "stargate.admin.dye") || return;
portal.isOwner(player))) {
ItemStack item = player.getInventory().getItem(hand);
if (item != null) {
String itemName = item.getType().toString();
if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
event.setUseInteractedBlock(Event.Result.ALLOW);
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1);
return;
}
}
} }
event.setUseInteractedBlock(Event.Result.DENY); event.setUseInteractedBlock(Event.Result.DENY);
@@ -279,6 +361,39 @@ public class PlayerEventListener implements Listener {
} }
} }
/**
* Tries to take care of a sign dye interaction
*
* @param event <p>The triggered player interaction event</p>
* @param player <p>The involved player</p>
* @param portal <p>The involved portal</p>
* @return <p>True if a sign was dyed</p>
*/
private boolean dyeSign(@NotNull PlayerInteractEvent event, @NotNull Player player, @NotNull Portal portal) {
EquipmentSlot hand = event.getHand();
// Check if the player is allowed to dye the sign
if (hand == null || (!PermissionHelper.hasPermission(player, "stargate.admin.dye") &&
!portal.isOwner(player))) {
return false;
}
// Check if the player is holding an item
ItemStack item = player.getInventory().getItem(hand);
if (item == null) {
return false;
}
String itemName = item.getType().toString();
// Check if the player's item can be used to dye the sign
if (itemName.endsWith("DYE") || itemName.endsWith("INK_SAC")) {
event.setUseInteractedBlock(Event.Result.ALLOW);
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), portal::drawSign, 1);
return true;
} else {
return false;
}
}
/** /**
* Check if a player should be denied from accessing (using) a portal * Check if a player should be denied from accessing (using) a portal
* *
@@ -286,12 +401,12 @@ public class PlayerEventListener implements Listener {
* @param portal <p>The portal the player is trying to use</p> * @param portal <p>The portal the player is trying to use</p>
* @return <p>True if the player should be denied</p> * @return <p>True if the player should be denied</p>
*/ */
private boolean cannotAccessPortal(Player player, Portal portal) { private boolean cannotAccessPortal(@NotNull Player player, @NotNull Portal portal) {
boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getCleanNetwork()); boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getCleanNetwork());
if (PermissionHelper.portalAccessDenied(player, portal, deny)) { if (PermissionHelper.portalAccessDenied(player, portal, deny)) {
if (!portal.getOptions().isSilent()) { if (!portal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); new SGFormatBuilder(Message.ACCESS_DENIED).error(player);
} }
return true; return true;
} }
@@ -306,14 +421,15 @@ public class PlayerEventListener implements Listener {
* @param block <p>The block the player clicked</p> * @param block <p>The block the player clicked</p>
* @param hand <p>The hand the player used to interact with the stargate</p> * @param hand <p>The hand the player used to interact with the stargate</p>
*/ */
private void handleRightClickBlock(PlayerInteractEvent event, Player player, Block block, EquipmentSlot hand) { private void handleRightClickBlock(@NotNull PlayerInteractEvent event, @NotNull Player player, @NotNull Block block,
@NotNull EquipmentSlot hand) {
if (block.getBlockData() instanceof WallSign) { if (block.getBlockData() instanceof WallSign) {
handleSignClick(event, player, block, false); handleSignClick(event, player, block, false);
return; return;
} }
//Prevent a double click caused by a Spigot bug //Prevent a double click caused by a Spigot bug
if (clickIsBug(event.getPlayer(), block)) { if (clickIsBug(event.getPlayer())) {
return; return;
} }
@@ -348,32 +464,29 @@ public class PlayerEventListener implements Listener {
/** /**
* Displays information about a clicked portal * Displays information about a clicked portal
* *
* <p>This will only display portal info if the portal has no sign and is not silent.</p> * <p>This will only display portal info if the portal has no sign and is not quiet.</p>
* *
* @param block <p>The clicked block</p> * @param block <p>The clicked block</p>
* @param player <p>The player that clicked the block</p> * @param player <p>The player that clicked the block</p>
*/ */
private void displayPortalInfo(Block block, Player player) { private void displayPortalInfo(@NotNull Block block, @NotNull Player player) {
Portal portal = PortalHandler.getByBlock(block); Portal portal = PortalHandler.getByBlock(block);
if (portal == null) { if (portal == null) {
return; return;
} }
//Display portal information as a portal without a sign does not display any //Display portal information as a portal without a sign does not display any
if (portal.getOptions().hasNoSign() && (!portal.getOptions().isSilent() || player.isSneaking())) { if (portal.getOptions().hasNoSign() && (!portal.getOptions().isQuiet() || player.isSneaking())) {
MessageSender sender = Stargate.getMessageSender(); FormatBuilder builder = new SGFormatBuilder();
sender.sendSuccessMessage(player, ChatColor.GOLD + Stargate.getString("portalInfoTitle")); builder.append(ChatColor.GOLD).append(Message.PORTAL_INFO_TITLE).append("\n").
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoName"), append(Message.PORTAL_INFO_NAME).replace("%name%", portal.getName()).append("\n").
"%name%", portal.getName())); append(Message.PORTAL_INFO_DESTINATION).replace("%destination%", portal.getDestinationName()).append("\n");
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoDestination"),
"%destination%", portal.getDestinationName()));
if (portal.getOptions().isBungee()) { if (portal.getOptions().isBungee()) {
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoServer"), builder.append(Message.PORTAL_INFO_SERVER).replace("%server%", portal.getNetwork());
"%server%", portal.getNetwork()));
} else { } else {
sender.sendSuccessMessage(player, Stargate.replaceVars(Stargate.getString("portalInfoNetwork"), builder.append(Message.PORTAL_INFO_NETWORK).replace("%network%", portal.getNetwork());
"%network%", portal.getNetwork()));
} }
builder.displayRaw(player);
} }
} }
@@ -385,10 +498,9 @@ public class PlayerEventListener implements Listener {
* clicking once the bug is fixed.</p> * clicking once the bug is fixed.</p>
* *
* @param player <p>The player performing the right-click</p> * @param player <p>The player performing the right-click</p>
* @param block <p>The block to check</p>
* @return <p>True if the click is a bug and should be cancelled</p> * @return <p>True if the click is a bug and should be cancelled</p>
*/ */
private boolean clickIsBug(Player player, Block block) { private boolean clickIsBug(@NotNull Player player) {
Long previousEventTime = previousEventTimes.get(player); Long previousEventTime = previousEventTimes.get(player);
if (previousEventTime != null && previousEventTime + 50 > System.currentTimeMillis()) { if (previousEventTime != null && previousEventTime + 50 > System.currentTimeMillis()) {
previousEventTimes.put(player, null); previousEventTimes.put(player, null);

View File

@@ -1,10 +1,14 @@
package net.knarcraft.stargate.listener; package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
/** /**
* This listener listens for any plugins being enabled or disabled to catch the loading of vault * This listener listens for any plugins being enabled or disabled to catch the loading of vault
@@ -19,7 +23,7 @@ public class PluginEventListener implements Listener {
* *
* @param stargate <p>A reference to the stargate plugin to </p> * @param stargate <p>A reference to the stargate plugin to </p>
*/ */
public PluginEventListener(Stargate stargate) { public PluginEventListener(@NotNull Stargate stargate) {
this.stargate = stargate; this.stargate = stargate;
} }
@@ -31,10 +35,13 @@ public class PluginEventListener implements Listener {
* @param ignored <p>The actual event called. This is currently not used</p> * @param ignored <p>The actual event called. This is currently not used</p>
*/ */
@EventHandler @EventHandler
public void onPluginEnable(PluginEnableEvent ignored) { public void onPluginEnable(@NotNull PluginEnableEvent ignored) {
if (Stargate.getEconomyConfig().setupEconomy(stargate.getServer().getPluginManager())) { if (Stargate.getEconomyConfig().setupEconomy(stargate.getServer().getPluginManager())) {
String vaultVersion = Stargate.getEconomyConfig().getVault().getDescription().getVersion(); Plugin vault = Stargate.getEconomyConfig().getVault();
Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion)); if (vault != null) {
String vaultVersion = vault.getDescription().getVersion();
Stargate.logInfo(new SGFormatBuilder(Message.VAULT_LOADED).replace("%version%", vaultVersion).toString());
}
} }
} }
@@ -44,7 +51,7 @@ public class PluginEventListener implements Listener {
* @param event <p>The event caused by disabling a plugin</p> * @param event <p>The event caused by disabling a plugin</p>
*/ */
@EventHandler @EventHandler
public void onPluginDisable(PluginDisableEvent event) { public void onPluginDisable(@NotNull PluginDisableEvent event) {
if (event.getPlugin().equals(Stargate.getEconomyConfig().getVault())) { if (event.getPlugin().equals(Stargate.getEconomyConfig().getVault())) {
Stargate.logInfo("Vault plugin lost."); Stargate.logInfo("Vault plugin lost.");
} }

View File

@@ -17,16 +17,17 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPortalEnterEvent; import org.bukkit.event.entity.EntityPortalEnterEvent;
import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.world.PortalCreateEvent; import org.bukkit.event.world.PortalCreateEvent;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.HashMap;
import java.util.List; import java.util.Map;
/** /**
* Listens for and cancels relevant portal events * Listens for and cancels relevant portal events
*/ */
public class PortalEventListener implements Listener { public class PortalEventListener implements Listener {
private static final List<FromTheEndTeleportation> playersFromTheEnd = new ArrayList<>(); private static final Map<Player, FromTheEndTeleportation> playersFromTheEnd = new HashMap<>();
/** /**
* Listens for and aborts vanilla portal creation caused by stargate creation * Listens for and aborts vanilla portal creation caused by stargate creation
@@ -34,7 +35,7 @@ public class PortalEventListener implements Listener {
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler @EventHandler
public void onPortalCreation(PortalCreateEvent event) { public void onPortalCreation(@NotNull PortalCreateEvent event) {
if (event.isCancelled()) { if (event.isCancelled()) {
return; return;
} }
@@ -56,32 +57,37 @@ public class PortalEventListener implements Listener {
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler @EventHandler
public void onEntityPortalEnter(EntityPortalEnterEvent event) { public void onEntityPortalEnter(@NotNull EntityPortalEnterEvent event) {
Location location = event.getLocation(); Location location = event.getLocation();
World world = location.getWorld(); World world = location.getWorld();
Entity entity = event.getEntity(); Entity entity = event.getEntity();
//Hijack normal portal teleportation if teleporting from a stargate
if (entity instanceof Player player && location.getBlock().getType() == Material.END_PORTAL && world != null &&
world.getEnvironment() == World.Environment.THE_END) {
Portal portal = PortalHandler.getByAdjacentEntrance(location);
if (portal == null) {
return;
}
//Hijack normal portal teleportation if teleporting from a stargate, and teleporting from an end portal in the
// end
if (!(entity instanceof Player player) || location.getBlock().getType() != Material.END_PORTAL ||
world == null || world.getEnvironment() != World.Environment.THE_END) {
return;
}
Portal portal = PortalHandler.getByAdjacentEntrance(location);
if (portal == null) {
return;
}
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Found player " + player + " entering END_PORTAL " + portal);
//Decide if the anything stops the player from teleporting
if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(),
player, null) || portal.getOptions().isBungee()) {
//Teleport the player back to the portal they came in, just in case
playersFromTheEnd.put(player, new FromTheEndTeleportation(portal));
Stargate.debug("PortalEventListener::onEntityPortalEnter", Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Found player " + player + " entering END_PORTAL " + portal); "Sending player back to the entrance");
} else {
//Remove any old player teleportations in case weird things happen Portal destination = portal.getPortalActivator().getDestination();
playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player)); if (destination != null) {
//Decide if the anything stops the player from teleporting playersFromTheEnd.put(player, new FromTheEndTeleportation(destination));
if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null) ||
portal.getOptions().isBungee()) {
//Teleport the player back to the portal they came in, just in case
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal));
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Sending player back to the entrance");
} else {
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
Stargate.debug("PortalEventListener::onEntityPortalEnter", Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Sending player to destination"); "Sending player to destination");
} }
@@ -94,16 +100,14 @@ public class PortalEventListener implements Listener {
* @param event <p>The triggered event</p> * @param event <p>The triggered event</p>
*/ */
@EventHandler @EventHandler
public void onRespawn(PlayerRespawnEvent event) { public void onRespawn(@NotNull PlayerRespawnEvent event) {
Player respawningPlayer = event.getPlayer(); Player respawningPlayer = event.getPlayer();
int playerIndex = playersFromTheEnd.indexOf(new FromTheEndTeleportation(respawningPlayer, null)); FromTheEndTeleportation teleportation = playersFromTheEnd.remove(respawningPlayer);
if (playerIndex == -1) { if (teleportation == null) {
return; return;
} }
FromTheEndTeleportation teleportation = playersFromTheEnd.get(playerIndex); Portal exitPortal = teleportation.exitPortal();
playersFromTheEnd.remove(playerIndex);
Portal exitPortal = teleportation.getExit();
//Overwrite respawn location to respawn in front of the portal //Overwrite respawn location to respawn in front of the portal
PlayerTeleporter teleporter = new PlayerTeleporter(exitPortal, respawningPlayer); PlayerTeleporter teleporter = new PlayerTeleporter(exitPortal, respawningPlayer);
Location respawnLocation = teleporter.getExit(); Location respawnLocation = teleporter.getExit();

View File

@@ -4,6 +4,7 @@ import net.knarcraft.stargate.portal.PortalHandler;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull;
/** /**
* This listener listens to teleportation-related events * This listener listens to teleportation-related events
@@ -21,7 +22,7 @@ public class TeleportEventListener implements Listener {
* @param event <p>The event to check and possibly cancel</p> * @param event <p>The event to check and possibly cancel</p>
*/ */
@EventHandler @EventHandler
public void onPlayerTeleport(PlayerTeleportEvent event) { public void onPlayerTeleport(@NotNull PlayerTeleportEvent event) {
PlayerTeleportEvent.TeleportCause cause = event.getCause(); PlayerTeleportEvent.TeleportCause cause = event.getCause();
//Block normal portal teleportation if teleporting from a stargate //Block normal portal teleportation if teleporting from a stargate

View File

@@ -1,6 +1,8 @@
package net.knarcraft.stargate.listener; package net.knarcraft.stargate.listener;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter; import net.knarcraft.stargate.portal.teleporter.VehicleTeleporter;
@@ -13,6 +15,8 @@ import org.bukkit.entity.Vehicle;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.vehicle.VehicleMoveEvent; import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
@@ -28,7 +32,7 @@ public class VehicleEventListener implements Listener {
* @param event <p>The triggered move event</p> * @param event <p>The triggered move event</p>
*/ */
@EventHandler @EventHandler
public void onVehicleMove(VehicleMoveEvent event) { public void onVehicleMove(@NotNull VehicleMoveEvent event) {
if (!Stargate.getGateConfig().handleVehicles()) { if (!Stargate.getGateConfig().handleVehicles()) {
return; return;
} }
@@ -58,7 +62,8 @@ public class VehicleEventListener implements Listener {
* @param entrancePortal <p>The portal the vehicle is entering</p> * @param entrancePortal <p>The portal the vehicle is entering</p>
* @param vehicle <p>The vehicle passing through</p> * @param vehicle <p>The vehicle passing through</p>
*/ */
private static void teleportVehicle(List<Entity> passengers, Portal entrancePortal, Vehicle vehicle) { private static void teleportVehicle(@NotNull List<Entity> passengers, @NotNull Portal entrancePortal,
@NotNull Vehicle vehicle) {
String route = "VehicleEventListener::teleportVehicle"; String route = "VehicleEventListener::teleportVehicle";
if (!passengers.isEmpty() && TeleportHelper.containsPlayer(passengers)) { if (!passengers.isEmpty() && TeleportHelper.containsPlayer(passengers)) {
@@ -83,14 +88,72 @@ public class VehicleEventListener implements Listener {
* @param entrancePortal <p>The portal the minecart entered</p> * @param entrancePortal <p>The portal the minecart entered</p>
* @param vehicle <p>The vehicle to teleport</p> * @param vehicle <p>The vehicle to teleport</p>
*/ */
private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle) { private static void teleportPlayerAndVehicle(@NotNull Portal entrancePortal, @NotNull Vehicle vehicle) {
Entity rootEntity = vehicle; Entity rootEntity = vehicle;
while (rootEntity.getVehicle() != null) { while (rootEntity.getVehicle() != null) {
rootEntity = rootEntity.getVehicle(); rootEntity = rootEntity.getVehicle();
} }
List<Player> players = TeleportHelper.getPlayers(rootEntity.getPassengers()); List<Player> players = TeleportHelper.getPlayers(rootEntity.getPassengers());
Portal destinationPortal = null; Portal destinationPortal = getDestinationPortal(players, entrancePortal);
//Cancel the teleport if no players activated the portal, or if any players are denied access
boolean cancelTeleportation = false;
for (Player player : players) {
if (destinationPortal == null) {
cancelTeleportation = true;
if (!entrancePortal.getOptions().isQuiet()) {
new SGFormatBuilder(Message.INVALID_DESTINATION).error(player);
}
} else if (!TeleportHelper.playerCanTeleport(player, entrancePortal, destinationPortal)) {
cancelTeleportation = true;
}
}
if (cancelTeleportation || destinationPortal == null) {
return;
}
//Take payment from all players
if (!takePayment(players, entrancePortal, destinationPortal)) {
return;
}
// Perform the teleportation
teleportPlayerAndVehicle(players, vehicle, entrancePortal, destinationPortal);
}
/**
* Performs the teleportation of one or more players in a vehicle
*
* @param players <p>The players to be teleported</p>
* @param vehicle <p>The vehicle that triggered the teleportation</p>
* @param entrancePortal <p>The portal the player(s) and vehicle entered from</p>
* @param destinationPortal <p>The portal the player(s) and vehicle are teleporting to</p>
*/
private static void teleportPlayerAndVehicle(@NotNull List<Player> players, @NotNull Vehicle vehicle,
@NotNull Portal entrancePortal, @NotNull Portal destinationPortal) {
//Teleport the vehicle and inform the user if the vehicle was teleported
boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
if (!teleported) {
return;
}
if (!entrancePortal.getOptions().isQuiet()) {
for (Player player : players) {
new SGFormatBuilder(Message.TELEPORTED).success(player);
}
}
entrancePortal.getPortalOpener().closePortal(false);
}
/**
* Tries to get the destination portal selected by one of the players included in the teleportation
*
* @param players <p>The players to be teleported</p>
* @param entrancePortal <p>The portal the players are entering</p>
* @return <p>The destination portal, or null if not found</p>
*/
@Nullable
private static Portal getDestinationPortal(@NotNull List<Player> players, @NotNull Portal entrancePortal) {
for (Player player : players) { for (Player player : players) {
//The entrance portal must be open for one player for the teleportation to happen //The entrance portal must be open for one player for the teleportation to happen
if (!entrancePortal.getPortalOpener().isOpenFor(player)) { if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
@@ -100,48 +163,36 @@ public class VehicleEventListener implements Listener {
//Check if any of the players has selected the destination //Check if any of the players has selected the destination
Portal possibleDestinationPortal = entrancePortal.getPortalActivator().getDestination(player); Portal possibleDestinationPortal = entrancePortal.getPortalActivator().getDestination(player);
if (possibleDestinationPortal != null) { if (possibleDestinationPortal != null) {
destinationPortal = possibleDestinationPortal; return possibleDestinationPortal;
} }
} }
//Cancel the teleport if no players activated the portal, or if any players are denied access return null;
boolean cancelTeleport = false; }
for (Player player : players) {
if (destinationPortal == null) {
cancelTeleport = true;
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
}
} else if (!TeleportHelper.playerCanTeleport(player, entrancePortal, destinationPortal)) {
cancelTeleport = true;
}
}
if (cancelTeleport) {
return;
}
//Take payment from all players /**
* Takes payment for the given players
*
* @param players <p>The players to take payment from</p>
* @param entrancePortal <p>The portal the players are travelling from</p>
* @param destinationPortal <p>The portal the players are travelling to</p>
* @return <p>True if payment was successfully taken, false otherwise</p>
*/
private static boolean takePayment(@NotNull List<Player> players, @NotNull Portal entrancePortal,
@NotNull Portal destinationPortal) {
for (Player player : players) { for (Player player : players) {
//To prevent the case where the first passenger pays and then the second passenger is denied, this has to be //To prevent the case where the first passenger pays and then the second passenger is denied, this has to be
// run after it has been confirmed that all passengers are able to pay // run after it has been confirmed that all passengers are able to pay. Also note that some players might
// not have to pay, and thus the cost check has to be in the loop,
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal); int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
if (cost > 0) { if (cost > 0) {
if (EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost)) { if (EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost)) {
return; return false;
} }
} }
} }
//Teleport the vehicle and inform the user if the vehicle was teleported return true;
boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleportEntity(entrancePortal);
if (teleported) {
if (!entrancePortal.getOptions().isSilent()) {
for (Player player : players) {
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
}
}
entrancePortal.getPortalOpener().closePortal(false);
}
} }
} }

View File

@@ -9,6 +9,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.event.world.WorldUnloadEvent;
import org.jetbrains.annotations.NotNull;
/** /**
* This listener listens for the loading and unloading of worlds to load and unload stargates * This listener listens for the loading and unloading of worlds to load and unload stargates
@@ -22,7 +23,7 @@ public class WorldEventListener implements Listener {
* @param event <p>The triggered world load event</p> * @param event <p>The triggered world load event</p>
*/ */
@EventHandler @EventHandler
public void onWorldLoad(WorldLoadEvent event) { public void onWorldLoad(@NotNull WorldLoadEvent event) {
StargateConfig config = Stargate.getStargateConfig(); StargateConfig config = Stargate.getStargateConfig();
if (!config.getManagedWorlds().contains(event.getWorld().getName()) && if (!config.getManagedWorlds().contains(event.getWorld().getName()) &&
PortalFileHelper.loadAllPortals(event.getWorld())) { PortalFileHelper.loadAllPortals(event.getWorld())) {
@@ -36,7 +37,7 @@ public class WorldEventListener implements Listener {
* @param event <p>The triggered world unload event</p> * @param event <p>The triggered world unload event</p>
*/ */
@EventHandler @EventHandler
public void onWorldUnload(WorldUnloadEvent event) { public void onWorldUnload(@NotNull WorldUnloadEvent event) {
Stargate.debug("onWorldUnload", "Reloading all Stargates"); Stargate.debug("onWorldUnload", "Reloading all Stargates");
World world = event.getWorld(); World world = event.getWorld();
String worldName = world.getName(); String worldName = world.getName();

View File

@@ -1,18 +1,19 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.SimpleVectorOperation;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.property.PortalLocation; import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.portal.property.PortalOption; import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.property.PortalOptions; import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.PortalStrings;
import net.knarcraft.stargate.portal.property.PortalStructure; import net.knarcraft.stargate.portal.property.PortalStructure;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.utility.DirectionHelper;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map; import java.util.Map;
@@ -25,7 +26,6 @@ public class Portal {
private final String cleanName; private final String cleanName;
private final String network; private final String network;
private final String cleanNetwork; private final String cleanNetwork;
private final SimpleVectorOperation vectorOperation;
private final PortalOwner portalOwner; private final PortalOwner portalOwner;
private boolean isRegistered; private boolean isRegistered;
@@ -42,27 +42,25 @@ public class Portal {
* *
* @param portalLocation <p>Object containing locations of all relevant blocks</p> * @param portalLocation <p>Object containing locations of all relevant blocks</p>
* @param button <p>The location of the portal's open button</p> * @param button <p>The location of the portal's open button</p>
* @param destination <p>The destination defined on the sign's destination line. "" for non-fixed gates</p> * @param portalStrings <p>The portal's string values, such as name, network and destination</p>
* @param name <p>The name of the portal defined on the sign's first line</p>
* @param network <p>The network the portal belongs to, defined on the sign's third</p>
* @param gate <p>The gate type to use for this portal</p> * @param gate <p>The gate type to use for this portal</p>
* @param portalOwner <p>The portal's owner</p> * @param portalOwner <p>The portal's owner</p>
* @param options <p>A map containing all possible portal options, with true for the ones enabled</p> * @param options <p>A map containing all possible portal options, with true for the ones enabled</p>
*/ */
public Portal(PortalLocation portalLocation, BlockLocation button, String destination, String name, String network, public Portal(@NotNull PortalLocation portalLocation, @Nullable BlockLocation button,
Gate gate, PortalOwner portalOwner, Map<PortalOption, Boolean> options) { @NotNull PortalStrings portalStrings, @NotNull Gate gate, @NotNull PortalOwner portalOwner,
@NotNull Map<PortalOption, Boolean> options) {
this.location = portalLocation; this.location = portalLocation;
this.network = network; this.network = portalStrings.network();
this.name = name; this.name = portalStrings.name();
this.portalOwner = portalOwner; this.portalOwner = portalOwner;
this.options = new PortalOptions(options, destination.length() > 0); this.options = new PortalOptions(options, !portalStrings.destination().isEmpty());
this.signDrawer = new PortalSignDrawer(this); this.signDrawer = new PortalSignDrawer(this);
this.portalOpener = new PortalOpener(this, destination); this.portalOpener = new PortalOpener(this, portalStrings.destination());
this.structure = new PortalStructure(this, gate, button); this.structure = new PortalStructure(this, gate, button);
this.portalActivator = portalOpener.getPortalActivator(); this.portalActivator = portalOpener.getPortalActivator();
this.cleanName = cleanString(name); this.cleanName = cleanString(name);
this.cleanNetwork = cleanString(network); this.cleanNetwork = cleanString(network);
this.vectorOperation = new SimpleVectorOperation(DirectionHelper.getBlockFaceFromYaw(portalLocation.getYaw()));
} }
/** /**
@@ -88,6 +86,7 @@ public class Portal {
* *
* @return <p>This portal's location data</p> * @return <p>This portal's location data</p>
*/ */
@NotNull
public PortalLocation getLocation() { public PortalLocation getLocation() {
return this.location; return this.location;
} }
@@ -100,6 +99,7 @@ public class Portal {
* *
* @return <p>This portal's structure</p> * @return <p>This portal's structure</p>
*/ */
@NotNull
public PortalStructure getStructure() { public PortalStructure getStructure() {
return this.structure; return this.structure;
} }
@@ -112,6 +112,7 @@ public class Portal {
* *
* @return <p>This portal's activator</p> * @return <p>This portal's activator</p>
*/ */
@NotNull
public PortalActivator getPortalActivator() { public PortalActivator getPortalActivator() {
return this.portalActivator; return this.portalActivator;
} }
@@ -128,6 +129,7 @@ public class Portal {
* *
* @return <p>This portal's portal options</p> * @return <p>This portal's portal options</p>
*/ */
@NotNull
public PortalOptions getOptions() { public PortalOptions getOptions() {
return this.options; return this.options;
} }
@@ -146,6 +148,7 @@ public class Portal {
* *
* @return <p>The player currently using this portal</p> * @return <p>The player currently using this portal</p>
*/ */
@Nullable
public Player getActivePlayer() { public Player getActivePlayer() {
return portalActivator.getActivePlayer(); return portalActivator.getActivePlayer();
} }
@@ -155,6 +158,7 @@ public class Portal {
* *
* @return <p>The network this portal belongs to</p> * @return <p>The network this portal belongs to</p>
*/ */
@NotNull
public String getNetwork() { public String getNetwork() {
return network; return network;
} }
@@ -164,6 +168,7 @@ public class Portal {
* *
* @return <p>The clean network name</p> * @return <p>The clean network name</p>
*/ */
@NotNull
public String getCleanNetwork() { public String getCleanNetwork() {
return cleanNetwork; return cleanNetwork;
} }
@@ -185,6 +190,7 @@ public class Portal {
* *
* @return <p>The name of this portal</p> * @return <p>The name of this portal</p>
*/ */
@NotNull
public String getName() { public String getName() {
return name; return name;
} }
@@ -194,6 +200,7 @@ public class Portal {
* *
* @return <p>The clean name of this portal</p> * @return <p>The clean name of this portal</p>
*/ */
@NotNull
public String getCleanName() { public String getCleanName() {
return cleanName; return cleanName;
} }
@@ -205,6 +212,7 @@ public class Portal {
* *
* @return <p>This portal's portal opener</p> * @return <p>This portal's portal opener</p>
*/ */
@NotNull
public PortalOpener getPortalOpener() { public PortalOpener getPortalOpener() {
return portalOpener; return portalOpener;
} }
@@ -214,6 +222,7 @@ public class Portal {
* *
* @return <p>The name of this portal's destination portal</p> * @return <p>The name of this portal's destination portal</p>
*/ */
@NotNull
public String getDestinationName() { public String getDestinationName() {
return portalOpener.getPortalActivator().getDestinationName(); return portalOpener.getPortalActivator().getDestinationName();
} }
@@ -223,6 +232,7 @@ public class Portal {
* *
* @return <p>The gate type used by this portal</p> * @return <p>The gate type used by this portal</p>
*/ */
@NotNull
public Gate getGate() { public Gate getGate() {
return structure.getGate(); return structure.getGate();
} }
@@ -234,6 +244,7 @@ public class Portal {
* *
* @return <p>This portal's owner</p> * @return <p>This portal's owner</p>
*/ */
@NotNull
public PortalOwner getOwner() { public PortalOwner getOwner() {
return portalOwner; return portalOwner;
} }
@@ -244,7 +255,7 @@ public class Portal {
* @param player <p>The player to check</p> * @param player <p>The player to check</p>
* @return <p>True if the player is the owner of this portal</p> * @return <p>True if the player is the owner of this portal</p>
*/ */
public boolean isOwner(Player player) { public boolean isOwner(@NotNull Player player) {
if (this.portalOwner.getUUID() != null) { if (this.portalOwner.getUUID() != null) {
return player.getUniqueId().compareTo(this.portalOwner.getUUID()) == 0; return player.getUniqueId().compareTo(this.portalOwner.getUUID()) == 0;
} else { } else {
@@ -257,6 +268,7 @@ public class Portal {
* *
* @return <p>The world this portal belongs to</p> * @return <p>The world this portal belongs to</p>
*/ */
@Nullable
public World getWorld() { public World getWorld() {
return location.getWorld(); return location.getWorld();
} }
@@ -266,6 +278,7 @@ public class Portal {
* *
* @return <p>The location of this portal's sign</p> * @return <p>The location of this portal's sign</p>
*/ */
@NotNull
public BlockLocation getSignLocation() { public BlockLocation getSignLocation() {
return this.location.getSignLocation(); return this.location.getSignLocation();
} }
@@ -287,6 +300,7 @@ public class Portal {
* *
* @return <p>The location of the top-left portal block</p> * @return <p>The location of the top-left portal block</p>
*/ */
@NotNull
public BlockLocation getTopLeft() { public BlockLocation getTopLeft() {
return this.location.getTopLeft(); return this.location.getTopLeft();
} }
@@ -297,8 +311,9 @@ public class Portal {
* @param vector <p>The relative block vector explaining the position of the block</p> * @param vector <p>The relative block vector explaining the position of the block</p>
* @return <p>The block at the given relative position</p> * @return <p>The block at the given relative position</p>
*/ */
public BlockLocation getBlockAt(RelativeBlockVector vector) { @NotNull
return (BlockLocation) getTopLeft().clone().add(vectorOperation.performToRealSpaceOperation(vector.toVector())); public BlockLocation getBlockAt(@NotNull RelativeBlockVector vector) {
return getTopLeft().getRelativeLocation(vector, getYaw());
} }
/** /**
@@ -307,11 +322,13 @@ public class Portal {
* @param string <p>The string to clean</p> * @param string <p>The string to clean</p>
* @return <p>The clean string</p> * @return <p>The clean string</p>
*/ */
public static String cleanString(String string) { @NotNull
public static String cleanString(@NotNull String string) {
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string)).toLowerCase(); return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string)).toLowerCase();
} }
@Override @Override
@NotNull
public String toString() { public String toString() {
return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name, return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name,
structure.getGate().getFilename()); structure.getGate().getFilename());
@@ -327,7 +344,7 @@ public class Portal {
} }
@Override @Override
public boolean equals(Object object) { public boolean equals(@Nullable Object object) {
if (this == object) { if (this == object) {
return true; return true;
} }

View File

@@ -1,14 +1,18 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.event.StargateActivateEvent; import net.knarcraft.stargate.event.StargateActivateEvent;
import net.knarcraft.stargate.event.StargateDeactivateEvent; import net.knarcraft.stargate.event.StargateDeactivateEvent;
import net.knarcraft.stargate.utility.ListHelper;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Random;
/** /**
* The portal activator activates/de-activates portals and keeps track of a portal's destinations * The portal activator activates/de-activates portals and keeps track of a portal's destinations
@@ -33,7 +37,7 @@ public class PortalActivator {
* @param portalOpener <p>The portal opener to trigger when the activation causes the portal to open</p> * @param portalOpener <p>The portal opener to trigger when the activation causes the portal to open</p>
* @param destination <p>The fixed destination specified on the portal's sign</p> * @param destination <p>The fixed destination specified on the portal's sign</p>
*/ */
public PortalActivator(Portal portal, PortalOpener portalOpener, String destination) { public PortalActivator(@NotNull Portal portal, @NotNull PortalOpener portalOpener, @NotNull String destination) {
this.portal = portal; this.portal = portal;
this.opener = portalOpener; this.opener = portalOpener;
this.destination = destination; this.destination = destination;
@@ -44,6 +48,7 @@ public class PortalActivator {
* *
* @return <p>The player this activator's portal is currently activated for</p> * @return <p>The player this activator's portal is currently activated for</p>
*/ */
@NotNull
public Player getActivePlayer() { public Player getActivePlayer() {
return activePlayer; return activePlayer;
} }
@@ -53,6 +58,7 @@ public class PortalActivator {
* *
* @return <p>The available portal destinations</p> * @return <p>The available portal destinations</p>
*/ */
@NotNull
public List<String> getDestinations() { public List<String> getDestinations() {
return new ArrayList<>(this.destinations); return new ArrayList<>(this.destinations);
} }
@@ -63,20 +69,21 @@ public class PortalActivator {
* @param player <p>Used for random gates to determine which destinations are available</p> * @param player <p>Used for random gates to determine which destinations are available</p>
* @return <p>The destination portal the player should teleport to</p> * @return <p>The destination portal the player should teleport to</p>
*/ */
public Portal getDestination(Player player) { @Nullable
public Portal getDestination(@Nullable Player player) {
String portalNetwork = portal.getCleanNetwork(); String portalNetwork = portal.getCleanNetwork();
if (portal.getOptions().isRandom()) { if (portal.getOptions().isRandom()) {
//Find possible destinations //Find possible destinations
List<String> destinations = PortalHandler.getDestinations(portal, player, portalNetwork); List<String> destinations = PortalHandler.getDestinations(portal, player, portalNetwork);
if (destinations.size() == 0) { if (destinations.isEmpty()) {
return null; return null;
} }
//Get one random destination //Get one random destination
String destination = destinations.get((new Random()).nextInt(destinations.size())); String randomDestination = ListHelper.getRandom(destinations);
return PortalHandler.getByName(Portal.cleanString(destination), portalNetwork); return PortalHandler.getByName(randomDestination, portalNetwork);
} else { } else {
//Just return the normal fixed destination //Just return the normal fixed destination
return PortalHandler.getByName(Portal.cleanString(destination), portalNetwork); return PortalHandler.getByName(destination, portalNetwork);
} }
} }
@@ -88,6 +95,7 @@ public class PortalActivator {
* *
* @return <p>The portal destination</p> * @return <p>The portal destination</p>
*/ */
@Nullable
public Portal getDestination() { public Portal getDestination() {
return getDestination(null); return getDestination(null);
} }
@@ -97,7 +105,7 @@ public class PortalActivator {
* *
* @param destination <p>The new destination of this portal activator's portal</p> * @param destination <p>The new destination of this portal activator's portal</p>
*/ */
public void setDestination(Portal destination) { public void setDestination(@NotNull Portal destination) {
setDestination(destination.getName()); setDestination(destination.getName());
} }
@@ -106,7 +114,7 @@ public class PortalActivator {
* *
* @param destination <p>The new destination of this portal activator's portal</p> * @param destination <p>The new destination of this portal activator's portal</p>
*/ */
public void setDestination(String destination) { public void setDestination(@NotNull String destination) {
this.destination = destination; this.destination = destination;
} }
@@ -115,6 +123,7 @@ public class PortalActivator {
* *
* @return <p>The name of the selected destination</p> * @return <p>The name of the selected destination</p>
*/ */
@NotNull
public String getDestinationName() { public String getDestinationName() {
return destination; return destination;
} }
@@ -125,7 +134,7 @@ public class PortalActivator {
* @param player <p>The player to activate the portal for</p> * @param player <p>The player to activate the portal for</p>
* @return <p>True if the portal was activated</p> * @return <p>True if the portal was activated</p>
*/ */
boolean activate(Player player) { public boolean activate(@NotNull Player player) {
//Clear previous destination data //Clear previous destination data
this.destination = ""; this.destination = "";
this.destinations.clear(); this.destinations.clear();
@@ -162,7 +171,7 @@ public class PortalActivator {
* @param player <p>The player trying to activate this activator's portal</p> * @param player <p>The player trying to activate this activator's portal</p>
* @return <p>True if the portal was activated. False otherwise</p> * @return <p>True if the portal was activated. False otherwise</p>
*/ */
private boolean triggerStargateActivationEvent(Player player) { private boolean triggerStargateActivationEvent(@NotNull Player player) {
StargateActivateEvent event = new StargateActivateEvent(portal, player, destinations, destination); StargateActivateEvent event = new StargateActivateEvent(portal, player, destinations, destination);
Stargate.getInstance().getServer().getPluginManager().callEvent(event); Stargate.getInstance().getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) { if (event.isCancelled()) {
@@ -209,7 +218,7 @@ public class PortalActivator {
* @return <p>Whether this portal activator's portal is active</p> * @return <p>Whether this portal activator's portal is active</p>
*/ */
public boolean isActive() { public boolean isActive() {
return portal.getOptions().isFixed() || (destinations.size() > 0); return portal.getOptions().isFixed() || (!destinations.isEmpty());
} }
/** /**
@@ -217,7 +226,7 @@ public class PortalActivator {
* *
* @param player <p>The player to cycle the gate for</p> * @param player <p>The player to cycle the gate for</p>
*/ */
public void cycleDestination(Player player) { public void cycleDestination(@NotNull Player player) {
cycleDestination(player, 1); cycleDestination(player, 1);
} }
@@ -227,7 +236,7 @@ public class PortalActivator {
* @param player <p>The player cycling destinations</p> * @param player <p>The player cycling destinations</p>
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p> * @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
*/ */
public void cycleDestination(Player player, int direction) { public void cycleDestination(@NotNull Player player, int direction) {
//Only allow going exactly one step in either direction //Only allow going exactly one step in either direction
if (direction != 1 && direction != -1) { if (direction != 1 && direction != -1) {
throw new IllegalArgumentException("The destination direction must be 1 or -1."); throw new IllegalArgumentException("The destination direction must be 1 or -1.");
@@ -241,15 +250,17 @@ public class PortalActivator {
} }
activate = true; activate = true;
Stargate.debug("cycleDestination", "Network Size: " + List<String> portalsInNetwork = PortalHandler.getNetwork(portal.getCleanNetwork());
PortalHandler.getNetwork(portal.getCleanNetwork()).size()); if (portalsInNetwork != null) {
Stargate.debug("cycleDestination", "Network Size: " + portalsInNetwork.size());
}
Stargate.debug("cycleDestination", "Player has access to: " + destinations.size()); Stargate.debug("cycleDestination", "Player has access to: " + destinations.size());
} }
//If no destinations are available, just tell the player and quit //If no destinations are available, just tell the player and quit
if (destinations.size() == 0) { if (destinations.isEmpty()) {
if (!portal.getOptions().isSilent()) { if (!portal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("destEmpty")); new SGFormatBuilder(Message.NO_DESTINATION).error(player);
} }
return; return;
} }

View File

@@ -1,6 +1,8 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.event.StargateCreateEvent; import net.knarcraft.stargate.event.StargateCreateEvent;
@@ -8,16 +10,22 @@ import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.portal.property.PortalOption; import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.property.PortalOptions; import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.PortalStrings;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.portal.property.gate.GateHandler; import net.knarcraft.stargate.portal.property.gate.GateHandler;
import net.knarcraft.stargate.utility.DirectionHelper; import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.EconomyHelper; import net.knarcraft.stargate.utility.EconomyHelper;
import net.knarcraft.stargate.utility.ListHelper;
import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import net.knarcraft.stargate.utility.PortalFileHelper; import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -39,7 +47,7 @@ public class PortalCreator {
* @param event <p>The sign change event which initialized the creation</p> * @param event <p>The sign change event which initialized the creation</p>
* @param player <p>The player creating the portal</p> * @param player <p>The player creating the portal</p>
*/ */
public PortalCreator(SignChangeEvent event, Player player) { public PortalCreator(@NotNull SignChangeEvent event, @NotNull Player player) {
this.event = event; this.event = event;
this.player = player; this.player = player;
} }
@@ -49,27 +57,31 @@ public class PortalCreator {
* *
* @return <p>The created portal</p> * @return <p>The created portal</p>
*/ */
@Nullable
public Portal createPortal() { public Portal createPortal() {
String route = "PortalCreator::createPortal";
BlockLocation signLocation = new BlockLocation(event.getBlock()); BlockLocation signLocation = new BlockLocation(event.getBlock());
Block signControlBlock = signLocation.getParent(); Block signControlBlock = signLocation.getParent();
//Return early if the sign is not placed on a block, or the block is not a control block //Return early if the sign is not placed on a block, or the block is not a control block
if (signControlBlock == null || GateHandler.getGatesByControlBlock(signControlBlock).length == 0) { if (signControlBlock == null || GateHandler.getGatesByControlBlock(signControlBlock).isEmpty()) {
Stargate.debug("createPortal", "Control block not registered"); Stargate.debug(route, "Control block not registered");
return null; return null;
} }
//The control block is already part of another portal //The control block is already part of another portal
if (PortalHandler.getByBlock(signControlBlock) != null) { if (PortalHandler.getByBlock(signControlBlock) != null) {
Stargate.debug("createPortal", "idParent belongs to existing stargate"); Stargate.debug(route, "idParent belongs to existing stargate");
return null; return null;
} }
//Get necessary information from the gate's sign //Get necessary information from the gate's sign
String portalName = PortalHandler.filterName(event.getLine(0)); @NotNull String portalName = PortalHandler.filterName(event.getLine(0));
String destinationName = PortalHandler.filterName(event.getLine(1)); @NotNull String destinationName = PortalHandler.filterName(event.getLine(1));
String network = PortalHandler.filterName(event.getLine(2)); @NotNull String network = PortalHandler.filterName(event.getLine(2));
String options = PortalHandler.filterName(event.getLine(3)).toLowerCase(); @NotNull String options = PortalHandler.filterName(event.getLine(3)).toLowerCase();
PortalStrings portalStrings = new PortalStrings(portalName, network, destinationName);
//Get portal options available to the player creating the portal //Get portal options available to the player creating the portal
Map<PortalOption, Boolean> portalOptions = PortalHandler.getPortalOptions(player, destinationName, options); Map<PortalOption, Boolean> portalOptions = PortalHandler.getPortalOptions(player, destinationName, options);
@@ -84,18 +96,26 @@ public class PortalCreator {
PortalLocation portalLocation = new PortalLocation(); PortalLocation portalLocation = new PortalLocation();
portalLocation.setButtonFacing(buttonFacing).setYaw(yaw).setSignLocation(signLocation); portalLocation.setButtonFacing(buttonFacing).setYaw(yaw).setSignLocation(signLocation);
Stargate.debug("createPortal", "Finished getting all portal info"); Stargate.debug(route, "Finished getting all portal info");
return createPortal(portalStrings, portalOptions, yaw, portalLocation);
}
@Nullable
private Portal createPortal(@NotNull PortalStrings portalStrings, @NotNull Map<PortalOption, Boolean> portalOptions,
float yaw, @NotNull PortalLocation portalLocation) {
String route = "PortalCreator::createPortal";
//Try and find a gate matching the new portal //Try and find a gate matching the new portal
Gate gate = PortalHandler.findMatchingGate(portalLocation, player.getWorld()); Gate gate = PortalHandler.findMatchingGate(portalLocation, player.getWorld());
if ((gate == null) || (portalLocation.getButtonVector() == null)) { if ((gate == null) || (portalLocation.getButtonVector() == null)) {
Stargate.debug("createPortal", "Could not find matching gate layout"); Stargate.debug(route, "Could not find matching gate layout");
return null; return null;
} }
//If the portal is a bungee portal and invalid, abort here //If the portal is a bungee portal and invalid, abort here
if (!PortalHandler.isValidBungeePortal(portalOptions, player, destinationName, network)) { if (!PortalHandler.isValidBungeePortal(portalOptions, player, portalStrings.destination(),
Stargate.debug("createPortal", "Portal is an invalid bungee portal"); portalStrings.network())) {
Stargate.debug(route, "Portal is an invalid bungee portal");
return null; return null;
} }
@@ -104,53 +124,29 @@ public class PortalCreator {
for (PortalOption option : portalOptions.keySet()) { for (PortalOption option : portalOptions.keySet()) {
builder.append(option.getCharacterRepresentation()).append(" = ").append(portalOptions.get(option)).append(" "); builder.append(option.getCharacterRepresentation()).append(" = ").append(portalOptions.get(option)).append(" ");
} }
Stargate.debug("createPortal", builder.toString()); Stargate.debug(route, builder.toString());
//Use default network if a proper alternative is not set
if (!portalOptions.get(PortalOption.BUNGEE) && (network.length() < 1 || network.length() >
getMaxNameNetworkLength())) {
network = Stargate.getDefaultNetwork();
}
boolean deny = false; boolean deny = false;
String denyMessage = ""; String denyMessage = "";
//Check if the player can create portals on this network. If not, create a personal portal if (!(boolean) portalOptions.get(PortalOption.BUNGEE)) {
if (!portalOptions.get(PortalOption.BUNGEE) && !PermissionHelper.canCreateNetworkGate(player, network)) { String networkName = getNetworkName(portalStrings);
Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal"); if (networkName == null) {
if (PermissionHelper.canCreatePersonalPortal(player)) {
network = player.getName();
if (network.length() > getMaxNameNetworkLength()) {
network = network.substring(0, getMaxNameNetworkLength());
}
Stargate.debug("createPortal", "Creating personal portal");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createPersonal"));
} else {
Stargate.debug("createPortal", "Player does not have access to network");
deny = true; deny = true;
denyMessage = Stargate.getString("createNetDeny"); denyMessage = new SGFormatBuilder(Message.CREATION_NETWORK_DENIED).toString();
} else {
portalStrings = new PortalStrings(portalStrings.name(), networkName, portalStrings.destination());
} }
} }
//Check if the player can create this gate layout // Check whether the player can create a portal with the specified gate in the specified world
String gateName = gate.getFilename(); if (!deny) {
gateName = gateName.substring(0, gateName.indexOf('.')); denyMessage = canCreatePortal(portalOptions.get(PortalOption.BUNGEE), portalStrings.network(), gate,
if (!deny && !PermissionHelper.canCreatePortal(player, gateName)) { portalStrings.destination());
Stargate.debug("createPortal", "Player does not have access to gate layout"); if (denyMessage != null) {
deny = true; deny = true;
denyMessage = Stargate.getString("createGateDeny"); } else {
} denyMessage = "";
//Check if the user can create portals to this world.
if (!portalOptions.get(PortalOption.BUNGEE) && !deny && destinationName.length() > 0) {
Portal portal = PortalHandler.getByName(destinationName, network);
if (portal != null) {
String world = portal.getWorld().getName();
if (PermissionHelper.cannotAccessWorld(player, world)) {
Stargate.debug("canCreateNetworkGate", "Player does not have access to destination world");
deny = true;
denyMessage = Stargate.getString("createWorldDeny");
}
} }
} }
@@ -160,11 +156,72 @@ public class PortalCreator {
} }
PortalOwner owner = new PortalOwner(player); PortalOwner owner = new PortalOwner(player);
this.portal = new Portal(portalLocation, null, destinationName, portalName, network, gate, owner, this.portal = new Portal(portalLocation, null, portalStrings, gate, owner, portalOptions);
portalOptions);
return validatePortal(denyMessage, event.getLines(), deny); return validatePortal(denyMessage, event.getLines(), deny);
} }
/**
* Gets the network name to use for the new portal
*
* @param portalStrings <p>The string values for the new portal</p>
* @return <p>The new network name, or null if the player does not have the necessary permission for any networks</p>
*/
@Nullable
private String getNetworkName(@NotNull PortalStrings portalStrings) {
String network = portalStrings.network();
String route = "PortalCreator::getNetworkName";
//Use default network if a proper alternative is not set
if (portalStrings.network().isEmpty() || portalStrings.network().length() > getMaxNameNetworkLength()) {
network = Stargate.getDefaultNetwork();
}
//Check if the player can create portals on this network. If not, create a personal portal
if (!PermissionHelper.canCreateNetworkGate(player, network)) {
Stargate.debug(route, "Player doesn't have create permissions on network. Trying personal");
if (PermissionHelper.canCreatePersonalPortal(player)) {
network = player.getName();
if (network.length() > getMaxNameNetworkLength()) {
network = network.substring(0, getMaxNameNetworkLength());
}
Stargate.debug(route, "Creating personal portal");
new SGFormatBuilder(Message.CREATION_PERSONAL).error(player);
return network;
} else {
Stargate.debug(route, "Player does not have access to network");
return null;
}
}
return network;
}
@Nullable
private String canCreatePortal(boolean bungee, @NotNull String network,
@NotNull Gate gate, @NotNull String destinationName) {
//Check if the player can create this gate layout
String gateName = gate.getFilename();
gateName = gateName.substring(0, gateName.indexOf('.'));
if (!PermissionHelper.canCreatePortal(player, gateName)) {
Stargate.debug("PortalCreator::canCreatePortal", "Player does not have access to gate layout");
return new SGFormatBuilder(Message.CREATION_GATE_DENIED).toString();
}
//Check if the user can create portals to this world.
if (!bungee && !destinationName.isEmpty()) {
Portal destinationPortal = PortalHandler.getByName(destinationName, network);
if (destinationPortal != null && destinationPortal.getWorld() != null) {
String world = destinationPortal.getWorld().getName();
if (PermissionHelper.cannotAccessWorld(player, world)) {
Stargate.debug("PortalCreator::canCreatePortal", "Player does not have access to destination world");
return new SGFormatBuilder(Message.CREATION_WORLD_DENIED).toString();
}
}
}
return null;
}
/** /**
* Validates the newly created portal assigned to this portal validator * Validates the newly created portal assigned to this portal validator
* *
@@ -173,7 +230,8 @@ public class PortalCreator {
* @param deny <p>Whether the portal creation has already been denied</p> * @param deny <p>Whether the portal creation has already been denied</p>
* @return <p>The portal or null if its creation was denied</p> * @return <p>The portal or null if its creation was denied</p>
*/ */
public Portal validatePortal(String denyMessage, String[] lines, boolean deny) { @Nullable
public Portal validatePortal(@NotNull String denyMessage, @NotNull String[] lines, boolean deny) {
PortalLocation portalLocation = portal.getLocation(); PortalLocation portalLocation = portal.getLocation();
Gate gate = portal.getStructure().getGate(); Gate gate = portal.getStructure().getGate();
PortalOptions portalOptions = portal.getOptions(); PortalOptions portalOptions = portal.getOptions();
@@ -193,7 +251,7 @@ public class PortalCreator {
//Tell the user why it was denied from creating the portal //Tell the user why it was denied from creating the portal
if (stargateCreateEvent.getDeny()) { if (stargateCreateEvent.getDeny()) {
if (!stargateCreateEvent.getDenyReason().trim().isEmpty()) { if (!stargateCreateEvent.getDenyReason().trim().isEmpty()) {
Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason()); new SGFormatBuilder(stargateCreateEvent.getDenyReason()).error(player);
} }
return null; return null;
} }
@@ -219,7 +277,9 @@ public class PortalCreator {
PortalHandler.updatePortalsPointingAtNewPortal(portal); PortalHandler.updatePortalsPointingAtNewPortal(portal);
} }
PortalFileHelper.saveAllPortals(portal.getWorld()); if (portal.getWorld() != null) {
PortalFileHelper.saveAllPortals(portal.getWorld());
}
return portal; return portal;
} }
@@ -231,35 +291,37 @@ public class PortalCreator {
* @param portalName <p>The name of the newly created portal</p> * @param portalName <p>The name of the newly created portal</p>
* @return <p>True if the portal is completely valid</p> * @return <p>True if the portal is completely valid</p>
*/ */
private boolean checkIfNewPortalIsValid(int cost, String portalName) { private boolean checkIfNewPortalIsValid(int cost, @NotNull String portalName) {
String route = "PortalCreator::checkIfNewPortalIsValid";
//Check if the portal name can fit on the sign with padding (>name<) //Check if the portal name can fit on the sign with padding (>name<)
if (portal.getCleanName().length() < 1 || portal.getCleanName().length() > getMaxNameNetworkLength()) { if (portal.getCleanName().isEmpty() || portal.getCleanName().length() > getMaxNameNetworkLength()) {
Stargate.debug("createPortal", String.format("Name length error. %s is too long.", Stargate.debug(route, String.format("Name length error. %s is too long.",
portal.getCleanName())); portal.getCleanName()));
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createNameLength")); new SGFormatBuilder(Message.CREATION_NAME_LENGTH).error(player);
return false; return false;
} }
if (portal.getOptions().isBungee()) { if (portal.getOptions().isBungee()) {
//Check if the bungee portal's name has been duplicated //Check if the bungee portal's name has been duplicated
if (PortalHandler.getBungeePortals().get(portal.getCleanName()) != null) { if (PortalRegistry.getBungeePortal(portal.getCleanName()) != null) {
Stargate.debug("createPortal::Bungee", "Gate name duplicate"); Stargate.debug(route, "Gate name duplicate");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists")); new SGFormatBuilder(Message.CREATION_NAME_COLLISION).error(player);
return false; return false;
} }
} else { } else {
//Check if the portal name has been duplicated on the network //Check if the portal name has been duplicated on the network
if (PortalHandler.getByName(portal.getCleanName(), portal.getCleanNetwork()) != null) { if (PortalHandler.getByName(portal.getCleanName(), portal.getCleanNetwork()) != null) {
Stargate.debug("createPortal", "Gate name duplicate"); Stargate.debug(route, "Gate name duplicate");
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists")); new SGFormatBuilder(Message.CREATION_NAME_COLLISION).error(player);
return false; return false;
} }
//Check if the number of portals in the network has been surpassed //Check if the number of portals in the network has been surpassed
List<String> networkList = PortalHandler.getAllPortalNetworks().get(portal.getCleanNetwork()); List<String> networkList = PortalHandler.getNetwork(portal.getCleanNetwork());
int maxGates = Stargate.getGateConfig().maxGatesEachNetwork(); int maxGates = Stargate.getGateConfig().maxGatesEachNetwork();
if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) { if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createFull")); new SGFormatBuilder(Message.CREATION_NETWORK_FULL).error(player);
return false; return false;
} }
} }
@@ -268,7 +330,7 @@ public class PortalCreator {
//Deduct the required fee from the player //Deduct the required fee from the player
if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) { if (!EconomyHelper.chargePlayerIfNecessary(player, cost)) {
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost); EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
Stargate.debug("createPortal", "Insufficient Funds"); Stargate.debug(route, "Insufficient Funds");
return false; return false;
} else { } else {
EconomyHelper.sendDeductMessage(portalName, player, cost); EconomyHelper.sendDeductMessage(portalName, player, cost);
@@ -282,7 +344,7 @@ public class PortalCreator {
* *
* @param destinationName <p>The name of the destination portal. Only used if set as always on</p> * @param destinationName <p>The name of the destination portal. Only used if set as always on</p>
*/ */
private void updateNewPortalOpenState(String destinationName) { private void updateNewPortalOpenState(@NotNull String destinationName) {
portal.drawSign(); portal.drawSign();
if (portal.getOptions().isRandom() || portal.getOptions().isBungee()) { if (portal.getOptions().isRandom() || portal.getOptions().isBungee()) {
//Open the implicitly always on portal //Open the implicitly always on portal
@@ -297,8 +359,12 @@ public class PortalCreator {
} else { } else {
//Update the block type for the portal's opening to the closed block as the closed block can be anything, //Update the block type for the portal's opening to the closed block as the closed block can be anything,
// not just air or water // not just air or water
@NotNull List<Material> possibleMaterials = MaterialHelper.specifiersToMaterials(
portal.getGate().getPortalClosedMaterials()).stream().toList();
Material closedType = ListHelper.getRandom(possibleMaterials);
for (BlockLocation entrance : portal.getStructure().getEntrances()) { for (BlockLocation entrance : portal.getStructure().getEntrances()) {
entrance.setType(portal.getGate().getPortalClosedBlock()); entrance.setType(closedType);
} }
} }
} }
@@ -312,12 +378,14 @@ public class PortalCreator {
* @param player <p>The player creating the new portal</p> * @param player <p>The player creating the new portal</p>
* @return <p>True if a conflict was found. False otherwise</p> * @return <p>True if a conflict was found. False otherwise</p>
*/ */
private static boolean conflictsWithExistingPortal(Gate gate, BlockLocation topLeft, double yaw, Player player) { private static boolean conflictsWithExistingPortal(@NotNull Gate gate, @NotNull BlockLocation topLeft, double yaw,
@NotNull Player player) {
for (RelativeBlockVector borderVector : gate.getLayout().getBorder()) { for (RelativeBlockVector borderVector : gate.getLayout().getBorder()) {
BlockLocation borderBlockLocation = topLeft.getRelativeLocation(borderVector, yaw); BlockLocation borderBlockLocation = topLeft.getRelativeLocation(borderVector, yaw);
if (PortalHandler.getByBlock(borderBlockLocation.getBlock()) != null) { if (PortalHandler.getByBlock(borderBlockLocation.getBlock()) != null) {
Stargate.debug("createPortal", "Gate conflicts with existing gate"); Stargate.debug("PortalCreator::conflictsWithExistingPortal",
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createConflict")); "Gate conflicts with existing gate");
new SGFormatBuilder(Message.CREATION_CONFLICT).error(player);
return true; return true;
} }
} }

View File

@@ -1,6 +1,9 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.config.material.BukkitTagSpecifier;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.property.PortalLocation; import net.knarcraft.stargate.portal.property.PortalLocation;
@@ -8,11 +11,15 @@ import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.property.PortalStructure; import net.knarcraft.stargate.portal.property.PortalStructure;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.portal.property.gate.GateHandler; import net.knarcraft.stargate.portal.property.gate.GateHandler;
import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -33,26 +40,19 @@ public class PortalHandler {
* *
* @return <p>A copy of all portal networks</p> * @return <p>A copy of all portal networks</p>
*/ */
@NotNull
public static Map<String, List<String>> getAllPortalNetworks() { public static Map<String, List<String>> getAllPortalNetworks() {
return PortalRegistry.getAllPortalNetworks(); return PortalRegistry.getAllPortalNetworks();
} }
/**
* Gets a copy of all bungee portals
*
* @return <p>A copy of all bungee portals</p>
*/
public static Map<String, Portal> getBungeePortals() {
return PortalRegistry.getBungeePortals();
}
/** /**
* Gets names of all portals within a network * Gets names of all portals within a network
* *
* @param network <p>The network to get portals from</p> * @param network <p>The network to get portals from</p>
* @return <p>A list of portal names</p> * @return <p>A list of portal names</p>
*/ */
public static List<String> getNetwork(String network) { @Nullable
public static List<String> getNetwork(@NotNull String network) {
return PortalRegistry.getNetwork(network); return PortalRegistry.getNetwork(network);
} }
@@ -64,53 +64,73 @@ public class PortalHandler {
* @param network <p>The network to get destinations from</p> * @param network <p>The network to get destinations from</p>
* @return <p>All destinations the player can go to</p> * @return <p>All destinations the player can go to</p>
*/ */
public static List<String> getDestinations(Portal entrancePortal, Player player, String network) { @NotNull
public static List<String> getDestinations(@NotNull Portal entrancePortal, @Nullable Player player,
@NotNull String network) {
List<String> destinations = new ArrayList<>(); List<String> destinations = new ArrayList<>();
for (String destination : PortalRegistry.getAllPortalNetworks().get(network)) { List<String> portalsInNetwork = PortalRegistry.getNetwork(network);
if (portalsInNetwork == null) {
return List.of();
}
for (String destination : portalsInNetwork) {
Portal portal = getByName(destination, network); Portal portal = getByName(destination, network);
if (portal == null) { if (portal == null) {
continue; continue;
} }
//Check if destination is a random portal
if (portal.getOptions().isRandom()) { if (isDestinationAvailable(entrancePortal, portal, player)) {
continue;
}
//Check if destination is always open (Don't show if so)
if (portal.getOptions().isAlwaysOn() && !portal.getOptions().isShown()) {
continue;
}
//Check if destination is this portal
if (destination.equals(entrancePortal.getCleanName())) {
continue;
}
//Check if destination is a fixed portal not pointing to this portal
if (portal.getOptions().isFixed() &&
!Portal.cleanString(portal.getDestinationName()).equals(entrancePortal.getCleanName())) {
continue;
}
//Allow random use by non-players (Minecarts)
if (player == null) {
destinations.add(portal.getName());
continue;
}
//Check if this player can access the destination world
if (PermissionHelper.cannotAccessWorld(player, portal.getWorld().getName())) {
continue;
}
//The portal is visible to the player
if (PermissionHelper.canSeePortal(player, portal)) {
destinations.add(portal.getName()); destinations.add(portal.getName());
} }
} }
return destinations; return destinations;
} }
/**
* Checks whether the given destination is available to the given player
*
* @param entrancePortal <p>The portal the player has activated</p>
* @param destinationPortal <p>The destination portal to check if is valid</p>
* @param player <p>The player trying to attempt the destination</p>
* @return <p>True if the destination is available</p>
*/
private static boolean isDestinationAvailable(@NotNull Portal entrancePortal, @NotNull Portal destinationPortal,
@Nullable Player player) {
//Check if destination is a random portal
if (destinationPortal.getOptions().isRandom()) {
return false;
}
//Check if destination is always open (Don't show if so)
if (destinationPortal.getOptions().isAlwaysOn() && !destinationPortal.getOptions().isShown()) {
return false;
}
//Check if destination is this portal
if (destinationPortal.equals(entrancePortal)) {
return false;
}
//Check if destination is a fixed portal not pointing to this portal
if (destinationPortal.getOptions().isFixed() &&
!Portal.cleanString(destinationPortal.getDestinationName()).equals(entrancePortal.getCleanName())) {
return false;
}
//Allow random use by non-players (Minecarts)
if (player == null) {
return true;
}
//Check if this player can access the destination world
if (destinationPortal.getWorld() != null && PermissionHelper.cannotAccessWorld(player,
destinationPortal.getWorld().getName())) {
return false;
}
//The portal is visible to the player
return PermissionHelper.canSeePortal(player, destinationPortal);
}
/** /**
* Registers a portal * Registers a portal
* *
* @param portal <p>The portal to register</p> * @param portal <p>The portal to register</p>
*/ */
public static void registerPortal(Portal portal) { public static void registerPortal(@NotNull Portal portal) {
PortalRegistry.registerPortal(portal); PortalRegistry.registerPortal(portal);
} }
@@ -123,19 +143,20 @@ public class PortalHandler {
* @param network <p>The name of the portal's network</p> * @param network <p>The name of the portal's network</p>
* @return <p>False if the portal is an invalid bungee portal. True otherwise</p> * @return <p>False if the portal is an invalid bungee portal. True otherwise</p>
*/ */
static boolean isValidBungeePortal(Map<PortalOption, Boolean> portalOptions, Player player, public static boolean isValidBungeePortal(@NotNull Map<PortalOption, Boolean> portalOptions, @NotNull Player player,
String destinationName, String network) { @NotNull String destinationName, String network) {
if (portalOptions.get(PortalOption.BUNGEE)) { if (!portalOptions.get(PortalOption.BUNGEE)) {
if (!PermissionHelper.hasPermission(player, "stargate.admin.bungee")) { return true;
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDeny")); }
return false; if (!PermissionHelper.hasPermission(player, "stargate.admin.bungee")) {
} else if (!Stargate.getGateConfig().enableBungee()) { new SGFormatBuilder(Message.BUNGEE_CREATION_DENIED).error(player);
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled")); return false;
return false; } else if (!Stargate.getGateConfig().enableBungee()) {
} else if (destinationName.isEmpty() || network.isEmpty()) { new SGFormatBuilder(Message.BUNGEE_DISABLED).error(player);
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeEmpty")); return false;
return false; } else if (destinationName.isEmpty() || network.isEmpty()) {
} new SGFormatBuilder(Message.BUNGEE_MISSING_INFO).error(player);
return false;
} }
return true; return true;
} }
@@ -147,13 +168,17 @@ public class PortalHandler {
* @param world <p>The world the player is located in</p> * @param world <p>The world the player is located in</p>
* @return <p>The matching gate type, or null if no such gate could be found</p> * @return <p>The matching gate type, or null if no such gate could be found</p>
*/ */
static Gate findMatchingGate(PortalLocation portalLocation, World world) { @Nullable
public static Gate findMatchingGate(@NotNull PortalLocation portalLocation, @NotNull World world) {
Block signParent = portalLocation.getSignLocation().getParent(); Block signParent = portalLocation.getSignLocation().getParent();
if (signParent == null) {
return null;
}
BlockLocation parent = new BlockLocation(world, signParent.getX(), signParent.getY(), BlockLocation parent = new BlockLocation(world, signParent.getX(), signParent.getY(),
signParent.getZ()); signParent.getZ());
//Get all gates with the used type of control blocks //Get all gates with the used type of control blocks
Gate[] possibleGates = GateHandler.getGatesByControlBlock(signParent); List<Gate> possibleGates = GateHandler.getGatesByControlBlock(signParent);
double yaw = portalLocation.getYaw(); double yaw = portalLocation.getYaw();
Gate gate = null; Gate gate = null;
@@ -172,6 +197,11 @@ public class PortalHandler {
portalLocation.setButtonVector(controlVector); portalLocation.setButtonVector(controlVector);
} }
} }
//If our gate has been found, look no further
if (gate != null) {
break;
}
} }
return gate; return gate;
@@ -182,12 +212,16 @@ public class PortalHandler {
* *
* @param portal <p>The newly created portal</p> * @param portal <p>The newly created portal</p>
*/ */
static void updatePortalsPointingAtNewPortal(Portal portal) { public static void updatePortalsPointingAtNewPortal(@NotNull Portal portal) {
for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getCleanNetwork())) { List<String> portalsInNetwork = PortalRegistry.getNetwork(portal.getCleanNetwork());
if (portalsInNetwork == null) {
return;
}
for (String originName : portalsInNetwork) {
Portal origin = getByName(originName, portal.getCleanNetwork()); Portal origin = getByName(originName, portal.getCleanNetwork());
if (origin == null || if (origin == null ||
!Portal.cleanString(origin.getDestinationName()).equals(portal.getCleanName()) || !Portal.cleanString(origin.getDestinationName()).equals(portal.getCleanName()) ||
!origin.getStructure().isVerified()) { !new BukkitTagSpecifier(Tag.WALL_SIGNS).asMaterials().contains(origin.getLocation().getSignLocation().getType())) {
continue; continue;
} }
//Update sign of fixed gates pointing at this gate //Update sign of fixed gates pointing at this gate
@@ -209,7 +243,9 @@ public class PortalHandler {
* @param options <p>The string on the option line of the sign</p> * @param options <p>The string on the option line of the sign</p>
* @return <p>A map containing all portal options and their values</p> * @return <p>A map containing all portal options and their values</p>
*/ */
static Map<PortalOption, Boolean> getPortalOptions(Player player, String destinationName, String options) { @NotNull
public static Map<PortalOption, Boolean> getPortalOptions(@NotNull Player player, @NotNull String destinationName,
@NotNull String options) {
Map<PortalOption, Boolean> portalOptions = new HashMap<>(); Map<PortalOption, Boolean> portalOptions = new HashMap<>();
for (PortalOption option : PortalOption.values()) { for (PortalOption option : PortalOption.values()) {
portalOptions.put(option, options.indexOf(option.getCharacterRepresentation()) != -1 && portalOptions.put(option, options.indexOf(option.getCharacterRepresentation()) != -1 &&
@@ -217,7 +253,7 @@ public class PortalHandler {
} }
//Can not create a non-fixed always-on portal //Can not create a non-fixed always-on portal
if (portalOptions.get(PortalOption.ALWAYS_ON) && destinationName.length() == 0) { if (portalOptions.get(PortalOption.ALWAYS_ON) && destinationName.isEmpty()) {
portalOptions.put(PortalOption.ALWAYS_ON, false); portalOptions.put(PortalOption.ALWAYS_ON, false);
} }
@@ -247,13 +283,9 @@ public class PortalHandler {
* @param network <p>The network the portal is connected to</p> * @param network <p>The network the portal is connected to</p>
* @return <p>The portal with the given name or null</p> * @return <p>The portal with the given name or null</p>
*/ */
public static Portal getByName(String name, String network) { @Nullable
Map<String, Map<String, Portal>> lookupMap = PortalRegistry.getPortalLookupByNetwork(); public static Portal getByName(@NotNull String name, @NotNull String network) {
if (!lookupMap.containsKey(network.toLowerCase())) { return PortalRegistry.getPortalInNetwork(Portal.cleanString(network), Portal.cleanString(name));
return null;
}
return lookupMap.get(network.toLowerCase()).get(name.toLowerCase());
} }
/** /**
@@ -262,8 +294,12 @@ public class PortalHandler {
* @param location <p>The location of the portal's entrance</p> * @param location <p>The location of the portal's entrance</p>
* @return <p>The portal at the given location</p> * @return <p>The portal at the given location</p>
*/ */
public static Portal getByEntrance(Location location) { @Nullable
return PortalRegistry.getLookupEntrances().get(new BlockLocation(location.getWorld(), location.getBlockX(), public static Portal getByEntrance(@NotNull Location location) {
if (location.getWorld() == null) {
return null;
}
return PortalRegistry.getPortalFromEntrance(new BlockLocation(location.getWorld(), location.getBlockX(),
location.getBlockY(), location.getBlockZ())); location.getBlockY(), location.getBlockZ()));
} }
@@ -273,8 +309,9 @@ public class PortalHandler {
* @param block <p>The block at the portal's entrance</p> * @param block <p>The block at the portal's entrance</p>
* @return <p>The portal at the given block's location</p> * @return <p>The portal at the given block's location</p>
*/ */
public static Portal getByEntrance(Block block) { @Nullable
return PortalRegistry.getLookupEntrances().get(new BlockLocation(block)); public static Portal getByEntrance(@NotNull Block block) {
return PortalRegistry.getPortalFromEntrance(new BlockLocation(block));
} }
/** /**
@@ -283,7 +320,8 @@ public class PortalHandler {
* @param location <p>A location adjacent to the portal's entrance</p> * @param location <p>A location adjacent to the portal's entrance</p>
* @return <p>The portal adjacent to the given location</p> * @return <p>The portal adjacent to the given location</p>
*/ */
public static Portal getByAdjacentEntrance(Location location) { @Nullable
public static Portal getByAdjacentEntrance(@NotNull Location location) {
return getByAdjacentEntrance(location, 1); return getByAdjacentEntrance(location, 1);
} }
@@ -294,7 +332,8 @@ public class PortalHandler {
* @param range <p>The range to scan for portals</p> * @param range <p>The range to scan for portals</p>
* @return <p>The portal adjacent to the given location</p> * @return <p>The portal adjacent to the given location</p>
*/ */
public static Portal getByAdjacentEntrance(Location location, int range) { @Nullable
public static Portal getByAdjacentEntrance(@NotNull Location location, int range) {
List<BlockLocation> adjacentPositions = new ArrayList<>(); List<BlockLocation> adjacentPositions = new ArrayList<>();
BlockLocation centerLocation = new BlockLocation(location.getBlock()); BlockLocation centerLocation = new BlockLocation(location.getBlock());
adjacentPositions.add(centerLocation); adjacentPositions.add(centerLocation);
@@ -313,7 +352,7 @@ public class PortalHandler {
} }
for (BlockLocation adjacentPosition : adjacentPositions) { for (BlockLocation adjacentPosition : adjacentPositions) {
Portal portal = PortalRegistry.getLookupEntrances().get(adjacentPosition); Portal portal = PortalRegistry.getPortalFromEntrance(adjacentPosition);
if (portal != null) { if (portal != null) {
return portal; return portal;
} }
@@ -327,8 +366,9 @@ public class PortalHandler {
* @param block <p>The portal's control block</p> * @param block <p>The portal's control block</p>
* @return <p>The portal with the given control block</p> * @return <p>The portal with the given control block</p>
*/ */
public static Portal getByControl(Block block) { @Nullable
return PortalRegistry.getLookupControls().get(new BlockLocation(block)); public static Portal getByControl(@NotNull Block block) {
return PortalRegistry.getPortalFromControl(new BlockLocation(block));
} }
/** /**
@@ -337,8 +377,9 @@ public class PortalHandler {
* @param block <p>One of the loaded lookup blocks</p> * @param block <p>One of the loaded lookup blocks</p>
* @return <p>The portal corresponding to the block</p> * @return <p>The portal corresponding to the block</p>
*/ */
public static Portal getByBlock(Block block) { @Nullable
return PortalRegistry.getLookupBlocks().get(new BlockLocation(block)); public static Portal getByBlock(@NotNull Block block) {
return PortalRegistry.getPortalFromFrame(new BlockLocation(block));
} }
/** /**
@@ -347,8 +388,9 @@ public class PortalHandler {
* @param name <p>The name of the bungee portal to get</p> * @param name <p>The name of the bungee portal to get</p>
* @return <p>A bungee portal</p> * @return <p>A bungee portal</p>
*/ */
public static Portal getBungeePortal(String name) { @Nullable
return PortalRegistry.getBungeePortals().get(name.toLowerCase()); public static Portal getBungeePortal(@NotNull String name) {
return PortalRegistry.getBungeePortal(name);
} }
/** /**
@@ -357,7 +399,8 @@ public class PortalHandler {
* @param portalData <p>The string list containing all information about a portal</p> * @param portalData <p>The string list containing all information about a portal</p>
* @return <p>A map between portal options and booleans</p> * @return <p>A map between portal options and booleans</p>
*/ */
public static Map<PortalOption, Boolean> getPortalOptions(String[] portalData) { @NotNull
public static Map<PortalOption, Boolean> getPortalOptions(@NotNull String[] portalData) {
Map<PortalOption, Boolean> portalOptions = new HashMap<>(); Map<PortalOption, Boolean> portalOptions = new HashMap<>();
for (PortalOption option : PortalOption.values()) { for (PortalOption option : PortalOption.values()) {
int saveIndex = option.getSaveIndex(); int saveIndex = option.getSaveIndex();
@@ -394,7 +437,18 @@ public class PortalHandler {
for (Portal portal : PortalRegistry.getAllPortals()) { for (Portal portal : PortalRegistry.getAllPortals()) {
//Try and verify the portal. Invalidate it if it cannot be validated //Try and verify the portal. Invalidate it if it cannot be validated
PortalStructure structure = portal.getStructure(); PortalStructure structure = portal.getStructure();
if (!structure.wasVerified() && (!structure.isVerified() || !structure.checkIntegrity())) {
Stargate.debug("PortalHandler::verifyAllPortals", "Checking portal: " + portal.getName() + " | " + portal.getNetwork());
if (!portal.getOptions().hasNoSign() && !(new BukkitTagSpecifier(Tag.WALL_SIGNS).asMaterials().contains(
portal.getLocation().getSignLocation().getType()))) {
Stargate.debug("PortalHandler::verifyAllPortals", "Stargate is missing its sign");
invalidPortals.add(portal);
} else if (!portal.getOptions().isAlwaysOn() && portal.getLocation().getButtonVector() != null &&
!MaterialHelper.isButtonCompatible(portal.getBlockAt(portal.getLocation().getButtonVector().addOut(1)).getType())) {
Stargate.debug("PortalHandler::verifyAllPortals", "Stargate is missing a valid button");
invalidPortals.add(portal);
} else if (!structure.checkIntegrity()) {
Stargate.debug("PortalHandler::verifyAllPortals", "Stargate's border or entrance has invalid blocks");
invalidPortals.add(portal); invalidPortals.add(portal);
} }
} }
@@ -410,18 +464,19 @@ public class PortalHandler {
* *
* @param portal <p>The portal of the star portal</p> * @param portal <p>The portal of the star portal</p>
*/ */
private static void unregisterInvalidPortal(Portal portal) { private static void unregisterInvalidPortal(@NotNull Portal portal) {
//Show debug information //Show debug information
for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) { for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) {
Block block = portal.getBlockAt(control).getBlock(); Block block = portal.getBlockAt(control).getBlock();
//Log control blocks not matching the gate layout //Log control blocks not matching the gate layout
if (!block.getType().equals(portal.getGate().getControlBlock())) { if (!MaterialHelper.specifiersToMaterials(portal.getGate().getControlBlockMaterials()).contains(
Stargate.debug("PortalHandler::destroyInvalidPortal", "Control Block Type == " + block.getType())) {
Stargate.debug("PortalHandler::unregisterInvalidPortal", "Control Block Type == " +
block.getType().name()); block.getType().name());
} }
} }
PortalRegistry.unregisterPortal(portal, false); PortalRegistry.unregisterPortal(portal, false);
Stargate.logInfo(String.format("Destroying stargate at %s", portal)); Stargate.logInfo(String.format("Disabled stargate at %s", portal));
} }
/** /**
@@ -442,7 +497,8 @@ public class PortalHandler {
* @param input <p>The name to filter</p> * @param input <p>The name to filter</p>
* @return <p>The filtered name</p> * @return <p>The filtered name</p>
*/ */
public static String filterName(String input) { @NotNull
public static String filterName(@Nullable String input) {
if (input == null) { if (input == null) {
return ""; return "";
} }

View File

@@ -1,15 +1,23 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.material.BukkitTagSpecifier;
import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.event.StargateCloseEvent; import net.knarcraft.stargate.event.StargateCloseEvent;
import net.knarcraft.stargate.event.StargateOpenEvent; import net.knarcraft.stargate.event.StargateOpenEvent;
import net.knarcraft.stargate.portal.property.PortalOptions; import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.utility.ListHelper;
import net.knarcraft.stargate.utility.MaterialHelper;
import org.bukkit.Axis; import org.bukkit.Axis;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.data.Orientable; import org.bukkit.block.data.Orientable;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/** /**
* The portal opener is responsible for opening and closing a portal * The portal opener is responsible for opening and closing a portal
@@ -28,7 +36,7 @@ public class PortalOpener {
* @param portal <p>The portal this portal opener should open</p> * @param portal <p>The portal this portal opener should open</p>
* @param destination <p>The fixed destination defined on the portal's sign</p> * @param destination <p>The fixed destination defined on the portal's sign</p>
*/ */
public PortalOpener(Portal portal, String destination) { public PortalOpener(@NotNull Portal portal, @NotNull String destination) {
this.portal = portal; this.portal = portal;
this.portalActivator = new PortalActivator(portal, this, destination); this.portalActivator = new PortalActivator(portal, this, destination);
} }
@@ -56,6 +64,7 @@ public class PortalOpener {
* *
* @return <p>The portal activator belonging to this portal opener</p> * @return <p>The portal activator belonging to this portal opener</p>
*/ */
@NotNull
public PortalActivator getPortalActivator() { public PortalActivator getPortalActivator() {
return this.portalActivator; return this.portalActivator;
} }
@@ -75,7 +84,7 @@ public class PortalOpener {
* @param openFor <p>The player to open the portal for</p> * @param openFor <p>The player to open the portal for</p>
* @param force <p>Whether to force the portal open, even if it's already open for some player</p> * @param force <p>Whether to force the portal open, even if it's already open for some player</p>
*/ */
public void openPortal(Player openFor, boolean force) { public void openPortal(@Nullable Player openFor, boolean force) {
//Call the StargateOpenEvent to allow the opening to be cancelled //Call the StargateOpenEvent to allow the opening to be cancelled
StargateOpenEvent event = new StargateOpenEvent(openFor, portal, force); StargateOpenEvent event = new StargateOpenEvent(openFor, portal, force);
Stargate.getInstance().getServer().getPluginManager().callEvent(event); Stargate.getInstance().getServer().getPluginManager().callEvent(event);
@@ -84,13 +93,16 @@ public class PortalOpener {
} }
//Get the material to change the opening to //Get the material to change the opening to
Material openType = portal.getGate().getPortalOpenBlock(); @NotNull List<Material> possibleMaterials = MaterialHelper.specifiersToMaterials(
portal.getGate().getPortalOpenMaterials()).stream().toList();
Material openType = ListHelper.getRandom(possibleMaterials);
//Adjust orientation if applicable //Adjust orientation if applicable
Axis axis = (openType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null; Axis axis = (openType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null;
//Change the entrance blocks to the correct type //Change the entrance blocks to the correct type
for (BlockLocation inside : portal.getStructure().getEntrances()) { for (BlockLocation inside : portal.getStructure().getEntrances()) {
Stargate.addBlockChangeRequest(new BlockChangeRequest(inside, openType, axis)); Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(inside, openType, axis));
} }
//Update the portal state to make is actually open //Update the portal state to make is actually open
@@ -102,7 +114,7 @@ public class PortalOpener {
* *
* @param openFor <p>The player to open this portal opener's portal for</p> * @param openFor <p>The player to open this portal opener's portal for</p>
*/ */
private void updatePortalOpenState(Player openFor) { private void updatePortalOpenState(@Nullable Player openFor) {
//Update the open state of this portal //Update the open state of this portal
isOpen = true; isOpen = true;
triggeredTime = System.currentTimeMillis() / 1000; triggeredTime = System.currentTimeMillis() / 1000;
@@ -134,8 +146,8 @@ public class PortalOpener {
//Set the destination portal to this opener's portal //Set the destination portal to this opener's portal
destination.getPortalActivator().setDestination(portal); destination.getPortalActivator().setDestination(portal);
//Update the destination's sign if it's verified //Update the destination's sign if it exists
if (destination.getStructure().isVerified()) { if (new BukkitTagSpecifier(Tag.WALL_SIGNS).asMaterials().contains(destination.getLocation().getSignLocation().getType())) {
destination.drawSign(); destination.drawSign();
} }
} }
@@ -165,9 +177,15 @@ public class PortalOpener {
} }
//Close the portal by requesting the opening blocks to change //Close the portal by requesting the opening blocks to change
Material closedType = portal.getGate().getPortalClosedBlock(); @NotNull List<Material> possibleMaterials = MaterialHelper.specifiersToMaterials(
portal.getGate().getPortalClosedMaterials()).stream().toList();
Material closedType = ListHelper.getRandom(possibleMaterials);
//Adjust orientation if applicable
Axis axis = (closedType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null;
for (BlockLocation entrance : portal.getStructure().getEntrances()) { for (BlockLocation entrance : portal.getStructure().getEntrances()) {
Stargate.addBlockChangeRequest(new BlockChangeRequest(entrance, closedType, null)); Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(entrance, closedType, axis));
} }
//Update the portal state to make it actually closed //Update the portal state to make it actually closed
@@ -207,7 +225,7 @@ public class PortalOpener {
* @param player <p>The player to check portal state for</p> * @param player <p>The player to check portal state for</p>
* @return <p>True if this portal opener's portal is open to the given player</p> * @return <p>True if this portal opener's portal is open to the given player</p>
*/ */
public boolean isOpenFor(Player player) { public boolean isOpenFor(@Nullable Player player) {
//If closed, it's closed for everyone //If closed, it's closed for everyone
if (!isOpen) { if (!isOpen) {
return false; return false;

View File

@@ -2,9 +2,13 @@ package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.DynmapManager; import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.config.material.BukkitTagSpecifier;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.utility.PortalFileHelper; import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -44,11 +48,11 @@ public class PortalRegistry {
* *
* @param world <p>The world containing the portals to clear</p> * @param world <p>The world containing the portals to clear</p>
*/ */
public static void clearPortals(World world) { public static void clearPortals(@NotNull World world) {
//Storing the portals to clear is necessary to avoid a concurrent modification exception //Storing the portals to clear is necessary to avoid a concurrent modification exception
List<Portal> portalsToRemove = new ArrayList<>(); List<Portal> portalsToRemove = new ArrayList<>();
allPortals.forEach((portal) -> { allPortals.forEach((portal) -> {
if (portal.getWorld().equals(world)) { if (portal.getWorld() != null && portal.getWorld().equals(world)) {
portalsToRemove.add(portal); portalsToRemove.add(portal);
} }
}); });
@@ -61,7 +65,7 @@ public class PortalRegistry {
* *
* @param portalsToRemove <p>A list of portals to remove</p> * @param portalsToRemove <p>A list of portals to remove</p>
*/ */
private static void clearPortals(List<Portal> portalsToRemove) { private static void clearPortals(@NotNull List<Portal> portalsToRemove) {
//Store the names of the portals to remove as some maps require the name, not the object //Store the names of the portals to remove as some maps require the name, not the object
List<String> portalNames = new ArrayList<>(); List<String> portalNames = new ArrayList<>();
portalsToRemove.forEach((portal) -> portalNames.add(portal.getCleanName())); portalsToRemove.forEach((portal) -> portalNames.add(portal.getCleanName()));
@@ -87,44 +91,58 @@ public class PortalRegistry {
* *
* @return <p>A copy of the list of all portals</p> * @return <p>A copy of the list of all portals</p>
*/ */
@NotNull
public static List<Portal> getAllPortals() { public static List<Portal> getAllPortals() {
return new ArrayList<>(allPortals); return new ArrayList<>(allPortals);
} }
/** /**
* Gets a copy of the lookup map for finding a portal by its frame * Gets a portal that the given frame block belongs to
* *
* @return <p>A copy of the frame block lookup map</p> * @param blockLocation <p>The location that might be a frame block</p>
* @return <p>The portal the frame block belongs to, or null</p>
*/ */
public static Map<BlockLocation, Portal> getLookupBlocks() { @Nullable
return new HashMap<>(lookupBlocks); public static Portal getPortalFromFrame(@NotNull BlockLocation blockLocation) {
return lookupBlocks.get(blockLocation);
} }
/** /**
* Gets a copy of the lookup map for finding a portal by its control block * Gets the portal that the given control block belongs to
* *
* @return <p>A copy of the control block lookup map</p> * @param blockLocation <p>The location that might be a portal control block</p>
* @return <p>The portal the control block belongs to, or null</p>
*/ */
public static Map<BlockLocation, Portal> getLookupControls() { @Nullable
return new HashMap<>(lookupControls); public static Portal getPortalFromControl(@NotNull BlockLocation blockLocation) {
return lookupControls.get(blockLocation);
} }
/** /**
* Gets a copy of the lookup map for finding all portals in a network * Gets the portal identified by the given network name and portal name
* *
* @return <p>A copy of the network portal lookup map</p> * @param networkName <p>The name of the network the portal belongs to</p>
* @param portalName <p>The name of the portal</p>
* @return <p>The portal, or null if no such network and/or portal exists</p>
*/ */
public static Map<String, Map<String, Portal>> getPortalLookupByNetwork() { @Nullable
return new HashMap<>(portalLookupByNetwork); public static Portal getPortalInNetwork(@NotNull String networkName, @NotNull String portalName) {
Map<String, Portal> portalsInNetwork = portalLookupByNetwork.get(Portal.cleanString(networkName));
if (portalsInNetwork == null) {
return null;
}
return portalsInNetwork.get(Portal.cleanString(portalName));
} }
/** /**
* Gets a copy of all portal entrances available for lookup * Gets a portal from the location of a possible entrance
* *
* @return <p>A copy of all entrances to portal mappings</p> * @param blockLocation <p>A location that might be a portal's entrance</p>
* @return <p>A portal, or null</p>
*/ */
public static Map<BlockLocation, Portal> getLookupEntrances() { @Nullable
return new HashMap<>(lookupEntrances); public static Portal getPortalFromEntrance(@NotNull BlockLocation blockLocation) {
return lookupEntrances.get(blockLocation);
} }
/** /**
@@ -132,17 +150,20 @@ public class PortalRegistry {
* *
* @return <p>A copy of all portal networks</p> * @return <p>A copy of all portal networks</p>
*/ */
@NotNull
public static Map<String, List<String>> getAllPortalNetworks() { public static Map<String, List<String>> getAllPortalNetworks() {
return new HashMap<>(allPortalNetworks); return new HashMap<>(allPortalNetworks);
} }
/** /**
* Gets a copy of all bungee portals * Gets the BungeeCord portal with the given name
* *
* @return <p>A copy of all bungee portals</p> * @param portalName <p>The name of the portal to get</p>
* @return <p>The portal, or null</p>
*/ */
public static Map<String, Portal> getBungeePortals() { @Nullable
return new HashMap<>(bungeePortals); public static Portal getBungeePortal(@NotNull String portalName) {
return bungeePortals.get(Portal.cleanString(portalName));
} }
/** /**
@@ -151,7 +172,8 @@ public class PortalRegistry {
* @param network <p>The network to get portals from</p> * @param network <p>The network to get portals from</p>
* @return <p>A list of portal names</p> * @return <p>A list of portal names</p>
*/ */
public static List<String> getNetwork(String network) { @Nullable
public static List<String> getNetwork(@NotNull String network) {
return allPortalNetworks.get(network.toLowerCase()); return allPortalNetworks.get(network.toLowerCase());
} }
@@ -161,7 +183,7 @@ public class PortalRegistry {
* @param portal <p>The portal to un-register</p> * @param portal <p>The portal to un-register</p>
* @param removeAll <p>Whether to remove the portal from the list of all portals</p> * @param removeAll <p>Whether to remove the portal from the list of all portals</p>
*/ */
public static void unregisterPortal(Portal portal, boolean removeAll) { public static void unregisterPortal(@NotNull Portal portal, boolean removeAll) {
Stargate.debug("Unregister", "Unregistering gate " + portal.getName()); Stargate.debug("Unregister", "Unregistering gate " + portal.getName());
portal.getPortalActivator().deactivate(); portal.getPortalActivator().deactivate();
portal.getPortalOpener().closePortal(true); portal.getPortalOpener().closePortal(true);
@@ -169,6 +191,51 @@ public class PortalRegistry {
String portalName = portal.getCleanName(); String portalName = portal.getCleanName();
String networkName = portal.getCleanNetwork(); String networkName = portal.getCleanNetwork();
clearLookupMaps(portal, removeAll);
if (portal.getOptions().isBungee()) {
//Remove the bungee listing
bungeePortals.remove(portalName);
} else {
//Remove from network lists
portalLookupByNetwork.get(networkName).remove(portalName);
allPortalNetworks.get(networkName).remove(portalName);
//Update all portals in the same network with this portal as its destination
for (String originName : allPortalNetworks.get(networkName)) {
Portal origin = PortalHandler.getByName(originName, portal.getCleanNetwork());
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
!new BukkitTagSpecifier(Tag.WALL_SIGNS).asMaterials().contains(origin.getLocation().getSignLocation().getType())) {
continue;
}
//Update the portal's sign
if (origin.getOptions().isFixed()) {
origin.drawSign();
}
//Close portal without destination
if (origin.getOptions().isAlwaysOn()) {
origin.getPortalOpener().closePortal(true);
}
}
}
//Mark the portal's sign as unregistered
new PortalSignDrawer(portal).drawUnregisteredSign();
if (portal.getWorld() != null) {
PortalFileHelper.saveAllPortals(portal.getWorld());
}
portal.setRegistered(false);
DynmapManager.removePortalMarker(portal);
}
/**
* Clears the given portal's presence from lookup maps
*
* @param portal <p>The portal to clear</p>
* @param removeAll <p>Whether to remove the portal from the list of all portals</p>
*/
private static void clearLookupMaps(@NotNull Portal portal, boolean removeAll) {
//Remove portal from lookup blocks //Remove portal from lookup blocks
for (BlockLocation block : portal.getStructure().getFrame()) { for (BlockLocation block : portal.getStructure().getFrame()) {
lookupBlocks.remove(block); lookupBlocks.remove(block);
@@ -193,39 +260,6 @@ public class PortalRegistry {
if (removeAll) { if (removeAll) {
allPortals.remove(portal); allPortals.remove(portal);
} }
if (portal.getOptions().isBungee()) {
//Remove the bungee listing
bungeePortals.remove(portalName);
} else {
//Remove from network lists
portalLookupByNetwork.get(networkName).remove(portalName);
allPortalNetworks.get(networkName).remove(portalName);
//Update all portals in the same network with this portal as its destination
for (String originName : allPortalNetworks.get(networkName)) {
Portal origin = PortalHandler.getByName(originName, portal.getCleanNetwork());
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
!origin.getStructure().isVerified()) {
continue;
}
//Update the portal's sign
if (origin.getOptions().isFixed()) {
origin.drawSign();
}
//Close portal without destination
if (origin.getOptions().isAlwaysOn()) {
origin.getPortalOpener().closePortal(true);
}
}
}
//Mark the portal's sign as unregistered
new PortalSignDrawer(portal).drawUnregisteredSign();
PortalFileHelper.saveAllPortals(portal.getWorld());
portal.setRegistered(false);
DynmapManager.removePortalMarker(portal);
} }
/** /**
@@ -233,8 +267,8 @@ public class PortalRegistry {
* *
* @param portal <p>The portal to register</p> * @param portal <p>The portal to register</p>
*/ */
static void registerPortal(Portal portal) { public static void registerPortal(@NotNull Portal portal) {
portal.getOptions().setFixed(portal.getDestinationName().length() > 0 || portal.getOptions().isRandom() || portal.getOptions().setFixed(!portal.getDestinationName().isEmpty() || portal.getOptions().isRandom() ||
portal.getOptions().isBungee()); portal.getOptions().isBungee());
String portalName = portal.getCleanName(); String portalName = portal.getCleanName();

View File

@@ -3,16 +3,22 @@ package net.knarcraft.stargate.portal;
import net.knarcraft.knarlib.property.ColorConversion; import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.ColorHelper; import net.knarcraft.knarlib.util.ColorHelper;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.container.SignData; import net.knarcraft.stargate.container.SignData;
import net.knarcraft.stargate.portal.property.PortalLocation; import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import net.knarcraft.stargate.utility.SignHelper;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* The portal sign drawer draws the sing of a given portal * The portal sign drawer draws the sing of a given portal
@@ -32,7 +38,7 @@ public class PortalSignDrawer {
* *
* @param portal <p>The portal whose sign this portal sign drawer is responsible for drawing</p> * @param portal <p>The portal whose sign this portal sign drawer is responsible for drawing</p>
*/ */
public PortalSignDrawer(Portal portal) { public PortalSignDrawer(@NotNull Portal portal) {
this.portal = portal; this.portal = portal;
} }
@@ -43,7 +49,7 @@ public class PortalSignDrawer {
* *
* @param newHighlightColor <p>The new highlight color</p> * @param newHighlightColor <p>The new highlight color</p>
*/ */
public static void setHighlightColor(ChatColor newHighlightColor) { public static void setHighlightColor(@NotNull ChatColor newHighlightColor) {
highlightColor = newHighlightColor; highlightColor = newHighlightColor;
} }
@@ -54,7 +60,7 @@ public class PortalSignDrawer {
* *
* @param newMainColor <p>The new main sign color</p> * @param newMainColor <p>The new main sign color</p>
*/ */
public static void setMainColor(ChatColor newMainColor) { public static void setMainColor(@NotNull ChatColor newMainColor) {
mainColor = newMainColor; mainColor = newMainColor;
} }
@@ -63,7 +69,7 @@ public class PortalSignDrawer {
* *
* @param freeColor <p>The new color to use for marking free stargates</p> * @param freeColor <p>The new color to use for marking free stargates</p>
*/ */
public static void setFreeColor(ChatColor freeColor) { public static void setFreeColor(@NotNull ChatColor freeColor) {
PortalSignDrawer.freeColor = freeColor; PortalSignDrawer.freeColor = freeColor;
} }
@@ -72,7 +78,7 @@ public class PortalSignDrawer {
* *
* @param signMainColors <p>The per-sign main colors</p> * @param signMainColors <p>The per-sign main colors</p>
*/ */
public static void setPerSignMainColors(Map<Material, ChatColor> signMainColors) { public static void setPerSignMainColors(@NotNull Map<Material, ChatColor> signMainColors) {
PortalSignDrawer.perSignMainColors = signMainColors; PortalSignDrawer.perSignMainColors = signMainColors;
} }
@@ -81,7 +87,7 @@ public class PortalSignDrawer {
* *
* @param signHighlightColors <p>The per-sign highlight colors</p> * @param signHighlightColors <p>The per-sign highlight colors</p>
*/ */
public static void setPerSignHighlightColors(Map<Material, ChatColor> signHighlightColors) { public static void setPerSignHighlightColors(@NotNull Map<Material, ChatColor> signHighlightColors) {
PortalSignDrawer.perSignHighlightColors = signHighlightColors; PortalSignDrawer.perSignHighlightColors = signHighlightColors;
} }
@@ -90,6 +96,7 @@ public class PortalSignDrawer {
* *
* @return <p>The currently used main sign color</p> * @return <p>The currently used main sign color</p>
*/ */
@NotNull
public static ChatColor getMainColor() { public static ChatColor getMainColor() {
return mainColor; return mainColor;
} }
@@ -99,6 +106,7 @@ public class PortalSignDrawer {
* *
* @return <p>The currently used highlighting sign color</p> * @return <p>The currently used highlighting sign color</p>
*/ */
@NotNull
public static ChatColor getHighlightColor() { public static ChatColor getHighlightColor() {
return highlightColor; return highlightColor;
} }
@@ -112,8 +120,7 @@ public class PortalSignDrawer {
return; return;
} }
SignData signData = new SignData(sign, getMainColor(sign.getType()), getHighlightColor(sign.getType())); drawSign(new SignData(sign, getMainColor(sign.getType()), getHighlightColor(sign.getType())));
drawSign(signData);
} }
/** /**
@@ -121,6 +128,7 @@ public class PortalSignDrawer {
* *
* @return <p>The sign of this sign drawer's portal</p> * @return <p>The sign of this sign drawer's portal</p>
*/ */
@Nullable
private Sign getSign() { private Sign getSign() {
Block signBlock = portal.getSignLocation().getBlock(); Block signBlock = portal.getSignLocation().getBlock();
BlockState state = signBlock.getState(); BlockState state = signBlock.getState();
@@ -140,42 +148,63 @@ public class PortalSignDrawer {
* *
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
*/ */
private void drawSign(SignData signData) { private void drawSign(@NotNull SignData signData) {
Sign sign = signData.getSign(); Sign sign = signData.getSign();
ChatColor highlightColor = signData.getHighlightSignColor(); ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
//Clear sign
clearSign(sign); // Initialize all lines as empty to prevent null
String[] lines = new String[4];
lines[0] = "";
lines[1] = "";
lines[2] = "";
lines[3] = "";
setLine(signData, 0, highlightColor + "-" + mainColor + translateAllColorCodes(portal.getName()) + setLine(signData, 0, highlightColor + "-" + mainColor + translateAllColorCodes(portal.getName()) +
highlightColor + "-"); highlightColor + "-", lines);
if (!portal.getPortalActivator().isActive()) { if (!portal.getPortalActivator().isActive()) {
//Default sign text //Default sign text
drawInactiveSign(signData); drawInactiveSign(signData, lines);
} else { } else {
if (portal.getOptions().isBungee()) { if (portal.getOptions().isBungee()) {
//Bungee sign //Bungee sign
drawBungeeSign(signData); drawBungeeSign(signData, lines);
} else if (portal.getOptions().isFixed()) { } else if (portal.getOptions().isFixed()) {
//Sign pointing at one other portal //Sign pointing at one other portal
drawFixedSign(signData); drawFixedSign(signData, lines);
} else { } else {
//Networking stuff //Networking stuff
drawNetworkSign(signData); drawNetworkSign(signData, lines);
} }
} }
sign.update(); updateSign(sign, lines);
} }
/** /**
* Clears all lines of a sign, but does not update the sign * Updates a sign, if necessary
* *
* @param sign <p>The sign to clear</p> * @param sign <p>The sign to update</p>
* @param lines <p>The sign's new lines</p>
*/ */
private void clearSign(Sign sign) { private void updateSign(@NotNull Sign sign, @NotNull String[] lines) {
for (int index = 0; index <= 3; index++) { boolean updateNecessary = false;
sign.setLine(index, "");
String[] oldLines = SignHelper.getLines(sign);
for (int i = 0; i < 4; i++) {
if (!oldLines[i].equals(lines[i])) {
updateNecessary = true;
break;
}
}
if (updateNecessary) {
for (int i = 0; i < 4; i++) {
SignHelper.setSignLine(sign, i, lines[i]);
}
sign.update();
} }
} }
@@ -187,8 +216,12 @@ public class PortalSignDrawer {
if (sign == null) { if (sign == null) {
return; return;
} }
clearSign(sign);
sign.setLine(0, translateAllColorCodes(portal.getName())); for (int index = 0; index <= 3; index++) {
SignHelper.setSignLine(sign, index, "");
}
SignHelper.setSignLine(sign, 0, translateAllColorCodes(portal.getName()));
sign.update(); sign.update();
} }
@@ -196,8 +229,9 @@ public class PortalSignDrawer {
* Draws a sign with choose-able network locations * Draws a sign with choose-able network locations
* *
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
* @param output <p>The output list to write to</p>
*/ */
private void drawNetworkSign(SignData signData) { private void drawNetworkSign(@NotNull SignData signData, @NotNull String[] output) {
PortalActivator destinations = portal.getPortalActivator(); PortalActivator destinations = portal.getPortalActivator();
int maxIndex = destinations.getDestinations().size() - 1; int maxIndex = destinations.getDestinations().size() - 1;
int signLineIndex = 0; int signLineIndex = 0;
@@ -207,21 +241,21 @@ public class PortalSignDrawer {
//Last, and not only entry. Draw the entry two back //Last, and not only entry. Draw the entry two back
if ((destinationIndex == maxIndex) && (maxIndex > 1)) { if ((destinationIndex == maxIndex) && (maxIndex > 1)) {
drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 2); drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 2, output);
} }
//Not first entry. Draw the previous entry //Not first entry. Draw the previous entry
if (destinationIndex > 0) { if (destinationIndex > 0) {
drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 1); drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex - 1, output);
} }
//Draw the chosen entry (line 2 or 3) //Draw the chosen entry (line 2 or 3)
drawNetworkSignChosenLine(signData, freeGatesColored, ++signLineIndex); drawNetworkSignChosenLine(signData, freeGatesColored, ++signLineIndex, output);
//Has another entry and space on the sign //Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 1)) { if ((maxIndex >= destinationIndex + 1)) {
drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex + 1); drawNetworkSignLine(signData, freeGatesColored, ++signLineIndex, destinationIndex + 1, output);
} }
//Has another entry and space on the sign //Has another entry and space on the sign
if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) { if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
drawNetworkSignLine(signData, freeGatesColored, signLineIndex, destinationIndex + 2); drawNetworkSignLine(signData, freeGatesColored, signLineIndex, destinationIndex + 2, output);
} }
} }
@@ -231,19 +265,21 @@ public class PortalSignDrawer {
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
* @param freeGatesColored <p>Whether to display free gates in a different color</p> * @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param signLineIndex <p>The line to draw on</p> * @param signLineIndex <p>The line to draw on</p>
* @param output <p>The output list to write to</p>
*/ */
private void drawNetworkSignChosenLine(SignData signData, boolean freeGatesColored, int signLineIndex) { private void drawNetworkSignChosenLine(@NotNull SignData signData, boolean freeGatesColored, int signLineIndex,
@NotNull String[] output) {
ChatColor highlightColor = signData.getHighlightSignColor(); ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
if (freeGatesColored) { if (freeGatesColored) {
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork()); Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination); boolean free = PermissionHelper.isFree(Objects.requireNonNull(portal.getActivePlayer()), portal, destination);
ChatColor nameColor = (free ? freeColor : highlightColor); ChatColor nameColor = (free ? freeColor : highlightColor);
setLine(signData, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) + setLine(signData, signLineIndex, nameColor + ">" + (free ? freeColor : mainColor) +
translateAllColorCodes(portal.getDestinationName()) + nameColor + "<"); translateAllColorCodes(portal.getDestinationName()) + nameColor + "<", output);
} else { } else {
setLine(signData, signLineIndex, highlightColor + ">" + mainColor + setLine(signData, signLineIndex, highlightColor + ">" + mainColor +
translateAllColorCodes(portal.getDestinationName()) + highlightColor + "<"); translateAllColorCodes(portal.getDestinationName()) + highlightColor + "<", output);
} }
} }
@@ -253,10 +289,11 @@ public class PortalSignDrawer {
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
* @param index <p>The index of the sign line to change</p> * @param index <p>The index of the sign line to change</p>
* @param text <p>The new text on the sign</p> * @param text <p>The new text on the sign</p>
* @param output <p>The output list to write to</p>
*/ */
public void setLine(SignData signData, int index, String text) { public void setLine(@NotNull SignData signData, int index, @NotNull String text, @NotNull String[] output) {
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
signData.getSign().setLine(index, mainColor + text); output[index] = mainColor + text;
} }
/** /**
@@ -266,17 +303,19 @@ public class PortalSignDrawer {
* @param freeGatesColored <p>Whether to display free gates in a different color</p> * @param freeGatesColored <p>Whether to display free gates in a different color</p>
* @param signLineIndex <p>The line to draw on</p> * @param signLineIndex <p>The line to draw on</p>
* @param destinationIndex <p>The index of the destination to draw</p> * @param destinationIndex <p>The index of the destination to draw</p>
* @param output <p>The output list to write to</p>
*/ */
private void drawNetworkSignLine(SignData signData, boolean freeGatesColored, int signLineIndex, int destinationIndex) { private void drawNetworkSignLine(@NotNull SignData signData, boolean freeGatesColored, int signLineIndex,
int destinationIndex, @NotNull String[] output) {
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
PortalActivator destinations = portal.getPortalActivator(); PortalActivator destinations = portal.getPortalActivator();
String destinationName = destinations.getDestinations().get(destinationIndex); String destinationName = destinations.getDestinations().get(destinationIndex);
if (freeGatesColored) { if (freeGatesColored) {
Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork()); Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork());
boolean free = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination); boolean free = PermissionHelper.isFree(Objects.requireNonNull(portal.getActivePlayer()), portal, destination);
setLine(signData, signLineIndex, (free ? freeColor : mainColor) + translateAllColorCodes(destinationName)); setLine(signData, signLineIndex, (free ? freeColor : mainColor) + translateAllColorCodes(destinationName), output);
} else { } else {
setLine(signData, signLineIndex, mainColor + translateAllColorCodes(destinationName)); setLine(signData, signLineIndex, mainColor + translateAllColorCodes(destinationName), output);
} }
} }
@@ -284,15 +323,16 @@ public class PortalSignDrawer {
* Draws the sign of a BungeeCord portal * Draws the sign of a BungeeCord portal
* *
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
* @param output <p>The output list to write to</p>
*/ */
private void drawBungeeSign(SignData signData) { private void drawBungeeSign(@NotNull SignData signData, @NotNull String[] output) {
ChatColor highlightColor = signData.getHighlightSignColor(); ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
setLine(signData, 1, Stargate.getString("bungeeSign")); setLine(signData, 1, new SGFormatBuilder(Message.BUNGEE_SIGN).toString(), output);
setLine(signData, 2, highlightColor + ">" + mainColor + translateAllColorCodes(portal.getDestinationName()) + setLine(signData, 2, highlightColor + ">" + mainColor +
highlightColor + "<"); translateAllColorCodes(portal.getDestinationName()) + highlightColor + "<", output);
setLine(signData, 3, highlightColor + "[" + mainColor + translateAllColorCodes(portal.getNetwork()) + setLine(signData, 3, highlightColor + "[" + mainColor + translateAllColorCodes(portal.getNetwork()) +
highlightColor + "]"); highlightColor + "]", output);
} }
/** /**
@@ -301,17 +341,18 @@ public class PortalSignDrawer {
* <p>The sign for an in-active portal should display the right-click prompt and the network.</p> * <p>The sign for an in-active portal should display the right-click prompt and the network.</p>
* *
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
* @param output <p>The output list to write to</p>
*/ */
private void drawInactiveSign(SignData signData) { private void drawInactiveSign(@NotNull SignData signData, @NotNull String[] output) {
ChatColor highlightColor = signData.getHighlightSignColor(); ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
setLine(signData, 1, Stargate.getString("signRightClick")); setLine(signData, 1, new SGFormatBuilder(Message.SIGN_RIGHT_CLICK).toString(), output);
setLine(signData, 2, Stargate.getString("signToUse")); setLine(signData, 2, new SGFormatBuilder(Message.SIGN_TO_USE).toString(), output);
if (!portal.getOptions().isNoNetwork()) { if (!portal.getOptions().isNoNetwork()) {
setLine(signData, 3, highlightColor + "(" + mainColor + translateAllColorCodes(portal.getNetwork()) + setLine(signData, 3, highlightColor + "(" + mainColor + translateAllColorCodes(portal.getNetwork()) +
highlightColor + ")"); highlightColor + ")", output);
} else { } else {
setLine(signData, 3, ""); setLine(signData, 3, "", output);
} }
} }
@@ -319,29 +360,28 @@ public class PortalSignDrawer {
* Draws a sign pointing to a fixed location * Draws a sign pointing to a fixed location
* *
* @param signData <p>All necessary sign information</p> * @param signData <p>All necessary sign information</p>
* @param output <p>The output list to write to</p>
*/ */
private void drawFixedSign(SignData signData) { private void drawFixedSign(@NotNull SignData signData, @NotNull String[] output) {
ChatColor highlightColor = signData.getHighlightSignColor(); ChatColor highlightColor = signData.getHighlightSignColor();
ChatColor mainColor = signData.getMainSignColor(); ChatColor mainColor = signData.getMainSignColor();
Portal destinationPortal = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()), Portal destinationPortal = PortalHandler.getByName(portal.getDestinationName(), portal.getCleanNetwork());
portal.getCleanNetwork()); String destinationName = portal.getOptions().isRandom() ? new SGFormatBuilder(Message.SIGN_RANDOM).toString() :
String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
(destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName()); (destinationPortal != null ? destinationPortal.getName() : portal.getDestinationName());
setLine(signData, 1, highlightColor + ">" + mainColor + translateAllColorCodes(destinationName) + setLine(signData, 1, highlightColor + ">" + mainColor + translateAllColorCodes(destinationName) +
highlightColor + "<"); highlightColor + "<", output);
if (portal.getOptions().isNoNetwork()) { if (portal.getOptions().isNoNetwork()) {
setLine(signData, 2, ""); setLine(signData, 2, "", output);
} else { } else {
setLine(signData, 2, highlightColor + "(" + mainColor + setLine(signData, 2, highlightColor + "(" + mainColor +
translateAllColorCodes(portal.getNetwork()) + highlightColor + ")"); translateAllColorCodes(portal.getNetwork()) + highlightColor + ")", output);
} }
Portal destination = PortalHandler.getByName(Portal.cleanString(portal.getDestinationName()), Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
portal.getNetwork());
if (destination == null && !portal.getOptions().isRandom()) { if (destination == null && !portal.getOptions().isRandom()) {
setLine(signData, 3, errorColor + Stargate.getString("signDisconnected")); setLine(signData, 3, errorColor + new SGFormatBuilder(Message.SIGN_DISCONNECTED).toString(), output);
} else { } else {
setLine(signData, 3, ""); setLine(signData, 3, "", output);
} }
} }
@@ -352,12 +392,13 @@ public class PortalSignDrawer {
* @param gateName <p>The name of the invalid gate type</p> * @param gateName <p>The name of the invalid gate type</p>
* @param lineIndex <p>The index of the line the invalid portal was found at</p> * @param lineIndex <p>The index of the line the invalid portal was found at</p>
*/ */
public static void markPortalWithInvalidGate(PortalLocation portalLocation, String gateName, int lineIndex) { public static void markPortalWithInvalidGate(@NotNull PortalLocation portalLocation, @NotNull String gateName,
int lineIndex) {
BlockState blockState = portalLocation.getSignLocation().getBlock().getState(); BlockState blockState = portalLocation.getSignLocation().getBlock().getState();
if (!(blockState instanceof Sign sign)) { if (!(blockState instanceof Sign sign)) {
return; return;
} }
sign.setLine(3, errorColor + Stargate.getString("signInvalidGate")); SignHelper.setSignLine(sign, 3, errorColor + new SGFormatBuilder(Message.SIGN_INVALID).toString());
sign.update(); sign.update();
Stargate.logInfo(String.format("Gate layout on line %d does not exist [%s]", lineIndex, gateName)); Stargate.logInfo(String.format("Gate layout on line %d does not exist [%s]", lineIndex, gateName));
@@ -369,7 +410,8 @@ public class PortalSignDrawer {
* @param signType <p>The sign type to get the main color for</p> * @param signType <p>The sign type to get the main color for</p>
* @return <p>The main color for the given sign type</p> * @return <p>The main color for the given sign type</p>
*/ */
private ChatColor getMainColor(Material signType) { @NotNull
private ChatColor getMainColor(@NotNull Material signType) {
ChatColor signColor = perSignMainColors.get(signType); ChatColor signColor = perSignMainColors.get(signType);
if (signColor == null) { if (signColor == null) {
return mainColor; return mainColor;
@@ -384,7 +426,8 @@ public class PortalSignDrawer {
* @param signType <p>The sign type to get the highlight color for</p> * @param signType <p>The sign type to get the highlight color for</p>
* @return <p>The highlight color for the given sign type</p> * @return <p>The highlight color for the given sign type</p>
*/ */
private ChatColor getHighlightColor(Material signType) { @NotNull
private ChatColor getHighlightColor(@NotNull Material signType) {
ChatColor signColor = perSignHighlightColors.get(signType); ChatColor signColor = perSignHighlightColors.get(signType);
if (signColor == null) { if (signColor == null) {
return highlightColor; return highlightColor;
@@ -399,7 +442,8 @@ public class PortalSignDrawer {
* @param input <p>The input to translate color codes for</p> * @param input <p>The input to translate color codes for</p>
* @return <p>The input with color codes converted translated from & to §</p> * @return <p>The input with color codes converted translated from & to §</p>
*/ */
private String translateAllColorCodes(String input) { @NotNull
private String translateAllColorCodes(@NotNull String input) {
return ColorHelper.translateColorCodes(input, ColorConversion.RGB); return ColorHelper.translateColorCodes(input, ColorConversion.RGB);
} }

View File

@@ -5,6 +5,8 @@ import net.knarcraft.stargate.container.RelativeBlockVector;
import org.bukkit.Axis; import org.bukkit.Axis;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Keeps track of location related data for a portal * Keeps track of location related data for a portal
@@ -23,6 +25,7 @@ public class PortalLocation {
* *
* @return <p>The top-left block of the portal</p> * @return <p>The top-left block of the portal</p>
*/ */
@NotNull
public BlockLocation getTopLeft() { public BlockLocation getTopLeft() {
return topLeft; return topLeft;
} }
@@ -41,6 +44,7 @@ public class PortalLocation {
* *
* @return <p>The location of the portal's sign</p> * @return <p>The location of the portal's sign</p>
*/ */
@NotNull
public BlockLocation getSignLocation() { public BlockLocation getSignLocation() {
return signLocation; return signLocation;
} }
@@ -50,6 +54,7 @@ public class PortalLocation {
* *
* @return <p>The relative location of the portal's button</p> * @return <p>The relative location of the portal's button</p>
*/ */
@Nullable
public RelativeBlockVector getButtonVector() { public RelativeBlockVector getButtonVector() {
return buttonVector; return buttonVector;
} }
@@ -59,16 +64,19 @@ public class PortalLocation {
* *
* @return <p>The button's block face</p> * @return <p>The button's block face</p>
*/ */
@NotNull
public BlockFace getButtonFacing() { public BlockFace getButtonFacing() {
return buttonFacing; return buttonFacing;
} }
/** /**
* Gets the rotation axis, which is the axis along which the gate is placed * Gets the rotation axis, which is the axis along which the gate is placed
*
* <p>The portal's rotation axis is the cross axis of the button's axis</p> * <p>The portal's rotation axis is the cross axis of the button's axis</p>
* *
* @return <p>The portal's rotation axis</p> * @return <p>The portal's rotation axis</p>
*/ */
@NotNull
public Axis getRotationAxis() { public Axis getRotationAxis() {
return getYaw() == 0.0F || getYaw() == 180.0F ? Axis.X : Axis.Z; return getYaw() == 0.0F || getYaw() == 180.0F ? Axis.X : Axis.Z;
} }
@@ -78,6 +86,7 @@ public class PortalLocation {
* *
* @return <p>The world this portal resides in</p> * @return <p>The world this portal resides in</p>
*/ */
@Nullable
public World getWorld() { public World getWorld() {
return topLeft.getWorld(); return topLeft.getWorld();
} }
@@ -91,7 +100,8 @@ public class PortalLocation {
* @param topLeft <p>The new top-left block of the portal's square structure</p> * @param topLeft <p>The new top-left block of the portal's square structure</p>
* @return <p>The portal location Object</p> * @return <p>The portal location Object</p>
*/ */
public PortalLocation setTopLeft(BlockLocation topLeft) { @NotNull
public PortalLocation setTopLeft(@NotNull BlockLocation topLeft) {
this.topLeft = topLeft; this.topLeft = topLeft;
return this; return this;
} }
@@ -104,6 +114,7 @@ public class PortalLocation {
* @param yaw <p>The portal's new yaw</p> * @param yaw <p>The portal's new yaw</p>
* @return <p>The portal location Object</p> * @return <p>The portal location Object</p>
*/ */
@NotNull
public PortalLocation setYaw(float yaw) { public PortalLocation setYaw(float yaw) {
this.yaw = yaw; this.yaw = yaw;
return this; return this;
@@ -115,7 +126,8 @@ public class PortalLocation {
* @param signLocation <p>The new sign location</p> * @param signLocation <p>The new sign location</p>
* @return <p>The portal location Object</p> * @return <p>The portal location Object</p>
*/ */
public PortalLocation setSignLocation(BlockLocation signLocation) { @NotNull
public PortalLocation setSignLocation(@NotNull BlockLocation signLocation) {
this.signLocation = signLocation; this.signLocation = signLocation;
return this; return this;
} }
@@ -126,7 +138,8 @@ public class PortalLocation {
* @param buttonVector <p>The new relative button location</p> * @param buttonVector <p>The new relative button location</p>
* @return <p>The portal location Object</p> * @return <p>The portal location Object</p>
*/ */
public PortalLocation setButtonVector(RelativeBlockVector buttonVector) { @NotNull
public PortalLocation setButtonVector(@Nullable RelativeBlockVector buttonVector) {
this.buttonVector = buttonVector; this.buttonVector = buttonVector;
return this; return this;
} }
@@ -137,7 +150,8 @@ public class PortalLocation {
* @param buttonFacing <p>The new block face of the portal's button</p> * @param buttonFacing <p>The new block face of the portal's button</p>
* @return <p>The portal location Object</p> * @return <p>The portal location Object</p>
*/ */
public PortalLocation setButtonFacing(BlockFace buttonFacing) { @NotNull
public PortalLocation setButtonFacing(@NotNull BlockFace buttonFacing) {
this.buttonFacing = buttonFacing; this.buttonFacing = buttonFacing;
return this; return this;
} }

View File

@@ -1,5 +1,7 @@
package net.knarcraft.stargate.portal.property; package net.knarcraft.stargate.portal.property;
import org.jetbrains.annotations.NotNull;
/** /**
* Each enum value represents one option a portal can have/use * Each enum value represents one option a portal can have/use
*/ */
@@ -8,57 +10,57 @@ public enum PortalOption {
/** /**
* This option allows a portal to be hidden from others * This option allows a portal to be hidden from others
*/ */
HIDDEN('h', "stargate.option.hidden", 11), HIDDEN('h', "hidden", 11),
/** /**
* This option allows a portal that's always on and does not need to be activated or opened each time * This option allows a portal that's always on and does not need to be activated or opened each time
*/ */
ALWAYS_ON('a', "stargate.option.alwayson", 12), ALWAYS_ON('a', "alwayson", 12),
/** /**
* This option allows a portal that's private to the stargate's owner * This option allows a portal that's private to the stargate's owner
*/ */
PRIVATE('p', "stargate.option.private", 13), PRIVATE('p', "private", 13),
/** /**
* This option allows a portal that's free even if stargates usually are not * This option allows a portal that's free even if stargates usually are not
*/ */
FREE('f', "stargate.option.free", 15), FREE('f', "free", 15),
/** /**
* This option allows a portal where players exit through the back of the portal * This option allows a portal where players exit through the back of the portal
*/ */
BACKWARDS('b', "stargate.option.backwards", 16), BACKWARDS('b', "backwards", 16),
/** /**
* This option shows the gate in the network list even if it's always on * This option shows the gate in the network list even if it's always on
*/ */
SHOW('s', "stargate.option.show", 17), SHOW('s', "show", 17),
/** /**
* This option hides the network name on the sign * This option hides the network name on the sign
*/ */
NO_NETWORK('n', "stargate.option.nonetwork", 18), NO_NETWORK('n', "nonetwork", 18),
/** /**
* This option allows a portal where players teleport to a random exit portal in the network * This option allows a portal where players teleport to a random exit portal in the network
*/ */
RANDOM('r', "stargate.option.random", 19), RANDOM('r', "random", 19),
/** /**
* This option allows a portal to teleport to another server connected through BungeeCord * This option allows a portal to teleport to another server connected through BungeeCord
*/ */
BUNGEE('u', "stargate.admin.bungee", 20), BUNGEE('u', "bungee", 20),
/** /**
* This option allows a portal which does not display a teleportation message, for better immersion * This option allows a portal which does not display a teleportation message, for better immersion
*/ */
SILENT('i', "stargate.option.silent", 21), QUIET('q', "quiet", 21),
/** /**
* This option causes a fixed portal's sign to be removed after creation * This option causes a fixed portal's sign to be removed after creation
*/ */
NO_SIGN('e', "stargate.option.nosign", 22); NO_SIGN('v', "nosign", 22);
private final char characterRepresentation; private final char characterRepresentation;
private final String permissionString; private final String permissionString;
@@ -70,9 +72,9 @@ public enum PortalOption {
* @param characterRepresentation <p>The character representation used on the sign to allow this option</p> * @param characterRepresentation <p>The character representation used on the sign to allow this option</p>
* @param permissionString <p>The permission necessary to use this option</p> * @param permissionString <p>The permission necessary to use this option</p>
*/ */
PortalOption(final char characterRepresentation, String permissionString, int saveIndex) { PortalOption(final char characterRepresentation, @NotNull String permissionString, int saveIndex) {
this.characterRepresentation = characterRepresentation; this.characterRepresentation = characterRepresentation;
this.permissionString = permissionString; this.permissionString = "stargate.option." + permissionString;
this.saveIndex = saveIndex; this.saveIndex = saveIndex;
} }
@@ -90,6 +92,7 @@ public enum PortalOption {
* *
* @return <p>The permission necessary for this option</p> * @return <p>The permission necessary for this option</p>
*/ */
@NotNull
public String getPermissionString() { public String getPermissionString() {
return this.permissionString; return this.permissionString;
} }

View File

@@ -1,6 +1,7 @@
package net.knarcraft.stargate.portal.property; package net.knarcraft.stargate.portal.property;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import org.jetbrains.annotations.NotNull;
import java.util.Map; import java.util.Map;
@@ -18,7 +19,7 @@ public class PortalOptions {
* @param options <p>All options to keep track of</p> * @param options <p>All options to keep track of</p>
* @param hasDestination <p>Whether the portal has a fixed destination</p> * @param hasDestination <p>Whether the portal has a fixed destination</p>
*/ */
public PortalOptions(Map<PortalOption, Boolean> options, boolean hasDestination) { public PortalOptions(@NotNull Map<PortalOption, Boolean> options, boolean hasDestination) {
this.options = options; this.options = options;
isFixed = hasDestination || this.isRandom() || this.isBungee(); isFixed = hasDestination || this.isRandom() || this.isBungee();
@@ -171,15 +172,15 @@ public class PortalOptions {
} }
/** /**
* Gets whether this portal is silent * Gets whether this portal is QUIET
* *
* <p>A silent portal does not output anything to the chat when teleporting. This option is mainly useful to keep * <p>A quiet portal does not output anything to the chat when teleporting. This option is mainly useful to keep
* the immersion during teleportation (for role-playing servers or similar).</p> * the immersion during teleportation (for role-playing servers or similar).</p>
* *
* @return <p>Whether this portal is silent</p> * @return <p>Whether this portal is quiet</p>
*/ */
public boolean isSilent() { public boolean isQuiet() {
return this.options.get(PortalOption.SILENT); return this.options.get(PortalOption.QUIET);
} }
/** /**

View File

@@ -3,7 +3,8 @@ package net.knarcraft.stargate.portal.property;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID; import java.util.UUID;
@@ -20,7 +21,7 @@ public class PortalOwner {
* *
* @param ownerIdentifier <p>A UUID, or a username for legacy support</p> * @param ownerIdentifier <p>A UUID, or a username for legacy support</p>
*/ */
public PortalOwner(String ownerIdentifier) { public PortalOwner(@NotNull String ownerIdentifier) {
parseIdentifier(ownerIdentifier); parseIdentifier(ownerIdentifier);
} }
@@ -29,7 +30,7 @@ public class PortalOwner {
* *
* @param player <p>The player which is the owner of the portal</p> * @param player <p>The player which is the owner of the portal</p>
*/ */
public PortalOwner(Player player) { public PortalOwner(@NotNull OfflinePlayer player) {
this.ownerUUID = player.getUniqueId(); this.ownerUUID = player.getUniqueId();
this.ownerName = player.getName(); this.ownerName = player.getName();
} }
@@ -39,6 +40,7 @@ public class PortalOwner {
* *
* @return <p>The UUID of this owner, or null if a UUID is not available</p> * @return <p>The UUID of this owner, or null if a UUID is not available</p>
*/ */
@Nullable
public UUID getUUID() { public UUID getUUID() {
return ownerUUID; return ownerUUID;
} }
@@ -51,7 +53,7 @@ public class PortalOwner {
* *
* @param uniqueId <p>The new unique id for the portal owner</p> * @param uniqueId <p>The new unique id for the portal owner</p>
*/ */
public void setUUID(UUID uniqueId) { public void setUUID(@NotNull UUID uniqueId) {
if (ownerUUID == null) { if (ownerUUID == null) {
ownerUUID = uniqueId; ownerUUID = uniqueId;
} else { } else {
@@ -64,7 +66,14 @@ public class PortalOwner {
* *
* @return <p>The name of this owner</p> * @return <p>The name of this owner</p>
*/ */
@NotNull
public String getName() { public String getName() {
if (this.ownerUUID != null && this.ownerName == null) {
this.ownerName = fetchName();
if (this.ownerName == null) {
this.ownerName = "UNKNOWN!";
}
}
return ownerName; return ownerName;
} }
@@ -76,6 +85,7 @@ public class PortalOwner {
* *
* @return <p>The owner's identifier</p> * @return <p>The owner's identifier</p>
*/ */
@NotNull
public String getIdentifier() { public String getIdentifier() {
if (ownerUUID != null) { if (ownerUUID != null) {
return ownerUUID.toString(); return ownerUUID.toString();
@@ -93,16 +103,14 @@ public class PortalOwner {
* *
* @param ownerIdentifier <p>The identifier for a portal's owner</p> * @param ownerIdentifier <p>The identifier for a portal's owner</p>
*/ */
private void parseIdentifier(String ownerIdentifier) { private void parseIdentifier(@NotNull String ownerIdentifier) {
UUID ownerUUID = null; UUID ownerUUID = null;
String ownerName; String ownerName = null;
if (ownerIdentifier.length() > 16) { if (ownerIdentifier.length() > 16) {
//If more than 16 characters, the string cannot be a username, so it's probably a UUID //If more than 16 characters, the string cannot be a username, so it's probably a UUID
try { try {
ownerUUID = UUID.fromString(ownerIdentifier); ownerUUID = UUID.fromString(ownerIdentifier);
OfflinePlayer offlineOwner = Bukkit.getServer().getOfflinePlayer(ownerUUID); } catch (IllegalArgumentException exception) {
ownerName = offlineOwner.getName();
} catch (IllegalArgumentException ex) {
//Invalid as UUID and username, so just keep it as owner name and hope the server owner fixes it //Invalid as UUID and username, so just keep it as owner name and hope the server owner fixes it
ownerName = ownerIdentifier; ownerName = ownerIdentifier;
Stargate.debug("loadAllPortals", "Invalid stargate owner string: " + ownerIdentifier); Stargate.debug("loadAllPortals", "Invalid stargate owner string: " + ownerIdentifier);
@@ -115,4 +123,14 @@ public class PortalOwner {
this.ownerUUID = ownerUUID; this.ownerUUID = ownerUUID;
} }
/**
* Gets the name of a player
*
* @return <p>The player to get the name of</p>
*/
@Nullable
private String fetchName() {
return Bukkit.getServer().getOfflinePlayer(ownerUUID).getName();
}
} }

View File

@@ -0,0 +1,13 @@
package net.knarcraft.stargate.portal.property;
import org.jetbrains.annotations.NotNull;
/**
* A record of a portal's string values
*
* @param name <p>The name of the portal</p>
* @param network <p>The name of the network the portal belongs to</p>
* @param destination <p>The name of the portal's destination</p>
*/
public record PortalStrings(@NotNull String name, @NotNull String network, @NotNull String destination) {
}

View File

@@ -5,6 +5,8 @@ import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* The portal structure is responsible for the physical properties of a portal * The portal structure is responsible for the physical properties of a portal
@@ -19,7 +21,6 @@ public class PortalStructure {
private BlockLocation button; private BlockLocation button;
private BlockLocation[] frame; private BlockLocation[] frame;
private BlockLocation[] entrances; private BlockLocation[] entrances;
private boolean verified;
/** /**
* Instantiates a new portal structure * Instantiates a new portal structure
@@ -28,10 +29,9 @@ public class PortalStructure {
* @param gate <p>The gate type used by this portal structure</p> * @param gate <p>The gate type used by this portal structure</p>
* @param button <p>The real location of the portal's button</p> * @param button <p>The real location of the portal's button</p>
*/ */
public PortalStructure(Portal portal, Gate gate, BlockLocation button) { public PortalStructure(@NotNull Portal portal, @NotNull Gate gate, @Nullable BlockLocation button) {
this.portal = portal; this.portal = portal;
this.gate = gate; this.gate = gate;
this.verified = false;
this.button = button; this.button = button;
} }
@@ -40,6 +40,7 @@ public class PortalStructure {
* *
* @return <p>The gate used by this portal structure</p> * @return <p>The gate used by this portal structure</p>
*/ */
@NotNull
public Gate getGate() { public Gate getGate() {
return gate; return gate;
} }
@@ -49,6 +50,7 @@ public class PortalStructure {
* *
* @return <p>The location of this portal's button</p> * @return <p>The location of this portal's button</p>
*/ */
@Nullable
public BlockLocation getButton() { public BlockLocation getButton() {
return button; return button;
} }
@@ -58,39 +60,10 @@ public class PortalStructure {
* *
* @param button <p>The location of this portal's button</p> * @param button <p>The location of this portal's button</p>
*/ */
public void setButton(BlockLocation button) { public void setButton(@NotNull BlockLocation button) {
this.button = button; this.button = button;
} }
/**
* Verifies that all control blocks in this portal follows its gate template
*
* @return <p>True if all control blocks were verified</p>
*/
public boolean isVerified() {
boolean verified = true;
if (!Stargate.getGateConfig().verifyPortals()) {
return true;
}
for (RelativeBlockVector control : gate.getLayout().getControls()) {
verified = verified && portal.getBlockAt(control).getBlock().getType().equals(gate.getControlBlock());
}
this.verified = verified;
return verified;
}
/**
* Gets the result of the last portal verification
*
* @return <p>True if this portal was verified</p>
*/
public boolean wasVerified() {
if (!Stargate.getGateConfig().verifyPortals()) {
return true;
}
return verified;
}
/** /**
* Checks if all blocks in a gate matches the gate template * Checks if all blocks in a gate matches the gate template
* *
@@ -113,7 +86,8 @@ public class PortalStructure {
* @param vectors <p>The relative block vectors to convert</p> * @param vectors <p>The relative block vectors to convert</p>
* @return <p>A list of block locations</p> * @return <p>A list of block locations</p>
*/ */
private BlockLocation[] relativeBlockVectorsToBlockLocations(RelativeBlockVector[] vectors) { @NotNull
private BlockLocation[] relativeBlockVectorsToBlockLocations(@NotNull RelativeBlockVector[] vectors) {
BlockLocation[] locations = new BlockLocation[vectors.length]; BlockLocation[] locations = new BlockLocation[vectors.length];
for (int i = 0; i < vectors.length; i++) { for (int i = 0; i < vectors.length; i++) {
locations[i] = portal.getBlockAt(vectors[i]); locations[i] = portal.getBlockAt(vectors[i]);
@@ -126,6 +100,7 @@ public class PortalStructure {
* *
* @return <p>The locations of this portal's entrances</p> * @return <p>The locations of this portal's entrances</p>
*/ */
@NotNull
public BlockLocation[] getEntrances() { public BlockLocation[] getEntrances() {
if (entrances == null) { if (entrances == null) {
//Get the locations of the entrances once, and only if necessary as it's an expensive operation //Get the locations of the entrances once, and only if necessary as it's an expensive operation
@@ -139,6 +114,7 @@ public class PortalStructure {
* *
* @return <p>The locations of this portal's frame</p> * @return <p>The locations of this portal's frame</p>
*/ */
@NotNull
public BlockLocation[] getFrame() { public BlockLocation[] getFrame() {
if (frame == null) { if (frame == null) {
//Get the locations of the frame blocks once, and only if necessary as it's an expensive operation //Get the locations of the frame blocks once, and only if necessary as it's an expensive operation

View File

@@ -1,14 +1,21 @@
package net.knarcraft.stargate.portal.property.gate; package net.knarcraft.stargate.portal.property.gate;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.material.BukkitMaterialSpecifier;
import net.knarcraft.stargate.config.material.MaterialSpecifier;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.utility.MaterialHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -20,11 +27,13 @@ public class Gate {
private final String filename; private final String filename;
private final GateLayout layout; private final GateLayout layout;
private final Map<Character, Material> characterMaterialMap; private final Map<Character, List<MaterialSpecifier>> characterMaterialMap;
//Gate materials //Gate materials
private final Material portalOpenBlock; private final List<MaterialSpecifier> portalOpenMaterials;
private final Material portalClosedBlock; private final List<MaterialSpecifier> portalClosedMaterials;
private final Material portalButton; private final List<MaterialSpecifier> portalButtonMaterials;
//Economy information //Economy information
private final int useCost; private final int useCost;
private final int createCost; private final int createCost;
@@ -34,30 +43,29 @@ public class Gate {
/** /**
* Instantiates a new gate * Instantiates a new gate
* *
* @param filename <p>The name of the gate file, including extension</p> * @param filename <p>The name of the gate file, including extension</p>
* @param layout <p>The gate layout defined in the gate file</p> * @param layout <p>The gate layout defined in the gate file</p>
* @param characterMaterialMap <p>The material types the different layout characters represent</p> * @param characterMaterialsMap <p>The material types the different layout characters represent</p>
* @param portalOpenBlock <p>The material to set the opening to when the portal is open</p> * @param portalOpenMaterials <p>The material to set the opening to when the portal is open</p>
* @param portalClosedBlock <p>The material to set the opening to when the portal is closed</p> * @param portalClosedMaterials <p>The material to set the opening to when the portal is closed</p>
* @param portalButton <p>The material to use for the portal button</p> * @param portalButtonMaterials <p>The material to use for the portal button</p>
* @param useCost <p>The cost of using a portal with this gate layout (-1 to disable)</p> * @param gateCosts <p>The costs and other economy information for the gate</p>
* @param createCost <p>The cost of creating a portal with this gate layout (-1 to disable)</p>
* @param destroyCost <p>The cost of destroying a portal with this gate layout (-1 to disable)</p>
* @param toOwner <p>Whether any payment should go to the owner of the gate, as opposed to just disappearing</p>
*/ */
public Gate(String filename, GateLayout layout, Map<Character, Material> characterMaterialMap, Material portalOpenBlock, public Gate(@NotNull String filename, @NotNull GateLayout layout,
Material portalClosedBlock, Material portalButton, int useCost, int createCost, int destroyCost, @NotNull Map<Character, List<MaterialSpecifier>> characterMaterialsMap,
boolean toOwner) { @NotNull List<MaterialSpecifier> portalOpenMaterials,
@NotNull List<MaterialSpecifier> portalClosedMaterials,
@NotNull List<MaterialSpecifier> portalButtonMaterials, @NotNull GateCosts gateCosts) {
this.filename = filename; this.filename = filename;
this.layout = layout; this.layout = layout;
this.characterMaterialMap = characterMaterialMap; this.characterMaterialMap = characterMaterialsMap;
this.portalOpenBlock = portalOpenBlock; this.portalOpenMaterials = portalOpenMaterials;
this.portalClosedBlock = portalClosedBlock; this.portalClosedMaterials = portalClosedMaterials;
this.portalButton = portalButton; this.portalButtonMaterials = portalButtonMaterials;
this.useCost = useCost; this.useCost = gateCosts.useCost();
this.createCost = createCost; this.createCost = gateCosts.createCost();
this.destroyCost = destroyCost; this.destroyCost = gateCosts.destroyCost();
this.toOwner = toOwner; this.toOwner = gateCosts.toOwner();
} }
/** /**
@@ -65,6 +73,7 @@ public class Gate {
* *
* @return <p>This gate's layout</p> * @return <p>This gate's layout</p>
*/ */
@NotNull
public GateLayout getLayout() { public GateLayout getLayout() {
return layout; return layout;
} }
@@ -74,7 +83,8 @@ public class Gate {
* *
* @return <p>The character to material map</p> * @return <p>The character to material map</p>
*/ */
public Map<Character, Material> getCharacterMaterialMap() { @NotNull
public Map<Character, List<MaterialSpecifier>> getCharacterMaterialMap() {
return new HashMap<>(characterMaterialMap); return new HashMap<>(characterMaterialMap);
} }
@@ -83,7 +93,8 @@ public class Gate {
* *
* @return <p>The material type used for control blocks</p> * @return <p>The material type used for control blocks</p>
*/ */
public Material getControlBlock() { @NotNull
public List<MaterialSpecifier> getControlBlockMaterials() {
return characterMaterialMap.get(GateHandler.getControlBlockCharacter()); return characterMaterialMap.get(GateHandler.getControlBlockCharacter());
} }
@@ -92,6 +103,7 @@ public class Gate {
* *
* @return <p>The filename of this gate's file</p> * @return <p>The filename of this gate's file</p>
*/ */
@NotNull
public String getFilename() { public String getFilename() {
return filename; return filename;
} }
@@ -101,8 +113,9 @@ public class Gate {
* *
* @return <p>The block type to use for the opening when open</p> * @return <p>The block type to use for the opening when open</p>
*/ */
public Material getPortalOpenBlock() { @NotNull
return portalOpenBlock; public List<MaterialSpecifier> getPortalOpenMaterials() {
return portalOpenMaterials;
} }
/** /**
@@ -110,8 +123,9 @@ public class Gate {
* *
* @return <p>The block type to use for the opening when closed</p> * @return <p>The block type to use for the opening when closed</p>
*/ */
public Material getPortalClosedBlock() { @NotNull
return portalClosedBlock; public List<MaterialSpecifier> getPortalClosedMaterials() {
return portalClosedMaterials;
} }
/** /**
@@ -119,8 +133,9 @@ public class Gate {
* *
* @return <p>The material to use for a portal's button if using this gate type</p> * @return <p>The material to use for a portal's button if using this gate type</p>
*/ */
public Material getPortalButton() { @NotNull
return portalButton; public List<MaterialSpecifier> getPortalButtonMaterials() {
return portalButtonMaterials;
} }
/** /**
@@ -137,6 +152,7 @@ public class Gate {
* *
* @return <p>The cost of creating a portal with this gate</p> * @return <p>The cost of creating a portal with this gate</p>
*/ */
@NotNull
public Integer getCreateCost() { public Integer getCreateCost() {
return createCost < 0 ? Stargate.getEconomyConfig().getDefaultCreateCost() : createCost; return createCost < 0 ? Stargate.getEconomyConfig().getDefaultCreateCost() : createCost;
} }
@@ -146,6 +162,7 @@ public class Gate {
* *
* @return <p>The cost of destroying a portal with this gate</p> * @return <p>The cost of destroying a portal with this gate</p>
*/ */
@NotNull
public Integer getDestroyCost() { public Integer getDestroyCost() {
return destroyCost < 0 ? Stargate.getEconomyConfig().getDefaultDestroyCost() : destroyCost; return destroyCost < 0 ? Stargate.getEconomyConfig().getDefaultDestroyCost() : destroyCost;
} }
@@ -155,6 +172,7 @@ public class Gate {
* *
* @return <p>Whether portal payments go to the owner</p> * @return <p>Whether portal payments go to the owner</p>
*/ */
@NotNull
public Boolean getToOwner() { public Boolean getToOwner() {
return toOwner; return toOwner;
} }
@@ -166,7 +184,7 @@ public class Gate {
* @param yaw <p>The yaw when looking directly outwards</p> * @param yaw <p>The yaw when looking directly outwards</p>
* @return <p>True if this gate matches the portal</p> * @return <p>True if this gate matches the portal</p>
*/ */
public boolean matches(BlockLocation topLeft, double yaw) { public boolean matches(@NotNull BlockLocation topLeft, double yaw) {
return matches(topLeft, yaw, false); return matches(topLeft, yaw, false);
} }
@@ -182,7 +200,7 @@ public class Gate {
* @param onCreate <p>Whether this is used in the context of creating a new gate</p> * @param onCreate <p>Whether this is used in the context of creating a new gate</p>
* @return <p>True if this gate matches the portal</p> * @return <p>True if this gate matches the portal</p>
*/ */
public boolean matches(BlockLocation topLeft, double yaw, boolean onCreate) { public boolean matches(@NotNull BlockLocation topLeft, double yaw, boolean onCreate) {
return verifyGateEntrancesMatch(topLeft, yaw, onCreate) && verifyGateBorderMatches(topLeft, yaw); return verifyGateEntrancesMatch(topLeft, yaw, onCreate) && verifyGateBorderMatches(topLeft, yaw);
} }
@@ -193,28 +211,29 @@ public class Gate {
* @param yaw <p>The yaw when looking directly outwards from the portal</p> * @param yaw <p>The yaw when looking directly outwards from the portal</p>
* @return <p>True if all border blocks of the gate match the layout</p> * @return <p>True if all border blocks of the gate match the layout</p>
*/ */
private boolean verifyGateBorderMatches(BlockLocation topLeft, double yaw) { private boolean verifyGateBorderMatches(@NotNull BlockLocation topLeft, double yaw) {
Map<Character, Material> characterMaterialMap = new HashMap<>(this.characterMaterialMap);
for (RelativeBlockVector borderVector : layout.getBorder()) { for (RelativeBlockVector borderVector : layout.getBorder()) {
int rowIndex = borderVector.getRight(); int rowIndex = borderVector.right();
int lineIndex = borderVector.getDown(); int lineIndex = borderVector.down();
Character key = layout.getLayout()[lineIndex][rowIndex]; Character key = layout.getLayout()[lineIndex][rowIndex];
Material materialInLayout = characterMaterialMap.get(key); List<MaterialSpecifier> materialInLayout = characterMaterialMap.get(key);
Material materialAtLocation = topLeft.getRelativeLocation(borderVector, yaw).getType(); Material materialAtLocation = topLeft.getRelativeLocation(borderVector, yaw).getType();
if (materialInLayout == null) { if (materialInLayout != null) {
if (!MaterialHelper.specifiersToMaterials(materialInLayout).contains(materialAtLocation)) {
Stargate.debug("Gate::Matches", String.format("Block Type Mismatch: %s != %s",
materialAtLocation, MaterialHelper.specifiersToMaterials(materialInLayout)));
return false;
}
} else {
/* This generally should not happen with proper checking, but just in case a material character is not /* This generally should not happen with proper checking, but just in case a material character is not
* recognized, but still allowed in previous checks, verify the gate as long as all such instances of * recognized, but still allowed in previous checks, verify the gate as long as all such instances of
* the character correspond to the same material in the physical gate. All subsequent gates will also * the character correspond to the same material in the physical gate. All subsequent gates will also
* need to match the first verified gate. */ * need to match the first verified gate. */
characterMaterialMap.put(key, materialAtLocation); this.characterMaterialMap.put(key, List.of(new BukkitMaterialSpecifier(materialAtLocation)));
Stargate.debug("Gate::Matches", String.format("Missing layout material in %s. Using %s from the" + Stargate.debug("Gate::Matches", String.format("Missing layout material in %s. Using %s from the" +
" physical portal.", getFilename(), materialAtLocation)); " physical portal.", getFilename(), materialAtLocation));
} else if (materialAtLocation != materialInLayout) {
Stargate.debug("Gate::Matches", String.format("Block Type Mismatch: %s != %s",
materialAtLocation, materialInLayout));
return false;
} }
} }
return true; return true;
@@ -228,7 +247,7 @@ public class Gate {
* @param onCreate <p>Whether this is used in the context of creating a new gate</p> * @param onCreate <p>Whether this is used in the context of creating a new gate</p>
* @return <p>Whether this is used in the context of creating a new gate</p> * @return <p>Whether this is used in the context of creating a new gate</p>
*/ */
private boolean verifyGateEntrancesMatch(BlockLocation topLeft, double yaw, boolean onCreate) { private boolean verifyGateEntrancesMatch(@NotNull BlockLocation topLeft, double yaw, boolean onCreate) {
Stargate.debug("verifyGateEntrancesMatch", String.valueOf(topLeft)); Stargate.debug("verifyGateEntrancesMatch", String.valueOf(topLeft));
for (RelativeBlockVector entranceVector : layout.getEntrances()) { for (RelativeBlockVector entranceVector : layout.getEntrances()) {
Stargate.debug("verifyGateEntrancesMatch", String.valueOf(entranceVector)); Stargate.debug("verifyGateEntrancesMatch", String.valueOf(entranceVector));
@@ -239,7 +258,8 @@ public class Gate {
continue; continue;
} }
if (type != portalClosedBlock && type != portalOpenBlock) { if (!MaterialHelper.specifiersToMaterials(portalClosedMaterials).contains(type) &&
!MaterialHelper.specifiersToMaterials(portalOpenMaterials).contains(type)) {
Stargate.debug("Gate::Matches", "Entrance/Exit Material Mismatch: " + type); Stargate.debug("Gate::Matches", "Entrance/Exit Material Mismatch: " + type);
return false; return false;
} }
@@ -254,20 +274,20 @@ public class Gate {
* *
* @param gateFolder <p>The folder to save the gate file in</p> * @param gateFolder <p>The folder to save the gate file in</p>
*/ */
public void save(String gateFolder) { public void save(@NotNull String gateFolder) {
try { try {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(gateFolder + filename)); BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File(gateFolder, filename)));
//Save main material names //Save main material names
writeConfig(bufferedWriter, "portal-open", portalOpenBlock.name()); writeConfig(bufferedWriter, "portal-open", MaterialHelper.specifiersToString(portalOpenMaterials));
writeConfig(bufferedWriter, "portal-closed", portalClosedBlock.name()); writeConfig(bufferedWriter, "portal-closed", MaterialHelper.specifiersToString(portalClosedMaterials));
writeConfig(bufferedWriter, "button", portalButton.name()); writeConfig(bufferedWriter, "button", MaterialHelper.specifiersToString(portalButtonMaterials));
//Save the values necessary for economy //Save the values necessary for economy
saveEconomyValues(bufferedWriter); saveEconomyValues(bufferedWriter);
//Store material types to use for frame blocks //Store material types to use for frame blocks
saveFrameBlockTypes(bufferedWriter); saveFrameBlockType(bufferedWriter);
bufferedWriter.newLine(); bufferedWriter.newLine();
@@ -275,8 +295,8 @@ public class Gate {
layout.saveLayout(bufferedWriter); layout.saveLayout(bufferedWriter);
bufferedWriter.close(); bufferedWriter.close();
} catch (IOException ex) { } catch (IOException exception) {
Stargate.logSevere(String.format("Could not save Gate %s - %s", filename, ex.getMessage())); Stargate.logSevere(String.format("Could not save Gate %s - %s", filename, exception.getMessage()));
} }
} }
@@ -286,7 +306,7 @@ public class Gate {
* @param bufferedWriter <p>The buffered writer to write to</p> * @param bufferedWriter <p>The buffered writer to write to</p>
* @throws IOException <p>If unable to write to the buffered writer</p> * @throws IOException <p>If unable to write to the buffered writer</p>
*/ */
private void saveEconomyValues(BufferedWriter bufferedWriter) throws IOException { private void saveEconomyValues(@NotNull BufferedWriter bufferedWriter) throws IOException {
//Write use cost if not disabled //Write use cost if not disabled
if (useCost != -1) { if (useCost != -1) {
writeConfig(bufferedWriter, "usecost", useCost); writeConfig(bufferedWriter, "usecost", useCost);
@@ -308,26 +328,37 @@ public class Gate {
* @param bufferedWriter <p>The buffered writer to write to</p> * @param bufferedWriter <p>The buffered writer to write to</p>
* @throws IOException <p>If unable to write to the buffered writer</p> * @throws IOException <p>If unable to write to the buffered writer</p>
*/ */
private void saveFrameBlockTypes(BufferedWriter bufferedWriter) throws IOException { private void saveFrameBlockType(@NotNull BufferedWriter bufferedWriter) throws IOException {
for (Map.Entry<Character, Material> entry : characterMaterialMap.entrySet()) { for (Map.Entry<Character, List<MaterialSpecifier>> entry : this.characterMaterialMap.entrySet()) {
Character type = entry.getKey(); Character key = entry.getKey();
Material value = entry.getValue();
//Skip characters not part of the frame //Skip characters not part of the frame
if (type.equals(GateHandler.getAnythingCharacter()) || if (key.equals(GateHandler.getAnythingCharacter()) ||
type.equals(GateHandler.getEntranceCharacter()) || key.equals(GateHandler.getEntranceCharacter()) ||
type.equals(GateHandler.getExitCharacter())) { key.equals(GateHandler.getExitCharacter())) {
continue; continue;
} }
saveFrameBlockType(key, MaterialHelper.specifiersToString(entry.getValue()), bufferedWriter);
bufferedWriter.append(type);
bufferedWriter.append('=');
if (value != null) {
bufferedWriter.append(value.toString());
}
bufferedWriter.newLine();
} }
} }
/**
* Saves a type of block used for the gate frame/border using a buffered writer
*
* @param key <p>The character key to store</p>
* @param value <p>The string value to store</p>
* @param bufferedWriter <p>The buffered writer to write to</p>
* @throws IOException <p>If unable to write to the buffered writer</p>
*/
private void saveFrameBlockType(@NotNull Character key, @Nullable String value,
@NotNull BufferedWriter bufferedWriter) throws IOException {
bufferedWriter.append(key.toString());
bufferedWriter.append('=');
if (value != null) {
bufferedWriter.append(value);
}
bufferedWriter.newLine();
}
/** /**
* Writes a formatted string to a buffered writer * Writes a formatted string to a buffered writer
* *
@@ -336,7 +367,8 @@ public class Gate {
* @param value <p>The config value to save</p> * @param value <p>The config value to save</p>
* @throws IOException <p>If unable to write to the buffered writer</p> * @throws IOException <p>If unable to write to the buffered writer</p>
*/ */
private void writeConfig(BufferedWriter bufferedWriter, String key, Object value) throws IOException { private void writeConfig(@NotNull BufferedWriter bufferedWriter, @NotNull String key,
@NotNull Object value) throws IOException {
//Figure out the correct formatting to use //Figure out the correct formatting to use
String format = "%s="; String format = "%s=";
if (value instanceof Boolean) { if (value instanceof Boolean) {

View File

@@ -0,0 +1,12 @@
package net.knarcraft.stargate.portal.property.gate;
/**
* The costs assigned to a gate
*
* @param useCost <p>The cost for using (entering) the gate</p>
* @param createCost <p>The cost for creating a portal with the gate type</p>
* @param destroyCost <p>The cost for destroying a portal with the gate type</p>
* @param toOwner <p>Whether the use cost is paid to the gate's owner</p>
*/
public record GateCosts(int useCost, int createCost, int destroyCost, boolean toOwner) {
}

View File

@@ -1,20 +1,26 @@
package net.knarcraft.stargate.portal.property.gate; package net.knarcraft.stargate.portal.property.gate;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.utility.GateReader; import net.knarcraft.stargate.config.material.BukkitMaterialSpecifier;
import net.knarcraft.stargate.config.material.MaterialSpecifier;
import net.knarcraft.stargate.utility.MaterialHelper; import net.knarcraft.stargate.utility.MaterialHelper;
import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import static net.knarcraft.stargate.utility.GateReader.generateLayoutMatrix; import static net.knarcraft.stargate.utility.GateReader.generateLayoutMatrix;
import static net.knarcraft.stargate.utility.GateReader.readGateConfig; import static net.knarcraft.stargate.utility.GateReader.readGateConfig;
@@ -34,8 +40,9 @@ public class GateHandler {
private static final Material defaultPortalBlockClosed = Material.AIR; private static final Material defaultPortalBlockClosed = Material.AIR;
private static final Material defaultButton = Material.STONE_BUTTON; private static final Material defaultButton = Material.STONE_BUTTON;
private static final HashMap<String, Gate> gates = new HashMap<>(); private static final Map<String, Gate> gates = new HashMap<>();
private static final HashMap<Material, List<Gate>> controlBlocks = new HashMap<>(); private static final Map<Material, List<Gate>> controlBlocks = new HashMap<>();
private static final Map<String, List<Gate>> controlBlockTags = new HashMap<>();
private GateHandler() { private GateHandler() {
@@ -46,6 +53,7 @@ public class GateHandler {
* *
* @return <p>The character used for blocks that are not part of the gate</p> * @return <p>The character used for blocks that are not part of the gate</p>
*/ */
@NotNull
public static Character getAnythingCharacter() { public static Character getAnythingCharacter() {
return ANYTHING; return ANYTHING;
} }
@@ -55,6 +63,7 @@ public class GateHandler {
* *
* @return <p>The character used for defining the entrance</p> * @return <p>The character used for defining the entrance</p>
*/ */
@NotNull
public static Character getEntranceCharacter() { public static Character getEntranceCharacter() {
return ENTRANCE; return ENTRANCE;
} }
@@ -64,6 +73,7 @@ public class GateHandler {
* *
* @return <p>The character used for defining the exit</p> * @return <p>The character used for defining the exit</p>
*/ */
@NotNull
public static Character getExitCharacter() { public static Character getExitCharacter() {
return EXIT; return EXIT;
} }
@@ -74,6 +84,7 @@ public class GateHandler {
* *
* @return <p>The character used for defining control blocks</p> * @return <p>The character used for defining control blocks</p>
*/ */
@NotNull
public static Character getControlBlockCharacter() { public static Character getControlBlockCharacter() {
return CONTROL_BLOCK; return CONTROL_BLOCK;
} }
@@ -83,16 +94,16 @@ public class GateHandler {
* *
* @param gate <p>The gate to register</p> * @param gate <p>The gate to register</p>
*/ */
private static void registerGate(Gate gate) { private static void registerGate(@NotNull Gate gate) {
gates.put(gate.getFilename(), gate); gates.put(gate.getFilename(), gate);
Material blockID = gate.getControlBlock(); Set<Material> blockTypes = MaterialHelper.specifiersToMaterials(gate.getControlBlockMaterials());
for (Material material : blockTypes) {
if (!controlBlocks.containsKey(blockID)) { if (!controlBlocks.containsKey(material)) {
controlBlocks.put(blockID, new ArrayList<>()); controlBlocks.put(material, new ArrayList<>());
}
controlBlocks.get(material).add(gate);
} }
controlBlocks.get(blockID).add(gate);
} }
/** /**
@@ -101,7 +112,8 @@ public class GateHandler {
* @param file <p>The file containing the gate data</p> * @param file <p>The file containing the gate data</p>
* @return <p>The loaded gate, or null if unable to load the gate</p> * @return <p>The loaded gate, or null if unable to load the gate</p>
*/ */
private static Gate loadGate(File file) { @Nullable
private static Gate loadGate(@NotNull File file) {
try (Scanner scanner = new Scanner(file)) { try (Scanner scanner = new Scanner(file)) {
return loadGate(file.getName(), file.getParent(), scanner); return loadGate(file.getName(), file.getParent(), scanner);
} catch (Exception exception) { } catch (Exception exception) {
@@ -118,19 +130,20 @@ public class GateHandler {
* @param scanner <p>The scanner to use for reading the gate data</p> * @param scanner <p>The scanner to use for reading the gate data</p>
* @return <p>The loaded gate or null if unable to load the gate</p> * @return <p>The loaded gate or null if unable to load the gate</p>
*/ */
private static Gate loadGate(String fileName, String parentFolder, Scanner scanner) { @Nullable
private static Gate loadGate(@NotNull String fileName, @NotNull String parentFolder,
@NotNull Scanner scanner) {
List<List<Character>> design = new ArrayList<>(); List<List<Character>> design = new ArrayList<>();
Map<Character, Material> characterMaterialMap = new HashMap<>(); Map<Character, List<MaterialSpecifier>> characterMaterialMap = new HashMap<>();
Map<String, String> config = new HashMap<>(); Map<String, String> config = new HashMap<>();
Set<Material> frameTypes = new HashSet<>();
//Initialize character to material map //Initialize character to material map
characterMaterialMap.put(ENTRANCE, Material.AIR); characterMaterialMap.put(ENTRANCE, List.of(new BukkitMaterialSpecifier(Material.AIR)));
characterMaterialMap.put(EXIT, Material.AIR); characterMaterialMap.put(EXIT, List.of(new BukkitMaterialSpecifier(Material.AIR)));
characterMaterialMap.put(ANYTHING, Material.AIR); characterMaterialMap.put(ANYTHING, List.of(new BukkitMaterialSpecifier(Material.AIR)));
//Read the file into appropriate lists and maps //Read the file into appropriate lists and maps
int columns = readGateFile(scanner, characterMaterialMap, fileName, design, frameTypes, config); int columns = readGateFile(scanner, characterMaterialMap, fileName, design, config);
if (columns < 0) { if (columns < 0) {
return null; return null;
} }
@@ -143,7 +156,7 @@ public class GateHandler {
} }
//Update gate file in case the format has changed between versions //Update gate file in case the format has changed between versions
gate.save(parentFolder + "/"); gate.save(parentFolder);
return gate; return gate;
} }
@@ -156,23 +169,26 @@ public class GateHandler {
* @param characterMaterialMap <p>A map between layout characters and the material to use</p> * @param characterMaterialMap <p>A map between layout characters and the material to use</p>
* @return <p>A new gate, or null if the config is invalid</p> * @return <p>A new gate, or null if the config is invalid</p>
*/ */
private static Gate createGate(Map<String, String> config, String fileName, Character[][] layout, @Nullable
Map<Character, Material> characterMaterialMap) { private static Gate createGate(@NotNull Map<String, String> config, @NotNull String fileName,
@NotNull Character[][] layout,
@NotNull Map<Character, List<MaterialSpecifier>> characterMaterialMap) {
//Read relevant material types //Read relevant material types
Material portalOpenBlock = readGateConfig(config, fileName, "portal-open", defaultPortalBlockOpen); List<MaterialSpecifier> portalOpenBlock = readGateConfig(config, fileName, "portal-open", defaultPortalBlockOpen);
Material portalClosedBlock = readGateConfig(config, fileName, "portal-closed", defaultPortalBlockClosed); List<MaterialSpecifier> portalClosedBlock = readGateConfig(config, fileName, "portal-closed", defaultPortalBlockClosed);
Material portalButton = readGateConfig(config, fileName, "button", defaultButton); List<MaterialSpecifier> portalButton = readGateConfig(config, fileName, "button", defaultButton);
//Read economy values //Read economy values
int useCost = GateReader.readGateConfig(config, fileName, "usecost"); int useCost = readGateConfig(config, fileName, "usecost");
int createCost = GateReader.readGateConfig(config, fileName, "createcost"); int createCost = readGateConfig(config, fileName, "createcost");
int destroyCost = GateReader.readGateConfig(config, fileName, "destroycost"); int destroyCost = readGateConfig(config, fileName, "destroycost");
boolean toOwner = (config.containsKey("toowner") ? Boolean.parseBoolean(config.get("toowner")) : boolean toOwner = (config.containsKey("toowner") ? Boolean.parseBoolean(config.get("toowner")) :
Stargate.getEconomyConfig().sendPaymentToOwner()); Stargate.getEconomyConfig().sendPaymentToOwner());
GateCosts gateCosts = new GateCosts(useCost, createCost, destroyCost, toOwner);
//Create the new gate //Create the new gate
Gate gate = new Gate(fileName, new GateLayout(layout), characterMaterialMap, portalOpenBlock, portalClosedBlock, Gate gate = new Gate(fileName, new GateLayout(layout), characterMaterialMap, portalOpenBlock, portalClosedBlock,
portalButton, useCost, createCost, destroyCost, toOwner); portalButton, gateCosts);
if (!validateGate(gate, fileName)) { if (!validateGate(gate, fileName)) {
return null; return null;
@@ -187,7 +203,7 @@ public class GateHandler {
* @param fileName <p>The filename of the loaded gate file</p> * @param fileName <p>The filename of the loaded gate file</p>
* @return <p>True if the gate is valid. False otherwise</p> * @return <p>True if the gate is valid. False otherwise</p>
*/ */
private static boolean validateGate(Gate gate, String fileName) { private static boolean validateGate(@NotNull Gate gate, @NotNull String fileName) {
String failString = String.format("Could not load Gate %s", fileName) + " - %s"; String failString = String.format("Could not load Gate %s", fileName) + " - %s";
if (gate.getLayout().getControls().length != 2) { if (gate.getLayout().getControls().length != 2) {
@@ -195,23 +211,28 @@ public class GateHandler {
return false; return false;
} }
if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) { if (gate.getLayout().getExit() == null) {
Stargate.logSevere(String.format(failString, "Gates must have one specified exit point"));
return false;
}
if (checkMaterialPredicateFail(gate.getPortalButtonMaterials(), MaterialHelper::isButtonCompatible)) {
Stargate.logSevere(String.format(failString, "Gate button must be a type of button.")); Stargate.logSevere(String.format(failString, "Gate button must be a type of button."));
return false; return false;
} }
if (!gate.getPortalOpenBlock().isBlock()) { if (checkMaterialPredicateFail(gate.getPortalOpenMaterials(), Material::isBlock)) {
Stargate.logSevere(String.format(failString, "Gate open block must be a type of block.")); Stargate.logSevere(String.format(failString, "Gate open block must be a type of block."));
return false; return false;
} }
if (!gate.getPortalClosedBlock().isBlock()) { if (checkMaterialPredicateFail(gate.getPortalClosedMaterials(), Material::isBlock)) {
Stargate.logSevere(String.format(failString, "Gate closed block must be a type of block.")); Stargate.logSevere(String.format(failString, "Gate closed block must be a type of block."));
return false; return false;
} }
for (Material material : gate.getCharacterMaterialMap().values()) { for (List<MaterialSpecifier> materialSpecifiers : gate.getCharacterMaterialMap().values()) {
if (!material.isBlock()) { if (checkMaterialPredicateFail(materialSpecifiers, Material::isBlock)) {
Stargate.logSevere(String.format(failString, "Every gate border block must be a type of block.")); Stargate.logSevere(String.format(failString, "Every gate border block must be a type of block."));
return false; return false;
} }
@@ -220,12 +241,31 @@ public class GateHandler {
return true; return true;
} }
/**
* Checks whether a predicate is true for a list of material specifiers
*
* @param materialSpecifiers <p>The material specifiers to test</p>
* @param predicate <p>The predicate to test</p>
* @return <p>True if the predicate failed for any specified materials</p>
*/
private static boolean checkMaterialPredicateFail(@NotNull List<MaterialSpecifier> materialSpecifiers,
@NotNull Predicate<Material> predicate) {
Set<Material> closedMaterials = MaterialHelper.specifiersToMaterials(materialSpecifiers);
for (Material material : closedMaterials) {
if (!predicate.test(material)) {
return true;
}
}
return false;
}
/** /**
* Loads all gates inside the given folder * Loads all gates inside the given folder
* *
* @param gateFolder <p>The folder containing the gates</p> * @param gateFolder <p>The folder containing the gates</p>
*/ */
public static void loadGates(String gateFolder) { public static void loadGates(@NotNull String gateFolder) {
File directory = new File(gateFolder); File directory = new File(gateFolder);
File[] files; File[] files;
@@ -258,11 +298,12 @@ public class GateHandler {
* *
* @param gateFolder <p>The folder containing gate config files</p> * @param gateFolder <p>The folder containing gate config files</p>
*/ */
public static void writeDefaultGatesToFolder(String gateFolder) { public static void writeDefaultGatesToFolder(@NotNull String gateFolder) {
loadGateFromJar("nethergate.gate", gateFolder); loadGateFromJar("nethergate.gate", gateFolder);
loadGateFromJar("watergate.gate", gateFolder); loadGateFromJar("watergate.gate", gateFolder);
loadGateFromJar("endgate.gate", gateFolder); loadGateFromJar("endgate.gate", gateFolder);
loadGateFromJar("squarenetherglowstonegate.gate", gateFolder); loadGateFromJar("squarenetherglowstonegate.gate", gateFolder);
loadGateFromJar("wool.gate", gateFolder);
} }
/** /**
@@ -271,7 +312,7 @@ public class GateHandler {
* @param gateFile <p>The name of the gate file</p> * @param gateFile <p>The name of the gate file</p>
* @param gateFolder <p>The folder containing gates</p> * @param gateFolder <p>The folder containing gates</p>
*/ */
private static void loadGateFromJar(String gateFile, String gateFolder) { private static void loadGateFromJar(@NotNull String gateFile, @NotNull String gateFolder) {
//Get an input stream for the internal file //Get an input stream for the internal file
InputStream gateFileStream = Gate.class.getResourceAsStream("/gates/" + gateFile); InputStream gateFileStream = Gate.class.getResourceAsStream("/gates/" + gateFile);
if (gateFileStream != null) { if (gateFileStream != null) {
@@ -293,7 +334,8 @@ public class GateHandler {
* @param block <p>The control block to check</p> * @param block <p>The control block to check</p>
* @return <p>A list of gates using the given control block</p> * @return <p>A list of gates using the given control block</p>
*/ */
public static Gate[] getGatesByControlBlock(Block block) { @NotNull
public static List<Gate> getGatesByControlBlock(@NotNull Block block) {
return getGatesByControlBlock(block.getType()); return getGatesByControlBlock(block.getType());
} }
@@ -306,12 +348,24 @@ public class GateHandler {
* @param type <p>The type of the control block to check</p> * @param type <p>The type of the control block to check</p>
* @return <p>A list of gates using the given material for control block</p> * @return <p>A list of gates using the given material for control block</p>
*/ */
public static Gate[] getGatesByControlBlock(Material type) { @NotNull
Gate[] result = new Gate[0]; public static List<Gate> getGatesByControlBlock(@NotNull Material type) {
List<Gate> lookup = controlBlocks.get(type); List<Gate> result = new ArrayList<>();
List<Gate> fromId = controlBlocks.get(type);
List<Gate> fromTag = null;
for (String tagString : controlBlockTags.keySet()) {
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.minecraft(tagString.replaceFirst(
"minecraft:", "")), Material.class);
if (tag != null && tag.isTagged(type)) {
fromTag = controlBlockTags.get(tag.getKey().toString());
}
}
if (lookup != null) { if (fromId != null) {
result = lookup.toArray(result); result.addAll(fromId);
}
if (fromTag != null) {
result.addAll(fromTag);
} }
return result; return result;
@@ -323,7 +377,8 @@ public class GateHandler {
* @param fileName <p>The filename of the gate to get</p> * @param fileName <p>The filename of the gate to get</p>
* @return <p>The gate with the given filename</p> * @return <p>The gate with the given filename</p>
*/ */
public static Gate getGateByName(String fileName) { @Nullable
public static Gate getGateByName(@NotNull String fileName) {
return gates.get(fileName); return gates.get(fileName);
} }
@@ -342,6 +397,7 @@ public class GateHandler {
public static void clearGates() { public static void clearGates() {
gates.clear(); gates.clear();
controlBlocks.clear(); controlBlocks.clear();
controlBlockTags.clear();
} }
} }

View File

@@ -1,6 +1,8 @@
package net.knarcraft.stargate.portal.property.gate; package net.knarcraft.stargate.portal.property.gate;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
@@ -28,7 +30,7 @@ public class GateLayout {
* *
* @param layout <p>A character matrix describing the layout</p> * @param layout <p>A character matrix describing the layout</p>
*/ */
public GateLayout(Character[][] layout) { public GateLayout(@NotNull Character[][] layout) {
this.layout = layout; this.layout = layout;
readLayout(); readLayout();
} }
@@ -38,6 +40,7 @@ public class GateLayout {
* *
* @return <p>The character array describing this layout</p> * @return <p>The character array describing this layout</p>
*/ */
@NotNull
public Character[][] getLayout() { public Character[][] getLayout() {
return this.layout; return this.layout;
} }
@@ -49,6 +52,7 @@ public class GateLayout {
* *
* @return <p>The locations of entrances for this gate</p> * @return <p>The locations of entrances for this gate</p>
*/ */
@NotNull
public RelativeBlockVector[] getEntrances() { public RelativeBlockVector[] getEntrances() {
return entrances; return entrances;
} }
@@ -61,6 +65,7 @@ public class GateLayout {
* *
* @return <p>The locations of border blocks for this gate</p> * @return <p>The locations of border blocks for this gate</p>
*/ */
@NotNull
public RelativeBlockVector[] getBorder() { public RelativeBlockVector[] getBorder() {
return border; return border;
} }
@@ -70,6 +75,7 @@ public class GateLayout {
* *
* @return <p>The exit block defined in the layout</p> * @return <p>The exit block defined in the layout</p>
*/ */
@Nullable
public RelativeBlockVector getExit() { public RelativeBlockVector getExit() {
return exitBlock; return exitBlock;
} }
@@ -82,6 +88,7 @@ public class GateLayout {
* *
* @return <p>All possible exits</p> * @return <p>All possible exits</p>
*/ */
@NotNull
public List<RelativeBlockVector> getExits() { public List<RelativeBlockVector> getExits() {
return exits; return exits;
} }
@@ -94,6 +101,7 @@ public class GateLayout {
* *
* @return <p>The locations of the control blocks for this gate</p> * @return <p>The locations of the control blocks for this gate</p>
*/ */
@NotNull
public RelativeBlockVector[] getControls() { public RelativeBlockVector[] getControls() {
return controls; return controls;
} }
@@ -104,7 +112,7 @@ public class GateLayout {
* @param bufferedWriter <p>The buffered writer to write to</p> * @param bufferedWriter <p>The buffered writer to write to</p>
* @throws IOException <p>If unable to write to the buffered writer</p> * @throws IOException <p>If unable to write to the buffered writer</p>
*/ */
public void saveLayout(BufferedWriter bufferedWriter) throws IOException { public void saveLayout(@NotNull BufferedWriter bufferedWriter) throws IOException {
for (Character[] line : this.layout) { for (Character[] line : this.layout) {
for (Character character : line) { for (Character character : line) {
bufferedWriter.append(character); bufferedWriter.append(character);
@@ -137,8 +145,9 @@ public class GateLayout {
* @param entranceList <p>The list of entrances to save to</p> * @param entranceList <p>The list of entrances to save to</p>
* @param borderList <p>The list of border blocks to save to</p> * @param borderList <p>The list of border blocks to save to</p>
*/ */
private void readLayout(List<RelativeBlockVector> controlList, List<RelativeBlockVector> entranceList, private void readLayout(@NotNull List<RelativeBlockVector> controlList,
List<RelativeBlockVector> borderList) { @NotNull List<RelativeBlockVector> entranceList,
@NotNull List<RelativeBlockVector> borderList) {
//Store the lowest opening for each column //Store the lowest opening for each column
int[] exitDepths = new int[layout[0].length]; int[] exitDepths = new int[layout[0].length];
@@ -173,9 +182,10 @@ public class GateLayout {
* @param entranceList <p>The list of entrances to save to</p> * @param entranceList <p>The list of entrances to save to</p>
* @param borderList <p>The list of border blocks to save to</p> * @param borderList <p>The list of border blocks to save to</p>
*/ */
private void parseLayoutCharacter(Character key, int columnIndex, int rowIndex, int[] exitDepths, private void parseLayoutCharacter(@NotNull Character key, int columnIndex, int rowIndex, int[] exitDepths,
List<RelativeBlockVector> controlList, List<RelativeBlockVector> entranceList, @NotNull List<RelativeBlockVector> controlList,
List<RelativeBlockVector> borderList) { @NotNull List<RelativeBlockVector> entranceList,
@NotNull List<RelativeBlockVector> borderList) {
//Add control blocks to the control block list //Add control blocks to the control block list
if (key.equals(GateHandler.getControlBlockCharacter())) { if (key.equals(GateHandler.getControlBlockCharacter())) {
controlList.add(new RelativeBlockVector(columnIndex, rowIndex, 0)); controlList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
@@ -202,7 +212,7 @@ public class GateLayout {
* @param character <p>The character to check</p> * @param character <p>The character to check</p>
* @return <p>True if the character represents an opening</p> * @return <p>True if the character represents an opening</p>
*/ */
private boolean isOpening(Character character) { private boolean isOpening(@NotNull Character character) {
return character.equals(GateHandler.getEntranceCharacter()) || character.equals(GateHandler.getExitCharacter()); return character.equals(GateHandler.getEntranceCharacter()) || character.equals(GateHandler.getExitCharacter());
} }

View File

@@ -3,6 +3,7 @@ package net.knarcraft.stargate.portal.teleporter;
import net.knarcraft.stargate.event.StargateEntityPortalEvent; import net.knarcraft.stargate.event.StargateEntityPortalEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
/** /**
* The portal teleporter takes care of the actual portal teleportation for any entities * The portal teleporter takes care of the actual portal teleportation for any entities
@@ -16,7 +17,7 @@ public class EntityTeleporter extends Teleporter {
* *
* @param targetPortal <p>The portal which is the target of the teleportation</p> * @param targetPortal <p>The portal which is the target of the teleportation</p>
*/ */
public EntityTeleporter(Portal targetPortal, Entity teleportingEntity) { public EntityTeleporter(@NotNull Portal targetPortal, @NotNull Entity teleportingEntity) {
super(targetPortal, teleportingEntity); super(targetPortal, teleportingEntity);
this.teleportingEntity = teleportingEntity; this.teleportingEntity = teleportingEntity;
} }
@@ -27,7 +28,7 @@ public class EntityTeleporter extends Teleporter {
* @param origin <p>The portal the entity is teleporting from</p> * @param origin <p>The portal the entity is teleporting from</p>
* @return <p>True if the entity was teleported. False otherwise</p> * @return <p>True if the entity was teleported. False otherwise</p>
*/ */
public boolean teleportEntity(Portal origin) { public boolean teleportEntity(@NotNull Portal origin) {
return teleport(origin, new StargateEntityPortalEvent(teleportingEntity, origin, portal, exit)); return teleport(origin, new StargateEntityPortalEvent(teleportingEntity, origin, portal, exit));
} }

View File

@@ -10,6 +10,8 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
@@ -26,7 +28,7 @@ public class PlayerTeleporter extends Teleporter {
* @param targetPortal <p>The portal which is the target of the teleportation</p> * @param targetPortal <p>The portal which is the target of the teleportation</p>
* @param player <p>The teleporting player</p> * @param player <p>The teleporting player</p>
*/ */
public PlayerTeleporter(Portal targetPortal, Player player) { public PlayerTeleporter(@NotNull Portal targetPortal, @NotNull Player player) {
super(targetPortal, player); super(targetPortal, player);
this.player = player; this.player = player;
} }
@@ -37,7 +39,7 @@ public class PlayerTeleporter extends Teleporter {
* @param origin <p>The portal the player teleports from</p> * @param origin <p>The portal the player teleports from</p>
* @param event <p>The player move event triggering the event</p> * @param event <p>The player move event triggering the event</p>
*/ */
public void teleportPlayer(Portal origin, PlayerMoveEvent event) { public void teleportPlayer(@NotNull Portal origin, @Nullable PlayerMoveEvent event) {
double velocity = player.getVelocity().length(); double velocity = player.getVelocity().length();
List<Entity> passengers = player.getPassengers(); List<Entity> passengers = player.getPassengers();

View File

@@ -20,6 +20,8 @@ import org.bukkit.entity.Entity;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -55,7 +57,7 @@ public abstract class Teleporter {
* @param portal <p>The portal which is the target of the teleportation</p> * @param portal <p>The portal which is the target of the teleportation</p>
* @param teleportedEntity <p>The entity teleported by this teleporter</p> * @param teleportedEntity <p>The entity teleported by this teleporter</p>
*/ */
public Teleporter(Portal portal, Entity teleportedEntity) { protected Teleporter(@NotNull Portal portal, @NotNull Entity teleportedEntity) {
this.portal = portal; this.portal = portal;
this.scheduler = Stargate.getInstance().getServer().getScheduler(); this.scheduler = Stargate.getInstance().getServer().getScheduler();
this.teleportedEntity = teleportedEntity; this.teleportedEntity = teleportedEntity;
@@ -69,11 +71,11 @@ public abstract class Teleporter {
* @param stargateTeleportEvent <p>The event to call to make sure the teleportation is valid</p> * @param stargateTeleportEvent <p>The event to call to make sure the teleportation is valid</p>
* @return <p>True if the teleportation was successfully performed</p> * @return <p>True if the teleportation was successfully performed</p>
*/ */
public boolean teleport(Portal origin, StargateTeleportEvent stargateTeleportEvent) { public boolean teleport(@NotNull Portal origin, @Nullable StargateTeleportEvent stargateTeleportEvent) {
List<Entity> passengers = teleportedEntity.getPassengers(); List<Entity> passengers = teleportedEntity.getPassengers();
//Call the StargateEntityPortalEvent to allow plugins to change destination //Call the StargateEntityPortalEvent to allow plugins to change destination
if (!origin.equals(portal)) { if (!origin.equals(portal) && stargateTeleportEvent != null) {
exit = triggerPortalEvent(origin, stargateTeleportEvent); exit = triggerPortalEvent(origin, stargateTeleportEvent);
if (exit == null) { if (exit == null) {
return false; return false;
@@ -96,6 +98,7 @@ public abstract class Teleporter {
* *
* @return <p>The exit location of this teleporter</p> * @return <p>The exit location of this teleporter</p>
*/ */
@NotNull
public Location getExit() { public Location getExit() {
return exit.clone(); return exit.clone();
} }
@@ -107,7 +110,9 @@ public abstract class Teleporter {
* @param stargateTeleportEvent <p>The exit location to teleport the entity to</p> * @param stargateTeleportEvent <p>The exit location to teleport the entity to</p>
* @return <p>The location the entity should be teleported to, or null if the event was cancelled</p> * @return <p>The location the entity should be teleported to, or null if the event was cancelled</p>
*/ */
protected Location triggerPortalEvent(Portal origin, StargateTeleportEvent stargateTeleportEvent) { @Nullable
protected Location triggerPortalEvent(@NotNull Portal origin,
@NotNull StargateTeleportEvent stargateTeleportEvent) {
Stargate.getInstance().getServer().getPluginManager().callEvent((Event) stargateTeleportEvent); Stargate.getInstance().getServer().getPluginManager().callEvent((Event) stargateTeleportEvent);
//Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake //Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake
if (stargateTeleportEvent.isCancelled()) { if (stargateTeleportEvent.isCancelled()) {
@@ -122,7 +127,7 @@ public abstract class Teleporter {
* *
* @param exit <p>The location the entity will exit from</p> * @param exit <p>The location the entity will exit from</p>
*/ */
protected void adjustExitLocationRotation(Location exit) { protected void adjustExitLocationRotation(@NotNull Location exit) {
int adjust = 0; int adjust = 0;
if (portal.getOptions().isBackwards()) { if (portal.getOptions().isBackwards()) {
adjust = 180; adjust = 180;
@@ -151,7 +156,9 @@ public abstract class Teleporter {
* @param entity <p>The travelling entity</p> * @param entity <p>The travelling entity</p>
* @return <p>A location which won't suffocate the entity inside the portal</p> * @return <p>A location which won't suffocate the entity inside the portal</p>
*/ */
private Location preventExitSuffocation(RelativeBlockVector relativeExit, Location exitLocation, Entity entity) { @NotNull
private Location preventExitSuffocation(@NotNull RelativeBlockVector relativeExit,
@NotNull Location exitLocation, @NotNull Entity entity) {
//Go left to find start of opening //Go left to find start of opening
RelativeBlockVector openingLeft = getPortalExitEdge(relativeExit, -1); RelativeBlockVector openingLeft = getPortalExitEdge(relativeExit, -1);
@@ -159,8 +166,8 @@ public abstract class Teleporter {
RelativeBlockVector openingRight = getPortalExitEdge(relativeExit, 1); RelativeBlockVector openingRight = getPortalExitEdge(relativeExit, 1);
//Get the width to check if the entity fits //Get the width to check if the entity fits
int openingWidth = openingRight.getRight() - openingLeft.getRight() + 1; int openingWidth = openingRight.right() - openingLeft.right() + 1;
int existingOffset = relativeExit.getRight() - openingLeft.getRight(); int existingOffset = relativeExit.right() - openingLeft.right();
double newOffset = (openingWidth - existingOffset) / 2D; double newOffset = (openingWidth - existingOffset) / 2D;
//Remove the half offset for better centering //Remove the half offset for better centering
@@ -180,7 +187,8 @@ public abstract class Teleporter {
* @param entity <p>The entity to adjust the exit location for</p> * @param entity <p>The entity to adjust the exit location for</p>
* @return <p>The adjusted exit location</p> * @return <p>The adjusted exit location</p>
*/ */
private Location moveExitLocationOutwards(Location exitLocation, Entity entity) { @NotNull
private Location moveExitLocationOutwards(@NotNull Location exitLocation, @NotNull Entity entity) {
double entitySize = EntityHelper.getEntityMaxSize(entity); double entitySize = EntityHelper.getEntityMaxSize(entity);
int entityBoxSize = EntityHelper.getEntityMaxSizeInt(entity); int entityBoxSize = EntityHelper.getEntityMaxSizeInt(entity);
if (entitySize > 1) { if (entitySize > 1) {
@@ -207,12 +215,13 @@ public abstract class Teleporter {
* @param direction <p>The direction to move (+1 for right, -1 for left)</p> * @param direction <p>The direction to move (+1 for right, -1 for left)</p>
* @return <p>The right or left edge of the opening</p> * @return <p>The right or left edge of the opening</p>
*/ */
private RelativeBlockVector getPortalExitEdge(RelativeBlockVector relativeExit, int direction) { @NotNull
private RelativeBlockVector getPortalExitEdge(@NotNull RelativeBlockVector relativeExit, int direction) {
RelativeBlockVector openingEdge = relativeExit; RelativeBlockVector openingEdge = relativeExit;
do { do {
RelativeBlockVector possibleOpening = new RelativeBlockVector(openingEdge.getRight() + direction, RelativeBlockVector possibleOpening = new RelativeBlockVector(openingEdge.right() + direction,
openingEdge.getDown(), openingEdge.getOut()); openingEdge.down(), openingEdge.out());
if (portal.getGate().getLayout().getExits().contains(possibleOpening)) { if (portal.getGate().getLayout().getExits().contains(possibleOpening)) {
openingEdge = possibleOpening; openingEdge = possibleOpening;
} else { } else {
@@ -234,7 +243,8 @@ public abstract class Teleporter {
* @param exitLocation <p>The exit location generated</p> * @param exitLocation <p>The exit location generated</p>
* @return <p>The location the travelling entity should be teleported to</p> * @return <p>The location the travelling entity should be teleported to</p>
*/ */
private Location adjustExitLocationHeight(Entity entity, Location exitLocation) { @NotNull
private Location adjustExitLocationHeight(@NotNull Entity entity, @Nullable Location exitLocation) {
if (exitLocation != null) { if (exitLocation != null) {
BlockData blockData = exitLocation.getBlock().getBlockData(); BlockData blockData = exitLocation.getBlock().getBlockData();
if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) || if ((blockData instanceof Bisected bisected && bisected.getHalf() == Bisected.Half.BOTTOM) ||
@@ -257,7 +267,8 @@ public abstract class Teleporter {
* @param entity <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p> * @param entity <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p>
* @return <p>The location the entity should be teleported to.</p> * @return <p>The location the entity should be teleported to.</p>
*/ */
private Location getExit(Entity entity) { @NotNull
private Location getExit(@NotNull Entity entity) {
Location exitLocation = null; Location exitLocation = null;
RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit(); RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
if (relativeExit != null) { if (relativeExit != null) {
@@ -270,12 +281,10 @@ public abstract class Teleporter {
} }
exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw); exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw);
if (entity != null) { double entitySize = EntityHelper.getEntityMaxSize(entity);
double entitySize = EntityHelper.getEntityMaxSize(entity); //Prevent exit suffocation for players riding horses or similar
//Prevent exit suffocation for players riding horses or similar if (entitySize > 1) {
if (entitySize > 1) { exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
}
} }
} else { } else {
Stargate.logWarning(String.format("Missing destination point in .gate file %s", Stargate.logWarning(String.format("Missing destination point in .gate file %s",
@@ -293,6 +302,7 @@ public abstract class Teleporter {
* *
* @return <p>A list of chunks to load</p> * @return <p>A list of chunks to load</p>
*/ */
@NotNull
private List<Chunk> getChunksToLoad() { private List<Chunk> getChunksToLoad() {
List<Chunk> chunksToLoad = new ArrayList<>(); List<Chunk> chunksToLoad = new ArrayList<>();
for (RelativeBlockVector vector : portal.getGate().getLayout().getEntrances()) { for (RelativeBlockVector vector : portal.getGate().getLayout().getEntrances()) {

View File

@@ -14,8 +14,10 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* The portal teleporter takes care of the actual portal teleportation for any vehicles * The portal teleporter takes care of the actual portal teleportation for any vehicles
@@ -30,7 +32,7 @@ public class VehicleTeleporter extends EntityTeleporter {
* @param targetPortal <p>The targetPortal which is the target of the teleportation</p> * @param targetPortal <p>The targetPortal which is the target of the teleportation</p>
* @param teleportingVehicle <p>The teleporting vehicle</p> * @param teleportingVehicle <p>The teleporting vehicle</p>
*/ */
public VehicleTeleporter(Portal targetPortal, Vehicle teleportingVehicle) { public VehicleTeleporter(@NotNull Portal targetPortal, @NotNull Vehicle teleportingVehicle) {
super(targetPortal, teleportingVehicle); super(targetPortal, teleportingVehicle);
this.teleportingVehicle = teleportingVehicle; this.teleportingVehicle = teleportingVehicle;
} }
@@ -45,7 +47,7 @@ public class VehicleTeleporter extends EntityTeleporter {
* @return <p>True if the vehicle was teleported. False otherwise</p> * @return <p>True if the vehicle was teleported. False otherwise</p>
*/ */
@Override @Override
public boolean teleportEntity(Portal origin) { public boolean teleportEntity(@NotNull Portal origin) {
Stargate.debug("VehicleTeleporter::teleport", "Preparing to teleport: " + teleportingVehicle); Stargate.debug("VehicleTeleporter::teleport", "Preparing to teleport: " + teleportingVehicle);
double velocity = teleportingVehicle.getVelocity().length(); double velocity = teleportingVehicle.getVelocity().length();
@@ -75,7 +77,7 @@ public class VehicleTeleporter extends EntityTeleporter {
* @param origin <p>The portal the vehicle teleported from</p> * @param origin <p>The portal the vehicle teleported from</p>
* @return <p>True if the vehicle was teleported. False otherwise</p> * @return <p>True if the vehicle was teleported. False otherwise</p>
*/ */
private boolean teleportVehicle(Location exit, Vector newVelocity, Portal origin) { private boolean teleportVehicle(@NotNull Location exit, @NotNull Vector newVelocity, @NotNull Portal origin) {
//Load chunks to make sure not to teleport to the void //Load chunks to make sure not to teleport to the void
loadChunks(); loadChunks();
@@ -113,7 +115,7 @@ public class VehicleTeleporter extends EntityTeleporter {
* @param passengers <p>The passengers to teleport</p> * @param passengers <p>The passengers to teleport</p>
* @return <p>True if the passengers are allowed to teleport</p> * @return <p>True if the passengers are allowed to teleport</p>
*/ */
private boolean vehiclePassengersAllowed(List<Entity> passengers) { private boolean vehiclePassengersAllowed(@NotNull List<Entity> passengers) {
StargateGateConfig config = Stargate.getGateConfig(); StargateGateConfig config = Stargate.getGateConfig();
//Don't teleport if the vehicle contains a creature and creature transportation is disabled //Don't teleport if the vehicle contains a creature and creature transportation is disabled
if (TeleportHelper.containsNonPlayer(passengers) && !config.handleCreatureTransportation()) { if (TeleportHelper.containsNonPlayer(passengers) && !config.handleCreatureTransportation()) {
@@ -131,7 +133,8 @@ public class VehicleTeleporter extends EntityTeleporter {
* @param newVelocity <p>The new velocity of the teleported vehicle</p> * @param newVelocity <p>The new velocity of the teleported vehicle</p>
* @param origin <p>The portal the vehicle teleported from</p> * @param origin <p>The portal the vehicle teleported from</p>
*/ */
private void teleportVehicle(List<Entity> passengers, Location exit, Vector newVelocity, Portal origin) { private void teleportVehicle(@NotNull List<Entity> passengers, @NotNull Location exit, @NotNull Vector newVelocity,
@NotNull Portal origin) {
if (teleportingVehicle.eject()) { if (teleportingVehicle.eject()) {
TeleportHelper.handleEntityPassengers(passengers, teleportingVehicle, origin, portal, exit.getDirection(), TeleportHelper.handleEntityPassengers(passengers, teleportingVehicle, origin, portal, exit.getDirection(),
newVelocity); newVelocity);
@@ -159,17 +162,18 @@ public class VehicleTeleporter extends EntityTeleporter {
* @param newVelocity <p>The new velocity of the new vehicle</p> * @param newVelocity <p>The new velocity of the new vehicle</p>
* @param origin <p>The portal the vehicle teleported from</p> * @param origin <p>The portal the vehicle teleported from</p>
*/ */
private void putPassengersInNewVehicle(List<Entity> passengers, Location exit, private void putPassengersInNewVehicle(@NotNull List<Entity> passengers, @NotNull Location exit,
Vector newVelocity, Portal origin) { @NotNull Vector newVelocity, Portal origin) {
World vehicleWorld = exit.getWorld(); World vehicleWorld = exit.getWorld();
if (vehicleWorld == null) { if (vehicleWorld == null) {
Stargate.logWarning("Unable to get the world to teleport the vehicle to"); Stargate.logWarning("Unable to get the world to teleport the vehicle to");
return; return;
} }
//Spawn a new vehicle //Spawn a new vehicle
Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass()); Vehicle newVehicle = (Vehicle) vehicleWorld.spawn(exit,
Objects.requireNonNull(teleportingVehicle.getType().getEntityClass()));
if (teleportingVehicle instanceof Boat boat) { if (teleportingVehicle instanceof Boat boat) {
((Boat) newVehicle).setBoatType(boat.getBoatType()); boat.setBoatType(boat.getBoatType());
} }
//Remove the old vehicle //Remove the old vehicle
if (teleportingVehicle.eject()) { if (teleportingVehicle.eject()) {

View File

@@ -8,11 +8,12 @@ import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.EndGateway; import org.bukkit.block.EndGateway;
import org.bukkit.block.data.Orientable; import org.bukkit.block.data.Orientable;
import org.jetbrains.annotations.NotNull;
/** /**
* This thread changes gate blocks to display a gate as open or closed * This thread changes gate blocks to display a gate as open or closed
* *
* <p>This thread fetches some entries from blockPopulateQueue each time it's called.</p> * <p>This thread fetches some entries from blockChangeRequestQueue each time it's called.</p>
*/ */
public class BlockChangeThread implements Runnable { public class BlockChangeThread implements Runnable {
@@ -34,7 +35,7 @@ public class BlockChangeThread implements Runnable {
*/ */
public static boolean pollQueue() { public static boolean pollQueue() {
//Abort if there's no work to be done //Abort if there's no work to be done
BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll(); BlockChangeRequest blockChangeRequest = Stargate.getControlBlockUpdateRequestQueue().poll();
if (blockChangeRequest == null) { if (blockChangeRequest == null) {
return true; return true;
} }
@@ -58,7 +59,7 @@ public class BlockChangeThread implements Runnable {
* *
* @param block <p>The block to fix</p> * @param block <p>The block to fix</p>
*/ */
private static void fixEndGatewayGate(Block block) { private static void fixEndGatewayGate(@NotNull Block block) {
EndGateway gateway = (EndGateway) block.getState(); EndGateway gateway = (EndGateway) block.getState();
gateway.setAge(Long.MIN_VALUE); gateway.setAge(Long.MIN_VALUE);
if (block.getWorld().getEnvironment() == World.Environment.THE_END) { if (block.getWorld().getEnvironment() == World.Environment.THE_END) {
@@ -74,7 +75,7 @@ public class BlockChangeThread implements Runnable {
* @param block <p>The block to orient</p> * @param block <p>The block to orient</p>
* @param axis <p>The axis to use for orienting the block</p> * @param axis <p>The axis to use for orienting the block</p>
*/ */
private static void orientBlock(Block block, Axis axis) { private static void orientBlock(@NotNull Block block, @NotNull Axis axis) {
Orientable orientable = (Orientable) block.getBlockData(); Orientable orientable = (Orientable) block.getBlockData();
orientable.setAxis(axis); orientable.setAxis(axis);
block.setBlockData(orientable); block.setBlockData(orientable);

View File

@@ -0,0 +1,50 @@
package net.knarcraft.stargate.thread;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.ControlBlockUpdateRequest;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.utility.DirectionHelper;
import net.knarcraft.stargate.utility.MaterialHelper;
import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.Material;
/**
* This thread updates the signs and buttons of Stargates, if deemed necessary
*/
public class ControlBlocksUpdateThread implements Runnable {
@Override
public void run() {
//Abort if there's no work to be done
ControlBlockUpdateRequest controlBlockUpdateRequest = Stargate.getButtonUpdateRequestQueue().poll();
if (controlBlockUpdateRequest == null) {
return;
}
Portal portal = controlBlockUpdateRequest.portal();
portal.drawSign();
BlockLocation buttonLocation = PortalFileHelper.getButtonLocation(portal);
if (buttonLocation == null) {
return;
}
Stargate.debug("ControlBlocksUpdateThread", "Updating control blocks for portal " + portal);
if (portal.getOptions().isAlwaysOn()) {
//Clear button if it exists
if (MaterialHelper.isButtonCompatible(buttonLocation.getType())) {
Material newMaterial = PortalFileHelper.decideRemovalMaterial(buttonLocation, portal);
Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(buttonLocation, newMaterial, null));
}
} else {
//Replace button if the material is not a button
if (!MaterialHelper.isButtonCompatible(buttonLocation.getType())) {
PortalFileHelper.generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw()));
}
}
}
}

View File

@@ -0,0 +1,55 @@
package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.property.gate.GateHandler;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bstats.charts.SingleLineChart;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
/**
* A helper for dealing with BStats
*/
public final class BStatsHelper {
private static boolean hasBeenInitialized = false;
private BStatsHelper() {
}
/**
* Initializes BStats
*
* @param plugin <p>The plugin to initialize BStats for</p>
*/
public static void initialize(@NotNull JavaPlugin plugin) {
if (hasBeenInitialized) {
throw new IllegalArgumentException("BStats initialized twice");
} else {
hasBeenInitialized = true;
}
int pluginId = 10451;
Metrics metrics = new Metrics(plugin, pluginId);
Map<ConfigOption, Object> configValues = Stargate.getStargateConfig().getConfigOptions();
Map<String, List<String>> portalNetworks = PortalHandler.getAllPortalNetworks();
int totalPortals = 0;
for (List<String> portals : portalNetworks.values()) {
totalPortals += portals.size();
}
metrics.addCustomChart(new SimplePie("language", () -> (String) configValues.get(ConfigOption.LANGUAGE)));
metrics.addCustomChart(new SimplePie("gateformats", () -> String.valueOf(GateHandler.getGateCount())));
int finalTotalPortals = totalPortals;
metrics.addCustomChart(new SingleLineChart("gatesv3", () -> finalTotalPortals));
}
}

View File

@@ -1,12 +1,15 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -36,6 +39,7 @@ public final class BungeeHelper {
* *
* @return <p>The bungee plugin channel</p> * @return <p>The bungee plugin channel</p>
*/ */
@NotNull
public static String getBungeeChannel() { public static String getBungeeChannel() {
return bungeeChannel; return bungeeChannel;
} }
@@ -48,9 +52,10 @@ public final class BungeeHelper {
* queue and teleported to the destination.</p> * queue and teleported to the destination.</p>
* *
* @param playerUUID <p>The UUID of the player to remove</p> * @param playerUUID <p>The UUID of the player to remove</p>
* @return <p>The name of the destination portal the player should be teleported to</p> * @return <p>The name of the destination portal the player should be teleported to, or null if not queued</p>
*/ */
public static String removeFromQueue(UUID playerUUID) { @Nullable
public static String removeFromQueue(@NotNull UUID playerUUID) {
return bungeeQueue.remove(playerUUID); return bungeeQueue.remove(playerUUID);
} }
@@ -61,7 +66,7 @@ public final class BungeeHelper {
* @param entrancePortal <p>The portal the player is teleporting from</p> * @param entrancePortal <p>The portal the player is teleporting from</p>
* @return <p>True if the message was successfully sent</p> * @return <p>True if the message was successfully sent</p>
*/ */
public static boolean sendTeleportationMessage(Player player, Portal entrancePortal) { public static boolean sendTeleportationMessage(@NotNull Player player, @NotNull Portal entrancePortal) {
try { try {
//Build the teleportation message, format is <player identifier>delimiter<destination> //Build the teleportation message, format is <player identifier>delimiter<destination>
String message = player.getUniqueId() + teleportMessageDelimiter + entrancePortal.getDestinationName(); String message = player.getUniqueId() + teleportMessageDelimiter + entrancePortal.getDestinationName();
@@ -72,7 +77,7 @@ public final class BungeeHelper {
//Build the message data and send it over the SGBungee BungeeCord channel //Build the message data and send it over the SGBungee BungeeCord channel
dataOutputStream.writeUTF("Forward"); dataOutputStream.writeUTF("Forward");
//Send the message to the server defined in the entrance portal's network line //Send the message to the server defined in the entrance portal's network line
dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork())); dataOutputStream.writeUTF(Portal.cleanString(entrancePortal.getNetwork()));
//Specify the sub-channel/tag to make it recognizable on arrival //Specify the sub-channel/tag to make it recognizable on arrival
dataOutputStream.writeUTF(bungeeSubChannel); dataOutputStream.writeUTF(bungeeSubChannel);
//Write the length of the message //Write the length of the message
@@ -81,9 +86,8 @@ public final class BungeeHelper {
dataOutputStream.writeBytes(message); dataOutputStream.writeBytes(message);
//Send the plugin message //Send the plugin message
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray()); player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
} catch (IOException ex) { } catch (IOException exception) {
Stargate.logSevere("Error sending BungeeCord teleport packet"); Stargate.logSevere("Error sending BungeeCord teleport packet! Message: " + exception.getMessage());
ex.printStackTrace();
return false; return false;
} }
return true; return true;
@@ -96,20 +100,19 @@ public final class BungeeHelper {
* @param entrancePortal <p>The bungee portal the player is teleporting from</p> * @param entrancePortal <p>The bungee portal the player is teleporting from</p>
* @return <p>True if the plugin message was sent successfully</p> * @return <p>True if the plugin message was sent successfully</p>
*/ */
public static boolean changeServer(Player player, Portal entrancePortal) { public static boolean changeServer(@NotNull Player player, @NotNull Portal entrancePortal) {
try { try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//Send a connect-message to connect the player to the server defined in the entrance portal's network line //Send a connect-message to connect the player to the server defined in the entrance portal's network line
dataOutputStream.writeUTF("Connect"); dataOutputStream.writeUTF("Connect");
dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork())); dataOutputStream.writeUTF(Portal.cleanString(entrancePortal.getNetwork()));
//Send the plugin message //Send the plugin message
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray()); player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
} catch (IOException ex) { } catch (IOException exception) {
Stargate.logSevere("Error sending BungeeCord connect packet"); Stargate.logSevere("Error sending BungeeCord connect packet! Message: " + exception.getMessage());
ex.printStackTrace();
return false; return false;
} }
return true; return true;
@@ -121,6 +124,7 @@ public final class BungeeHelper {
* @param message <p>The byte array to read</p> * @param message <p>The byte array to read</p>
* @return <p>The message contained in the byte array, or null on failure</p> * @return <p>The message contained in the byte array, or null on failure</p>
*/ */
@Nullable
public static String readPluginMessage(byte[] message) { public static String readPluginMessage(byte[] message) {
byte[] data; byte[] data;
try { try {
@@ -137,9 +141,8 @@ public final class BungeeHelper {
data = new byte[dataLength]; data = new byte[dataLength];
//Read the message to the prepared array //Read the message to the prepared array
dataInputStream.readFully(data); dataInputStream.readFully(data);
} catch (IOException ex) { } catch (IOException exception) {
Stargate.logSevere("Error receiving BungeeCord message"); Stargate.logSevere("Error receiving BungeeCord message. Message: " + exception.getMessage());
ex.printStackTrace();
return null; return null;
} }
return new String(data); return new String(data);
@@ -150,7 +153,7 @@ public final class BungeeHelper {
* *
* @param receivedMessage <p>The received teleport message</p> * @param receivedMessage <p>The received teleport message</p>
*/ */
public static void handleTeleportMessage(String receivedMessage) { public static void handleTeleportMessage(@NotNull String receivedMessage) {
//Get the player id and destination from the message //Get the player id and destination from the message
String[] messageParts = receivedMessage.split(teleportMessageDelimiter); String[] messageParts = receivedMessage.split(teleportMessageDelimiter);
UUID playerUUID = UUID.fromString(messageParts[0]); UUID playerUUID = UUID.fromString(messageParts[0]);
@@ -179,11 +182,12 @@ public final class BungeeHelper {
* @param event <p>The event causing the teleportation</p> * @param event <p>The event causing the teleportation</p>
* @return <p>True if the teleportation was successful</p> * @return <p>True if the teleportation was successful</p>
*/ */
public static boolean bungeeTeleport(Player player, Portal entrancePortal, PlayerMoveEvent event) { public static boolean bungeeTeleport(@NotNull Player player, @NotNull Portal entrancePortal,
@NotNull PlayerMoveEvent event) {
//Check if bungee is actually enabled //Check if bungee is actually enabled
if (!Stargate.getGateConfig().enableBungee()) { if (!Stargate.getGateConfig().enableBungee()) {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled")); new SGFormatBuilder(Message.BUNGEE_DISABLED).error(player);
} }
entrancePortal.getPortalOpener().closePortal(false); entrancePortal.getPortalOpener().closePortal(false);
return false; return false;
@@ -208,14 +212,4 @@ public final class BungeeHelper {
return true; return true;
} }
/**
* Strips all color tags from a string
*
* @param string <p>The string to strip color from</p>
* @return <p>The string without color codes</p>
*/
private static String stripColor(String string) {
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string));
}
} }

View File

@@ -3,6 +3,7 @@ package net.knarcraft.stargate.utility;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
/** /**
* This class helps with direction-related calculations * This class helps with direction-related calculations
@@ -24,7 +25,7 @@ public final class DirectionHelper {
* @param location2 <p>The second location, which the yaw will point towards</p> * @param location2 <p>The second location, which the yaw will point towards</p>
* @return <p>The yaw pointing from the first location to the second location</p> * @return <p>The yaw pointing from the first location to the second location</p>
*/ */
public static float getYawFromLocationDifference(Location location1, Location location2) { public static float getYawFromLocationDifference(@NotNull Location location1, @NotNull Location location2) {
Location difference = location1.clone().subtract(location2.clone()); Location difference = location1.clone().subtract(location2.clone());
if (difference.getX() > 0) { if (difference.getX() > 0) {
return 90; return 90;
@@ -45,8 +46,10 @@ public final class DirectionHelper {
* *
* @param yaw <p>The yaw value to convert</p> * @param yaw <p>The yaw value to convert</p>
* @return <p>The block face the yaw corresponds to</p> * @return <p>The block face the yaw corresponds to</p>
* @throws IllegalArgumentException <p>If a yaw not divisible by 90 us given</p>
*/ */
public static BlockFace getBlockFaceFromYaw(double yaw) { @NotNull
public static BlockFace getBlockFaceFromYaw(double yaw) throws IllegalArgumentException {
//Make sure the yaw is between 0 and 360 //Make sure the yaw is between 0 and 360
yaw = normalizeYaw(yaw); yaw = normalizeYaw(yaw);
@@ -68,8 +71,10 @@ public final class DirectionHelper {
* *
* @param yaw <p>The yaw to convert to a direction vector</p> * @param yaw <p>The yaw to convert to a direction vector</p>
* @return <p>The direction vector pointing in the same direction as the yaw</p> * @return <p>The direction vector pointing in the same direction as the yaw</p>
* @throws IllegalArgumentException <p>If a yaw not divisible by 90 is given</p>
*/ */
public static Vector getDirectionVectorFromYaw(double yaw) { @NotNull
public static Vector getDirectionVectorFromYaw(double yaw) throws IllegalArgumentException {
//Make sure the yaw is between 0 and 360 //Make sure the yaw is between 0 and 360
yaw = normalizeYaw(yaw); yaw = normalizeYaw(yaw);
@@ -99,7 +104,8 @@ public final class DirectionHelper {
* @param yaw <p>The yaw when looking directly outwards from a portal</p> * @param yaw <p>The yaw when looking directly outwards from a portal</p>
* @return <p>A location relative to the given location</p> * @return <p>A location relative to the given location</p>
*/ */
public static Location moveLocation(Location location, double right, double down, double out, double yaw) { @NotNull
public static Location moveLocation(@NotNull Location location, double right, double down, double out, double yaw) {
return location.add(getCoordinateVectorFromRelativeVector(right, down, out, yaw)); return location.add(getCoordinateVectorFromRelativeVector(right, down, out, yaw));
} }
@@ -111,8 +117,14 @@ public final class DirectionHelper {
* @param out <p>The distance outward from the top-left origin</p> * @param out <p>The distance outward from the top-left origin</p>
* @param yaw <p>The yaw when looking directly outwards from a portal</p> * @param yaw <p>The yaw when looking directly outwards from a portal</p>
* @return <p>A normal vector</p> * @return <p>A normal vector</p>
* @throws IllegalArgumentException <p>If a yaw not divisible by 90 is given</p>
*/ */
public static Vector getCoordinateVectorFromRelativeVector(double right, double down, double out, double yaw) { @NotNull
public static Vector getCoordinateVectorFromRelativeVector(double right, double down, double out,
double yaw) throws IllegalArgumentException {
//Make sure the yaw is between 0 and 360
yaw = normalizeYaw(yaw);
if (yaw == 0) { if (yaw == 0) {
//South //South
return new Vector(right, -down, out); return new Vector(right, -down, out);

View File

@@ -1,13 +1,18 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.knarlib.formatting.FormatBuilder;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.EconomyConfig; import net.knarcraft.stargate.config.EconomyConfig;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID; import java.util.UUID;
@@ -28,7 +33,7 @@ public final class EconomyHelper {
* @param cost <p>The cost of teleportation</p> * @param cost <p>The cost of teleportation</p>
* @return <p>False if payment was successful. True if the payment was unsuccessful</p> * @return <p>False if payment was successful. True if the payment was unsuccessful</p>
*/ */
public static boolean cannotPayTeleportFee(Portal entrancePortal, Player player, int cost) { public static boolean cannotPayTeleportFee(@NotNull Portal entrancePortal, @NotNull Player player, int cost) {
boolean success; boolean success;
//Try to charge the player. Paying the portal owner is only possible if a UUID is available //Try to charge the player. Paying the portal owner is only possible if a UUID is available
@@ -77,10 +82,8 @@ public final class EconomyHelper {
* @param portalOwner <p>The owner of the portal</p> * @param portalOwner <p>The owner of the portal</p>
* @param earnings <p>The amount the owner earned</p> * @param earnings <p>The amount the owner earned</p>
*/ */
public static void sendObtainMessage(String portalName, Player portalOwner, int earnings) { public static void sendObtainMessage(@NotNull String portalName, @NotNull Player portalOwner, int earnings) {
String obtainedMsg = Stargate.getString("ecoObtain"); replacePlaceholders(new SGFormatBuilder(Message.ECONOMY_OBTAINED), portalName, earnings).success(portalOwner);
obtainedMsg = replacePlaceholders(obtainedMsg, portalName, earnings);
Stargate.getMessageSender().sendSuccessMessage(portalOwner, obtainedMsg);
} }
/** /**
@@ -90,10 +93,8 @@ public final class EconomyHelper {
* @param player <p>The interacting player</p> * @param player <p>The interacting player</p>
* @param cost <p>The cost of the interaction</p> * @param cost <p>The cost of the interaction</p>
*/ */
public static void sendDeductMessage(String portalName, Player player, int cost) { public static void sendDeductMessage(@NotNull String portalName, @NotNull Player player, int cost) {
String deductMsg = Stargate.getString("ecoDeduct"); replacePlaceholders(new SGFormatBuilder(Message.ECONOMY_DEDUCTED), portalName, cost).success(player);
deductMsg = replacePlaceholders(deductMsg, portalName, cost);
Stargate.getMessageSender().sendSuccessMessage(player, deductMsg);
} }
/** /**
@@ -103,10 +104,8 @@ public final class EconomyHelper {
* @param player <p>The interacting player</p> * @param player <p>The interacting player</p>
* @param cost <p>The cost of the interaction</p> * @param cost <p>The cost of the interaction</p>
*/ */
public static void sendInsufficientFundsMessage(String portalName, Player player, int cost) { public static void sendInsufficientFundsMessage(@NotNull String portalName, @NotNull Player player, int cost) {
String inFundMsg = Stargate.getString("ecoInFunds"); replacePlaceholders(new SGFormatBuilder(Message.ECONOMY_INSUFFICIENT), portalName, cost).error(player);
inFundMsg = replacePlaceholders(inFundMsg, portalName, cost);
Stargate.getMessageSender().sendErrorMessage(player, inFundMsg);
} }
/** /**
@@ -116,10 +115,8 @@ public final class EconomyHelper {
* @param player <p>The player breaking the portal</p> * @param player <p>The player breaking the portal</p>
* @param cost <p>The amount the user has to pay for destroying the portal. (expects a negative value)</p> * @param cost <p>The amount the user has to pay for destroying the portal. (expects a negative value)</p>
*/ */
public static void sendRefundMessage(String portalName, Player player, int cost) { public static void sendRefundMessage(@NotNull String portalName, @NotNull Player player, int cost) {
String refundMsg = Stargate.getString("ecoRefund"); replacePlaceholders(new SGFormatBuilder(Message.ECONOMY_REFUNDED), portalName, -cost).success(player);
refundMsg = replacePlaceholders(refundMsg, portalName, -cost);
Stargate.getMessageSender().sendSuccessMessage(player, refundMsg);
} }
/** /**
@@ -130,7 +127,7 @@ public final class EconomyHelper {
* @param destination <p>The destination portal</p> * @param destination <p>The destination portal</p>
* @return <p>The cost of using the portal</p> * @return <p>The cost of using the portal</p>
*/ */
public static int getUseCost(Player player, Portal source, Portal destination) { public static int getUseCost(@NotNull Player player, @NotNull Portal source, @Nullable Portal destination) {
EconomyConfig config = Stargate.getEconomyConfig(); EconomyConfig config = Stargate.getEconomyConfig();
//No payment required //No payment required
if (!config.useEconomy() || source.getOptions().isFree()) { if (!config.useEconomy() || source.getOptions().isFree()) {
@@ -160,7 +157,7 @@ public final class EconomyHelper {
* @param cost <p>The cost of the transaction</p> * @param cost <p>The cost of the transaction</p>
* @return <p>True if the player was charged successfully</p> * @return <p>True if the player was charged successfully</p>
*/ */
public static boolean chargePlayerIfNecessary(Player player, UUID target, int cost) { public static boolean chargePlayerIfNecessary(@NotNull Player player, @NotNull UUID target, int cost) {
if (skipPayment(cost)) { if (skipPayment(cost)) {
return true; return true;
} }
@@ -175,17 +172,43 @@ public final class EconomyHelper {
* @param amount <p>The amount to charge</p> * @param amount <p>The amount to charge</p>
* @return <p>True if the payment succeeded, or if no payment was necessary</p> * @return <p>True if the payment succeeded, or if no payment was necessary</p>
*/ */
private static boolean chargePlayer(Player player, double amount) { private static boolean chargePlayer(@NotNull Player player, double amount) {
Economy economy = Stargate.getEconomyConfig().getEconomy(); Economy economy = Stargate.getEconomyConfig().getEconomy();
if (Stargate.getEconomyConfig().isEconomyEnabled() && economy != null) { if (Stargate.getEconomyConfig().isEconomyEnabled() && economy != null) {
if (!economy.has(player, amount)) { if (!economy.has(player, amount)) {
return false; return false;
} }
economy.withdrawPlayer(player, amount); if (amount > 0) {
economy.withdrawPlayer(player, amount);
} else {
economy.depositPlayer(player, -amount);
}
} }
return true; return true;
} }
/**
* Transfers the given fees to the tax account
*
* @param economy <p>The economy to use</p>
* @param cost <p>The cost to transfer</p>
*/
@SuppressWarnings("deprecation")
private static void transferFees(@NotNull Economy economy, int cost) {
String accountName = Stargate.getEconomyConfig().getTaxAccount();
if (accountName == null || accountName.isEmpty()) {
return;
}
try {
UUID accountId = UUID.fromString(accountName);
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(accountId);
economy.depositPlayer(offlinePlayer, cost);
} catch (IllegalArgumentException exception) {
economy.depositPlayer(accountName, cost);
}
}
/** /**
* Charges the player for an action, if required * Charges the player for an action, if required
* *
@@ -193,12 +216,20 @@ public final class EconomyHelper {
* @param cost <p>The cost of the transaction</p> * @param cost <p>The cost of the transaction</p>
* @return <p>True if the player was charged successfully</p> * @return <p>True if the player was charged successfully</p>
*/ */
public static boolean chargePlayerIfNecessary(Player player, int cost) { public static boolean chargePlayerIfNecessary(@NotNull Player player, int cost) {
if (skipPayment(cost)) { if (skipPayment(cost)) {
return true; return true;
} }
//Charge player //Charge player
return chargePlayer(player, cost); boolean charged = chargePlayer(player, cost);
// Transfer the charged amount to the tax account
Economy economy = Stargate.getEconomyConfig().getEconomy();
if (charged && economy != null) {
transferFees(economy, cost);
}
return charged;
} }
/** /**
@@ -219,9 +250,10 @@ public final class EconomyHelper {
* @param amount <p>The amount to charge</p> * @param amount <p>The amount to charge</p>
* @return <p>True if the payment succeeded, or if no payment was necessary</p> * @return <p>True if the payment succeeded, or if no payment was necessary</p>
*/ */
private static boolean chargePlayer(Player player, UUID target, double amount) { private static boolean chargePlayer(@NotNull Player player, @NotNull UUID target, double amount) {
Economy economy = Stargate.getEconomyConfig().getEconomy(); Economy economy = Stargate.getEconomyConfig().getEconomy();
if (Stargate.getEconomyConfig().isEconomyEnabled() && player.getUniqueId().compareTo(target) != 0 && economy != null) { if (Stargate.getEconomyConfig().isEconomyEnabled() && player.getUniqueId().compareTo(target) != 0 &&
economy != null) {
if (!economy.has(player, amount)) { if (!economy.has(player, amount)) {
return false; return false;
} }
@@ -233,16 +265,16 @@ public final class EconomyHelper {
} }
/** /**
* Replaces the cost and portal variables in a string * Replaces the cost and portal variables in a format builder
* *
* @param message <p>The message to replace variables in</p> * @param builder <p>The format builder to replace variables for</p>
* @param portalName <p>The name of the relevant portal</p> * @param portalName <p>The name of the relevant portal</p>
* @param cost <p>The cost for a given interaction</p> * @param cost <p>The cost for a given interaction</p>
* @return <p>The same string with cost and portal variables replaced</p> * @return <p>The same format builder</p>
*/ */
private static String replacePlaceholders(String message, String portalName, int cost) { private static FormatBuilder replacePlaceholders(@NotNull FormatBuilder builder, @NotNull String portalName, int cost) {
return StringFormatter.replacePlaceholders(message, new String[]{"%cost%", "%portal%"}, builder.replace("%cost%", Stargate.getEconomyConfig().format(cost)).replace("%portal%", portalName);
new String[]{Stargate.getEconomyConfig().format(cost), portalName}); return builder;
} }
} }

View File

@@ -1,6 +1,7 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
/** /**
* This helper class helps with entity properties not immediately available * This helper class helps with entity properties not immediately available
@@ -21,7 +22,7 @@ public final class EntityHelper {
* @param entity <p>The entity to get max size for</p> * @param entity <p>The entity to get max size for</p>
* @return <p>The max size of the entity</p> * @return <p>The max size of the entity</p>
*/ */
public static int getEntityMaxSizeInt(Entity entity) { public static int getEntityMaxSizeInt(@NotNull Entity entity) {
return (int) Math.ceil((float) getEntityMaxSize(entity)); return (int) Math.ceil((float) getEntityMaxSize(entity));
} }
@@ -31,7 +32,7 @@ public final class EntityHelper {
* @param entity <p>The entity to get max size for</p> * @param entity <p>The entity to get max size for</p>
* @return <p>The max size of the entity</p> * @return <p>The max size of the entity</p>
*/ */
public static double getEntityMaxSize(Entity entity) { public static double getEntityMaxSize(@NotNull Entity entity) {
return Math.max(entity.getBoundingBox().getWidthX(), entity.getBoundingBox().getWidthZ()); return Math.max(entity.getBoundingBox().getWidthX(), entity.getBoundingBox().getWidthZ());
} }

View File

@@ -1,13 +1,16 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.material.BukkitMaterialSpecifier;
import net.knarcraft.stargate.config.material.MaterialSpecifier;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.Set;
/** /**
* Helper class for reading gate files * Helper class for reading gate files
@@ -25,15 +28,16 @@ public final class GateReader {
* @param characterMaterialMap <p>The map of characters to store valid symbols in</p> * @param characterMaterialMap <p>The map of characters to store valid symbols in</p>
* @param fileName <p>The filename of the loaded gate config file</p> * @param fileName <p>The filename of the loaded gate config file</p>
* @param design <p>The list to store the loaded design/layout to</p> * @param design <p>The list to store the loaded design/layout to</p>
* @param frameTypes <p>The set to store frame/border materials to</p>
* @param config <p>The map of config values to store to</p> * @param config <p>The map of config values to store to</p>
* @return <p>The column count/width of the loaded gate</p> * @return <p>The column count/width of the loaded gate</p>
*/ */
public static int readGateFile(Scanner scanner, Map<Character, Material> characterMaterialMap, String fileName, public static int readGateFile(@NotNull Scanner scanner,
List<List<Character>> design, Set<Material> frameTypes, Map<String, String> config) { @NotNull Map<Character, List<MaterialSpecifier>> characterMaterialMap,
@NotNull String fileName, @NotNull List<List<Character>> design,
@NotNull Map<String, String> config) {
boolean designing = false; boolean designing = false;
int columns = 0; int columns = 0;
try { try (scanner) {
while (scanner.hasNextLine()) { while (scanner.hasNextLine()) {
String line = scanner.nextLine(); String line = scanner.nextLine();
@@ -46,7 +50,7 @@ public final class GateReader {
} else { } else {
if (!line.isEmpty() && !line.startsWith("#")) { if (!line.isEmpty() && !line.startsWith("#")) {
//Read a normal config value //Read a normal config value
readGateConfigValue(line, characterMaterialMap, frameTypes, config); readGateConfigValue(line, characterMaterialMap, config);
} else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) { } else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) {
//An empty line marks the start of the gate's layout/design //An empty line marks the start of the gate's layout/design
designing = true; designing = true;
@@ -56,10 +60,6 @@ public final class GateReader {
} catch (Exception exception) { } catch (Exception exception) {
Stargate.logSevere(String.format("Could not load Gate %s - %s", fileName, exception.getMessage())); Stargate.logSevere(String.format("Could not load Gate %s - %s", fileName, exception.getMessage()));
return -1; return -1;
} finally {
if (scanner != null) {
scanner.close();
}
} }
return columns; return columns;
} }
@@ -77,8 +77,9 @@ public final class GateReader {
* @param design <p>The two-dimensional list to store the loaded design to</p> * @param design <p>The two-dimensional list to store the loaded design to</p>
* @return <p>The new max columns value of the design</p> * @return <p>The new max columns value of the design</p>
*/ */
private static int readGateDesignLine(String line, int maxColumns, Map<Character, Material> characterMaterialMap, private static int readGateDesignLine(@NotNull String line, int maxColumns,
String fileName, List<List<Character>> design) { @NotNull Map<Character, List<MaterialSpecifier>> characterMaterialMap,
@NotNull String fileName, @NotNull List<List<Character>> design) {
List<Character> row = new ArrayList<>(); List<Character> row = new ArrayList<>();
//Update the max columns number if this line has more columns //Update the max columns number if this line has more columns
@@ -88,7 +89,7 @@ public final class GateReader {
for (Character symbol : line.toCharArray()) { for (Character symbol : line.toCharArray()) {
//Refuse read gate designs with unknown characters //Refuse read gate designs with unknown characters
if (symbol.equals('?') || (!characterMaterialMap.containsKey(symbol))) { if (symbol.equals('?') || !characterMaterialMap.containsKey(symbol)) {
Stargate.logSevere(String.format("Could not load Gate %s - Unknown symbol '%s' in diagram", fileName, Stargate.logSevere(String.format("Could not load Gate %s - Unknown symbol '%s' in diagram", fileName,
symbol)); symbol));
return -1; return -1;
@@ -107,12 +108,12 @@ public final class GateReader {
* *
* @param line <p>The line to read</p> * @param line <p>The line to read</p>
* @param characterMaterialMap <p>The character to material map to store to</p> * @param characterMaterialMap <p>The character to material map to store to</p>
* @param frameTypes <p>The set to store gate frame/border types to</p>
* @param config <p>The config value map to store to</p> * @param config <p>The config value map to store to</p>
* @throws Exception <p>If an invalid material is encountered</p> * @throws InvalidConfigurationException <p>If an invalid material is encountered</p>
*/ */
private static void readGateConfigValue(String line, Map<Character, Material> characterMaterialMap, private static void readGateConfigValue(@NotNull String line,
Set<Material> frameTypes, Map<String, String> config) throws Exception { @NotNull Map<Character, List<MaterialSpecifier>> characterMaterialMap,
@NotNull Map<String, String> config) throws InvalidConfigurationException {
String[] split = line.split("="); String[] split = line.split("=");
String key = split[0].trim(); String key = split[0].trim();
String value = split[1].trim(); String value = split[1].trim();
@@ -120,14 +121,13 @@ public final class GateReader {
if (key.length() == 1) { if (key.length() == 1) {
//Read a gate frame material //Read a gate frame material
Character symbol = key.charAt(0); Character symbol = key.charAt(0);
Material material = Material.getMaterial(value);
if (material == null) { List<MaterialSpecifier> materials = MaterialHelper.parseTagsAndMaterials(value);
throw new Exception("Invalid material in line: " + line); if (!materials.isEmpty()) {
characterMaterialMap.put(symbol, materials);
} else {
throw new InvalidConfigurationException("Invalid material in line: " + line);
} }
//Register the map between the read symbol and the corresponding material
characterMaterialMap.put(symbol, material);
//Save the material as one of the frame materials used for this kind of gate
frameTypes.add(material);
} else { } else {
//Read a normal config value //Read a normal config value
config.put(key, value); config.put(key, value);
@@ -142,12 +142,13 @@ public final class GateReader {
* @param key <p>The config key to read</p> * @param key <p>The config key to read</p>
* @return <p>The read value, or -1 if it could not be read</p> * @return <p>The read value, or -1 if it could not be read</p>
*/ */
public static int readGateConfig(Map<String, String> config, String fileName, String key) { public static int readGateConfig(@NotNull Map<String, String> config, @NotNull String fileName,
@NotNull String key) {
if (config.containsKey(key)) { if (config.containsKey(key)) {
try { try {
return Integer.parseInt(config.get(key)); return Integer.parseInt(config.get(key));
} catch (NumberFormatException ex) { } catch (NumberFormatException exception) {
Stargate.logWarning(String.format("%s reading %s: %s is not numeric", ex.getClass().getName(), Stargate.logWarning(String.format("%s reading %s: %s is not numeric", exception.getClass().getName(),
fileName, key)); fileName, key));
} }
} }
@@ -164,17 +165,18 @@ public final class GateReader {
* @param defaultMaterial <p>The default material to use, in case the config is invalid</p> * @param defaultMaterial <p>The default material to use, in case the config is invalid</p>
* @return <p>The material specified in the config, or the default material if it could not be read</p> * @return <p>The material specified in the config, or the default material if it could not be read</p>
*/ */
public static Material readGateConfig(Map<String, String> config, String fileName, String key, @NotNull
Material defaultMaterial) { public static List<MaterialSpecifier> readGateConfig(@NotNull Map<String, String> config, @NotNull String fileName,
@NotNull String key, @NotNull Material defaultMaterial) {
if (config.containsKey(key)) { if (config.containsKey(key)) {
Material material = Material.getMaterial(config.get(key)); List<MaterialSpecifier> materialSpecifiers = MaterialHelper.parseTagsAndMaterials(config.get(key));
if (material != null) { if (!materialSpecifiers.isEmpty()) {
return material; return materialSpecifiers;
} else { } else {
Stargate.logWarning(String.format("Error reading %s: %s is not a material", fileName, key)); Stargate.logWarning(String.format("Error reading %s: %s is not a material", fileName, key));
} }
} }
return defaultMaterial; return List.of(new BukkitMaterialSpecifier(defaultMaterial));
} }
/** /**
@@ -187,7 +189,8 @@ public final class GateReader {
* @param columns <p>The largest amount of columns in the design</p> * @param columns <p>The largest amount of columns in the design</p>
* @return <p>A matrix containing the gate's layout</p> * @return <p>A matrix containing the gate's layout</p>
*/ */
public static Character[][] generateLayoutMatrix(List<List<Character>> design, int columns) { @NotNull
public static Character[][] generateLayoutMatrix(@NotNull List<List<Character>> design, int columns) {
Character[][] layout = new Character[design.size()][columns]; Character[][] layout = new Character[design.size()][columns];
for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) { for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) {
List<Character> row = design.get(lineIndex); List<Character> row = design.get(lineIndex);

View File

@@ -0,0 +1,28 @@
package net.knarcraft.stargate.utility;
import java.util.List;
import java.util.Random;
/**
* A helper class for dealing with lists
*/
public final class ListHelper {
private static final Random random = new Random();
private ListHelper() {
}
/**
* Gets a random item from a list
*
* @param list <p>The list to get an item from</p>
* @param <T> <p>The type of item the list contains</p>
* @return <p>A random item</p>
*/
public static <T> T getRandom(List<T> list) {
return list.get(random.nextInt(list.size()));
}
}

View File

@@ -1,7 +1,19 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.config.material.BukkitMaterialSpecifier;
import net.knarcraft.stargate.config.material.BukkitTagSpecifier;
import net.knarcraft.stargate.config.material.MaterialSpecifier;
import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag; import org.bukkit.Tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/** /**
* This class helps decide properties of materials not already present in the Spigot API * This class helps decide properties of materials not already present in the Spigot API
@@ -18,7 +30,7 @@ public final class MaterialHelper {
* @param material <p>The material to check</p> * @param material <p>The material to check</p>
* @return <p>True if the material is a wall coral</p> * @return <p>True if the material is a wall coral</p>
*/ */
public static boolean isWallCoral(Material material) { public static boolean isWallCoral(@NotNull Material material) {
//Unfortunately, there is no tag for dead wall corals, so they need to be checked manually //Unfortunately, there is no tag for dead wall corals, so they need to be checked manually
return Tag.WALL_CORALS.isTagged(material) || return Tag.WALL_CORALS.isTagged(material) ||
material.equals(Material.DEAD_BRAIN_CORAL_WALL_FAN) || material.equals(Material.DEAD_BRAIN_CORAL_WALL_FAN) ||
@@ -34,7 +46,7 @@ public final class MaterialHelper {
* @param material <p>The material to check</p> * @param material <p>The material to check</p>
* @return <p>True if the material is a container</p> * @return <p>True if the material is a container</p>
*/ */
public static boolean isContainer(Material material) { public static boolean isContainer(@NotNull Material material) {
return Tag.SHULKER_BOXES.isTagged(material) || material == Material.CHEST || return Tag.SHULKER_BOXES.isTagged(material) || material == Material.CHEST ||
material == Material.TRAPPED_CHEST || material == Material.ENDER_CHEST; material == Material.TRAPPED_CHEST || material == Material.ENDER_CHEST;
} }
@@ -45,8 +57,84 @@ public final class MaterialHelper {
* @param material <p>The material to check</p> * @param material <p>The material to check</p>
* @return <p>True if the material can be used as a button</p> * @return <p>True if the material can be used as a button</p>
*/ */
public static boolean isButtonCompatible(Material material) { public static boolean isButtonCompatible(@NotNull Material material) {
return Tag.BUTTONS.isTagged(material) || isWallCoral(material) || isContainer(material); return Tag.BUTTONS.isTagged(material) || isWallCoral(material) || isContainer(material);
} }
@NotNull
public static String specifiersToString(@NotNull List<MaterialSpecifier> specifiers) {
List<String> names = new ArrayList<>();
for (MaterialSpecifier specifier : specifiers) {
names.add(specifier.asString());
}
return String.join(",", names);
}
/**
* Converts a list of material specifiers to a set of materials
*
* @param specifiers <p>The material specifiers to convert</p>
* @return <p>The materials the specifiers represent</p>
*/
@NotNull
public static Set<Material> specifiersToMaterials(@NotNull List<MaterialSpecifier> specifiers) {
Set<Material> output = new HashSet<>();
for (MaterialSpecifier specifier : specifiers) {
output.addAll(specifier.asMaterials());
}
return output;
}
/**
* Parses all materials and material tags found in the input string
*
* @param input <p>The input string to parse</p>
* @return <p>All material specifiers found</p>
*/
@NotNull
public static List<MaterialSpecifier> parseTagsAndMaterials(@NotNull String input) {
List<MaterialSpecifier> specifiers = new ArrayList<>();
// Nothing to parse
if (input.isBlank()) {
return specifiers;
}
String[] parts;
if (input.contains(",")) {
parts = input.split(",");
} else {
parts = new String[]{input};
}
for (String part : parts) {
MaterialSpecifier materialSpecifier = parseTagOrMaterial(part.trim());
if (materialSpecifier != null) {
specifiers.add(materialSpecifier);
}
}
return specifiers;
}
@Nullable
private static MaterialSpecifier parseTagOrMaterial(@NotNull String input) {
if (input.startsWith("#")) {
String tagString = input.replaceFirst("#", "").toLowerCase();
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.minecraft(tagString), Material.class);
if (tag != null) {
return new BukkitTagSpecifier(tag);
}
} else {
Material material = Material.matchMaterial(input);
if (material != null) {
return new BukkitMaterialSpecifier(material);
}
}
return null;
}
} }

View File

@@ -1,12 +1,16 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.event.StargateAccessEvent; import net.knarcraft.stargate.event.StargateAccessEvent;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.property.PortalOption; import net.knarcraft.stargate.portal.property.PortalOption;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static net.knarcraft.stargate.Stargate.getMaxNameNetworkLength; import static net.knarcraft.stargate.Stargate.getMaxNameNetworkLength;
@@ -25,7 +29,7 @@ public final class PermissionHelper {
* @param player <p>The player opening the portal</p> * @param player <p>The player opening the portal</p>
* @param portal <p>The portal to open</p> * @param portal <p>The portal to open</p>
*/ */
public static void openPortal(Player player, Portal portal) { public static void openPortal(@NotNull Player player, @NotNull Portal portal) {
Portal destination = portal.getPortalActivator().getDestination(); Portal destination = portal.getPortalActivator().getDestination();
//For an always open portal, no action is necessary //For an always open portal, no action is necessary
@@ -35,8 +39,8 @@ public final class PermissionHelper {
//Destination is invalid or the same portal. Send an error message //Destination is invalid or the same portal. Send an error message
if (destination == null || destination == portal) { if (destination == null || destination == portal) {
if (!portal.getOptions().isSilent()) { if (!portal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg")); new SGFormatBuilder(Message.INVALID_DESTINATION).error(player);
} }
return; return;
} }
@@ -50,28 +54,8 @@ public final class PermissionHelper {
return; return;
} }
//Deny access if another player has activated the portal, and it's still in use // Check if the player is able to open the portal
if (!portal.getOptions().isFixed() && portal.getPortalActivator().isActive() && if (canNotOpen(player, portal, destination)) {
portal.getActivePlayer() != player) {
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
return;
}
//Check if the player can use the private gate
if (portal.getOptions().isPrivate() && !PermissionHelper.canUsePrivatePortal(player, portal)) {
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
}
return;
}
//Destination is currently in use by another player, blocking teleportation
if (destination.isOpen() && !destination.getOptions().isAlwaysOn()) {
if (!portal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("blockMsg"));
}
return; return;
} }
@@ -79,6 +63,43 @@ public final class PermissionHelper {
portal.getPortalOpener().openPortal(player, false); portal.getPortalOpener().openPortal(player, false);
} }
/**
* Checks whether something prevents the player from opening the given portal to the given destination
*
* @param player <p>The player trying to open the portal</p>
* @param portal <p>The portal to open</p>
* @param destination <p>The destination the player is attempting to open</p>
* @return <p>True if the player cannot open the portal</p>
*/
private static boolean canNotOpen(Player player, Portal portal, Portal destination) {
//Deny access if another player has activated the portal, and it's still in use
if (!portal.getOptions().isFixed() && portal.getPortalActivator().isActive() &&
portal.getActivePlayer() != player) {
if (!portal.getOptions().isQuiet()) {
new SGFormatBuilder(Message.ACCESS_DENIED).error(player);
}
return true;
}
//Check if the player can use the private gate
if (portal.getOptions().isPrivate() && !PermissionHelper.canUsePrivatePortal(player, portal)) {
if (!portal.getOptions().isQuiet()) {
new SGFormatBuilder(Message.ACCESS_DENIED).error(player);
}
return true;
}
//Destination is currently in use by another player, blocking teleportation
if (destination.isOpen() && !destination.getOptions().isAlwaysOn()) {
if (!portal.getOptions().isQuiet()) {
new SGFormatBuilder(Message.DESTINATION_BLOCKED).error(player);
}
return true;
}
return false;
}
/** /**
* Creates a StargateAccessEvent and gets the updated deny value * Creates a StargateAccessEvent and gets the updated deny value
* *
@@ -89,7 +110,7 @@ public final class PermissionHelper {
* @param deny <p>Whether the player's access has already been denied by a previous check</p> * @param deny <p>Whether the player's access has already been denied by a previous check</p>
* @return <p>False if the player should be allowed through the portal</p> * @return <p>False if the player should be allowed through the portal</p>
*/ */
public static boolean portalAccessDenied(Player player, Portal portal, boolean deny) { public static boolean portalAccessDenied(@NotNull Player player, @NotNull Portal portal, boolean deny) {
StargateAccessEvent event = new StargateAccessEvent(player, portal, deny); StargateAccessEvent event = new StargateAccessEvent(player, portal, deny);
Stargate.getInstance().getServer().getPluginManager().callEvent(event); Stargate.getInstance().getServer().getPluginManager().callEvent(event);
return event.getDeny(); return event.getDeny();
@@ -103,23 +124,32 @@ public final class PermissionHelper {
* @param destination <p>The portal the user wants to exit from</p> * @param destination <p>The portal the user wants to exit from</p>
* @return <p>False if the user is allowed to access the portal</p> * @return <p>False if the user is allowed to access the portal</p>
*/ */
public static boolean cannotAccessPortal(Player player, Portal entrancePortal, Portal destination) { public static boolean cannotAccessPortal(@NotNull Player player, @NotNull Portal entrancePortal,
@Nullable Portal destination) {
boolean deny = false; boolean deny = false;
String route = "PermissionHelper::cannotAccessPortal";
if (entrancePortal.getOptions().isBungee()) { if (entrancePortal.getOptions().isBungee()) {
if (!PermissionHelper.canAccessServer(player, entrancePortal.getCleanNetwork())) { if (!PermissionHelper.canAccessServer(player, entrancePortal.getCleanNetwork())) {
//If the portal is a bungee portal, and the player cannot access the server, deny //If the portal is a bungee portal, and the player cannot access the server, deny
Stargate.debug("cannotAccessPortal", "Cannot access server"); Stargate.debug(route, "Cannot access server");
deny = true; deny = true;
} }
} else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getCleanNetwork())) { } else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getCleanNetwork())) {
//If the player does not have access to the network, deny //If the player does not have access to the network, deny
Stargate.debug("cannotAccessPortal", "Cannot access network"); Stargate.debug(route, "Cannot access network");
deny = true;
} else if (PermissionHelper.cannotAccessWorld(player, destination.getWorld().getName())) {
//If the player does not have access to the portal's world, deny
Stargate.debug("cannotAccessPortal", "Cannot access world");
deny = true; deny = true;
} else {
if (destination == null) {
//If there is no destination, deny
Stargate.debug(route, "Portal has no destination");
deny = true;
} else if (destination.getWorld() != null &&
PermissionHelper.cannotAccessWorld(player, destination.getWorld().getName())) {
//If the player does not have access to the portal's world, deny
Stargate.debug(route, "Cannot access world");
deny = true;
}
} }
//Allow other plugins to override whether the player can access the portal //Allow other plugins to override whether the player can access the portal
return portalAccessDenied(player, entrancePortal, deny); return portalAccessDenied(player, entrancePortal, deny);
@@ -134,7 +164,7 @@ public final class PermissionHelper {
* @param permission <p>The permission to check</p> * @param permission <p>The permission to check</p>
* @return <p>True if the player has the permission</p> * @return <p>True if the player has the permission</p>
*/ */
public static boolean hasPermission(Player player, String permission) { public static boolean hasPermission(@NotNull Player player, @NotNull String permission) {
if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) { if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
Stargate.debug("hasPerm::Permission(" + player.getName() + ")", permission + " => " + Stargate.debug("hasPerm::Permission(" + player.getName() + ")", permission + " => " +
player.hasPermission(permission)); player.hasPermission(permission));
@@ -152,7 +182,7 @@ public final class PermissionHelper {
* @param permission <p>The permission to check</p> * @param permission <p>The permission to check</p>
* @return <p>True if the player has the permission implicitly or explicitly</p> * @return <p>True if the player has the permission implicitly or explicitly</p>
*/ */
public static boolean hasPermissionImplicit(Player player, String permission) { public static boolean hasPermissionImplicit(@NotNull Player player, @NotNull String permission) {
if (!player.isPermissionSet(permission)) { if (!player.isPermissionSet(permission)) {
if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) { if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
Stargate.debug("hasPermissionImplicit::Permission", permission + " => implicitly true"); Stargate.debug("hasPermissionImplicit::Permission", permission + " => implicitly true");
@@ -173,7 +203,7 @@ public final class PermissionHelper {
* @param world <p>The world the player is trying to access</p> * @param world <p>The world the player is trying to access</p>
* @return <p>False if the player should be allowed to access the world</p> * @return <p>False if the player should be allowed to access the world</p>
*/ */
public static boolean cannotAccessWorld(Player player, String world) { public static boolean cannotAccessWorld(@NotNull Player player, @NotNull String world) {
//The player can access all worlds //The player can access all worlds
if (hasPermission(player, "stargate.world")) { if (hasPermission(player, "stargate.world")) {
//Check if the world permission has been explicitly denied //Check if the world permission has been explicitly denied
@@ -190,7 +220,7 @@ public final class PermissionHelper {
* @param network <p>The network to check</p> * @param network <p>The network to check</p>
* @return <p>True if the player is denied from accessing the network</p> * @return <p>True if the player is denied from accessing the network</p>
*/ */
public static boolean cannotAccessNetwork(Player player, String network) { public static boolean cannotAccessNetwork(@NotNull Player player, @NotNull String network) {
//The player can access all networks //The player can access all networks
if (hasPermission(player, "stargate.network")) { if (hasPermission(player, "stargate.network")) {
//Check if the world permission has been explicitly denied //Check if the world permission has been explicitly denied
@@ -215,7 +245,7 @@ public final class PermissionHelper {
* @param server <p>The server the player is trying to connect to</p> * @param server <p>The server the player is trying to connect to</p>
* @return <p>True if the player is allowed to access the given server</p> * @return <p>True if the player is allowed to access the given server</p>
*/ */
public static boolean canAccessServer(Player player, String server) { public static boolean canAccessServer(@NotNull Player player, @NotNull String server) {
//The player can access all servers //The player can access all servers
if (hasPermission(player, "stargate.server")) { if (hasPermission(player, "stargate.server")) {
//Check if the server permission has been explicitly denied //Check if the server permission has been explicitly denied
@@ -233,7 +263,7 @@ public final class PermissionHelper {
* @param dest <p>The portal the player wants to teleport to</p> * @param dest <p>The portal the player wants to teleport to</p>
* @return <p>True if the player can travel for free</p> * @return <p>True if the player can travel for free</p>
*/ */
public static boolean isFree(Player player, Portal src, Portal dest) { public static boolean isFree(@NotNull Player player, @NotNull Portal src, @Nullable Portal dest) {
//This portal is free //This portal is free
if (src.getOptions().isFree()) { if (src.getOptions().isFree()) {
return true; return true;
@@ -255,7 +285,7 @@ public final class PermissionHelper {
* @param portal <p>The portal to check</p> * @param portal <p>The portal to check</p>
* @return <p>True if the given player can see the given portal</p> * @return <p>True if the given player can see the given portal</p>
*/ */
public static boolean canSeePortal(Player player, Portal portal) { public static boolean canSeePortal(@NotNull Player player, @NotNull Portal portal) {
//The portal is not hidden //The portal is not hidden
if (!portal.getOptions().isHidden()) { if (!portal.getOptions().isHidden()) {
return true; return true;
@@ -275,7 +305,7 @@ public final class PermissionHelper {
* @param portal <p>The private portal used</p> * @param portal <p>The private portal used</p>
* @return <p>True if the player is allowed to use the portal</p> * @return <p>True if the player is allowed to use the portal</p>
*/ */
public static boolean canUsePrivatePortal(Player player, Portal portal) { public static boolean canUsePrivatePortal(@NotNull Player player, @NotNull Portal portal) {
//Check if the player is the owner of the gate //Check if the player is the owner of the gate
if (portal.isOwner(player)) { if (portal.isOwner(player)) {
return true; return true;
@@ -291,7 +321,7 @@ public final class PermissionHelper {
* @param option <p>The option the player is trying to use</p> * @param option <p>The option the player is trying to use</p>
* @return <p>True if the player is allowed to create a portal with the given option</p> * @return <p>True if the player is allowed to create a portal with the given option</p>
*/ */
public static boolean canUseOption(Player player, PortalOption option) { public static boolean canUseOption(@NotNull Player player, @NotNull PortalOption option) {
return hasPermission(player, option.getPermissionString()); return hasPermission(player, option.getPermissionString());
} }
@@ -302,7 +332,7 @@ public final class PermissionHelper {
* @param network <p>The network the player is trying to create a gate on</p> * @param network <p>The network the player is trying to create a gate on</p>
* @return <p>True if the player is allowed to create the new gate</p> * @return <p>True if the player is allowed to create the new gate</p>
*/ */
public static boolean canCreateNetworkGate(Player player, String network) { public static boolean canCreateNetworkGate(@NotNull Player player, @NotNull String network) {
//Check if the player is allowed to create a portal on any network //Check if the player is allowed to create a portal on any network
if (hasPermission(player, "stargate.create.network")) { if (hasPermission(player, "stargate.create.network")) {
//Check if the network has been explicitly denied //Check if the network has been explicitly denied
@@ -318,7 +348,7 @@ public final class PermissionHelper {
* @param player <p>The player trying to create the new gate</p> * @param player <p>The player trying to create the new gate</p>
* @return <p>True if the player is allowed</p> * @return <p>True if the player is allowed</p>
*/ */
public static boolean canCreatePersonalPortal(Player player) { public static boolean canCreatePersonalPortal(@NotNull Player player) {
return hasPermission(player, "stargate.create.personal"); return hasPermission(player, "stargate.create.personal");
} }
@@ -329,7 +359,7 @@ public final class PermissionHelper {
* @param gate <p>The gate type of the new portal</p> * @param gate <p>The gate type of the new portal</p>
* @return <p>True if the player is allowed to create a portal with the given gate layout</p> * @return <p>True if the player is allowed to create a portal with the given gate layout</p>
*/ */
public static boolean canCreatePortal(Player player, String gate) { public static boolean canCreatePortal(@NotNull Player player, @NotNull String gate) {
//Check if the player is allowed to create all gates //Check if the player is allowed to create all gates
if (hasPermission(player, "stargate.create.gate")) { if (hasPermission(player, "stargate.create.gate")) {
//Check if the gate type has been explicitly denied //Check if the gate type has been explicitly denied
@@ -346,7 +376,7 @@ public final class PermissionHelper {
* @param portal <p>The portal to destroy</p> * @param portal <p>The portal to destroy</p>
* @return <p>True if the player is allowed to destroy the portal</p> * @return <p>True if the player is allowed to destroy the portal</p>
*/ */
public static boolean canDestroyPortal(Player player, Portal portal) { public static boolean canDestroyPortal(@NotNull Player player, @NotNull Portal portal) {
String network = portal.getCleanNetwork(); String network = portal.getCleanNetwork();
//Use a special check for bungee portals //Use a special check for bungee portals
@@ -376,7 +406,8 @@ public final class PermissionHelper {
* @param event <p>The move event causing the teleportation</p> * @param event <p>The move event causing the teleportation</p>
* @return <p>True if the player cannot teleport. False otherwise</p> * @return <p>True if the player cannot teleport. False otherwise</p>
*/ */
public static boolean playerCannotTeleport(Portal entrancePortal, Portal destination, Player player, PlayerMoveEvent event) { public static boolean playerCannotTeleport(@Nullable Portal entrancePortal, @Nullable Portal destination,
@NotNull Player player, @Nullable PlayerMoveEvent event) {
//No portal or not open //No portal or not open
if (entrancePortal == null || !entrancePortal.isOpen()) { if (entrancePortal == null || !entrancePortal.isOpen()) {
return true; return true;
@@ -384,24 +415,27 @@ public final class PermissionHelper {
//Not open for this player //Not open for this player
if (!entrancePortal.getPortalOpener().isOpenFor(player)) { if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); new SGFormatBuilder(Message.ACCESS_DENIED).error(player);
} }
new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event); new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
return true; return true;
} }
//No destination //No destination
if (!entrancePortal.getOptions().isBungee() && destination == null) { boolean isBungee = entrancePortal.getOptions().isBungee();
if (!isBungee && destination == null) {
return true; return true;
} }
//Player cannot access portal //Player cannot access portal
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destination)) { if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destination)) {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); new SGFormatBuilder(Message.ACCESS_DENIED).error(player);
} }
new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event); new PlayerTeleporter(entrancePortal, player).teleportPlayer(entrancePortal, event);
Stargate.debug("PermissionHelper::playerCannotTeleport", "Closed portal because player is " +
"missing necessary permissions");
entrancePortal.getPortalOpener().closePortal(false); entrancePortal.getPortalOpener().closePortal(false);
return true; return true;
} }

View File

@@ -3,6 +3,7 @@ package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.container.ControlBlockUpdateRequest;
import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
@@ -10,6 +11,7 @@ import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.property.PortalLocation; import net.knarcraft.stargate.portal.property.PortalLocation;
import net.knarcraft.stargate.portal.property.PortalOptions; import net.knarcraft.stargate.portal.property.PortalOptions;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import net.knarcraft.stargate.portal.property.PortalStrings;
import net.knarcraft.stargate.portal.property.gate.Gate; import net.knarcraft.stargate.portal.property.gate.Gate;
import net.knarcraft.stargate.portal.property.gate.GateHandler; import net.knarcraft.stargate.portal.property.gate.GateHandler;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -20,11 +22,14 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional; import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.Waterlogged;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Scanner; import java.util.Scanner;
import static net.knarcraft.stargate.portal.PortalSignDrawer.markPortalWithInvalidGate; import static net.knarcraft.stargate.portal.PortalSignDrawer.markPortalWithInvalidGate;
@@ -43,7 +48,7 @@ public final class PortalFileHelper {
* *
* @param world <p>The world to save portals for</p> * @param world <p>The world to save portals for</p>
*/ */
public static void saveAllPortals(World world) { public static void saveAllPortals(@NotNull World world) {
Stargate.getStargateConfig().addManagedWorld(world.getName()); Stargate.getStargateConfig().addManagedWorld(world.getName());
String saveFileLocation = Stargate.getPortalFolder() + "/" + world.getName() + ".db"; String saveFileLocation = Stargate.getPortalFolder() + "/" + world.getName() + ".db";
@@ -52,17 +57,22 @@ public final class PortalFileHelper {
for (Portal portal : PortalRegistry.getAllPortals()) { for (Portal portal : PortalRegistry.getAllPortals()) {
//Skip portals in other worlds //Skip portals in other worlds
String worldName = portal.getWorld().getName(); if (portal.getWorld() == null) {
if (!worldName.equalsIgnoreCase(world.getName())) { Stargate.logSevere(String.format("Could not save portal %s because its world is null",
continue; portal.getName()));
} else {
String worldName = portal.getWorld().getName();
if (!worldName.equalsIgnoreCase(world.getName())) {
continue;
}
//Save the portal
savePortal(bufferedWriter, portal);
} }
//Save the portal
savePortal(bufferedWriter, portal);
} }
bufferedWriter.close(); bufferedWriter.close();
} catch (Exception e) { } catch (Exception exception) {
Stargate.logSevere(String.format("Exception while writing stargates to %s: %s", saveFileLocation, e)); Stargate.logSevere(String.format("Exception while writing stargates to %s: %s", saveFileLocation, exception));
} }
} }
@@ -73,13 +83,13 @@ public final class PortalFileHelper {
* @param portal <p>The portal to save</p> * @param portal <p>The portal to save</p>
* @throws IOException <p>If unable to write to the buffered writer</p> * @throws IOException <p>If unable to write to the buffered writer</p>
*/ */
private static void savePortal(BufferedWriter bufferedWriter, Portal portal) throws IOException { private static void savePortal(@NotNull BufferedWriter bufferedWriter, @NotNull Portal portal) throws IOException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
BlockLocation button = portal.getStructure().getButton(); BlockLocation button = portal.getStructure().getButton();
//WARNING: Because of the primitive save format, any change in order will break everything! //WARNING: Because of the primitive save format, any change in order will break everything!
builder.append(portal.getName()).append(':'); builder.append(portal.getName()).append(':');
builder.append(portal.getSignLocation().toString()).append(':'); builder.append(portal.getSignLocation()).append(':');
builder.append((button != null) ? button.toString() : "").append(':'); builder.append((button != null) ? button.toString() : "").append(':');
//Add removes config values to keep indices consistent //Add removes config values to keep indices consistent
@@ -87,7 +97,7 @@ public final class PortalFileHelper {
builder.append(0).append(':'); builder.append(0).append(':');
builder.append(portal.getYaw()).append(':'); builder.append(portal.getYaw()).append(':');
builder.append(portal.getTopLeft().toString()).append(':'); builder.append(portal.getTopLeft()).append(':');
builder.append(portal.getGate().getFilename()).append(':'); builder.append(portal.getGate().getFilename()).append(':');
//Only save the destination name if the gate is fixed as it doesn't matter otherwise //Only save the destination name if the gate is fixed as it doesn't matter otherwise
@@ -111,20 +121,24 @@ public final class PortalFileHelper {
* @param portal <p>The portal to save</p> * @param portal <p>The portal to save</p>
* @param builder <p>The string builder to append to</p> * @param builder <p>The string builder to append to</p>
*/ */
private static void savePortalOptions(Portal portal, StringBuilder builder) { private static void savePortalOptions(@NotNull Portal portal, @NotNull StringBuilder builder) {
PortalOptions options = portal.getOptions(); PortalOptions options = portal.getOptions();
builder.append(':'); builder.append(':');
builder.append(options.isHidden()).append(':'); builder.append(options.isHidden()).append(':');
builder.append(options.isAlwaysOn()).append(':'); builder.append(options.isAlwaysOn()).append(':');
builder.append(options.isPrivate()).append(':'); builder.append(options.isPrivate()).append(':');
builder.append(portal.getWorld().getName()).append(':'); if (portal.getWorld() != null) {
builder.append(portal.getWorld().getName()).append(':');
} else {
builder.append(':');
}
builder.append(options.isFree()).append(':'); builder.append(options.isFree()).append(':');
builder.append(options.isBackwards()).append(':'); builder.append(options.isBackwards()).append(':');
builder.append(options.isShown()).append(':'); builder.append(options.isShown()).append(':');
builder.append(options.isNoNetwork()).append(':'); builder.append(options.isNoNetwork()).append(':');
builder.append(options.isRandom()).append(':'); builder.append(options.isRandom()).append(':');
builder.append(options.isBungee()).append(':'); builder.append(options.isBungee()).append(':');
builder.append(options.isSilent()).append(':'); builder.append(options.isQuiet()).append(':');
builder.append(options.hasNoSign()); builder.append(options.hasNoSign());
} }
@@ -134,7 +148,7 @@ public final class PortalFileHelper {
* @param world <p>The world to load portals for</p> * @param world <p>The world to load portals for</p>
* @return <p>True if portals could be loaded</p> * @return <p>True if portals could be loaded</p>
*/ */
public static boolean loadAllPortals(World world) { public static boolean loadAllPortals(@NotNull World world) {
String location = Stargate.getPortalFolder(); String location = Stargate.getPortalFolder();
File database = new File(location, world.getName() + ".db"); File database = new File(location, world.getName() + ".db");
@@ -154,7 +168,7 @@ public final class PortalFileHelper {
* @param database <p>The database file containing the portals</p> * @param database <p>The database file containing the portals</p>
* @return <p>True if the portals were loaded successfully</p> * @return <p>True if the portals were loaded successfully</p>
*/ */
private static boolean loadPortals(World world, File database) { private static boolean loadPortals(@NotNull World world, @NotNull File database) {
int lineIndex = 0; int lineIndex = 0;
try { try {
Scanner scanner = new Scanner(database); Scanner scanner = new Scanner(database);
@@ -170,10 +184,9 @@ public final class PortalFileHelper {
"Starting post loading tasks", world)); "Starting post loading tasks", world));
doPostLoadTasks(world, needsToSaveDatabase); doPostLoadTasks(world, needsToSaveDatabase);
return true; return true;
} catch (Exception e) { } catch (Exception exception) {
Stargate.logSevere(String.format("Exception while reading stargates from %s: %d", database.getName(), Stargate.logSevere(String.format("Exception while reading stargates from %s: %d! Message: %s",
lineIndex)); database.getName(), lineIndex, exception.getMessage()));
e.printStackTrace();
} }
return false; return false;
} }
@@ -186,7 +199,7 @@ public final class PortalFileHelper {
* @param world <p>The world for which portals are currently being read</p> * @param world <p>The world for which portals are currently being read</p>
* @return <p>True if the read portal has changed and the world's database needs to be saved</p> * @return <p>True if the read portal has changed and the world's database needs to be saved</p>
*/ */
private static boolean readPortalLine(Scanner scanner, int lineIndex, World world) { private static boolean readPortalLine(@NotNull Scanner scanner, int lineIndex, @NotNull World world) {
String line = scanner.nextLine().trim(); String line = scanner.nextLine().trim();
//Ignore empty and comment lines //Ignore empty and comment lines
@@ -214,7 +227,7 @@ public final class PortalFileHelper {
* @param world <p>The world portals have been loaded for</p> * @param world <p>The world portals have been loaded for</p>
* @param needsToSaveDatabase <p>Whether the portal database's file needs to be updated</p> * @param needsToSaveDatabase <p>Whether the portal database's file needs to be updated</p>
*/ */
private static void doPostLoadTasks(World world, boolean needsToSaveDatabase) { private static void doPostLoadTasks(@NotNull World world, boolean needsToSaveDatabase) {
//Open any always-on portals. Do this here as it should be more efficient than in the loop. //Open any always-on portals. Do this here as it should be more efficient than in the loop.
PortalHandler.verifyAllPortals(); PortalHandler.verifyAllPortals();
int portalCount = PortalRegistry.getAllPortals().size(); int portalCount = PortalRegistry.getAllPortals().size();
@@ -224,11 +237,16 @@ public final class PortalFileHelper {
Stargate.logInfo(String.format("{%s} Loaded %d stargates with %d set as always-on", world.getName(), Stargate.logInfo(String.format("{%s} Loaded %d stargates with %d set as always-on", world.getName(),
portalCount, openCount)); portalCount, openCount));
//Re-draw the signs in case a bug in the config prevented the portal from loading and has been fixed since //Re-draw the signs in case a bug in the config prevented the portal from loading and has been fixed since
Stargate.debug("PortalFileHelper::doPostLoadTasks::update",
String.format("Queueing portal sign/button updates for %s", world));
for (Portal portal : PortalRegistry.getAllPortals()) { for (Portal portal : PortalRegistry.getAllPortals()) {
if (portal.isRegistered()) { if (portal.isRegistered() && portal.getWorld() != null && portal.getWorld().equals(world) &&
portal.drawSign(); world.getWorldBorder().isInside(portal.getSignLocation())) {
updatePortalButton(portal); Stargate.addControlBlockUpdateRequest(new ControlBlockUpdateRequest(portal));
Stargate.debug("UpdateSignsButtons", String.format("Queued sign and button updates for portal %s",
portal.getName()));
} }
} }
//Save the portals to disk to update with any changes //Save the portals to disk to update with any changes
@@ -246,10 +264,10 @@ public final class PortalFileHelper {
* @param lineIndex <p>The line index to report in case the user needs to fix an error</p> * @param lineIndex <p>The line index to report in case the user needs to fix an error</p>
* @return <p>True if the portal's data has changed and its database needs to be updated</p> * @return <p>True if the portal's data has changed and its database needs to be updated</p>
*/ */
private static boolean loadPortal(String[] portalData, World world, int lineIndex) { private static boolean loadPortal(@NotNull String[] portalData, @NotNull World world, int lineIndex) {
//Load min. required portal data //Load min. required portal data
String name = portalData[0]; String name = portalData[0];
BlockLocation button = (portalData[2].length() > 0) ? new BlockLocation(world, portalData[2]) : null; BlockLocation button = (!portalData[2].isEmpty()) ? new BlockLocation(world, portalData[2]) : null;
//Load the portal's location //Load the portal's location
PortalLocation portalLocation = new PortalLocation(); PortalLocation portalLocation = new PortalLocation();
@@ -275,7 +293,8 @@ public final class PortalFileHelper {
PortalOwner owner = new PortalOwner(ownerString); PortalOwner owner = new PortalOwner(ownerString);
//Create the new portal //Create the new portal
Portal portal = new Portal(portalLocation, button, destination, name, network, gate, owner, PortalStrings portalStrings = new PortalStrings(name, network, destination);
Portal portal = new Portal(portalLocation, button, portalStrings, gate, owner,
PortalHandler.getPortalOptions(portalData)); PortalHandler.getPortalOptions(portalData));
//Register the portal, and close it in case it wasn't properly closed when the server stopped //Register the portal, and close it in case it wasn't properly closed when the server stopped
@@ -285,27 +304,6 @@ public final class PortalFileHelper {
return buttonLocationChanged; return buttonLocationChanged;
} }
/**
* Updates a portal's button if it does not match the correct material
*
* @param portal <p>The portal update the button of</p>
*/
private static void updatePortalButton(Portal portal) {
BlockLocation buttonLocation = getButtonLocation(portal);
if (portal.getOptions().isAlwaysOn()) {
//Clear button if not already air or water
if (MaterialHelper.isButtonCompatible(buttonLocation.getType())) {
Material newMaterial = decideRemovalMaterial(buttonLocation, portal);
Stargate.addBlockChangeRequest(new BlockChangeRequest(buttonLocation, newMaterial, null));
}
} else {
//Replace button if the material does not match
if (buttonLocation.getType() != portal.getGate().getPortalButton()) {
generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw()));
}
}
}
/** /**
* Decides the material to use for removing a portal's button/sign * Decides the material to use for removing a portal's button/sign
* *
@@ -313,7 +311,8 @@ public final class PortalFileHelper {
* @param portal <p>The portal the button/sign belongs to</p> * @param portal <p>The portal the button/sign belongs to</p>
* @return <p>The material to use for removing the button/sign</p> * @return <p>The material to use for removing the button/sign</p>
*/ */
public static Material decideRemovalMaterial(BlockLocation location, Portal portal) { @NotNull
public static Material decideRemovalMaterial(@NotNull BlockLocation location, @NotNull Portal portal) {
//Get the blocks to each side of the location //Get the blocks to each side of the location
Location leftLocation = location.getRelativeLocation(-1, 0, 0, portal.getYaw()); Location leftLocation = location.getRelativeLocation(-1, 0, 0, portal.getYaw());
Location rightLocation = location.getRelativeLocation(1, 0, 0, portal.getYaw()); Location rightLocation = location.getRelativeLocation(1, 0, 0, portal.getYaw());
@@ -334,7 +333,7 @@ public final class PortalFileHelper {
* @param location <p>The location to check</p> * @param location <p>The location to check</p>
* @return <p>True if the location is underwater</p> * @return <p>True if the location is underwater</p>
*/ */
private static boolean isUnderwater(Location location) { private static boolean isUnderwater(@NotNull Location location) {
BlockData blockData = location.getBlock().getBlockData(); BlockData blockData = location.getBlock().getBlockData();
return blockData.getMaterial() == Material.WATER || return blockData.getMaterial() == Material.WATER ||
(blockData instanceof Waterlogged waterlogged && waterlogged.isWaterlogged()); (blockData instanceof Waterlogged waterlogged && waterlogged.isWaterlogged());
@@ -349,7 +348,7 @@ public final class PortalFileHelper {
* @param portal <p>The portal to update the button vector for</p> * @param portal <p>The portal to update the button vector for</p>
* @return <p>True if the calculated button location is not the same as the one in the portal file</p> * @return <p>True if the calculated button location is not the same as the one in the portal file</p>
*/ */
private static boolean updateButtonVector(Portal portal) { private static boolean updateButtonVector(@NotNull Portal portal) {
for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) { for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) {
BlockLocation controlLocation = portal.getLocation().getTopLeft().getRelativeLocation(control, BlockLocation controlLocation = portal.getLocation().getTopLeft().getRelativeLocation(control,
portal.getYaw()); portal.getYaw());
@@ -360,7 +359,7 @@ public final class PortalFileHelper {
BlockLocation oldButtonLocation = portal.getStructure().getButton(); BlockLocation oldButtonLocation = portal.getStructure().getButton();
if (oldButtonLocation != null && !oldButtonLocation.equals(buttonLocation)) { if (oldButtonLocation != null && !oldButtonLocation.equals(buttonLocation)) {
Stargate.addBlockChangeRequest(new BlockChangeRequest(oldButtonLocation, Material.AIR, null)); Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(oldButtonLocation, Material.AIR, null));
portal.getStructure().setButton(buttonLocation); portal.getStructure().setButton(buttonLocation);
return true; return true;
} }
@@ -375,13 +374,24 @@ public final class PortalFileHelper {
* @param portal <p>The portal to generate button for</p> * @param portal <p>The portal to generate button for</p>
* @param buttonFacing <p>The direction the button should be facing</p> * @param buttonFacing <p>The direction the button should be facing</p>
*/ */
public static void generatePortalButton(Portal portal, BlockFace buttonFacing) { public static void generatePortalButton(@NotNull Portal portal, @NotNull BlockFace buttonFacing) {
//Go one block outwards to find the button's location rather than the control block's location //Go one block outwards to find the button's location rather than the control block's location
BlockLocation button = getButtonLocation(portal); BlockLocation button = getButtonLocation(portal);
Directional buttonData = (Directional) Bukkit.createBlockData(portal.getGate().getPortalButton()); // If the button location is null here, it is assumed that the button generation wasn't necessary
buttonData.setFacing(buttonFacing); if (button == null) {
button.getBlock().setBlockData(buttonData); return;
}
if (!MaterialHelper.isButtonCompatible(button.getType())) {
@NotNull List<Material> possibleMaterials = MaterialHelper.specifiersToMaterials(
portal.getGate().getPortalButtonMaterials()).stream().toList();
Material buttonType = ListHelper.getRandom(possibleMaterials);
Directional buttonData = (Directional) Bukkit.createBlockData(buttonType);
buttonData.setFacing(buttonFacing);
button.getBlock().setBlockData(buttonData);
}
portal.getStructure().setButton(button); portal.getStructure().setButton(button);
} }
@@ -391,11 +401,16 @@ public final class PortalFileHelper {
* @param portal <p>The portal to find the button for</p> * @param portal <p>The portal to find the button for</p>
* @return <p>The location of the portal's button</p> * @return <p>The location of the portal's button</p>
*/ */
private static BlockLocation getButtonLocation(Portal portal) { @Nullable
public static BlockLocation getButtonLocation(@NotNull Portal portal) {
BlockLocation topLeft = portal.getTopLeft(); BlockLocation topLeft = portal.getTopLeft();
RelativeBlockVector buttonVector = portal.getLocation().getButtonVector(); RelativeBlockVector buttonVector = portal.getLocation().getButtonVector();
return topLeft.getRelativeLocation(buttonVector.addToVector(RelativeBlockVector.Property.OUT, 1),
portal.getYaw()); if (buttonVector == null) {
return null;
}
return topLeft.getRelativeLocation(buttonVector.addOut(1), portal.getYaw());
} }
} }

View File

@@ -0,0 +1,51 @@
package net.knarcraft.stargate.utility;
import org.bukkit.DyeColor;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A helper class for dealing with signs
*/
public final class SignHelper {
private SignHelper() {
}
/**
* Gets the lines of the given sign
*
* @param sign <p>The sign to get lines from</p>
* @return <p>The lines of the sign</p>
*/
@NotNull
public static String[] getLines(@NotNull Sign sign) {
return sign.getSide(Side.FRONT).getLines();
}
/**
* Gets the dye color of the given sign
*
* @param sign <p>The sign to check</p>
* @return <p>The dye currently applied to the sign</p>
*/
@Nullable
public static DyeColor getDye(@NotNull Sign sign) {
return sign.getSide(Side.FRONT).getColor();
}
/**
* Sets the text of a line on a sign
*
* @param sign <p>The sign to set text for</p>
* @param line <p>The line to set</p>
* @param text <p>The text to set</p>
*/
public static void setSignLine(@NotNull Sign sign, int line, @NotNull String text) {
sign.getSide(Side.FRONT).setLine(line, text);
}
}

View File

@@ -1,6 +1,8 @@
package net.knarcraft.stargate.utility; package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.teleporter.EntityTeleporter; import net.knarcraft.stargate.portal.teleporter.EntityTeleporter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -10,6 +12,7 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -31,7 +34,7 @@ public final class TeleportHelper {
* @param player <p>The player trying to teleport</p> * @param player <p>The player trying to teleport</p>
* @return <p>False if the player has leashed any creatures that cannot go through the portal</p> * @return <p>False if the player has leashed any creatures that cannot go through the portal</p>
*/ */
public static boolean noLeashedCreaturesPreventTeleportation(Player player) { public static boolean noLeashedCreaturesPreventTeleportation(@NotNull Player player) {
//Find any nearby leashed entities to teleport with the player //Find any nearby leashed entities to teleport with the player
List<Creature> nearbyCreatures = getLeashedCreatures(player); List<Creature> nearbyCreatures = getLeashedCreatures(player);
@@ -41,7 +44,6 @@ public final class TeleportHelper {
return false; return false;
} }
} }
//TODO: Improve this to account for any players sitting on any of the lead creatures
//If it's enabled, there is no problem //If it's enabled, there is no problem
if (Stargate.getGateConfig().handleLeashedCreatures()) { if (Stargate.getGateConfig().handleLeashedCreatures()) {
@@ -57,7 +59,8 @@ public final class TeleportHelper {
* @param player <p>The player to check</p> * @param player <p>The player to check</p>
* @return <p>A list of all creatures the player is holding in a leash (lead)</p> * @return <p>A list of all creatures the player is holding in a leash (lead)</p>
*/ */
public static List<Creature> getLeashedCreatures(Player player) { @NotNull
public static List<Creature> getLeashedCreatures(@NotNull Player player) {
List<Creature> leashedCreatures = new ArrayList<>(); List<Creature> leashedCreatures = new ArrayList<>();
//Find any nearby leashed entities to teleport with the player //Find any nearby leashed entities to teleport with the player
List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15); List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);
@@ -81,8 +84,8 @@ public final class TeleportHelper {
* @param exitDirection <p>The direction of any passengers exiting the stargate</p> * @param exitDirection <p>The direction of any passengers exiting the stargate</p>
* @param newVelocity <p>The new velocity of the teleported passenger</p> * @param newVelocity <p>The new velocity of the teleported passenger</p>
*/ */
public static void teleportAndAddPassenger(Entity targetVehicle, Entity passenger, Vector exitDirection, public static void teleportAndAddPassenger(@NotNull Entity targetVehicle, @NotNull Entity passenger,
Vector newVelocity) { @NotNull Vector exitDirection, @NotNull Vector newVelocity) {
Location passengerExit = targetVehicle.getLocation().clone().setDirection(exitDirection); Location passengerExit = targetVehicle.getLocation().clone().setDirection(exitDirection);
if (!passenger.teleport(passengerExit)) { if (!passenger.teleport(passengerExit)) {
Stargate.debug("TeleportHelper::handleVehiclePassengers", "Failed to teleport passenger" + Stargate.debug("TeleportHelper::handleVehiclePassengers", "Failed to teleport passenger" +
@@ -113,8 +116,9 @@ public final class TeleportHelper {
* @param exitRotation <p>The rotation of any passengers exiting the stargate</p> * @param exitRotation <p>The rotation of any passengers exiting the stargate</p>
* @param newVelocity <p>The new velocity of the teleported passengers</p> * @param newVelocity <p>The new velocity of the teleported passengers</p>
*/ */
public static void handleEntityPassengers(List<Entity> passengers, Entity entity, Portal origin, Portal target, public static void handleEntityPassengers(@NotNull List<Entity> passengers, @NotNull Entity entity,
Vector exitRotation, Vector newVelocity) { @NotNull Portal origin, @NotNull Portal target,
@NotNull Vector exitRotation, @NotNull Vector newVelocity) {
for (Entity passenger : passengers) { for (Entity passenger : passengers) {
List<Entity> passengerPassengers = passenger.getPassengers(); List<Entity> passengerPassengers = passenger.getPassengers();
if (!passengerPassengers.isEmpty()) { if (!passengerPassengers.isEmpty()) {
@@ -145,7 +149,7 @@ public final class TeleportHelper {
* @param origin <p>The portal the player is teleporting from</p> * @param origin <p>The portal the player is teleporting from</p>
* @param target <p>The portal the player is teleporting to</p> * @param target <p>The portal the player is teleporting to</p>
*/ */
public static void teleportLeashedCreatures(Player player, Portal origin, Portal target) { public static void teleportLeashedCreatures(@NotNull Player player, @NotNull Portal origin, @NotNull Portal target) {
//If this feature is disabled, just return //If this feature is disabled, just return
if (!Stargate.getGateConfig().handleLeashedCreatures()) { if (!Stargate.getGateConfig().handleLeashedCreatures()) {
return; return;
@@ -172,7 +176,7 @@ public final class TeleportHelper {
* @param entities <p>The list of entities to check</p> * @param entities <p>The list of entities to check</p>
* @return <p>True if at least one entity is not a player</p> * @return <p>True if at least one entity is not a player</p>
*/ */
public static boolean containsNonPlayer(List<Entity> entities) { public static boolean containsNonPlayer(@NotNull List<Entity> entities) {
for (Entity entity : entities) { for (Entity entity : entities) {
if (!(entity instanceof Player) || containsNonPlayer(entity.getPassengers())) { if (!(entity instanceof Player) || containsNonPlayer(entity.getPassengers())) {
return true; return true;
@@ -187,7 +191,7 @@ public final class TeleportHelper {
* @param entities <p>The list of entities to check</p> * @param entities <p>The list of entities to check</p>
* @return <p>True if at least one player is present among the passengers</p> * @return <p>True if at least one player is present among the passengers</p>
*/ */
public static boolean containsPlayer(List<Entity> entities) { public static boolean containsPlayer(@NotNull List<Entity> entities) {
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity instanceof Player || containsPlayer(entity.getPassengers())) { if (entity instanceof Player || containsPlayer(entity.getPassengers())) {
return true; return true;
@@ -202,7 +206,8 @@ public final class TeleportHelper {
* @param entities <p>The entities to check for players</p> * @param entities <p>The entities to check for players</p>
* @return <p>The found players</p> * @return <p>The found players</p>
*/ */
public static List<Player> getPlayers(List<Entity> entities) { @NotNull
public static List<Player> getPlayers(@NotNull List<Entity> entities) {
List<Player> players = new ArrayList<>(5); List<Player> players = new ArrayList<>(5);
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity instanceof Player) { if (entity instanceof Player) {
@@ -221,11 +226,12 @@ public final class TeleportHelper {
* @param destinationPortal <p>The portal the player is to exit from</p> * @param destinationPortal <p>The portal the player is to exit from</p>
* @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p> * @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p>
*/ */
public static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) { public static boolean playerCanTeleport(@NotNull Player player, @NotNull Portal entrancePortal,
@NotNull Portal destinationPortal) {
//Make sure the user can access the portal //Make sure the user can access the portal
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) { if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg")); new SGFormatBuilder(Message.ACCESS_DENIED).error(player);
} }
entrancePortal.getPortalOpener().closePortal(false); entrancePortal.getPortalOpener().closePortal(false);
return false; return false;
@@ -235,8 +241,8 @@ public final class TeleportHelper {
int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal); int cost = EconomyHelper.getUseCost(player, entrancePortal, destinationPortal);
boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost); boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
if (!canAffordFee) { if (!canAffordFee) {
if (!entrancePortal.getOptions().isSilent()) { if (!entrancePortal.getOptions().isQuiet()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds")); new SGFormatBuilder(Message.ECONOMY_INSUFFICIENT).error(player);
} }
return false; return false;
} }

View File

@@ -7,6 +7,7 @@ import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalOwner;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.World; import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -35,7 +36,7 @@ public final class UUIDMigrationHelper {
* *
* @param player <p>The player to migrate</p> * @param player <p>The player to migrate</p>
*/ */
public static void migrateUUID(OfflinePlayer player) { public static void migrateUUID(@NotNull OfflinePlayer player) {
Map<String, List<Portal>> playersToMigrate = getPlayersToMigrate(); Map<String, List<Portal>> playersToMigrate = getPlayersToMigrate();
String playerName = player.getName(); String playerName = player.getName();
@@ -53,7 +54,7 @@ public final class UUIDMigrationHelper {
migratePortalsToUUID(portalsOwned, player.getUniqueId()); migratePortalsToUUID(portalsOwned, player.getUniqueId());
//Remove the player to prevent the migration to happen every time the player joins //Remove the player to prevent the migration from happening every time the player joins
playersToMigrate.remove(playerName); playersToMigrate.remove(playerName);
} }
@@ -63,7 +64,7 @@ public final class UUIDMigrationHelper {
* @param portals <p>The portals to migrate</p> * @param portals <p>The portals to migrate</p>
* @param uniqueId <p>The unique ID of the portals' owner</p> * @param uniqueId <p>The unique ID of the portals' owner</p>
*/ */
private static void migratePortalsToUUID(List<Portal> portals, UUID uniqueId) { private static void migratePortalsToUUID(@NotNull List<Portal> portals, @NotNull UUID uniqueId) {
Set<World> worldsToSave = new HashSet<>(); Set<World> worldsToSave = new HashSet<>();
//Get the real portal from the copy and set UUID //Get the real portal from the copy and set UUID
@@ -86,6 +87,7 @@ public final class UUIDMigrationHelper {
* *
* @return <p>The player names to migrate</p> * @return <p>The player names to migrate</p>
*/ */
@NotNull
private static Map<String, List<Portal>> getPlayersToMigrate() { private static Map<String, List<Portal>> getPlayersToMigrate() {
//Make sure to only go through portals once //Make sure to only go through portals once
if (playerNamesToMigrate != null) { if (playerNamesToMigrate != null) {

View File

@@ -1,7 +1,8 @@
lang=language lang=language
defaultNetwork=defaultGateNetwork defaultNetwork=gates.defaultGateNetwork
use-mysql= use-mysql=
ignoreEntrance= ignoreEntrance=
enableEconomy=economy.useEconomy
portal-save-location=folders.portalFolder portal-save-location=folders.portalFolder
portal-folder=folders.portalFolder portal-folder=folders.portalFolder
gate-folder=folders.gateFolder gate-folder=folders.gateFolder
@@ -16,7 +17,7 @@ sortLists=gates.cosmetic.sortNetworkDestinations
protectEntrance=gates.integrity.protectEntrance protectEntrance=gates.integrity.protectEntrance
enableBungee=gates.functionality.enableBungee enableBungee=gates.functionality.enableBungee
verifyPortals=gates.integrity.verifyPortals verifyPortals=gates.integrity.verifyPortals
signColor=gates.cosmetic.signColor signColor=gates.cosmetic.mainSignColor
gates.cosmetic.signColor=gates.cosmetic.mainSignColor gates.cosmetic.signColor=gates.cosmetic.mainSignColor
debug=debugging.debug debug=debugging.debug
permdebug=debugging.permissionDebug permdebug=debugging.permissionDebug
@@ -45,5 +46,6 @@ portal-open=
portal-closed= portal-closed=
cost-type= cost-type=
cost-to-activate= cost-to-activate=
taxaccount=taxAccount taxAccount=economy.taxAccount
taxaccount=economy.taxAccount
usevault= usevault=

View File

@@ -1,31 +1,137 @@
# stargate Configuration File # Version: ${project.version}
# Main stargate config # +--------------▄▄▄-- ‚——. -▄--▄-▄--▄-▄-▄▄▄▄▄---------------------------------------------------+ #
# | █▄▄▀ (“‡‡”) █▄▄▀ █▄▄▀ █ █ Support available at: sgrewritten.org/discord | #
# | █▄▄█ \__/ █ █ █ █ █ █ -. | #
# | —————————————————————————————————————————————————— ((_)) —————————————————— | #
# | - | #
# | .|'''.| |''||''| | '||''|. ..|'''.| | |''||''| '||''''| | #
# | ||.. ' || ||| || || .|' ' ||| || || . | #
# | ''|||. || | || ||''|' || .... | || || ||''| | #
# | . '|| || .''''|. || |. '|. || ; |. || || | #
# | '....|' .||. .|. .||. .||. '|' ''|...'| .|. .||. .||. .||.....| | #
# +----------------------------------------------------------------------------------------------+ #
# | UNIFIED LEGACY BRANCH | #
# +----------------------------------------------+-----------------------------------------------+ #
# | Documentation: sgrewritten.org/legacywiki | Bug Reports: sgrewritten.org/report | #
# +----------------------------------------------+-----------------------------------------------+ #
# language - The language file to load for messages (de,en,es,fr,hu,it,ja,nb-no,nl,nn-no,pt-br,ru,zh_cn) # +----------------------------------------------------------------------------------------------+ #
# | General Preferences | #
# +----------------------------------------------------------------------------------------------+ #
# What language will stargate use when communicating with your users?
# Supported values: [cs, de, en, es, fr, hu, it, ja, nb, nl, nn, pt, ru, sv, tr, uk, zh]
#
# If SG isn't yet available in your language, please consider adding a translation:
# https://sgrewritten.org/translate
# For more information on language codes, see ISO 639-1: https://git.io/JcwaI
language: en language: en
# adminUpdateAlert - Whether to alert admins about new plugin updates
# Would you like to us to notify admin users when new StarGate updates are available?
adminUpdateAlert: true adminUpdateAlert: true
folders:
# portalFolder - The folder for storing portals # +----------------------------------------------------------------------------------------------+ #
portalFolder: plugins/Stargate/portals/ # | Compatibility | #
# gateFolder - The folder for storing gate layouts # +----------------------------------------------------------------------------------------------+ #
gateFolder: plugins/Stargate/gates/ dynmap:
# Should StarGate enable integration with Dynmap? This will show StarGates on your map.
enableDynmap: true
# Should StarGate icons be hidden by default? (must users manually enable their checkbox?)
dynmapIconsHiddenByDefault: true
# +----------------------------------------------------------------------------------------------+ #
# | Gate Behaviour | #
# +----------------------------------------------------------------------------------------------+ #
gates: gates:
# maxGatesEachNetwork - The maximum number of gates allowed on a network - 0 for unlimited # What is the maximum number of gates a single network may contain? (0 for unlimited)
maxGatesEachNetwork: 0 maxGatesEachNetwork: 0
# defaultGateNetwork - The default gate network
# What network will be used when none has been specified? (Max length 12 characters)
#
# Note that this primarily applies to users with the stargate.create.network node.
# Generally, that node is given to staff (we recommend stargate.create.personal for users).
defaultGateNetwork: central defaultGateNetwork: central
# exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity
# At what speed should players be sent out of portals?
# When exiting a gate, players retain their original movement velocity, multiplied by this value.
exitVelocity: 0.1 exitVelocity: 0.1
functionality:
# Should an alternative (and less effective) teleportation script be used to teleport vehicles?
# This will fix an incompatibility with CraftBook, but will cause vehicles' data to be wiped on teleportation.
enableCraftBookRemoveOnEjectFix: false
# Are you connected to a BungeeCord-compatible proxy?
# Set this value to true if you intend on building gates with the bUngee flag.
enableBungee: false
# Will vehicles and their passengers be able to travel through StarGate portals?
# [minecarts, boats, & saddled mobs = vehicles | players & mobs = passengers]
handleVehicles: true
# Should vehicles without any passengers be allowed to go through a StarGate?
handleEmptyVehicles: true
# Should StarGate teleport creatures through portals?
# For example, if a player and a mob are in a boat, should the teleportation be allowed?
handleCreatureTransportation: true
# If handleCreatureTransportation is true, must the player be present?
# I.e., can a mob in a vehicle go through a gate on its own?
handleNonPlayerVehicles: true
# Should StarGate also handle creatures attached to a player via a lead?
handleLeashedCreatures: true
integrity:
# Can StarGates be broken via an explosion?
# [tnt, creepers, etc.]
destroyedByExplosion: false
# Will the server re-verify all existing portals on startup?
#
# This checks that the expected gates are both present and using a valid layout.
# Designed to catch .gate file modifications, world changes, and terrain regeneration.
#
# …««»»… If you set this to true, you should also set protectEntrance (below) to true!
# “NOTE” Otherwise, disallowed players, block updates, and snowmen can invalidate your portals!
verifyPortals: false
# Should the portal verification process account for iris (open/closed) materials?
# i.e. will a gate still validate if its portal-open material isn't present?
#
# This is more resource intensive, and should really only be used if verifyPortals is true.
# Or if using an easily destroyable open/closed material.
protectEntrance: false
# How many ticks should go between each Stargate control update? This process updates any signs that have incorrect
# information, and buttons that are missing. While a value of one works fine for small servers with few Stargates,
# it has been known to cause lag and high initial RAM usage for huge servers. A value of 20 is one second, which
# should work no matter how many Stargates the server has.
controlUpdateDelay: 3
# +----------------------------------------------------------------------------------------------+ #
# | Aesthetic Tweaks | #
# +----------------------------------------------------------------------------------------------+ #
cosmetic: cosmetic:
# rememberDestination - Whether to remember the cursor location between uses # Will the destination a networked portal last connected to be listed first in its scroll menu?
rememberDestination: false rememberDestination: false
# sortNetworkDestinations - Whether to sort network lists alphabetically
# For networked gates, are destinations listed alphabetically instead of chronologically?
# (This applies to all non-fixed and non-random gates).
sortNetworkDestinations: false sortNetworkDestinations: false
# mainSignColor - The color used for drawing signs (Default: BLACK).
# What color will StarGate use for the text on gate signs?
# Note that players can override this with DYE and/or GLOW_INK_SAC
mainSignColor: BLACK mainSignColor: BLACK
# highlightSignColor - The color used for sign markings (Default: WHITE)
# What color will StarGate use to accent the above text?
highlightSignColor: WHITE highlightSignColor: WHITE
# Text and highlight colors can be modified on a per-sign basis (below).
# Format: 'SIGN_TYPE:mainSignColor,highlightSignColor'
perSignColors: perSignColors:
- 'ACACIA:default,default' - 'ACACIA:default,default'
- 'BIRCH:default,default' - 'BIRCH:default,default'
@@ -35,73 +141,90 @@ gates:
- 'OAK:default,default' - 'OAK:default,default'
- 'SPRUCE:inverted,inverted' - 'SPRUCE:inverted,inverted'
- 'WARPED:inverted,inverted' - 'WARPED:inverted,inverted'
integrity: - 'BAMBOO:default,default'
# destroyedByExplosion - Whether to destroy gates with explosions (Creeper, TNT, etc.) - 'CHERRY:default,default'
destroyedByExplosion: false - 'PALE_OAK:default,default'
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded. - 'MANGROVE:default,default'
verifyPortals: false
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using
# destroyable open/closed material)
protectEntrance: false
functionality:
enableBungee: false
# handleVehicles - Whether to allow vehicles through gates. This overrides other vehicle settings
handleVehicles: true
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
handleEmptyVehicles: true
# handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts,
# boats) through gates
handleCreatureTransportation: true
# handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates.
# handleCreatureTransportation must be enabled
handleNonPlayerVehicles: true
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
handleLeashedCreatures: true
# enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle
# teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
enableCraftBookRemoveOnEjectFix: false
# ######################## #
# stargate economy options #
# ######################## #
economy: economy:
# useEconomy - Whether to use an economy plugin # When scrolling through a networked portal's destination list, should SG color free gates?
useEconomy: false
# createCost - The cost to create a gate
createCost: 0
# destroyCost - The cost to destroy a gate
destroyCost: 0
# useCost - The cost to use a gate
useCost: 0
# toOwner - Whether the charge for using a gate goes to the gate's owner
toOwner: false
# chargeFreeDestination - Whether a gate whose destination is a free gate is still charged
chargeFreeDestination: true
# freeGatesColored - Whether a free gate in the destination list is marked with a color
freeGatesColored: false freeGatesColored: false
# freeGatesColor - The color to use for marking free gates
# If freeGatesColored is true, which color should SG use?
#
# All color names should be a hex RGB color (#ffffff) or follow this format:
# https://hub.spigotmc.org/javadocs/spigot/org/bukkit/ChatColor.html
freeGatesColor: DARK_GREEN freeGatesColor: DARK_GREEN
# ############# # # +----------------------------------------------------------------------------------------------+ #
# Debug options # # | Economy | #
# ############# # # +----------------------------------------------------------------------------------------------+ #
debugging:
# debug - Debug -- Only enable if you have issues, massive console output
debug: false
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging
# (Requires debug: true)
permissionDebug: false
advanced:
# waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle.
# On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
waitForPlayerAfterTeleportDelay: 6
# ############## # # Will StarGate interact with your server's economy?
# Dynmap options # #
# ############## # # …««»»… For these features, StarGate depends on the Vault plugin.
dynmap: # “NOTE” https://www.spigotmc.org/resources/vault.34315/
# enableDynmap - Whether to display Stargates in Dynmap's map useEconomy: false
enableDynmap: true
# dynmapIconsHiddenByDefault - Whether to hide the set of Stargate icons by default, requiring users to # How much will be deducted from players' accounts when creating a new gate?
# manually enable them with a checkbox. createCost: 0
dynmapIconsHiddenByDefault: true
# How much will be deducted from players' accounts when destroying an existing gate?
destroyCost: 0
# How much will be deducted from players' accounts when using a stargate to teleport?
# This does not apply to stargates with the Free flag.
useCost: 0
# Will fees collected for usecost be paid to whomever created (owns) the applicable stargate?
# If false, collected funds will be deleted.
toOwner: false
# Will createcost still be charged if the new gate's destination is a gate with the Free flag?
# Note that this only applies to fixed gates.
chargeFreeDestination: true
# Does your server have a tax account (closed economy)?
# If so, please provide the name of your tax account (collected money will be sent to it).
# If not, leave this section blank (collected money will be deleted).
#
# Note that useCost money is excluded from this system when toOwner is true.
taxAccount: ''
# +----------------------------------------------------------------------------------------------+ #
# | Technical | #
# +----------------------------------------------------------------------------------------------+ #
# | [ Storage ] | #
# |__ These settings are provided to customise how SG stores its data. __| #
folders:
# Currently, all valid gates, their details, and their owners, are stored in a flatfile database
# Where should that flatfile be stored?
#
# This option is provided as a patch to allow data to be imported from some older forks.
portalFolder: plugins/Stargate/portals/
# Currently, on startup, a folder is checked for gate layouts stored as .gate files.
# Where is that folder?
#
# This option is provided as a patch to allow data to be imported from some older forks.
gateFolder: plugins/Stargate/gates/
# | [ Debug ] | #
# |__ These settings are provided to help developers diagnose issues with this plugin. __| #
debugging:
# Should SG spam console with A LOT of technical information?
# This includes checks, events, etc.
debug: false
# Should SG spam console with A LOT of permission-based information?
# This visualises how stargate determines what players can do.
#
# Note that (regardless of this setting), permdebug is always hidden when debug is false.
permissionDebug: false
advanced:
# How long should SG wait before returning players to their vehicles after teleportation?
# This is done to prevent possible visual bugs; slower servers need larger values.
# In most cases, a value of 6 should be fine.
waitForPlayerAfterTeleportDelay: 6

View File

@@ -0,0 +1,12 @@
portal-open=WATER
portal-closed=AIR
button=STONE_BUTTON
toowner=false
X=#WOOL
-=#WOOL
XXXXX
X...X
-...-
X.*.X
XXXXX

View File

@@ -0,0 +1,28 @@
# Stargate Legacy Localisation File: Czech
# For a more intuitive interface, please use https://translate.sgrewritten.org
author=Domavatus
bungeeDeny=Nemáte oprávnění vytvářet bungee brány!
bungeeDisabled=Podpora Bungeecord není povolena.
bungeeEmpty=Starší bungee brány vyžadují určení cílové brány a server.
createConflict=Tato brána je v konfliktu s existující branou.
createExists=Brána se stejným názvem již existuje.
createFull=Tato síť je plná!
createGateDeny=Nemáte přístup k tomuto schématu brány!
createNameLength=Název je příliš krátký nebo příliš dlouhý!
createNetDeny=Nemáte přístup k této síti!
createPersonal=Vytváření brány v osobní síti.
denyMsg=Přístup zamítnut!
destEmpty=Seznam cílů je prázdný!
destroyMsg=Brána zničena!
ecoDeduct=Odečteno %cost%.
ecoInFunds=Nedostatek prostředků!
ecoObtain=Získáno %cost% od Hvězdné brány %portal%.!
invalidMsg=Neplatný cíl!
prefix=[Stargate]
reloaded=Konfigurace obnovena!
signDisconnected=Odpojeno
signRandom=Náhodná
signRightClick=Pravý klik
signToUse=k použití brány
teleportMsg=Teleportován!

View File

@@ -1,28 +1,32 @@
author=EduardBaer # Stargate Legacy Localisation File: German
prefix=[Stargate] # For a more intuitive interface, please use https://translate.sgrewritten.org
teleportMsg=Du wurdest Teleportiert.
destroyMsg=Gate zerstört author=EduardBaer & Matriarch!
invalidMsg=Ungültiges Ziel
blockMsg=Ziel blockiert blockMsg=Ziel blockiert
destEmpty=Zielliste leer bungeeDeny=Du hast keine Berechtigung, Bungee-Tore zu erstellen!
denyMsg=Zugriff verweigert bungeeDisabled=Bungeecord-Unterstützung ist nicht aktiviert.
bungeeEmpty=Legacy-Bungee-Gates erfordern, dass Sie ein Zieltor und einen Server angeben.
ecoDeduct=%cost% abgezogen createConflict=Dieses Tor steht im Widerspruch zu einem bestehenden Tor.
ecoRefund=%cost% zurückerstattet createExists=Es existiert schon ein Portal mit diesem Namen.
ecoObtain=%cost% von Stargate %portal% erhalten createFull=Dieses Netzwerk ist voll !
ecoInFunds=Das kannst du dir nicht leisten. createGateDeny=Du hast kein Zugang zu dieses Portal format!
createMsg=Gate erstellt. createMsg=Gate erstellt.
createNetDeny=Du hast keinen Zugriff auf dieses Netzwerk. createNameLength=Name zu kurz oder zu lang!
createGateDeny=Du hast keinen Zugriff auf dieses Gate-Layout. createNetDeny=Du hast kein Zugang zu dieses Netzwerk!
createPersonal=Gate im persönlichen Netzwerk erstellt. createPersonal=Erstelle Tor im persönlichen Netzwerk.
createNameLength=Name zu kurz oder zu lang.
createExists=Ein Gate mit diesem Name existiert bereits.
createFull=Dieses Netzwerk ist voll.
createWorldDeny=Du hast keinen Zugriff auf diese Welt. createWorldDeny=Du hast keinen Zugriff auf diese Welt.
createConflict=Dieses Gate steht im Konflikt mit einem bereits existierenden. denyMsg=Zugang verweigert!
destEmpty=Zielliste ist leer!
signRightClick=Right click destroyMsg=Tor zerstört
signToUse=to use gate ecoDeduct=%cost% abgezogen .
signRandom=Random ecoInFunds=Unzureichende Mittel
signDisconnected=Disconnected ecoObtain=%cost% von StarGate %portal% erhalten!
ecoRefund=%cost% zurückerstattet
invalidMsg=Ungültiger Ziel!
prefix=[Stargate]
reloaded=Konfiguration wurde neu geladen!
signDisconnected=Verbindung getrennt
signRandom=Willkürlich
signRightClick=Rechtsklick
signToUse=um Tor zu benutzen
teleportMsg=Teleportiert!

View File

@@ -1,43 +1,41 @@
prefix=[Stargate] # Stargate Legacy Localisation File: English
teleportMsg=Teleported # For a more intuitive interface, please use https://translate.sgrewritten.org
destroyMsg=Gate Destroyed
invalidMsg=Invalid Destination
blockMsg=Destination Blocked blockMsg=Destination Blocked
destEmpty=Destination List Empty
denyMsg=Access Denied
reloaded=Stargate Reloaded
ecoDeduct=Deducted %cost%
ecoRefund=Refunded %cost%
ecoObtain=Obtained %cost% from Stargate %portal%
ecoInFunds=Insufficient Funds
ecoLoadError=Vault was loaded, but no economy plugin could be hooked into
vaultLoadError=Economy is enabled but Vault could not be loaded. Economy disabled
vaultLoaded=Vault v%version% found
createMsg=Gate Created
createNetDeny=You do not have access to that network
createGateDeny=You do not have access to that gate layout
createPersonal=Creating gate on personal network
createNameLength=Name too short or too long.
createExists=A gate by that name already exists
createFull=This network is full
createWorldDeny=You do not have access to that world
createConflict=Gate conflicts with existing gate
signRightClick=Right click
signToUse=to use gate
signRandom=Random
signDisconnected=Disconnected
signInvalidGate=Invalid gate
bungeeDisabled=BungeeCord support is disabled.
bungeeDeny=You do not have permission to create BungeeCord gates. bungeeDeny=You do not have permission to create BungeeCord gates.
bungeeDisabled=BungeeCord support is disabled.
bungeeEmpty=BungeeCord gates require both a destination and network. bungeeEmpty=BungeeCord gates require both a destination and network.
bungeeSign=Teleport to bungeeSign=Teleport to
createConflict=Gate conflicts with existing gate
portalInfoTitle=[STARGATE INFO] createExists=A gate by that name already exists
portalInfoName=Name: %name% createFull=This network is full
createGateDeny=You do not have access to that gate layout
createMsg=Gate Created
createNameLength=Name too short or too long.
createNetDeny=You do not have access to that network
createPersonal=Creating gate on personal network
createWorldDeny=You do not have access to that world
denyMsg=Access Denied
destEmpty=Destination List Empty
destroyMsg=Gate Destroyed
ecoDeduct=Deducted %cost%
ecoInFunds=Insufficient Funds
ecoLoadError=Vault was loaded, but no economy plugin could be hooked into
ecoObtain=Obtained %cost% from Stargate %portal%
ecoRefund=Refunded %cost%
invalidMsg=Invalid Destination
portalInfoDestination=Destination: %destination% portalInfoDestination=Destination: %destination%
portalInfoName=Name: %name%
portalInfoNetwork=Network: %network% portalInfoNetwork=Network: %network%
portalInfoServer=Server: %server% portalInfoServer=Server: %server%
portalInfoTitle=[STARGATE INFO]
prefix=[Stargate]
reloaded=Stargate Reloaded
signDisconnected=Disconnected
signInvalidGate=Invalid gate
signRandom=Random
signRightClick=Right click
signToUse=to use gate
teleportMsg=Teleported
vaultLoadError=Economy is enabled but Vault could not be loaded. Economy disabled
vaultLoaded=Vault v%version% found

View File

@@ -1,28 +1,32 @@
author=Manuestaire # Stargate Legacy Localisation File: Spanish
prefix=[Stargate] # For a more intuitive interface, please use https://translate.sgrewritten.org
teleportMsg=Teletransportado
destroyMsg=Portal Destruído author= Manuestaire & Translated s.r.l.
invalidMsg=Elige Destino
blockMsg=Destino Bloqueado blockMsg=Destino Bloqueado
destEmpty=La lista de destinos está vacía bungeeDeny=¡No tienes permiso para hacer puertas bungee!
denyMsg=Acceso denegado bungeeDisabled=El soporte de Bungeecord no está habilitado.
bungeeEmpty=Las puertas bungee antiguas requieren que especifiques una puerta de destino y un servidor.
ecoDeduct=Pagaste %cost% createConflict=Esta puerta entra en conflicto con una puerta existente.
ecoRefund=Reembolsado %cost% createExists=¡Ya existe una puerta con ese nombre!
ecoObtain=Obtenido %cost% del Portal %portal% createFull=¡Esa red está llena!
ecoInFunds=No tienes suficiente dinero createGateDeny=¡No tienes acceso a ese diseño de puerta!
createMsg=Portal creado createMsg=Portal creado
createNetDeny=No tienes acceso a esta red createNameLength=¡Nombre demasiado corto o demasiado largo!
createGateDeny=No tienes acceso a este diseño de portal createNetDeny=¡No tienes acceso a esa red!
createPersonal=Creando el portal en una red personal createPersonal=Creando puerta en la red personal.
createNameLength=Nombre demasiado largo o demasiado corto
createExists=Ya existe una puerta con este nombre
createFull=Esta red está llena
createWorldDeny=No tienes permisos para acceder a ese mundo createWorldDeny=No tienes permisos para acceder a ese mundo
createConflict=El portal entra en conflicto con un portal ya existente denyMsg=¡Acceso denegado!
destEmpty=¡Lista de destinos vacía!
signRightClick=Click derecho destroyMsg=¡Puerta destruida!
signToUse=para usar ecoDeduct=Se han restado %cost%.
signRandom=Aleatorio ecoInFunds=¡Fondos insuficientes!
ecoObtain=¡Has obtenido %cost% del portal %portal% de StarGate!
ecoRefund=Reembolsado %cost%
invalidMsg=¡Destino no válido!
prefix=[Stargate]
reloaded=¡Configuración cargada!
signDisconnected=Desconectado signDisconnected=Desconectado
signRandom=Aleatorio
signRightClick=Clic derecho
signToUse=y usa la puerta
teleportMsg=¡Teletransportación completada!

View File

@@ -1,28 +1,42 @@
author=Dauphin14 # Stargate Legacy Localisation File: French
prefix=[Stargate] # For a more intuitive interface, please use https://translate.sgrewritten.org
teleportMsg=Téléportation Réussie.
destroyMsg=Portail detruit. author=Damiendier
invalidMsg=Destination invalide.
blockMsg=Destination bloquée. blockMsg=Destination bloquée.
destEmpty=Aucune Destination disponible. bungeeDeny=Vous n'avez pas la permission de faire des Portail bungee !
denyMsg=Accès Refusé. bungeeDisabled=La prise en charge de Bungeecord n'est pas activée.
bungeeEmpty=Legacy bungee vous demandent de spécifier un portail de destination et un serveur.
ecoDeduct=Retrait de %cost%. bungeeSign=Téléportation vers :
ecoRefund=Remboursement de %cost%. createConflict=Ce portail entre en conflit avec un portail existant.
ecoObtain=Gain de %cost% du Portail %portal%. createExists=Un portail portant ce nom existe déjà !
ecoInFunds=Ressources insuffisantes. createFull=Ce réseau est plein !
createGateDeny=Vous n'avez pas accès à la disposition de ce Portail !
createMsg=Portail Créé createMsg=Portail créée
createNetDeny=Vous n'avez pas accès à ce réseau. createNameLength=Nom trop court ou trop long !
createGateDeny=Vous n'avez pas accès à ce type de portail. createNetDeny=Vous n'avez pas accès à ce réseau !
createPersonal=Portail créé sur le réseau personnel. createPersonal=Création d'un Portail sur le réseau personnel.
createNameLength=Nom trop long ou trop court. createWorldDeny=Vous n'avez pas accès à ce monde !
createExists=Il existe déjà un portail avec le même nom. denyMsg=Accès refusé !
createFull=Le reseau est plein. destEmpty=Liste de destination vide !
createWorldDeny=Vous n'avez pas accès à ce monde. destroyMsg=Portail détruit !
createConflict=Ce portail entre en conflit avec un portail déjà existant. ecoDeduct=Déduction de %cost%.
ecoInFunds=Fonds insuffisants !
signRightClick=Right click ecoLoad=Vault a été chargé, mais aucun plugin d'économie n'a pu être connecté
signToUse=to use gate ecoObtain=Obtenu %cost% par StarGate %portal% !
signRandom=Random ecoRefund=%cost% remboursé
signDisconnected=Disconnected invalidMsg=Destination invalide !
portalInfoDestination=Destination : %destination%
portalInfoName=Nom : %name%
portalInfoNetwork=%network%
portalInfoServer=%server%
portalInfoTitle=[STARGATE INFO]
prefix=[Stargate]
reloaded=Configuration rechargée !
signDisconnected=Déconnecté
signInvalidGate=Portail invalide
signRandom=Aléatoire
signRightClick=Clic droit
signToUse=pour utiliser le portail
teleportMsg=Téléporté !
vaultLoadError=L'économie est activée, mais Vault n'a pas pu être chargé. Économie désactivée
vaultLoaded=Vault v%version% trouvé

View File

@@ -1,28 +1,28 @@
# Stargate Legacy Localisation File: Hungarian
# For a more intuitive interface, please use https://translate.sgrewritten.org
author=HPoltergeist author=HPoltergeist
prefix=[Stargate]
teleportMsg=Teleportálás
destroyMsg=Kapu törölve
invalidMsg=Nincs ilyen cél
blockMsg=Cél blokkolva blockMsg=Cél blokkolva
destEmpty=A cél lista üres createConflict=Ez a kapu ütközik egy meglévö kapuval.
denyMsg=Hozzáférés megtagadva createExists=Már van ilyen nevű kapu!
createFull=Ez a hálózat tele van!
ecoDeduct=%cost% levonva createGateDeny=Nincs hozzáférésed ahhoz a kapucsoporthoz!
ecoRefund=%cost% visszatérítve
ecoObtain=%cost% bevétel a következő kapuból: %portal%
ecoInFunds=Nincs elég pénzed
createMsg=Kapu elkészült createMsg=Kapu elkészült
createNetDeny=Nincs hozzáférésed ahhoz a hálózathoz createNameLength=A név túl rövid vagy túl hosszú!
createGateDeny=Nincs hozzáférésed ahhoz a kapucsoporthoz createNetDeny=Nincs hozzáférésed ahhoz a hálózathoz!
createPersonal=Kapu készítése magán hálózaton createPersonal=Kapu készítése magán hálózaton.
createNameLength=A név túl rövid vagy túl hosszú
createExists=Már van ilyen nevű kapu
createFull=Ez a hálózat tele van
createWorldDeny=Nincs hozzáférésed ahhoz a világhoz createWorldDeny=Nincs hozzáférésed ahhoz a világhoz
createConflict=Ez a kapu ütközik egy meglévö kapuval denyMsg=Hozzáférés megtagadva!
destEmpty=A cél lista üres!
destroyMsg=Kapu törölve!
ecoDeduct=%cost% levonva.
ecoInFunds=Nincs elég pénzed!
ecoObtain=%cost% bevétel a következő kapuból: %portal%!
ecoRefund=%cost% visszatérítve
invalidMsg=Nincs ilyen cél!
prefix=[Stargate]
signDisconnected=Szétkapcsolva
signRandom=Random
signRightClick=Jobb katt a signRightClick=Jobb katt a
signToUse=használathoz signToUse=használathoz
signRandom=Random teleportMsg=Teleportálás!
signDisconnected=Szétkapcsolva

View File

@@ -1,28 +1,32 @@
author=fr33soul # Stargate Legacy Localisation File: Italian
prefix=[Stargate] # For a more intuitive interface, please use https://translate.sgrewritten.org
teleportMsg=Teletrasporto
destroyMsg=Portale distrutto author=fr33soul & herbie_23
invalidMsg=Destinazione invalida
blockMsg=Destinazione bloccata blockMsg=Destinazione bloccata
destEmpty=Lista destinazioni vuota bungeeDeny=Non sei autorizzato a creare portali Bungee!
denyMsg=Accesso Negato bungeeDisabled=Il supporto a Bungeecord non è abilitato.
bungeeEmpty=I portali Bungee ereditari ti richiedono di specificare un portale e server di destinazione.
ecoDeduct=%cost% pagato createConflict=Questo portale è in conflitto con un portale esistente.
ecoRefund=%cost% rimborsato createExists=Un portale con quel nome esiste già!
ecoObtain=%cost% ottenuto dal portale %portal% createFull=Quella rete è al completo!
ecoInFunds=Credito insufficiente createGateDeny=Non hai accesso a quella disposizione del portale!
createMsg=Portale creato createMsg=Portale creato
createNetDeny=Non hai accesso a questa rete createNameLength=Nome troppo breve o troppo lungo!
createGateDeny=Non hai accesso a questo portale speciale createNetDeny=Non hai accesso a quella rete!
createPersonal=Creazione di un portale sulla rete personale createPersonal=Creazione del portale sulla rete personale.
createNameLength=Nome troppo corto o troppo lungo.
createExists=Questo nome gia' esiste
createFull=Questa rete e' piena
createWorldDeny=Non hai accesso a questo mondo createWorldDeny=Non hai accesso a questo mondo
createConflict=Il portale crea conflitti con uno gia' esistente denyMsg=Accesso negato!
destEmpty=Elenco delle destinazioni vuoto!
signRightClick=Right click destroyMsg=Portale distrutto!
signToUse=to use gate ecoDeduct=%cost% detratto.
signRandom=Random ecoInFunds=Fondi Insufficienti!
signDisconnected=Disconnected ecoObtain=%cost% ottenuto dallo StarGate %portal%!
ecoRefund=%cost% rimborsato
invalidMsg=Destinazione non valida!
prefix=[Stargate]
reloaded=Configurazione ricaricata!
signDisconnected=Disconnesso
signRandom=Casuale
signRightClick=Click destro
signToUse=usare portale
teleportMsg=Teletrasportato!

View File

@@ -1,44 +1,42 @@
author=furplag # Stargate Legacy Localisation File: Japanese
prefix=[Stargate] # For a more intuitive interface, please use https://translate.sgrewritten.org
teleportMsg=テレポート
destroyMsg=ゲートが破壊されました author=Furplag & Translated s.r.l.
invalidMsg=無効な行き先
blockMsg=ブロックされた行き先 blockMsg=ブロックされた行き先
destEmpty=行き先リストが空です bungeeDeny=バンジーゲートを作る権限がありません!
denyMsg=アクセスが拒否されました bungeeDisabled=Bungeecordサポートが有効になっていません。
reloaded= Stargate をリロードしました bungeeEmpty=従来のバンジーゲートでは、宛先ゲートとサーバーを指定する必要があります。
bungeeSign=テレポート先:
ecoDeduct=cost の値引き createConflict=このゲートは既存のゲートと競合します。
ecoRefund=cost の返金 createExists=その名前のゲートはすでに存在しています!
ecoObtain= Stargate portal から cost を得ました createFull=ネットワークがいっぱいです!
ecoInFunds=資金の不足 createGateDeny=そのゲートレイアウトへのアクセス権を持っていません!
ecoLoadError= Vault が読み込まれましたが、Economy プラグインをフックできませんでした
vaultLoadError=Economy は有効になっていますが、Vault をロードできないため Economy は無効化されました
vaultLoaded= Vault vversion が見つかりました
createMsg=ゲートが作成されました createMsg=ゲートが作成されました
createNetDeny=対象のネットワークにアクセスできません createNameLength=名前が短すぎるか、長すぎます!
createGateDeny=対象のゲートレイアウトにアクセスできません createNetDeny=そのネットワークへのアクセス権を持っていません
createPersonal=パーソナルネットワーク上にゲートを作成する createPersonal=パーソナルネットワーク上にゲートを作成します。
createNameLength=ゲート名が短すぎるか長すぎます
createExists=すでに存在するゲート名です
createFull=対象のネットワークはいっぱいです
createWorldDeny=あなたはその世界にアクセスできません createWorldDeny=あなたはその世界にアクセスできません
createConflict=ゲートが既存のゲートと競合しています denyMsg=アクセスが拒否されました!
destEmpty=目的地リストが空です!
signRightClick=右クリック destroyMsg=ゲートが破壊されました!
signToUse=ゲートを使用する ecoDeduct=%cost%を差し引きました。
signRandom=ランダム ecoInFunds=お金が足りません!
ecoLoad=Vault が読み込まれましたが、Economy プラグインをフックできませんでした
ecoObtain=StarGate%portal%から%cost%を入手しました!
ecoRefund=%cost% の返金
invalidMsg=目的地が無効です!
portalInfoDestination=行き先: %destination%
portalInfoName=ゲート名: %name%
portalInfoNetwork=ネットワーク: %network%
portalInfoServer=サーバー: %server%
portalInfoTitle=[STARGATE INFO]
prefix=[スターゲイト]
reloaded=設定をリロードしました!
signDisconnected=切断 signDisconnected=切断
signInvalidGate=無効なゲート signInvalidGate=無効なゲート
signRandom=ランダム
bungeeDisabled=BungeeCord サポートは無効になっています signRightClick=右クリック
bungeeDeny=BungeeCord ゲートを作成する権限がありません signToUse=ゲートの使用方法
bungeeEmpty=BungeeCord ゲートには、行き先とネットワークの両方が必要です teleportMsg=瞬間移動しました!
bungeeSign=テレポート先: vaultLoadError=Economy は有効になっていますが、Vault をロードできないため Economy は無効化されました
vaultLoaded=Vault v%version% が見つかりました
portalInfoTitle=[STARGATE INFO]
portalInfoName=ゲート名: name
portalInfoDestination=行き先: destination
portalInfoNetwork=ネットワーク: network
portalInfoServer=サーバー: server

Some files were not shown because too many files have changed in this diff Show More