This branch adds a world aspect to almost all commands. Although the
Bukkit World class is used for reference, the world includes any nether
or end worlds too. By enabling multiworld, things like the protection
grid will operate independently in different world groups. The idea is
to enable one plugin to run mutliple worlds. For example run AcidIsland,
ASkyGrid and BSkyBlock at the same time.
In addition to this big change, I added an admin command to copy and
paste "simple" schematics that I called "schems". It does not work
completely correctly right now, especially for chest contents.
Unit tests pass, not tested in-game yet. Still no WiFi.
North Platte, Nebraska. 1856km to San Francisco. 800kph ground speed.
107kph headwind. -56C outside temperature. 12035m altitude.
Unit test passes. Not tested in-game because I'm 9930m above Chicago,
it's 2858km to San Francisco, it's dark, I'm wearing sunglasses, and I
have no Wi-Fi!
A listener can be added to a flag. This listener is the same as a panel
item listener. When the settings flag is clicked, it'll call the
listener. There is a default listener. Right now the default is called
UpDownClick.java. This makes the rank go up when you left click and down
when you right click. Another implementation may be to just have the
rank loop around with left clicks.
I added two more ranks - Admin and Mod. These are special ranks that
have a value above owner. If a player is given this rank, they can
bypass protections. This will avoid the need to use permissions and also
enable islands to be set up that for example, only Admins can edit, but
Mods cannot.
So, it's now possible for an owner to lock out team members from the
island as well as visitors. This is a bit weird and so more click
classes should be created. For example, one that just toggles between
Owner and Visitor.
Currently, only an island owner can change settings, but this could be
expanded to allow members. Also, it will need to be expanded to allow
Admins.
Island lock is combined with island ban in terms of the Listener. It is
LockAndBanListener. It is a flag because after thinking about it, it
made sense to be just like any other island setting. Also, island owners
can now (in theory) lock out others by rank.
Although the test class says everything works, the Settings GUI needs to
enable toggling so that players can lock the island.
Enjoy banning players!
This prevents players from entering islands when they are banned. In the
future, it should also be extended to enable island locking.
Still needs a bit of work around Ops and bypass perms.
plugin.getLogger() is a final class and so cannot be mocked. It was
making development of tests very hard. By making three logging methods
in BSkyBlock.java, they default to do nothing when BSkyBlock is mocked.
Previously, every time there was a use of logger in testing it was
throwing NPE's because plugin.getLogger() was returning null and the
getLogger() method could not be made not null by mocking because it was
final (in JavaPlugin).
Needs more testing, but seems to work. The main problem is that it pulls
in the MongoDB Java driver which boosts the size of the JAR to 2.3MB. It
may be better to put the Mongo driver into an addon so that only Mongo
users have to have the larger JAR.
Splited TRAPDOOR from DOOR
Splited HURT_VILLAGERS from HURT_ANIMALS
Renamed HURT_MOBS to HURT_ANIMALS
Renamed MOB_SPAWN to ANIMAL_SPAWN
Made FIRE_SPREAD a SETTING type Flag
Fixed MobSpawnListener with mishandling of ANIMAL/MONSTER spawn
Added some code to the Flag, Flags and FlagManager classes to enable
passing the tests.
Realized that some flags had duplicate icons. This means that the
getFlagByIcon() method doesn't work because there could be more than
one. If we want to allow duplicate icons then we need to change the
manager. Also, do we need to getFlagByIcon method?
It currently just displays a panel with all the flags in it. And throws exception when clicking on an item :P
Flag no longer have a PanelItem but Material instead as the icon.
Added a toPanelItem() method in Flag
Made the Panel(Builder) not using the Optional as fields anymore
Added a method to easily get named addons from other addons.
Fixed bugs with addonclassloader.
Added ignores to some unavoidable line items
Added auto-cancel to panels so that items cannot be taken from them by
default.
It breaks the addon class loading and using lamda functions doesn't end
up being neater because it must be able to throw a
ClassNotFoundExcepetion to the Bukkit code.
Cleared up the description settings methods. Using these will add to the
description of the item.
Temporarily removed JavaDoc and Source jar creation from the POM to save
time when compiling. Will put it back when we need it.
Also, I worked out how to run the Bukkit server setup for tests. See the
setUp method in the tests. This works (at last).
It works, but it is more like a DIY patch thing. It has a few problems with the current implementation :
1. It doesn't suit our "code style" : it uses an Handler instead of a Manager, eg.
2. It is a bit laggy (I've got the feeling that it could be improved)
3. It doesn't hook to other Placeholder APIs for now
And a few other things.
I think this is more like a Proof of Concept : it will have to be improved in the next weeks.
Since Java 8, we can use Supplier for logger, which will be evaluated
lazily.
In general, the debug stuff should be removed when we have more
stability.
When File.delete fails, this boolean method simply returns false with no
indication of the cause. On the other hand, when Files.delete fails,
this void method returns one of a series of exception types to better
indicate the cause of the failure. More information is generally better
in a debugging situation, so I'll use this option.
When all the keys of a Map are values from the same enum, the Map can be
replaced with an EnumMap, which can be much more efficient than other
sets because the underlying data structure is a simple array.
This approach simulates an enum, but one that can be extended by others
to add custom flags. I added a handy values() method that uses
reflection to provide a list of all the flags in the class.
See TestBSkyBlock.java test classes for the tests of the default flag
registration and the custom flag registration.
Added the adapter annotation to MySQL and fixed issues with empty
hashmaps causing null errors.
Added a flag serializer adapter for the protection flags so that flags
are saved and loaded correctly.
Renamed the Adapter notation class to be clearer about what it is doing.
Added serializer adapter for the Flags hashmap in Island.
Teams don't work. Need to work out why.
PVP doesn't work correctly. It allows members to hit visitors anytime,
but visitors can only hit others if PVP is off. This isn't how it is
supposed to work!
This is required for automated testing (can't use static getInstance). I
really need automated testing of the protection classes, so even though
this adds a parameter to the classes, it's important to have it right
now.
Generally these are very easy to understand. They use an abstract class
for common code.
I have not tested these in-game. I would like to see if I can create
some test classes but it may not be possible because of the static
BSkyBlock calls.
There's a lot more that needs to be checked in these listeners! I moved
some common methods into the abstract class because they will be used
again and again by other listeners.
Added an anvil listener.
Added the flags. They were from ASkyBlock so may have name changes.
Made getIslandsAt() Optional to enable better code structures in the
listeners.
Created an abstract class to simplify flag protection listeners.
Added default setting for flags that will be able to be set by config.
This default is used for any space in the worlds not occupied by an
island.
While writing the admin tp command, I realized that subcommand aliases
were not working. Also, it was not possible to tell what alias had been
used for a command. I added that capability. i.e., if the alias is used,
then the label of that command is set to the alias.
When finding a spot for a new island, the algorithm will ensure the
island location is on the grid and check around for any blocks that may
be there already. If they exist, then they will be added as unowned
islands to the database.
The sign text was not using the correct locale tags.
Saves a backup of the config after validation in the database so it can
be checked.
To Be Done: Validation of the config when it is loaded against the
database version.
These methods are used specifically for loading and saving settings
classes (those use the ISettings interface). The saving saves a copy of
any settings class in the database for future reference. The loading
loads a copy from the database if it exists and checks if any fields are
different from the config file. If they are different and some action
needs to be taken, the action is taken. This is still be to be coded.
In other news, the saving of arrays is unsupported and currently should
be avoided. Use Lists or Sets instead.
Reworked locales so they use a nice and pretty folder structure.
Added the ability to define adapters to serialize certain data
structures. Added the PotionType list adapter.
Saving and loading of configs basically works. Known issues:
1. The config.yml is saved and loaded to/from the database folder
2. More error handling is required for the config loading. e.g., a list
value with only one value in it is not read as a list. This could get
tricky.
3. Comments are not saved (yet)
Currently it handles the @ConfigEntry path and specificTo fields.
Experimental: There is a class called Setting2.java. It has an
annotation that defines its filename as config.yml. Currently, it is
using the database folder as its location, but it could be the plugin's
datafolder in the future. By placing the config.yml file in the database
folder, it will be read. See the code in BSkyBlock onEnable() for how
that is done.
The main differences between Settings2.java and Settings.java are that
all fields are NOT static and therefore it is an object and uses getters
and setters. This is because it is a JavaBean. In other code, settings
should be queried using this config object.
Added the concept of an adapter class that would convert the YAML input
to the setting type and value.
I included an example adapter class for Enum.
I fixed a number of the settings to match the config/yml or the other
way around.
After compiling and running, do /bsb reload to see the result.
This is a WIP and obviously not finished.
a lot of unused/useless Settings has been removed
Settings class has been moved to the main package, because the config package would then only contain it
I need feedback about it
it was due to the null value possibly returned by the LocalesManager#get(user, reference) method when nothing has been found, leading the variables replacement to cause a NPE.
User#getTranslation(reference, ...variables) now does the check and return the reference if the translation found equals null BEFORE trying to replace variables.
User#getTranslationOrNothing(reference, ...variables) works the same as before, it just checks if the returned translation is the same than the reference (therefore it returns the blank String), otherwise it sends the translation.
Renamed island multihome to start with "Custom" to make it clearer. This
class is as much an example as anything of how to override the default
help.
Renamed my author tag to be tastybento. :-)
This is a more flexible and natural way to provide the display for the help, especially for the colors.
I had to remove the "/" from the usage though. If you think it should be there, re-add it but remove it from the locale then.
This is a first working version and can probably be improved.
Firstly, the plugin will save any BSkyBlock language files to the locale
folder from the BSkyBlock jar if and only if the locale folder does not
exist. It will then do the same for any addons as they are loaded. Addon
language files are prefixed with their addon name to keep them separate
and recongnizable.
Then the plugin loads the language files and merges common languages
together into a YAMLConfiguration that is held in memory. The combined
config is never saved out to the file system.
If a request is made for a particular reference to a language that does
not exist or if the reference does not exist, then the default language
is tried.
The original code did not allow addons to talk to each other in any way.
After trying loads of things with class path I studied the bukkit code
and saw that they override the findClass method in URLClassLoader. This
enables addons to find classes in other addons. All that was then needed
was a map in the AddonsManager of classes that this manager knows about
and a getter and setter method for them. After all that (3 hours) it
works.
I'm working on addons and realized it would be a better approach to be
able to register the listener for a panel explicitly for each panel.
This is optional. Also, added the ability to open the panel immediately
for a player.
Used reflection to get the command map from the server instead of using
the NMS call.
Also, more importantly, this commit enables CompositeCommands to
auto-register their top-level command in the constructor. No need to
separately obtain the command manager object. Yes, easy API. :-)
Moved PremadeEvent to api/events
Made use of PremadeEvent for all existing events
Renamed TeamReason to Reason in TeamEvent
Made the addon events follow the used builder pattern
Renamed #loadAddons() to #enableAddons() in AddonsManager
Added #disableAddons() in AddonsManager
Commands now require a setup to define their permission, player/console
status, description and any parameters they have. This is also where any
subcommands are created if they exist.
Each command automatically has a help subcommand. This is used to
display help. This will also recursively go to any other sub commands
and get help from them.
Note that getUsage() now *only* shows the command and any sub commands.
It turns out that Bukkit requires this to start with a / because it
actually uses this in its own help system and the server will not start
if it is not in the right format. Therefore I split off parameters into
their own string. This also enables them to be translatable.
Everything should work at this point. It's just waiting on the locale
system to work to display the strings in the locale files.
Sub commands work, tab complete works. See the TestIslandCommand.java
test command for how to use the API and unit tests.
Still need to do the auto-help.
Commands work and tab complete works somewhat.
Help still needs to be done. Added in NotSetup And PluginConfig to just
make the plugin work. It's fine to remove them when there is a working
alternative.
Removed the old localization system
Started implementation of the new one
For build reasons, removed protection listeners - they were requiring too much work to update them, and they need to be reworked due to the boilerplate code.
Implemented a recursive composite command that can be extended with
subcommands to infinity (and beyond!).
Composite command also tries to create help text and a list of help
commands. These are not current used and need more work.
This has not been tested yet completely.
Removed current config "API"
Removed a few unused or duplicate settings
Removed OfflineHistoryMessages
Removed visitor blocked commands (should be an addon)
This is a bit of a hack. The AbstractCommand class had to be pulled
apart to enable the ArgumentHandler to be imported by another plugin
without the other plugin having to extend AbstractCommand, which is
something it does not want to do because it is not defining a new
command, but just adding arguments.
There's too much passing of arguments in this implementation, but it
works. I'll see if I can simplify it.
This follows the proper builder approach, where all variables are
defined in a builder with a final build at the end to make the object.
The variables in the object are final so cannot be changed afterwards.
TeamEvent is used for all team events. Removed the extra classes that
are not needed anymore.
See this for a good summary on builder patterns:
http://minborgsjavapot.blogspot.com/2014/08/creating-objects-using-builder-pattern.html
Plan is to replace the island events with builder pattern too, so that
we only need one class for typical island events.
Changed the response for canUse to return an error code because the
error could be different depending on the reason. For tabComplete no
error is shown, but for commands, the error can be shown.
Implemented the invite and uninvite commands and filled in the team
command.
Args no longer include the sub-command, just the args after the sub
command.
Improved tab complete so that it completes half-written commands
Fixed deprecation issue with visitor guard.
* Added more database functions.
Added ability to check if a uniqueId exists without creating it - used
to check if a player is known or not.
Added join/quit listener.
* Hooked in grid database to track where islands are.
Added Nether events and portal function.
Added default /island command operation.
* Added protection for islands.
* Updated license to BSD license.
* Removed unused imports.
Added configs.
* Added more protection listeners.
Flying mobs, visitor protection
This is required when islands are reset or players deleted, for example.
The deletion is done based on the uniqueId of the object. Tested and
working for flat file and MySQL.
To make an island do /is create. To reset do /is reset.
Worked on PluginConfig.loadPluginConfig(). Changed the NotSetup
processing : when loading config, it will store errors and if there are,
it will run the plugin as "NotSetup" and send to users what is wrong and
why. Major parts are still remaining as it is a "preview" of an
unfinished and "waiting-for-improvements" work.
If the class to be saved does not define its own uuid, then one will be
generated at random by the database manager. For flat file databases,
the UUID is used for filenames. For other databases, it's an index
record. If the class defines a UUID then the same record will be
replaced again and again. i.e., it's like a config file.