Added Invincible Visitor settings.

This led to work to enable saving of the config.yml file with comments.
I added the ability to have multiple lines of comments as annotations.
I also enabled comments to align with the exact path of the field.
To do this I used BSBConfig for the Settings class and retired ISettings
When the plugin disables, it now saves the config.yml with comments and
the Invincible Visitor settings.

Note that any settings in the config.yml stored in the jar will still
exist in the file and stay there unless they are manually deleted. They
just will not have any comments on them after saving.
This commit is contained in:
tastybento 2018-06-05 00:06:55 -07:00
parent aed648e6e7
commit 8a339f755a
12 changed files with 380 additions and 163 deletions

View File

@ -1,8 +1,6 @@
############################################################################
# Config for BSkyBlock V${version} # Config for BSkyBlock V${version}
#
# Created and maintained by Tastybento with the help of Poslovitch # Created and maintained by Tastybento with the help of Poslovitch
############################################################################
### General Settings ### ### General Settings ###
general: general:
@ -324,16 +322,9 @@ protection:
# Includes blaze and ghast. # Includes blaze and ghast.
restrict-flying-mobs: true restrict-flying-mobs: true
# Invincible visitors - Prevent players from killing them (intentionally or by accident) # Invincible visitors. List of damages that will not affect visitors.
# If they fall to the void, they get TP'd to their island. # Make list blank if visitors should receive all damages
invincible-visitors: invincible-visitors:
# Toggle the invincibility
use: true
# This allow you to customize what kind of damage visitors should not receive
# If you want visitors to receive a listed damage, put a "#" at the start of the line
# See this for more info about options : https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/entity/EntityDamageEvent.DamageCause.html
options:
- BLOCK_EXPLOSION - BLOCK_EXPLOSION
- CONTACT - CONTACT
- CUSTOM - CUSTOM
@ -353,13 +344,11 @@ protection:
- SUFFOCATION - SUFFOCATION
- THORNS - THORNS
- WITHER - WITHER
# 1.9+ only
- DRAGON_BREATH - DRAGON_BREATH
- FLY_INTO_WALL - FLY_INTO_WALL
# 1.10+ only
- HOT_FLOOR - HOT_FLOOR
# 1.11+ only
- CRAMMING - CRAMMING
- VOID
# Visitor banned commands: Visitors to islands cannot use these commands # Visitor banned commands: Visitors to islands cannot use these commands
visitor-banned-commands: visitor-banned-commands:

View File

@ -332,6 +332,8 @@ protection:
HURT_VILLAGERS: "HURT_VILLAGERS" HURT_VILLAGERS: "HURT_VILLAGERS"
ITEM_DROP: "ITEM_DROP" ITEM_DROP: "ITEM_DROP"
ITEM_PICKUP: "ITEM_PICKUP" ITEM_PICKUP: "ITEM_PICKUP"
INVINCIBLE_VISITORS:
name: "Invincible Visitors"
LEASH: "LEASH" LEASH: "LEASH"
LOCK: LOCK:
name: "Lock island" name: "Lock island"

View File

@ -4,6 +4,7 @@ import org.bukkit.World;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import us.tastybento.bskyblock.api.configuration.BSBConfig;
import us.tastybento.bskyblock.api.configuration.WorldSettings; import us.tastybento.bskyblock.api.configuration.WorldSettings;
import us.tastybento.bskyblock.api.placeholders.PlaceholderHandler; import us.tastybento.bskyblock.api.placeholders.PlaceholderHandler;
import us.tastybento.bskyblock.api.user.Notifier; import us.tastybento.bskyblock.api.user.Notifier;
@ -64,21 +65,8 @@ public class BSkyBlock extends JavaPlugin {
saveDefaultConfig(); saveDefaultConfig();
setInstance(this); setInstance(this);
settings = new Settings();
// Load settings from config.yml. This will check if there are any issues with it too. // Load settings from config.yml. This will check if there are any issues with it too.
try { settings = new BSBConfig<>(this, Settings.class).loadConfigObject("");
settings = settings.loadSettings();
} catch (Exception e) {
logError("Settings could not be loaded " + e.getMessage());
}
// Save a backup of settings to the database so it can be checked next time
try {
settings.saveBackup();
} catch (Exception e) {
logError("Settings backup could not be saved" + e.getMessage());
}
// Start Database managers // Start Database managers
playersManager = new PlayersManager(this); playersManager = new PlayersManager(this);
// Check if this plugin is now disabled (due to bad database handling) // Check if this plugin is now disabled (due to bad database handling)
@ -133,7 +121,6 @@ public class BSkyBlock extends JavaPlugin {
islandsManager.load(); islandsManager.load();
// Save islands & players data asynchronously every X minutes // Save islands & players data asynchronously every X minutes
getSettings().setDatabaseBackupPeriod(10 * 60 * 20);
instance.getServer().getScheduler().runTaskTimer(instance, () -> { instance.getServer().getScheduler().runTaskTimer(instance, () -> {
playersManager.save(true); playersManager.save(true);
islandsManager.save(true); islandsManager.save(true);
@ -175,6 +162,8 @@ public class BSkyBlock extends JavaPlugin {
if (islandsManager != null) { if (islandsManager != null) {
islandsManager.shutdown(); islandsManager.shutdown();
} }
// Save settings
new BSBConfig<>(this, Settings.class).saveConfigObject(settings);
} }
private void registerCustomCharts(){ private void registerCustomCharts(){

View File

@ -16,11 +16,11 @@ import org.bukkit.potion.PotionEffectType;
import us.tastybento.bskyblock.Constants.GameType; import us.tastybento.bskyblock.Constants.GameType;
import us.tastybento.bskyblock.api.configuration.ConfigComment; import us.tastybento.bskyblock.api.configuration.ConfigComment;
import us.tastybento.bskyblock.api.configuration.ConfigEntry; import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.api.configuration.ISettings;
import us.tastybento.bskyblock.api.configuration.StoreAt; import us.tastybento.bskyblock.api.configuration.StoreAt;
import us.tastybento.bskyblock.api.configuration.WorldSettings; import us.tastybento.bskyblock.api.configuration.WorldSettings;
import us.tastybento.bskyblock.api.flags.Flag; import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.database.BSBDbSetup.DatabaseType; import us.tastybento.bskyblock.database.BSBDbSetup.DatabaseType;
import us.tastybento.bskyblock.database.objects.DataObject;
import us.tastybento.bskyblock.database.objects.adapters.Adapter; import us.tastybento.bskyblock.database.objects.adapters.Adapter;
import us.tastybento.bskyblock.database.objects.adapters.PotionEffectListAdapter; import us.tastybento.bskyblock.database.objects.adapters.PotionEffectListAdapter;
@ -29,37 +29,61 @@ import us.tastybento.bskyblock.database.objects.adapters.PotionEffectListAdapter
* @author Tastybento * @author Tastybento
*/ */
@StoreAt(filename="config.yml") // Explicitly call out what name this should have. @StoreAt(filename="config.yml") // Explicitly call out what name this should have.
public class Settings implements ISettings<Settings>, WorldSettings { public class Settings implements DataObject, WorldSettings {
private String uniqueId = "config";
// --------------------------------------------- // ---------------------------------------------
/* GENERAL */ /* GENERAL */
@ConfigComment("BSkyBlock uses bStats.org to get global data about the plugin to help improving it.")
@ConfigComment("bStats has nearly no effect on your server's performance and the sent data is completely")
@ConfigComment("anonymous so please consider twice if you really want to disable it.")
@ConfigEntry(path = "general.metrics")
private boolean metrics = true;
@ConfigComment("Check for updates - this will tell Ops and the console if there is a new")
@ConfigComment("version available. It contacts dev.bukkit.org to request the latest version")
@ConfigComment("info. It does not download the latest version or change any files")
@ConfigEntry(path = "general.check-updates") @ConfigEntry(path = "general.check-updates")
private boolean checkUpdates = true; private boolean checkUpdates = true;
@ConfigComment("Default language for new players.")
@ConfigComment("This is the filename in the locale folder without .yml.")
@ConfigComment("If this does not exist, the default en-US will be used.")
@ConfigEntry(path = "general.default-language") @ConfigEntry(path = "general.default-language")
private String defaultLanguage = "en-US"; private String defaultLanguage = "en-US";
@ConfigComment("Use economy or not. If true, an economy plugin is required. If false, no money is used or give.")
@ConfigComment("If there is no economy plugin present anyway, money will be automatically disabled.")
@ConfigEntry(path = "general.use-economy") @ConfigEntry(path = "general.use-economy")
private boolean useEconomy = true; private boolean useEconomy = true;
@ConfigComment("Starting money - this is how much money new players will have as their")
@ConfigComment("balance at the start of an island.")
@ConfigEntry(path = "general.starting-money")
private double startingMoney = 10.0;
// Purge // Purge
@ConfigComment("Only islands below this level will be removed if they are abandoned and admins issue the purge command")
@ConfigEntry(path = "general.purge.max-island-level") @ConfigEntry(path = "general.purge.max-island-level")
private int purgeMaxIslandLevel = 50; private int purgeMaxIslandLevel = 50;
@ConfigComment("Remove user data when its island gets purged.")
@ConfigComment("Helps a lot to avoid huge backups and can save some performance on startup,")
@ConfigComment("but the player settings and data will be reset.")
@ConfigEntry(path = "general.purge.remove-user-data") @ConfigEntry(path = "general.purge.remove-user-data")
private boolean purgeRemoveUserData = false; private boolean purgeRemoveUserData = false;
// Database // Database
@ConfigComment("FLATFILE, MYSQL, MONGO")
@ConfigComment("if you use MONGO, you must also run the BSBMongo plugin (not addon)")
@ConfigComment("See https://github.com/tastybento/bsbMongo/releases/")
@ConfigEntry(path = "general.database.type") @ConfigEntry(path = "general.database.type")
private DatabaseType databaseType = DatabaseType.FLATFILE; private DatabaseType databaseType = DatabaseType.FLATFILE;
@ConfigEntry(path = "general.database.host") @ConfigEntry(path = "general.database.host")
private String dbHost = "localhost"; private String dbHost = "localhost";
@ConfigComment("Port 3306 is MySQL's default. Port 27017 is MongoDB's default.")
@ConfigEntry(path = "general.database.port") @ConfigEntry(path = "general.database.port")
private int dbPort = 3306; private int dbPort = 3306;
@ -72,12 +96,32 @@ public class Settings implements ISettings<Settings>, WorldSettings {
@ConfigEntry(path = "general.database.password") @ConfigEntry(path = "general.database.password")
private String dbPassword = "password"; private String dbPassword = "password";
@ConfigComment("How often the data will be saved to file in mins. Default is 5 minutes.")
@ConfigComment("This helps prevent issues if the server crashes.")
@ConfigComment("Data is also saved at important points in the game.")
@ConfigEntry(path = "general.database.backup-period") @ConfigEntry(path = "general.database.backup-period")
private int databaseBackupPeriod = 5; private int databaseBackupPeriod = 5;
@ConfigComment("Recover super flat - if the generator does not run for some reason, you can get")
@ConfigComment("super flat chunks (grass). To remove automatically, select this option. Turn off")
@ConfigComment("if there are no more because it may cause lag.")
@ConfigComment("This will regenerate any chunks with bedrock at y=0 when they are loaded")
@ConfigEntry(path = "general.recover-super-flat")
private boolean recoverSuperFlat = false;
@ConfigComment("Mute death messages")
@ConfigEntry(path = "general.mute-death-messages")
private boolean muteDeathMessages = false;
@ConfigComment("Allow FTB Autonomous Activator to work (will allow a pseudo player [CoFH] to place and break blocks and hang items)")
@ConfigComment("Add other fake player names here if required")
@ConfigEntry(path = "general.fakeplayers") @ConfigEntry(path = "general.fakeplayers")
private Set<String> fakePlayers = new HashSet<>(); private Set<String> fakePlayers = new HashSet<>();
@ConfigComment("Allow obsidian to be scooped up with an empty bucket back into lava")
@ConfigComment("This only works if there is a single block of obsidian (no obsidian within 10 blocks)")
@ConfigComment("Recommendation is to keep this true so that newbies don't bother you or reset their")
@ConfigComment("island unnecessarily.")
@ConfigEntry(path = "general.allow-obsidian-scooping") @ConfigEntry(path = "general.allow-obsidian-scooping")
private boolean allowObsidianScooping = true; private boolean allowObsidianScooping = true;
@ -88,18 +132,33 @@ public class Settings implements ISettings<Settings>, WorldSettings {
// --------------------------------------------- // ---------------------------------------------
/* WORLD */ /* WORLD */
@ConfigComment("Friendly name for this world. Used in admin commands. Must be a single word")
@ConfigEntry(path = "world.friendly-name", needsReset = true) @ConfigEntry(path = "world.friendly-name", needsReset = true)
private String friendlyName = "BSkyBlock"; private String friendlyName = "BSkyBlock";
@ConfigComment("Name of the world - if it does not exist then it will be generated.")
@ConfigComment("It acts like a prefix for nether and end (e.g. BSkyBlock, BSkyBlock_nether, BSkyBlock_end)")
@ConfigEntry(path = "world.world-name", needsReset = true) @ConfigEntry(path = "world.world-name", needsReset = true)
private String worldName = "BSkyBlock-world"; private String worldName = "BSkyBlock-world";
@ConfigComment("Radius of island in blocks. (So distance between islands is twice this)")
@ConfigComment("Will be rounded up to the nearest 16 blocks.")
@ConfigComment("It is the same for every dimension : Overworld, Nether and End.")
@ConfigComment("This value cannot be changed mid-game and the plugin will not start if it is different.")
@ConfigEntry(path = "world.distance-between-islands", needsReset = true) @ConfigEntry(path = "world.distance-between-islands", needsReset = true)
private int islandDistance = 200; private int islandDistance = 200;
@ConfigComment("Default protection range radius in blocks. Cannot be larger than distance.")
@ConfigComment("Admins can change protection sizes for players individually using /bsadmin setrange")
@ConfigComment("or set this permission: bskyblock.island.range.<number>")
@ConfigEntry(path = "world.protection-range", overrideOnChange = true) @ConfigEntry(path = "world.protection-range", overrideOnChange = true)
private int islandProtectionRange = 100; private int islandProtectionRange = 100;
@ConfigComment("Start islands at these coordinates. This is where new islands will start in the")
@ConfigComment("world. These must be a factor of your island distance, but the plugin will auto")
@ConfigComment("calculate the closest location on the grid. Islands develop around this location")
@ConfigComment("both positively and negatively in a square grid.")
@ConfigComment("If none of this makes sense, leave it at 0,0.")
@ConfigEntry(path = "world.start-x", needsReset = true) @ConfigEntry(path = "world.start-x", needsReset = true)
private int islandStartX = 0; private int islandStartX = 0;
@ -109,28 +168,51 @@ public class Settings implements ISettings<Settings>, WorldSettings {
private int islandXOffset; private int islandXOffset;
private int islandZOffset; private int islandZOffset;
@ConfigEntry(path = "world.sea-height") @ConfigComment("Island height - Lowest is 5.")
private int seaHeight = 0; @ConfigComment("It is the y coordinate of the bedrock block in the schematic")
@ConfigEntry(path = "world.island-height") @ConfigEntry(path = "world.island-height")
private int islandHeight = 100; private int islandHeight = 100;
@ConfigComment("Sea height (don't changes this mid-game unless you delete the world)")
@ConfigComment("Minimum is 0, which means you are playing Skyblock!")
@ConfigComment("If sea height is less than about 10, then players will drop right through it")
@ConfigComment("if it exists. Makes for an interesting variation on skyblock.")
@ConfigEntry(path = "world.sea-height")
private int seaHeight = 0;
@ConfigComment("Maximum number of islands in the world. Set to 0 for unlimited. ")
@ConfigComment("If the number of islands is greater than this number, no new island will be created.")
@ConfigEntry(path = "world.max-islands") @ConfigEntry(path = "world.max-islands")
private int maxIslands = -1; private int maxIslands = -1;
// Nether // Nether
@ConfigComment("Generate Nether - if this is false, the nether world will not be made and access to")
@ConfigComment("the nether will not occur. Other plugins may still enable portal usage.")
@ConfigComment("Note: Some challenges will not be possible if there is no nether.")
@ConfigComment("Note that with a standard nether all players arrive at the same portal and entering a")
@ConfigComment("portal will return them back to their islands.")
@ConfigEntry(path = "world.nether.generate") @ConfigEntry(path = "world.nether.generate")
private boolean netherGenerate = true; private boolean netherGenerate = true;
@ConfigComment("Islands in Nether. Change to false for standard vanilla nether.")
@ConfigEntry(path = "world.nether.islands", needsReset = true) @ConfigEntry(path = "world.nether.islands", needsReset = true)
private boolean netherIslands = true; private boolean netherIslands = true;
@ConfigComment("Nether trees are made if a player grows a tree in the nether (gravel and glowstone)")
@ConfigComment("Applies to both vanilla and islands Nether")
@ConfigEntry(path = "world.nether.trees") @ConfigEntry(path = "world.nether.trees")
private boolean netherTrees = true; private boolean netherTrees = true;
@ConfigComment("Make the nether roof, if false, there is nothing up there")
@ConfigComment("Change to false if lag is a problem from the generation")
@ConfigComment("Only applies to islands Nether")
@ConfigEntry(path = "world.nether.roof") @ConfigEntry(path = "world.nether.roof")
private boolean netherRoof = true; private boolean netherRoof = true;
@ConfigComment("Nether spawn protection radius - this is the distance around the nether spawn")
@ConfigComment("that will be protected from player interaction (breaking blocks, pouring lava etc.)")
@ConfigComment("Minimum is 0 (not recommended), maximum is 100. Default is 25.")
@ConfigComment("Only applies to vanilla nether")
@ConfigEntry(path = "world.nether.spawn-radius") @ConfigEntry(path = "world.nether.spawn-radius")
private int netherSpawnRadius = 32; private int netherSpawnRadius = 32;
@ -144,6 +226,10 @@ public class Settings implements ISettings<Settings>, WorldSettings {
@ConfigEntry(path = "world.end.dragon-spawn") @ConfigEntry(path = "world.end.dragon-spawn")
private boolean dragonSpawn = false; private boolean dragonSpawn = false;
@ConfigComment("Disable redstone operation on islands unless a team member is online.")
@ConfigComment("This may reduce lag but it can cause problems with visitors needing to use a redstone system.")
@ConfigComment("Default is false, because it is an experimental feature that can break a lot of redstone systems.")
private boolean disableOfflineRedstone = false;
// --------------------------------------------- // ---------------------------------------------
@ -154,49 +240,79 @@ public class Settings implements ISettings<Settings>, WorldSettings {
@ConfigEntry(path = "island.limits.tile-entities") @ConfigEntry(path = "island.limits.tile-entities")
private Map<String, Integer> tileEntityLimits = new HashMap<>(); private Map<String, Integer> tileEntityLimits = new HashMap<>();
@ConfigComment("Default max team size")
@ConfigComment("Use this permission to set for specific user groups: askyblock.team.maxsize.<number>")
@ConfigComment("Permission size cannot be less than the default below. ")
@ConfigEntry(path = "island.max-team-size") @ConfigEntry(path = "island.max-team-size")
private int maxTeamSize = 4; private int maxTeamSize = 4;
@ConfigComment("Default maximum number of homes a player can have. Min = 1")
@ConfigComment("Accessed via sethome <number> or go <number>")
@ConfigComment("Use this permission to set for specific user groups: askyblock.island.maxhomes.<number>")
@ConfigEntry(path = "island.max-homes") @ConfigEntry(path = "island.max-homes")
private int maxHomes = 5; private int maxHomes = 5;
@ConfigComment("Island naming")
@ConfigComment("Only players with the TODO can name their island")
@ConfigComment("It is displayed in the top ten and enter and exit announcements")
@ConfigComment("It replaces the owner's name. Players can use & for color coding if they have the TODO permission")
@ConfigComment("These set the minimum and maximum size of a name.")
@ConfigEntry(path = "island.name.min-length") @ConfigEntry(path = "island.name.min-length")
private int nameMinLength = 4; private int nameMinLength = 4;
@ConfigEntry(path = "island.name.max-length") @ConfigEntry(path = "island.name.max-length")
private int nameMaxLength = 20; private int nameMaxLength = 20;
@ConfigComment("How long a player must wait until they can rejoin a team island after being")
@ConfigComment("kicked in minutes. This slows the effectiveness of players repeating challenges")
@ConfigComment("by repetitively being invited to a team island.")
@ConfigEntry(path = "island.invite-wait") @ConfigEntry(path = "island.invite-wait")
private int inviteWait = 60; private int inviteWait = 60;
// Reset // Reset
@ConfigComment("How many resets a player is allowed (override with /asadmin clearreset <player>)")
@ConfigComment("Value of -1 means unlimited, 0 means hardcore - no resets.")
@ConfigComment("Example, 2 resets means they get 2 resets or 3 islands lifetime")
@ConfigEntry(path = "island.reset.reset-limit") @ConfigEntry(path = "island.reset.reset-limit")
private int resetLimit = -1; private int resetLimit = -1;
@ConfigEntry(path = "island.require-confirmation.reset") @ConfigEntry(path = "island.require-confirmation.reset")
private boolean resetConfirmation = true; private boolean resetConfirmation = true;
@ConfigComment("How long a player must wait before they can reset their island again in second")
@ConfigEntry(path = "island.reset-wait") @ConfigEntry(path = "island.reset-wait")
private long resetWait = 10L; private long resetWait = 300;
@ConfigComment("Kicked or leaving players lose resets")
@ConfigComment("Players who leave a team will lose an island reset chance")
@ConfigComment("If a player has zero resets left and leaves a team, they cannot make a new")
@ConfigComment("island by themselves and can only join a team.")
@ConfigComment("Leave this true to avoid players exploiting free islands")
@ConfigEntry(path = "island.reset.leavers-lose-reset") @ConfigEntry(path = "island.reset.leavers-lose-reset")
private boolean leaversLoseReset = false; private boolean leaversLoseReset = false;
@ConfigComment("Allow kicked players to keep their inventory.")
@ConfigComment("If false, kicked player's inventory will be thrown at the island leader if the")
@ConfigComment("kicked player is online and in the island world.")
@ConfigEntry(path = "island.reset.kicked-keep-inventory") @ConfigEntry(path = "island.reset.kicked-keep-inventory")
private boolean kickedKeepInventory = false; private boolean kickedKeepInventory = false;
// Remove mobs // Remove mobs
@ConfigComment("Removing mobs - this kills all monsters in the vicinity. Benefit is that it helps")
@ConfigComment("players return to their island if the island has been overrun by monsters.")
@ConfigComment("Con is that it kills any mob grinders.")
@ConfigEntry(path = "island.remove-mobs.on-login") @ConfigEntry(path = "island.remove-mobs.on-login")
private boolean removeMobsOnLogin = false; private boolean removeMobsOnLogin = false;
@ConfigComment("Remove mobs when /island.")
@ConfigEntry(path = "island.remove-mobs.on-island") @ConfigEntry(path = "island.remove-mobs.on-island")
private boolean removeMobsOnIsland = false; private boolean removeMobsOnIsland = false;
@ConfigComment("Mob white list - these mobs will NOT be removed when logging in or doing /island")
@ConfigEntry(path = "island.remove-mobs.whitelist") @ConfigEntry(path = "island.remove-mobs.whitelist")
private List<String> removeMobsWhitelist = new ArrayList<>(); private List<String> removeMobsWhitelist = new ArrayList<>();
@ConfigComment("Make island if player teleports to the island world and does not have one")
@ConfigEntry(path = "island.make-island-if-none") @ConfigEntry(path = "island.make-island-if-none")
private boolean makeIslandIfNone = false; private boolean makeIslandIfNone = false;
@ConfigComment("Immediately teleport player to their island (home 1 if it exists) when entering the world")
@ConfigEntry(path = "island.immediate-teleport-on-island") @ConfigEntry(path = "island.immediate-teleport-on-island")
private boolean immediateTeleportOnIsland = false; private boolean immediateTeleportOnIsland = false;
@ConfigComment("Have player's respawn on their island if they die")
@ConfigEntry(path = "island.respawn-on-island")
private boolean respawnOnIsland = true; private boolean respawnOnIsland = true;
// Deaths // Deaths
@ -213,9 +329,13 @@ public class Settings implements ISettings<Settings>, WorldSettings {
// --------------------------------------------- // ---------------------------------------------
/* PROTECTION */ /* PROTECTION */
@ConfigComment("Allow pistons to push outside of the protected area (maybe to make bridges)")
@ConfigEntry(path = "protection.allow-piston-push") @ConfigEntry(path = "protection.allow-piston-push")
private boolean allowPistonPush = false; private boolean allowPistonPush = false;
@ConfigComment("Restrict Wither and other flying mobs.")
@ConfigComment("Any flying mobs that exit the island space where they were spawned will be removed.")
@ConfigComment("Includes blaze and ghast. ")
@ConfigEntry(path = "protection.restrict-flying-mobs") @ConfigEntry(path = "protection.restrict-flying-mobs")
private boolean restrictFlyingMobs = true; private boolean restrictFlyingMobs = true;
@ -232,6 +352,12 @@ public class Settings implements ISettings<Settings>, WorldSettings {
private boolean allowCreeperGriefing; private boolean allowCreeperGriefing;
private boolean allowMobDamageToItemFrames; private boolean allowMobDamageToItemFrames;
// Invincible visitor settings
@ConfigComment("Invincible visitors. List of damages that will not affect visitors.")
@ConfigComment("Make list blank if visitors should receive all damages")
@ConfigEntry(path = "protection.invincible-visitors")
private List<String> ivSettings = new ArrayList<>();
//TODO flags //TODO flags
// --------------------------------------------- // ---------------------------------------------
@ -276,6 +402,8 @@ public class Settings implements ISettings<Settings>, WorldSettings {
private boolean teamJoinDeathReset; private boolean teamJoinDeathReset;
// Timeout for team kick and leave commands // Timeout for team kick and leave commands
@ConfigComment("Ask the player to confirm the command he is using by typing it again.")
@ConfigComment("The 'wait' value is the number of seconds to wait for confirmation.")
@ConfigEntry(path = "island.require-confirmation.kick") @ConfigEntry(path = "island.require-confirmation.kick")
private boolean kickConfirmation = true; private boolean kickConfirmation = true;
@ -288,7 +416,70 @@ public class Settings implements ISettings<Settings>, WorldSettings {
@ConfigEntry(path = "island.require-confirmation.leave-wait") @ConfigEntry(path = "island.require-confirmation.leave-wait")
private long leaveWait = 10L; private long leaveWait = 10L;
private String uniqueId = "config";
// Getters and setters
/**
* @return the metrics
*/
public boolean isMetrics() {
return metrics;
}
/**
* @param metrics the metrics to set
*/
public void setMetrics(boolean metrics) {
this.metrics = metrics;
}
/**
* @return the startingMoney
*/
public double getStartingMoney() {
return startingMoney;
}
/**
* @param startingMoney the startingMoney to set
*/
public void setStartingMoney(double startingMoney) {
this.startingMoney = startingMoney;
}
/**
* @return the recoverSuperFlat
*/
public boolean isRecoverSuperFlat() {
return recoverSuperFlat;
}
/**
* @param recoverSuperFlat the recoverSuperFlat to set
*/
public void setRecoverSuperFlat(boolean recoverSuperFlat) {
this.recoverSuperFlat = recoverSuperFlat;
}
/**
* @return the muteDeathMessages
*/
public boolean isMuteDeathMessages() {
return muteDeathMessages;
}
/**
* @param muteDeathMessages the muteDeathMessages to set
*/
public void setMuteDeathMessages(boolean muteDeathMessages) {
this.muteDeathMessages = muteDeathMessages;
}
/**
* @return the disableOfflineRedstone
*/
public boolean isDisableOfflineRedstone() {
return disableOfflineRedstone;
}
/**
* @param disableOfflineRedstone the disableOfflineRedstone to set
*/
public void setDisableOfflineRedstone(boolean disableOfflineRedstone) {
this.disableOfflineRedstone = disableOfflineRedstone;
}
/** /**
* @return the acidDamage * @return the acidDamage
*/ */
@ -403,10 +594,6 @@ public class Settings implements ISettings<Settings>, WorldSettings {
public Map<EntityType, Integer> getEntityLimits() { public Map<EntityType, Integer> getEntityLimits() {
return entityLimits; return entityLimits;
} }
@Override
public Settings getInstance() {
return this;
}
/** /**
* Number of minutes to wait * Number of minutes to wait
* @return the inviteWait * @return the inviteWait
@ -1306,4 +1493,18 @@ public class Settings implements ISettings<Settings>, WorldSettings {
return "bskyblock"; return "bskyblock";
} }
/**
* @return the ivSettings
*/
public List<String> getIvSettings() {
return ivSettings;
}
/**
* @param ivSettings the ivSettings to set
*/
public void setIvSettings(List<String> ivSettings) {
this.ivSettings = ivSettings;
}
} }

View File

@ -90,5 +90,4 @@ public class BSBConfig<T> {
return handler.objectExists(name); return handler.objectExists(name);
} }
} }

View File

@ -4,13 +4,22 @@ import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RUNTIME) @Retention(RUNTIME)
@Repeatable(ConfigComment.Line.class)
@Target({ FIELD, METHOD }) @Target({ FIELD, METHOD })
public @interface ConfigComment { public @interface ConfigComment {
String value(); String value();
@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, METHOD })
@interface Line {
ConfigComment[] value();
}
} }

View File

@ -1,67 +0,0 @@
package us.tastybento.bskyblock.api.configuration;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDbSetup;
import us.tastybento.bskyblock.database.flatfile.ConfigHandler;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
/**
* Simple interface for tagging all classes containing ConfigEntries.
*
* @author Poslovitch
* @author tastybento
* @param <T>
*/
public interface ISettings<T> {
// ----------------Saver-------------------
@SuppressWarnings("unchecked")
default void saveSettings() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
// Get the handler
ConfigHandler<T> settingsHandler = (ConfigHandler<T>) new FlatFileDatabase().getConfig(getInstance().getClass());
// Load every field in the config class
settingsHandler.saveSettings(getInstance());
}
default void saveBackup() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
// Save backup
@SuppressWarnings("unchecked")
AbstractDatabaseHandler<T> backupHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass());
backupHandler.saveObject(getInstance());
}
// --------------- Loader ------------------
@SuppressWarnings("unchecked")
default T loadSettings() throws InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, IntrospectionException {
// See if this settings object already exists in the database
AbstractDatabaseHandler<T> dbhandler = (AbstractDatabaseHandler<T>) BSBDbSetup.getDatabase().getHandler(getClass());
T dbConfig = null;
if (dbhandler.objectExists(this.getUniqueId())) {
// Load it
dbConfig = dbhandler.loadObject(getUniqueId());
}
// Get the handler
ConfigHandler<T> configHandler = (ConfigHandler<T> ) new FlatFileDatabase().getConfig(getInstance().getClass());
// Load every field in the config class
return configHandler.loadSettings(getUniqueId(), dbConfig);
}
/**
* @return instance of the implementing class, i.e., return this.
*/
T getInstance();
/**
* @return the uniqueId
*/
String getUniqueId();
/**
* @param uniqueId - unique ID the uniqueId to set
*/
void setUniqueId(String uniqueId);
}

View File

@ -21,8 +21,10 @@ public class Panel implements HeadRequester {
private Map<Integer, PanelItem> items; private Map<Integer, PanelItem> items;
private PanelListener listener; private PanelListener listener;
private User user; private User user;
private final String name;
public Panel(String name, Map<Integer, PanelItem> items, int size, User user, PanelListener listener) { public Panel(String name, Map<Integer, PanelItem> items, int size, User user, PanelListener listener) {
this.name = name;
this.items = items; this.items = items;
// If size is undefined (0) then use the number of items // If size is undefined (0) then use the number of items
if (size == 0) { if (size == 0) {
@ -135,4 +137,11 @@ public class Panel implements HeadRequester {
} }
} }
} }
/**
* @return the name
*/
public String getName() {
return name;
}
} }

View File

@ -56,11 +56,11 @@ public interface DatabaseConnecter {
/** /**
* Save the Yaml Config * Save the Yaml Config
* @param yamlConfig - the YAML config * @param yamlConfig - the YAML config
* @param tableName - analogous to a table in a database * @param path - analogous to a table name in a database
* @param fileName - the name of the record. Must be unique. * @param fileName - the name of the record. Must be unique.
* @param commentMap - map of comments, may be empty * @param commentMap - map of comments, may be empty
*/ */
void saveYamlFile(YamlConfiguration yamlConfig, String tableName, String fileName, Map<String, String> commentMap); void saveYamlFile(YamlConfiguration yamlConfig, String path, String fileName, Map<String, String> commentMap);
} }

View File

@ -240,13 +240,11 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
Map<String, String> yamlComments = new HashMap<>(); Map<String, String> yamlComments = new HashMap<>();
// Only allow storing in an arbitrary place if it is a config object. Otherwise it is in the database // Only allow storing in an arbitrary place if it is a config object. Otherwise it is in the database
if (configFlag) {
StoreAt storeAt = instance.getClass().getAnnotation(StoreAt.class); StoreAt storeAt = instance.getClass().getAnnotation(StoreAt.class);
if (storeAt != null) { if (storeAt != null) {
path = storeAt.path(); path = storeAt.path();
filename = storeAt.filename(); filename = storeAt.filename();
} }
}
// Run through all the fields in the class that is being stored. EVERY field must have a get and set method // Run through all the fields in the class that is being stored. EVERY field must have a get and set method
for (Field field : dataObject.getDeclaredFields()) { for (Field field : dataObject.getDeclaredFields()) {
@ -272,15 +270,22 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
} }
// Comments // Get path for comments
String parent = "";
if (storageLocation.contains(".")) {
parent = storageLocation.substring(0, storageLocation.lastIndexOf(".")) + ".";
}
// See if there are multiple comments
ConfigComment.Line comments = field.getAnnotation(ConfigComment.Line.class);
if (comments != null) {
for (ConfigComment comment : comments.value()) {
setComment(comment, config, yamlComments, parent);
}
}
// Handle single line comments
ConfigComment comment = field.getAnnotation(ConfigComment.class); ConfigComment comment = field.getAnnotation(ConfigComment.class);
if (comment != null) { if (comment != null) {
// Create a random placeholder string setComment(comment, config, yamlComments, parent);
String random = "comment-" + UUID.randomUUID().toString();
// Store placeholder
config.set(random, " ");
// Create comment
yamlComments.put(random, "# " + comment.value());
} }
// Adapter // Adapter
@ -345,6 +350,14 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
databaseConnecter.saveYamlFile(config, path, filename, yamlComments); databaseConnecter.saveYamlFile(config, path, filename, yamlComments);
} }
private void setComment(ConfigComment comment, YamlConfiguration config, Map<String, String> yamlComments, String parent) {
String random = "comment-" + UUID.randomUUID().toString();
// Store placeholder
config.set(parent + random, " ");
// Create comment
yamlComments.put(random, "# " + comment.value());
}
/** /**
* Serialize an object if required * Serialize an object if required
* @param object * @param object
@ -465,5 +478,4 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// Not used // Not used
} }
} }

View File

@ -0,0 +1,71 @@
/**
*
*/
package us.tastybento.bskyblock.listeners.flags;
import java.util.Arrays;
import org.bukkit.Material;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.inventory.ClickType;
import us.tastybento.bskyblock.api.panels.Panel;
import us.tastybento.bskyblock.api.panels.PanelItem.ClickHandler;
import us.tastybento.bskyblock.api.panels.builders.PanelBuilder;
import us.tastybento.bskyblock.api.panels.builders.PanelItemBuilder;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.util.Util;
/**
* @author tastybento
*
*/
public class InvincibleVisitorsListener extends AbstractFlagListener implements ClickHandler {
@Override
public boolean onClick(Panel panel, User user, ClickType clickType, int slot) {
String ivPanelName = user.getTranslation("protection.flags.INVINCIBLE_VISITORS.name");
if (panel.getName().equals(ivPanelName)) {
// This is a click on the IV panel
// Slot relates to the enum
DamageCause c = Arrays.asList(EntityDamageEvent.DamageCause.values()).get(slot);
if (getPlugin().getSettings().getIvSettings().contains(c.name())) {
getPlugin().getSettings().getIvSettings().remove(c.name());
} else {
getPlugin().getSettings().getIvSettings().add(c.name());
}
}
// Open the IV Settings panel
openPanel(user, ivPanelName);
return true;
}
private void openPanel(User user, String ivPanelName) {
// Close the current panel
user.closeInventory();
// Open a new panel for visitor protection
PanelBuilder pb = new PanelBuilder();
pb.user(user).name(ivPanelName);
// Make panel items
Arrays.stream(EntityDamageEvent.DamageCause.values()).forEach(c -> {
PanelItemBuilder pib = new PanelItemBuilder();
pib.name(Util.prettifyText(c.toString()));
pib.clickHandler(this);
if (getPlugin().getSettings().getIvSettings().contains(c.name())) {
pib.icon(Material.GREEN_GLAZED_TERRACOTTA);
pib.description(user.getTranslation("protection.panel.flag-item.setting-active"));
} else {
pib.icon(Material.RED_GLAZED_TERRACOTTA);
pib.description(user.getTranslation("protection.panel.flag-item.setting-disabled"));
}
pb.item(pib.build());
});
pb.build();
}
}

View File

@ -20,6 +20,7 @@ import us.tastybento.bskyblock.listeners.flags.EntityInteractListener;
import us.tastybento.bskyblock.listeners.flags.FireListener; import us.tastybento.bskyblock.listeners.flags.FireListener;
import us.tastybento.bskyblock.listeners.flags.HurtingListener; import us.tastybento.bskyblock.listeners.flags.HurtingListener;
import us.tastybento.bskyblock.listeners.flags.InventoryListener; import us.tastybento.bskyblock.listeners.flags.InventoryListener;
import us.tastybento.bskyblock.listeners.flags.InvincibleVisitorsListener;
import us.tastybento.bskyblock.listeners.flags.ItemDropPickUpListener; import us.tastybento.bskyblock.listeners.flags.ItemDropPickUpListener;
import us.tastybento.bskyblock.listeners.flags.LeashListener; import us.tastybento.bskyblock.listeners.flags.LeashListener;
import us.tastybento.bskyblock.listeners.flags.LockAndBanListener; import us.tastybento.bskyblock.listeners.flags.LockAndBanListener;
@ -147,7 +148,9 @@ public class Flags {
.listener(new PistonPushListener()) .listener(new PistonPushListener())
.onClick(new SettingsToggleClickListener("PISTON_PUSH")) .onClick(new SettingsToggleClickListener("PISTON_PUSH"))
.build(); .build();
static InvincibleVisitorsListener ilv = new InvincibleVisitorsListener();
public static final Flag INVINCIBLE_VISITORS = new FlagBuilder().id("INVINCIBLE_VISITORS").icon(Material.DIAMOND_CHESTPLATE).type(Type.SETTING)
.listener(ilv).onClick(ilv).build();
/** /**
* @return List of all the flags in this class * @return List of all the flags in this class