Merge branch 'develop'

This commit is contained in:
Florian CUNY 2019-08-14 10:11:00 +02:00
commit 3e71178024
328 changed files with 10939 additions and 4280 deletions

View File

@ -1,76 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at poslovitch@bentobox.world. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -1,60 +0,0 @@
---
name: Bug report
about: Report a bug or a problem you're encountering with BentoBox.
title: ''
labels: 'Status: Pending, Type: Bug'
assignees: ''
---
### Description
#### Describe the bug
<!-- A clear and concise description of the problem you're encountering. -->
<!-- /!\ Leaving this section blank will result in your ticket being closed without further explanation. -->
<!-- Please type below this line. -->
#### Steps to reproduce the behavior
<!-- Step-by-step instructions for us to reproduce the bug on our side. -->
<!-- /!\ Leaving this section blank will result in your ticket being closed without further explanation. -->
<!-- Please type below this line. -->
#### Screenshots and videos
<!-- Videos and screenshots are helpful as they can provide better information about your problem. -->
<!-- Please type below this line. -->
#### Expected behavior
<!-- Clear and concise description of what you actually expected to happen when you encountered this bug. -->
<!-- Please type below this line. -->
### Environment
#### Server
<!-- /!\ Leaving this section blank will result in your ticket being closed without further explanation. -->
<!-- Please replace the underscores with your answer. Do not remove the '*' characters. -->
- OS: **________**
- Java version: **________**
#### Plugins
<!-- /!\ Leaving this section blank will result in your ticket being closed without further explanation. -->
<!-- Please paste the `/plugins` output inside the code block below (remove the underscores). Do not provide an image. -->
```
_______
```
#### BentoBox setup
##### BentoBox and Addons
<!-- /!\ Leaving this section blank will result in your ticket being closed without further explanation. -->
<!-- Please paste the output of `/bentobox version` in the code block below (replace the underscores). Do not provide an image. -->
```
_______
```
##### Configuration
<!-- /!\ Leaving this section blank will result in your ticket being closed without further explanation. -->
<!-- Please replace the underscores with your answer. Do not remove the '*' characters. -->
- Database: **________** <!-- Available options: YAML, JSON, MYSQL, MARIADB, MONGODB -->
### Additional context
<!-- Any additional information you'd like to provide us. -->
<!-- Please type below this line. -->

View File

@ -1,25 +0,0 @@
---
name: Feature request
about: Suggest an idea to improve BentoBox
title: ''
labels: 'Status: Pending, Type: Enhancement'
assignees: ''
---
### Description
#### Is your feature request related to a problem?
<!-- A clear and concise description of the problem you're encountering, if any. -->
<!-- Please type below this line. -->
#### Describe the solution you'd like us to implement.
<!-- A clear and concise description of what you want us to do to resolve your problem. -->
<!-- Please type below this line. -->
#### Describe alternatives you've considered.
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
<!-- Please type below this line. -->
### Additional context
<!-- Add any other context or screenshots about the feature request here. -->
<!-- Please type below this line. -->

View File

@ -1,15 +0,0 @@
---
name: Placeholder request
about: Suggest a placeholder to use via PlaceholderAPI
title: 'Placeholder: '
labels: 'Status: Pending, Type: Enhancement'
assignees: ''
---
**Description**
<!-- A clear and concise description of the placeholder you want us to add. -->
<!-- Please type below this line. -->
**Placeholder**: `__________`
<!-- Replace the underscores above with the actual placeholder. E.g: island_name -->

View File

@ -9,10 +9,16 @@ addons:
- develop
- master
jdk:
- oraclejdk8
- openjdk8
- openjdk11
matrix:
allow_failures:
- jdk: openjdk11
script:
#- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package -P sonar sonar:sonar -B
#- sonar-scanner
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package -P sonar sonar:sonar -B
#- echo "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
cache:
directories:

View File

@ -90,7 +90,7 @@ Do not submit PRs that only address code formatting because they will not be acc
BentoBox uses Maven, and its Maven repository is kindly provided by [CodeMC](https://codemc.org).
### Maven dependency
### Maven
```xml
<repositories>
<repository>
@ -108,3 +108,14 @@ BentoBox uses Maven, and its Maven repository is kindly provided by [CodeMC](htt
</dependency>
</dependencies>
```
### Gradle
```groovy
repositories {
maven { url "https://repo.codemc.org/repository/maven-public/" }
}
dependencies {
compileOnly 'world.bentobox:bentobox:PUT-VERSION-HERE'
}
```

View File

@ -1,300 +0,0 @@
# Locale References
This file contains a list of the locale references in the source code. See the commit date/time for the last update.
## References
/!\ Most command-related references are not listed at the moment.
```
commands.admin.setrange.range-updated
commands.help.description
commands.help.end
commands.help.header
commands.help.parameters
commands.help.syntax
commands.island.about.description
commands.island.create.creating-island
commands.island.create.unable-create-island
commands.island.go.description
commands.island.go.parameters
commands.island.go.teleport
commands.island.go.teleported
commands.island.reset.must-remove-members
commands.island.sethome.home-set
commands.island.sethome.must-be-on-your-island
commands.island.sethome.num-homes
commands.island.setname.too-long
commands.island.setname.too-short
commands.island.team.demote.failure
commands.island.team.demote.success
commands.island.team.invite.accept.name-joined-your-island
commands.island.team.invite.accept.you-joined-island
commands.island.team.invite.already-on-team
commands.island.team.invite.cannot-invite-self
commands.island.team.invite.cooldown
commands.island.team.invite.errors.invalid-invite
commands.island.team.invite.errors.island-is-full
commands.island.team.invite.errors.none-invited-you
commands.island.team.invite.errors.you-already-are-in-team
commands.island.team.invite.invitation-sent
commands.island.team.invite.name-has-invited-you
commands.island.team.invite.reject.name-rejected-your-invite
commands.island.team.invite.reject.you-rejected-invite
commands.island.team.invite.removing-invite
commands.island.team.invite.to-accept-or-reject
commands.island.team.invite.you-can-invite
commands.island.team.invite.you-will-lose-your-island
commands.island.team.kick.leader-kicked
commands.island.team.kick.type-again
commands.island.team.leave.left-your-island
commands.island.team.leave.type-again
commands.island.team.promote.failure
commands.island.team.promote.success
commands.island.team.setowner.errors.cant-transfer-to-yourself
commands.island.team.setowner.errors.target-is-not-member
commands.island.team.setowner.name-is-the-owner
commands.island.team.setowner.you-are-the-owner
commands.help.end
commands.help.description
commands.help.header
commands.help.parameters
commands.help.syntax
general.confirm
general.errors.already-have-island
general.errors.command-cancelled
general.errors.general
general.errors.no-island
general.errors.no-permission
general.errors.no-team
general.errors.not-in-team
general.errors.not-owner
general.errors.offline-player
general.errors.player-has-island
general.errors.player-has-no-island
general.errors.unknown-command
general.errors.unknown-player
general.errors.unknown-player-name
general.errors.use-in-game
general.errors.warp-not-safe
general.errors.wrong-world
general.errors.you-must-wait
general.errors.you-need
general.previous-request-cancelled
general.request-cancelled
general.success
general.tips.changing-obsidian-to-lava
language.edited
language.panel-title
language.selected
protection.command-is-banned
protection.flags.ANIMAL_SPAWN.description
protection.flags.ANIMAL_SPAWN.name
protection.flags.ANVIL.description
protection.flags.ANVIL.hint
protection.flags.ANVIL.name
protection.flags.ARMOR_STAND.description
protection.flags.ARMOR_STAND.hint
protection.flags.ARMOR_STAND.name
protection.flags.BEACON.description
protection.flags.BEACON.hint
protection.flags.BEACON.name
protection.flags.BED.description
protection.flags.BED.hint
protection.flags.BED.name
protection.flags.BREAK_BLOCKS.description
protection.flags.BREAK_BLOCKS.hint
protection.flags.BREAK_BLOCKS.name
protection.flags.BREEDING.description
protection.flags.BREEDING.hint
protection.flags.BREEDING.name
protection.flags.BREWING.description
protection.flags.BREWING.hint
protection.flags.BREWING.name
protection.flags.BUCKET.description
protection.flags.BUCKET.hint
protection.flags.BUCKET.name
protection.flags.BUTTON.description
protection.flags.BUTTON.hint
protection.flags.BUTTON.name
protection.flags.CHEST.description
protection.flags.CHEST.hint
protection.flags.CHEST.name
protection.flags.CHEST_DAMAGE.description
protection.flags.CHEST_DAMAGE.name
protection.flags.CHORUS_FRUIT.description
protection.flags.CHORUS_FRUIT.hint
protection.flags.CHORUS_FRUIT.name
protection.flags.CLEAN_SUPER_FLAT.description
protection.flags.CLEAN_SUPER_FLAT.name
protection.flags.COLLECT_LAVA.description
protection.flags.COLLECT_LAVA.hint
protection.flags.COLLECT_LAVA.name
protection.flags.COLLECT_WATER.description
protection.flags.COLLECT_WATER.hint
protection.flags.COLLECT_WATER.name
protection.flags.CRAFTING.description
protection.flags.CRAFTING.hint
protection.flags.CRAFTING.name
protection.flags.CREEPER_DAMAGE.description
protection.flags.CREEPER_DAMAGE.name
protection.flags.CREEPER_GRIEFING.description
protection.flags.CREEPER_GRIEFING.name
protection.flags.CROP_TRAMPLE.description
protection.flags.CROP_TRAMPLE.hint
protection.flags.CROP_TRAMPLE.name
protection.flags.DOOR.description
protection.flags.DOOR.hint
protection.flags.DOOR.name
protection.flags.EGGS.description
protection.flags.EGGS.hint
protection.flags.EGGS.name
protection.flags.ELYTRA.description
protection.flags.ELYTRA.hint
protection.flags.ELYTRA.name
protection.flags.ENCHANTING.description
protection.flags.ENCHANTING.hint
protection.flags.ENCHANTING.name
protection.flags.ENDERMAN_DEATH_DROP.description
protection.flags.ENDERMAN_DEATH_DROP.name
protection.flags.ENDERMAN_GRIEFING.description
protection.flags.ENDERMAN_GRIEFING.name
protection.flags.ENDER_PEARL.description
protection.flags.ENDER_PEARL.hint
protection.flags.ENDER_PEARL.name
protection.flags.ENTER_EXIT_MESSAGES.description
protection.flags.ENTER_EXIT_MESSAGES.island
protection.flags.ENTER_EXIT_MESSAGES.name
protection.flags.ENTER_EXIT_MESSAGES.now-entering
protection.flags.ENTER_EXIT_MESSAGES.now-leaving
protection.flags.FIRE.description
protection.flags.FIRE.hint
protection.flags.FIRE.name
protection.flags.FIRE_EXTINGUISH.description
protection.flags.FIRE_EXTINGUISH.hint
protection.flags.FIRE_EXTINGUISH.name
protection.flags.FIRE_SPREAD.description
protection.flags.FIRE_SPREAD.hint
protection.flags.FIRE_SPREAD.name
protection.flags.FURNACE.description
protection.flags.FURNACE.hint
protection.flags.FURNACE.name
protection.flags.GATE.description
protection.flags.GATE.hint
protection.flags.GATE.name
protection.flags.GEO_LIMIT_MOBS.description
protection.flags.GEO_LIMIT_MOBS.name
protection.flags.HURT_ANIMALS.description
protection.flags.HURT_ANIMALS.hint
protection.flags.HURT_ANIMALS.name
protection.flags.HURT_MONSTERS.description
protection.flags.HURT_MONSTERS.hint
protection.flags.HURT_MONSTERS.name
protection.flags.HURT_VILLAGERS.description
protection.flags.HURT_VILLAGERS.hint
protection.flags.HURT_VILLAGERS.name
protection.flags.ITEM_FRAME_DAMAGE.description
protection.flags.ITEM_FRAME_DAMAGE.name
protection.flags.INVINCIBLE_VISITORS.description
protection.flags.INVINCIBLE_VISITORS.hint
protection.flags.INVINCIBLE_VISITORS.name
protection.flags.ISLAND_RESPAWN.description
protection.flags.ISLAND_RESPAWN.name
protection.flags.ITEM_DROP.description
protection.flags.ITEM_DROP.hint
protection.flags.ITEM_DROP.name
protection.flags.ITEM_PICKUP.description
protection.flags.ITEM_PICKUP.hint
protection.flags.ITEM_PICKUP.name
protection.flags.JUKEBOX.description
protection.flags.JUKEBOX.hint
protection.flags.JUKEBOX.name
protection.flags.LEASH.description
protection.flags.LEASH.hint
protection.flags.LEASH.name
protection.flags.LEVER.description
protection.flags.LEVER.hint
protection.flags.LEVER.name
protection.flags.LOCK.description
protection.flags.LOCK.name
protection.flags.MILKING.description
protection.flags.MILKING.hint
protection.flags.MILKING.name
protection.flags.MONSTER_SPAWN.description
protection.flags.MONSTER_SPAWN.name
protection.flags.MOUNT_INVENTORY.description
protection.flags.MOUNT_INVENTORY.hint
protection.flags.MOUNT_INVENTORY.name
protection.flags.NOTE_BLOCK.description
protection.flags.NOTE_BLOCK.hint
protection.flags.NOTE_BLOCK.name
protection.flags.OFFLINE_REDSTONE.description
protection.flags.OFFLINE_REDSTONE.name
protection.flags.PISTON_PUSH.description
protection.flags.PISTON_PUSH.name
protection.flags.PLACE_BLOCKS.description
protection.flags.PLACE_BLOCKS.hint
protection.flags.PLACE_BLOCKS.name
protection.flags.PORTAL.description
protection.flags.PORTAL.hint
protection.flags.PORTAL.name
protection.flags.PRESSURE_PLATE.description
protection.flags.PRESSURE_PLATE.hint
protection.flags.PRESSURE_PLATE.name
protection.flags.PVP_END.description
protection.flags.PVP_END.hint
protection.flags.PVP_END.name
protection.flags.PVP_NETHER.description
protection.flags.PVP_NETHER.hint
protection.flags.PVP_NETHER.name
protection.flags.PVP_OVERWORLD.description
protection.flags.PVP_OVERWORLD.hint
protection.flags.PVP_OVERWORLD.name
protection.flags.REDSTONE.description
protection.flags.REDSTONE.hint
protection.flags.REDSTONE.name
protection.flags.RIDING.description
protection.flags.RIDING.hint
protection.flags.RIDING.name
protection.flags.REMOVE_MOBS.description
protection.flags.REMOVE_MOBS.name
protection.flags.SHEARING.description
protection.flags.SHEARING.hint
protection.flags.SHEARING.name
protection.flags.SPAWN_EGGS.description
protection.flags.SPAWN_EGGS.hint
protection.flags.SPAWN_EGGS.name
protection.flags.TNT.description
protection.flags.TNT.hint
protection.flags.TNT.name
protection.flags.TRADING.description
protection.flags.TRADING.hint
protection.flags.TRADING.name
protection.flags.TRAPDOOR.description
protection.flags.TRAPDOOR.hint
protection.flags.TRAPDOOR.name
protection.locked
protection.panel.flag-item.allowed_rank
protection.panel.flag-item.blocked_rank
protection.panel.flag-item.description-layout
protection.panel.flag-item.name-layout
protection.panel.flag-item.menu-layout
protection.panel.flag-item.minimal_rank
protection.panel.flag-item.setting-active
protection.panel.flag-item.setting-disabled
protection.panel.flag-item.setting-layout
protection.panel.PROTECTION.description
protection.panel.PROTECTION.title
protection.panel.SETTING.description
protection.panel.SETTING.title
protection.panel.WORLD_SETTING.description
protection.panel.WORLD_SETTING.title
protection.protected
ranks.admin
ranks.banned
ranks.coop
ranks.member
ranks.mod
ranks.owner
ranks.visitor
```

36
pom.xml
View File

@ -66,13 +66,13 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- Non-minecraft related dependencies -->
<powermock.version>1.7.4</powermock.version>
<powermock.version>2.0.2</powermock.version>
<mongodb.version>3.8.0</mongodb.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.13.2-R0.1-SNAPSHOT</spigot.version>
<bstats.version>1.5</bstats.version>
<vault.version>1.7</vault.version>
<placeholderapi.version>2.10.1</placeholderapi.version>
<placeholderapi.version>2.10.3</placeholderapi.version>
<mvdwplaceholderapi.version>2.5.1-SNAPSHOT</mvdwplaceholderapi.version>
<githubapi.version>1.0</githubapi.version>
<!-- Revision variable removes warning about dynamic version -->
@ -80,7 +80,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>1.5.3</build.version>
<build.version>1.6.0</build.version>
</properties>
<!-- Profiles will allow to automatically change build version. -->
@ -166,6 +166,10 @@
<id>dynmap-repo</id>
<url>http://repo.mikeprimm.com/</url>
</repository>
<repository>
<id>worldedit-repo</id>
<url>http://maven.sk89q.com/repo/</url>
</repository>
</repositories>
<dependencies>
@ -176,12 +180,6 @@
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<!-- Some APIs from us :D -->
<dependency>
<groupId>world.bentobox</groupId>
<artifactId>GitHubAPI4Java</artifactId>
<version>${githubapi.version}</version>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>org.bstats</groupId>
@ -191,8 +189,8 @@
<!-- Mockito (Unit testing) -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<artifactId>mockito-core</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
@ -203,7 +201,7 @@
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
@ -243,6 +241,18 @@
<artifactId>dynmap-api</artifactId>
<version>3.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-core</artifactId>
<version>7.0.0</version>
<scope>provided</scope>
</dependency>
<!-- Shaded APIs -->
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>GitHubWebAPI4Java</artifactId>
<version>d5f5e0bbd8</version>
</dependency>
<!-- Static analysis -->
<!-- We are using Eclipse's annotations.
@ -336,7 +346,7 @@
<shadedPattern>world.bentobox.bentobox.util.metrics</shadedPattern>
</relocation>
<relocation>
<pattern>world.bentobox.githubapi4java</pattern>
<pattern>io.github.TheBusyBiscuit.GitHubWebAPI4Java</pattern>
<shadedPattern>world.bentobox.bentobox.api.github</shadedPattern>
</relocation>
</relocations>

View File

@ -4,7 +4,10 @@ import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.flags.Flag;
/**
* @author Poslovitch
@ -33,11 +36,14 @@ public class BStats {
}
private void registerCustomMetrics() {
// Simple Pie Charts
// Pie Charts
registerDefaultLanguageChart();
registerDatabaseTypeChart();
registerAddonsChart();
registerGameModeAddonsChart();
registerHooksChart();
registerPlayersPerServerChart();
registerFlagsDisplayModeChart();
// Single Line charts
registerIslandsCountChart();
@ -102,4 +108,53 @@ public class BStats {
return values;
}));
}
/**
* Sends the enabled Hooks of this server.
* @since 1.6.0
*/
private void registerHooksChart() {
metrics.addCustomChart(new Metrics.AdvancedPie("hooks", () -> {
Map<String, Integer> values = new HashMap<>();
plugin.getHooks().getHooks().forEach(hook -> values.put(hook.getPluginName(), 1));
return values;
}));
}
/**
* Sends the "category" this server is in depending on how many players it has.
* @since 1.6.0
*/
private void registerPlayersPerServerChart() {
metrics.addCustomChart(new Metrics.SimplePie("playersPerServer", () -> {
int players = Bukkit.getOnlinePlayers().size();
if (players <= 10) return "0-10";
else if (players <= 30) return "11-30";
else if (players <= 50) return "31-50";
else if (players <= 100) return "51-100";
else if (players <= 200) return "101-200";
else return "201+";
}));
}
/**
* Sends the "flags display mode" of all the online players.
* @since 1.6.0
*/
private void registerFlagsDisplayModeChart() {
metrics.addCustomChart(new Metrics.AdvancedPie("flagsDisplayMode", () -> {
Map<String, Integer> values = new HashMap<>();
Bukkit.getOnlinePlayers().forEach(player -> {
Flag.Mode mode = plugin.getPlayers().getFlagsDisplayMode(player.getUniqueId());
if (values.containsKey(mode.name())) {
values.put(mode.name(), values.get(mode.name()) + 1);
} else {
values.put(mode.name(), 1);
}
});
return values;
}));
}
}

View File

@ -19,15 +19,15 @@ import world.bentobox.bentobox.api.user.Notifier;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.commands.BentoBoxCommand;
import world.bentobox.bentobox.hooks.DynmapHook;
import world.bentobox.bentobox.hooks.placeholders.MVdWPlaceholderAPIHook;
import world.bentobox.bentobox.hooks.MultiverseCoreHook;
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.hooks.WorldEditHook;
import world.bentobox.bentobox.hooks.placeholders.MVdWPlaceholderAPIHook;
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
import world.bentobox.bentobox.listeners.BannedVisitorCommands;
import world.bentobox.bentobox.listeners.BlockEndDragon;
import world.bentobox.bentobox.listeners.DeathListener;
import world.bentobox.bentobox.listeners.JoinLeaveListener;
import world.bentobox.bentobox.listeners.NetherTreesListener;
import world.bentobox.bentobox.listeners.PanelListenerManager;
import world.bentobox.bentobox.listeners.PortalTeleportationListener;
import world.bentobox.bentobox.listeners.StandardSpawnProtectionListener;
@ -52,6 +52,7 @@ import world.bentobox.bentobox.versions.ServerCompatibility;
* @author tastybento, Poslovitch
*/
public class BentoBox extends JavaPlugin {
private static BentoBox instance;
// Databases
@ -85,6 +86,8 @@ public class BentoBox extends JavaPlugin {
@Nullable
private BStats metrics;
private Config<Settings> configObject;
@Override
public void onEnable(){
if (!ServerCompatibility.getInstance().checkCompatibility().isCanLaunch()) {
@ -200,6 +203,7 @@ public class BentoBox extends JavaPlugin {
// Register additional hooks
hooksManager.registerHook(new DynmapHook());
hooksManager.registerHook(new WorldEditHook());
webManager = new WebManager(this);
@ -229,8 +233,6 @@ public class BentoBox extends JavaPlugin {
manager.registerEvents(new StandardSpawnProtectionListener(this), this);
// Nether portals
manager.registerEvents(new PortalTeleportationListener(this), this);
// Nether trees conversion
manager.registerEvents(new NetherTreesListener(this), this);
// End dragon blocking
manager.registerEvents(new BlockEndDragon(this), this);
// Banned visitor commands
@ -338,7 +340,8 @@ public class BentoBox extends JavaPlugin {
public boolean loadSettings() {
log("Loading Settings from config.yml...");
// Load settings from config.yml. This will check if there are any issues with it too.
settings = new Config<>(this, Settings.class).loadConfigObject();
if (configObject == null) configObject = new Config<>(this, Settings.class);
settings = configObject.loadConfigObject();
if (settings == null) {
// Settings did not load correctly. Disable plugin.
logError("Settings did not load correctly - disabling plugin - please check config.yml");
@ -350,7 +353,7 @@ public class BentoBox extends JavaPlugin {
@Override
public void saveConfig() {
if (settings != null) new Config<>(this, Settings.class).saveConfigObject(settings);
if (settings != null) configObject.saveConfigObject(settings);
}
/**

View File

@ -1,16 +1,13 @@
package world.bentobox.bentobox;
import java.util.HashSet;
import java.util.Set;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.api.configuration.ConfigEntry;
import world.bentobox.bentobox.api.configuration.ConfigObject;
import world.bentobox.bentobox.api.configuration.StoreAt;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.managers.RanksManager;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* All the plugin settings are here
@ -38,10 +35,11 @@ public class Settings implements ConfigObject {
private boolean useEconomy = true;
// Database
@ConfigComment("JSON, MYSQL, MARIADB (10.2.3+), MONGODB, and YAML(deprecated).")
@ConfigComment("JSON, MYSQL, MARIADB (10.2.3+), MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).")
@ConfigComment("Transition database options are:")
@ConfigComment(" YAML2JSON, YAML2MARIADB, YAML2MYSQL")
@ConfigComment(" JSON2MARIADB, JSON2MYSQL, MYSQL2JSON")
@ConfigComment(" YAML2JSON, YAML2MARIADB, YAML2MYSQL, YAML2MONGODB, YAML2SQLITE")
@ConfigComment(" JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE, JSON2POSTGRESQL")
@ConfigComment(" MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON, POSTGRESQL2JSON")
@ConfigComment("If you need others, please make a feature request.")
@ConfigComment("Transition options enable migration from one database type to another. Use /bbox migrate.")
@ConfigComment("YAML and JSON are file-based databases.")
@ -78,10 +76,6 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "general.fakeplayers", experimental = true)
private Set<String> fakePlayers = new HashSet<>();
@ConfigComment("Rank required to use a command. e.g., use the invite command. Default is owner rank is required.")
@ConfigEntry(path = "general.rank-command")
private Map<String, Integer> rankCommand = new HashMap<>();
@ConfigEntry(path = "panel.close-on-click-outside")
private boolean closePanelOnClickOutside = true;
@ -134,6 +128,11 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "island.confirmation.time")
private int confirmationTime = 10;
// Timeout for team kick and leave commands
@ConfigComment("Time in seconds that players have to stand still before teleport commands activate, e.g. island go.")
@ConfigEntry(path = "island.delay.time")
private int delayTime = 0;
@ConfigComment("Ask the player to confirm the command he is using by typing it again.")
@ConfigEntry(path = "island.confirmation.commands.kick")
private boolean kickConfirmation = true;
@ -150,6 +149,13 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "island.name.max-length")
private int nameMaxLength = 20;
@ConfigComment("Remove hostile mob on teleport box radius")
@ConfigComment("If hostile mobs are cleared on player teleport, then this sized box will be cleared")
@ConfigComment("around the player. e.g. 5 means a 10 x 10 x 10 box around the player")
@ConfigComment("Be careful not to make this too big. Does not cover standard nether or end teleports.")
@ConfigEntry(path = "island.clear-radius")
private int clearRadius = 5;
@ConfigComment("Number of blocks to paste per tick when pasting blueprints")
@ConfigComment("Smaller values will help reduce noticeable lag but will make pasting take longer")
@ConfigEntry(path = "island.paste-speed")
@ -190,10 +196,10 @@ public class Settings implements ConfigObject {
@ConfigComment("Time in minutes between each connection to the GitHub API.")
@ConfigComment("This allows for up-to-the-minute information gathering.")
@ConfigComment("However, as the GitHub API data does not get updated instantly, this value cannot be set less than 15 minutes.")
@ConfigComment("However, as the GitHub API data does not get updated instantly, this value cannot be set to less than 60 minutes.")
@ConfigComment("Setting this to 0 will make BentoBox download data only at startup.")
@ConfigEntry(path = "web.github.connection-interval", since = "1.5.0")
private int githubConnectionInterval = 60;
private int githubConnectionInterval = 120;
@ConfigEntry(path = "web.updater.check-updates.bentobox", since = "1.3.0", hidden = true)
private boolean checkBentoBoxUpdates = true;
@ -292,22 +298,6 @@ public class Settings implements ConfigObject {
this.fakePlayers = fakePlayers;
}
public Map<String, Integer> getRankCommand() {
return rankCommand;
}
public int getRankCommand(String command) {
return rankCommand.getOrDefault(command, RanksManager.OWNER_RANK);
}
public void setRankCommand(String command, int rank) {
rankCommand.put(command, rank);
}
public void setRankCommand(Map<String, Integer> rankCommand) {
this.rankCommand = rankCommand;
}
public boolean isClosePanelOnClickOutside() {
return closePanelOnClickOutside;
}
@ -497,4 +487,33 @@ public class Settings implements ConfigObject {
public void setLogGithubDownloadData(boolean logGithubDownloadData) {
this.logGithubDownloadData = logGithubDownloadData;
}
public int getDelayTime() {
return delayTime;
}
/**
* @param delayTime the delayTime to set
*/
public void setDelayTime(int delayTime) {
this.delayTime = delayTime;
}
/**
* @return the clearRadius
*/
public int getClearRadius() {
if (clearRadius < 0) clearRadius = 0;
return clearRadius;
}
/**
* @param clearRadius the clearRadius to set. Cannot be negative.
*/
public void setClearRadius(int clearRadius) {
if (clearRadius < 0) clearRadius = 0;
this.clearRadius = clearRadius;
}
}

View File

@ -1,16 +1,5 @@
package world.bentobox.bentobox.api.addons;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Listener;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -21,6 +10,18 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Listener;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.request.AddonRequestHandler;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
/**
* Add-on class for BentoBox. Extend this to create an add-on. The operation
* and methods are very similar to Bukkit's JavaPlugin.
@ -385,7 +386,7 @@ public abstract class Addon {
/**
* Register request handler to answer requests from plugins.
* @param handler
* @param handler request handler
*/
public void registerRequestHandler(AddonRequestHandler handler) {
requestHandlers.put(handler.getLabel(), handler);
@ -393,8 +394,8 @@ public abstract class Addon {
/**
* Send request to addon.
* @param label
* @param metaData
* @param label label
* @param metaData meta data
* @return request response, null if no response.
*/
public Object request(String label, Map<String, Object> metaData) {

View File

@ -1,18 +1,5 @@
package world.bentobox.bentobox.api.addons;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.util.permissions.DefaultPermissions;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonInheritException;
import world.bentobox.bentobox.managers.AddonsManager;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
@ -23,12 +10,27 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.util.permissions.DefaultPermissions;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonInheritException;
import world.bentobox.bentobox.managers.AddonsManager;
/**
* Loads addons and sets up permissions
* @author Tastybento, ComminQ
*/
public class AddonClassLoader extends URLClassLoader {
private static final String DEFAULT = ".default";
private final Map<String, Class<?>> classes = new HashMap<>();
private Addon addon;
private AddonsManager loader;
@ -70,7 +72,7 @@ public class AddonClassLoader extends URLClassLoader {
if (data.isConfigurationSection("permissions")) {
ConfigurationSection perms = data.getConfigurationSection("permissions");
perms.getKeys(true).forEach(perm -> {
if (perms.contains(perm + ".default") && perms.contains(perm + ".description")) {
if (perms.contains(perm + DEFAULT) && perms.contains(perm + ".description")) {
registerPermission(perms, perm);
}
});
@ -78,7 +80,11 @@ public class AddonClassLoader extends URLClassLoader {
}
private void registerPermission(ConfigurationSection perms, String perm) {
PermissionDefault pd = PermissionDefault.getByName(perms.getString(perm + ".default"));
if (perms.getString(perm + DEFAULT) == null) {
Bukkit.getLogger().severe("Permission default is invalid : " + perms.getName());
return;
}
PermissionDefault pd = PermissionDefault.getByName(perms.getString(perm + DEFAULT));
if (pd == null) {
Bukkit.getLogger().severe("Permission default is invalid : " + perms.getName());
return;
@ -137,7 +143,6 @@ public class AddonClassLoader extends URLClassLoader {
result = super.findClass(name);
} catch (ClassNotFoundException | NoClassDefFoundError e) {
// Do nothing.
result = null;
}
if (result != null) {
loader.setClass(name, result);

View File

@ -1,12 +1,12 @@
package world.bentobox.bentobox.api.addons;
import org.bukkit.Material;
import org.eclipse.jdt.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Material;
import org.eclipse.jdt.annotation.NonNull;
/**
* @author tastybento, Poslovitch
*/

View File

@ -39,7 +39,8 @@ public abstract class GameModeAddon extends Addon {
/**
* Make the worlds for this GameMode in this method. BentoBox will call it
* after onLoad() and before onEnable().
* after onLoad() and before onEnable(). Do not register flags in this method.
* They ,ust be registered afterwards in onEnable()
* {@link #islandWorld} must be created and assigned,
* {@link #netherWorld} and {@link #endWorld} are optional and may be null.
*/
@ -117,10 +118,10 @@ public abstract class GameModeAddon extends Addon {
* Defines the world generator for this game mode
* @param worldName - name of world that this applies to
* @param id - id if any
* @return Chunk generator
* @return Chunk generator or null if one does not exist, e.g. the use own generator setting is true
* @since 1.2.0
*/
@NonNull
@Nullable
public abstract ChunkGenerator getDefaultWorldGenerator(String worldName, String id);
/**

View File

@ -18,7 +18,7 @@ public class AddonRequestBuilder
/**
* Define the addon you wish to request.
*
* @param addonName
* @param addonName addon name
*/
public AddonRequestBuilder addon(String addonName) {
this.addonName = addonName;
@ -28,7 +28,7 @@ public class AddonRequestBuilder
/**
* Define label for addon request.
*
* @param requestLabel
* @param requestLabel request label
*/
public AddonRequestBuilder label(String requestLabel) {
this.requestLabel = requestLabel;
@ -38,8 +38,8 @@ public class AddonRequestBuilder
/**
* Add meta data to addon request.
*
* @param key
* @param value
* @param key key
* @param value value
*/
public AddonRequestBuilder addMetaData(String key, Object value) {
metaData.put(key, value);

View File

@ -24,7 +24,7 @@ public abstract class AddonRequestHandler
* This is used only for Addons to respond to addon requests from plugins.
* Example: request island level from Levels addon.
*
* @param metaData
* @param metaData meta data
* @return request response
*/
public abstract Object handle(Map<String, Object> metaData);

View File

@ -238,8 +238,8 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
* Does not traverse the tree of subcommands in args.
* Event is not fired and it cannot be cancelled.
* @param user - user calling this command
* @param label - label used
* @param args - list of args
* @param cmdLabel - label used
* @param cmdArgs - list of args
* @return {@code true} if successful, {@code false} if not.
* @since 1.5.3
*/
@ -250,7 +250,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
return false;
}
// Check perms, but only if this isn't the console
if (user.isPlayer() && !user.isOp() && !getPermission().isEmpty() && !user.hasPermission(getPermission())) {
if (user.isPlayer() && !user.isOp() && getPermission() != null && !getPermission().isEmpty() && !user.hasPermission(getPermission())) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, getPermission());
return false;
}
@ -592,7 +592,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
if (command.isOnlyPlayer() && !(sender instanceof Player)) {
return options;
}
if (!command.getPermission().isEmpty() && !sender.hasPermission(command.getPermission()) && !sender.isOp()) {
if (command.getPermission() != null && !command.getPermission().isEmpty() && !sender.hasPermission(command.getPermission()) && !sender.isOp()) {
return options;
}
// Add any tab completion from the subcommand
@ -624,7 +624,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
@NonNull
private List<String> getSubCommandLabels(@NonNull CommandSender sender, @NonNull CompositeCommand command) {
return command.getSubCommands().values().stream()
.filter(cmd -> !cmd.isOnlyPlayer() || sender.isOp() || (sender instanceof Player && (cmd.getPermission().isEmpty() || sender.hasPermission(cmd.getPermission()))) )
.filter(cmd -> !cmd.isOnlyPlayer() || sender.isOp() || (sender instanceof Player && cmd.getPermission() != null && (cmd.getPermission().isEmpty() || sender.hasPermission(cmd.getPermission()))) )
.map(CompositeCommand::getLabel).collect(Collectors.toList());
}

View File

@ -91,6 +91,11 @@ public abstract class ConfirmableCommand extends CompositeCommand {
askConfirmation(user, "", confirmed);
}
/**
* Holds the data to run once the confirmation is given
* @author tastybento
*
*/
private class Confirmer {
private final String topLabel;
private final String label;

View File

@ -0,0 +1,155 @@
package world.bentobox.bentobox.api.commands;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.scheduler.BukkitTask;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.user.User;
/**
* BentoBox Delayed Teleport Command
* Adds ability to require the player stays still for a period of time before a command is executed
* @author tastybento
*/
public abstract class DelayedTeleportCommand extends CompositeCommand implements Listener {
/**
* User monitor map
*/
private static Map<UUID, DelayedCommand> toBeMonitored = new HashMap<>();
@EventHandler
public void onPlayerMove(PlayerMoveEvent e) {
UUID uuid = e.getPlayer().getUniqueId();
// Only check x,y,z
if (toBeMonitored.containsKey(uuid) && !e.getTo().toVector().equals(toBeMonitored.get(uuid).getLocation().toVector())) {
// Player moved
toBeMonitored.get(uuid).getTask().cancel();
toBeMonitored.remove(uuid);
// Player has another outstanding confirmation request that will now be cancelled
User.getInstance(e.getPlayer()).notify("commands.delay.moved-so-command-cancelled");
}
}
/**
* Top level command
* @param addon - addon creating the command
* @param label - string for this command
* @param aliases - aliases
*/
public DelayedTeleportCommand(Addon addon, String label, String... aliases) {
super(addon, label, aliases);
Bukkit.getPluginManager().registerEvents(this, getPlugin());
}
/**
* Command to register a command from an addon under a parent command (that could be from another addon)
* @param addon - this command's addon
* @param parent - parent command
* @param aliases - aliases for this command
*/
public DelayedTeleportCommand(Addon addon, CompositeCommand parent, String label, String... aliases ) {
super(addon, parent, label, aliases);
Bukkit.getPluginManager().registerEvents(this, getPlugin());
}
public DelayedTeleportCommand(CompositeCommand parent, String label, String... aliases) {
super(parent, label, aliases);
Bukkit.getPluginManager().registerEvents(this, getPlugin());
}
/**
* Tells user to stand still for a period of time before teleporting
* @param user User to tell
* @param message Optional message to send to the user to give them a bit more context. It must already be translated.
* @param confirmed Runnable to be executed if successfully delayed.
*/
public void delayCommand(User user, String message, Runnable confirmed) {
if (getSettings().getDelayTime() < 1) {
Bukkit.getScheduler().runTask(getPlugin(), confirmed);
return;
}
// Check for pending delays
UUID uuid = user.getUniqueId();
if (toBeMonitored.containsKey(uuid)) {
// A double request - clear out the old one
toBeMonitored.get(uuid).getTask().cancel();
toBeMonitored.remove(uuid);
// Player has another outstanding confirmation request that will now be cancelled
user.sendMessage("commands.delay.previous-command-cancelled");
}
// Send user the context message if it is not empty
if (!message.trim().isEmpty()) {
user.sendRawMessage(message);
}
// Tell user that they need to stand still
user.sendMessage("commands.delay.stand-still", "[seconds]", String.valueOf(getSettings().getDelayTime()));
// Set up the run task
BukkitTask task = Bukkit.getScheduler().runTaskLater(getPlugin(), () -> {
Bukkit.getScheduler().runTask(getPlugin(), toBeMonitored.get(uuid).getRunnable());
toBeMonitored.remove(uuid);
}, getPlugin().getSettings().getDelayTime() * 20L);
// Add to the monitor
toBeMonitored.put(uuid, new DelayedCommand(confirmed, task, user.getLocation()));
}
/**
* Tells user to stand still for a period of time before teleporting
* @param user User to monitor.
* @param command Runnable to be executed if player does not move.
*/
public void delayCommand(User user, Runnable command) {
delayCommand(user, "", command);
}
/**
* Holds the data to run once the confirmation is given
* @author tastybento
*
*/
private class DelayedCommand {
private final Runnable runnable;
private final BukkitTask task;
private final Location location;
/**
* @param runnable - runnable to run when confirmed
* @param task - task ID to cancel when confirmed
* @param location - location
*/
DelayedCommand(Runnable runnable, BukkitTask task, Location location) {
this.runnable = runnable;
this.task = task;
this.location = location;
}
/**
* @return the runnable
*/
public Runnable getRunnable() {
return runnable;
}
/**
* @return the task
*/
public BukkitTask getTask() {
return task;
}
/**
* @return the location
*/
public Location getLocation() {
return location;
}
}
}

View File

@ -5,6 +5,8 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.util.Vector;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
@ -27,10 +29,10 @@ public class AdminDeleteCommand extends ConfirmableCommand {
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() != 1) {
showHelp(this, user);
return false;
}
if (args.size() != 1) {
showHelp(this, user);
return false;
}
// Get target
UUID targetUUID = getPlayers().getUUID(args.get(0));
if (targetUUID == null) {
@ -65,10 +67,9 @@ public class AdminDeleteCommand extends ConfirmableCommand {
private void deletePlayer(User user, UUID targetUUID) {
// Delete player and island
user.sendMessage("commands.admin.delete.deleted-island", "[xyz]", Util.xyz(getIslands().getIsland(getWorld(), targetUUID).getCenter().toVector()));
// Get the target's island
Island oldIsland = getIslands().getIsland(getWorld(), targetUUID);
Vector vector = null;
if (oldIsland != null) {
// Check if player is online and on the island
User target = User.getInstance(targetUUID);
@ -86,10 +87,15 @@ public class AdminDeleteCommand extends ConfirmableCommand {
getPlugin().getVault().ifPresent(vault -> vault.withdraw(target, vault.getBalance(target)));
}
}
getIslands().deleteIsland(oldIsland, true);
vector = oldIsland.getCenter().toVector();
getIslands().deleteIsland(oldIsland, true, targetUUID);
}
getPlayers().clearHomeLocations(getWorld(), targetUUID);
user.sendMessage("general.success");
if (vector == null) {
user.sendMessage("general.success");
} else {
user.sendMessage("commands.admin.delete.deleted-island", "[xyz]", Util.xyz(vector));
}
}
@Override

View File

@ -53,7 +53,7 @@ public class AdminEmptyTrashCommand extends ConfirmableCommand {
} else {
this.askConfirmation(user, () -> {
getIslands().deleteQuarantinedIslandByUser(getWorld(), targetUUID);
user.sendMessage("general.success");
user.sendMessage("commands.admin.emptytrash.success");
});
return true;
}

View File

@ -82,7 +82,7 @@ public class AdminRegisterCommand extends ConfirmableCommand {
Bukkit.getServer().getPluginManager().callEvent(event);
return true;
}).orElse(false)) {
// Island does not exist
// Island does not exist - this is a reservation
user.sendMessage("commands.admin.register.no-island-here");
this.askConfirmation(user, () -> {
// Make island here
@ -92,13 +92,13 @@ public class AdminRegisterCommand extends ConfirmableCommand {
return;
}
getIslands().setOwner(user, targetUUID, i);
getWorld().getBlockAt(i.getCenter()).setType(Material.BEDROCK);
user.sendMessage("commands.admin.register.registered-island", "[xyz]", Util.xyz(i.getCenter().toVector()));
user.sendMessage("general.success");
i.setReserved(true);
i.getCenter().getBlock().setType(Material.BEDROCK);
user.sendMessage("commands.admin.register.reserved-island", "[xyz]", Util.xyz(i.getCenter().toVector()));
IslandBaseEvent event = IslandEvent.builder()
.island(i)
.location(i.getCenter())
.reason(IslandEvent.Reason.CREATED)
.reason(IslandEvent.Reason.RESERVED)
.involvedPlayer(targetUUID)
.admin(true)
.build();

View File

@ -29,7 +29,7 @@ public class AdminResetFlagsCommand extends ConfirmableCommand {
// Everything's fine, we can set the island as spawn :)
askConfirmation(user, () -> {
getIslands().resetAllFlags(getWorld());
user.sendMessage("general.success");
user.sendMessage("commands.admin.resetflags.success");
});
return true;
}

View File

@ -6,6 +6,8 @@ import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -18,6 +20,10 @@ import world.bentobox.bentobox.managers.RanksManager;
*/
public class AdminSetrankCommand extends CompositeCommand {
private int rankValue;
private @Nullable UUID targetUUID;
private RanksManager rm;
public AdminSetrankCommand(CompositeCommand adminCommand) {
super(adminCommand, "setrank");
}
@ -28,17 +34,18 @@ public class AdminSetrankCommand extends CompositeCommand {
setOnlyPlayer(false);
setParametersHelp("commands.admin.setrank.parameters");
setDescription("commands.admin.setrank.description");
rm = getPlugin().getRanksManager();
}
@Override
public boolean execute(User user, String label, List<String> args) {
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() != 2) {
// Show help
showHelp(this, user);
return false;
}
// Get target player
UUID targetUUID = getPlayers().getUUID(args.get(0));
targetUUID = getPlayers().getUUID(args.get(0));
if (targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
@ -48,16 +55,23 @@ public class AdminSetrankCommand extends CompositeCommand {
return false;
}
// Get rank
RanksManager rm = getPlugin().getRanksManager();
int rankValue = rm.getRanks().entrySet().stream()
rankValue = rm.getRanks().entrySet().stream()
.filter(r -> user.getTranslation(r.getKey()).equalsIgnoreCase(args.get(1))).findFirst()
.map(Map.Entry::getValue).orElse(-999);
if (rankValue < RanksManager.BANNED_RANK) {
user.sendMessage("commands.admin.setrank.unknown-rank");
return false;
}
User target = User.getInstance(targetUUID);
if (rankValue <= RanksManager.VISITOR_RANK) {
user.sendMessage("commands.admin.setrank.not-possible");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
User target = User.getInstance(targetUUID);
Island island = getPlugin().getIslands().getIsland(getWorld(), targetUUID);
int currentRank = island.getRank(target);
island.setRank(target, rankValue);

View File

@ -75,7 +75,6 @@ public class AdminSetspawnCommand extends ConfirmableCommand {
}
getIslands().setSpawn(i);
i.setSpawnPoint(World.Environment.NORMAL, user.getLocation());
user.sendMessage("general.success");
user.sendMessage("commands.admin.setspawn.success");
}
}

View File

@ -0,0 +1,86 @@
package world.bentobox.bentobox.api.commands.admin;
import java.util.List;
import java.util.UUID;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.builders.TabbedPanelBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.panels.settings.SettingsTab;
import world.bentobox.bentobox.panels.settings.WorldDefaultSettingsTab;
/**
* @author tastybento
* @since 1.6.0
*/
public class AdminSettingsCommand extends CompositeCommand {
private Island island;
public AdminSettingsCommand(CompositeCommand islandCommand) {
super(islandCommand, "settings", "flags", "options");
}
@Override
public void setup() {
setPermission("admin.settings");
setOnlyPlayer(true);
setParametersHelp("commands.admin.settings.parameters");
setDescription("commands.admin.settings.description");
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() > 1) {
// Show help
showHelp(this, user);
return false;
}
if (args.isEmpty()) {
// World settings
return true;
}
// Get target player
@Nullable UUID targetUUID = getPlayers().getUUID(args.get(0));
if (targetUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
island = getIslands().getIsland(getWorld(), targetUUID);
if (island == null || !getPlugin().getIslands().hasIsland(getWorld(), targetUUID)) {
user.sendMessage("general.errors.player-has-no-island");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.isEmpty()) {
new TabbedPanelBuilder()
.user(user)
.world(getWorld())
.tab(1, new SettingsTab(getWorld(), user, Flag.Type.WORLD_SETTING))
.tab(2, new WorldDefaultSettingsTab(getWorld(), user))
.startingSlot(1)
.size(54)
.build().openPanel();
return true;
}
// Player settings
new TabbedPanelBuilder()
.user(user)
.world(getWorld())
.tab(1, new SettingsTab(getWorld(), user, island, Flag.Type.PROTECTION))
.tab(2, new SettingsTab(getWorld(), user, island, Flag.Type.SETTING))
.startingSlot(1)
.size(54)
.build().openPanel();
return true;
}
}

View File

@ -1,11 +1,11 @@
package world.bentobox.bentobox.api.commands.admin;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
import java.util.List;
/**
* @since 1.5.0
* @author tastybento

View File

@ -1,9 +1,11 @@
package world.bentobox.bentobox.api.commands.admin;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.apache.commons.lang.math.NumberUtils;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
@ -14,6 +16,7 @@ import world.bentobox.bentobox.database.objects.Island;
public class AdminSwitchtoCommand extends ConfirmableCommand {
private UUID targetUUID;
private @NonNull List<Island> islands;
/**
* Switch player's island to the numbered one in trash
@ -22,6 +25,7 @@ public class AdminSwitchtoCommand extends ConfirmableCommand {
*/
public AdminSwitchtoCommand(CompositeCommand parent) {
super(parent, "switchto");
islands = new ArrayList<>();
}
@Override
@ -45,37 +49,35 @@ public class AdminSwitchtoCommand extends ConfirmableCommand {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
// Check island number
islands = getIslands().getQuarantinedIslandByUser(getWorld(), targetUUID);
if (islands.isEmpty()) {
user.sendMessage("commands.admin.trash.no-islands-in-trash");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
// Check island number
List<Island> islands = getIslands().getQuarantinedIslandByUser(getWorld(), targetUUID);
if (islands.isEmpty()) {
user.sendMessage("commands.admin.trash.no-islands-in-trash");
return false;
} else {
// Check number
if (NumberUtils.isDigits(args.get(1))) {
try {
Integer n = Integer.valueOf(args.get(1));
if (n < 1 || n > islands.size()) {
user.sendMessage("commands.admin.switchto.out-of-range", TextVariables.NUMBER, String.valueOf(islands.size()), TextVariables.LABEL, getTopLabel());
return false;
}
this.askConfirmation(user, () -> {
if (getIslands().switchIsland(getWorld(), targetUUID, islands.get(n -1))) {
user.sendMessage("general.success");
} else {
user.sendMessage("commands.admin.switchto.cannot-switch");
}
});
return true;
} catch (Exception e) {
showHelp(this, user);
if (NumberUtils.isDigits(args.get(1))) {
try {
Integer n = Integer.valueOf(args.get(1));
if (n < 1 || n > islands.size()) {
user.sendMessage("commands.admin.switchto.out-of-range", TextVariables.NUMBER, String.valueOf(islands.size()), TextVariables.LABEL, getTopLabel());
return false;
}
this.askConfirmation(user, () -> {
if (getIslands().switchIsland(getWorld(), targetUUID, islands.get(n -1))) {
user.sendMessage("commands.admin.switchto.success");
} else {
user.sendMessage("commands.admin.switchto.cannot-switch");
}
});
return true;
} catch (Exception e) {
showHelp(this, user);
return false;
}
}
return true;

View File

@ -60,7 +60,6 @@ public class AdminTeleportCommand extends CompositeCommand {
.entity(user.getPlayer())
.location(warpSpot)
.failureMessage(failureMessage)
.overrideGamemode(false)
.build();
return true;
}

View File

@ -63,7 +63,6 @@ public class AdminUnregisterCommand extends ConfirmableCommand {
private void unregisterPlayer(User user, UUID targetUUID) {
// Unregister island
Island oldIsland = getIslands().getIsland(getWorld(), targetUUID);
user.sendMessage("commands.admin.unregister.unregistered-island", "[xyz]", Util.xyz(oldIsland.getCenter().toVector()));
IslandBaseEvent event = IslandEvent.builder()
.island(oldIsland)
.location(oldIsland.getCenter())
@ -77,7 +76,7 @@ public class AdminUnregisterCommand extends ConfirmableCommand {
getIslands().removePlayer(getWorld(), m);
getPlayers().clearHomeLocations(getWorld(), m);
});
user.sendMessage("general.success");
user.sendMessage("commands.admin.unregister.unregistered-island", "[xyz]", Util.xyz(oldIsland.getCenter().toVector()));
}
@Override

View File

@ -48,7 +48,7 @@ public class AdminWhyCommand extends ConfirmableCommand {
}
// Determine the debug mode and toggle if required
boolean newValue = !target.getPlayer().getMetadata(getWorld().getName() + "_why_debug").stream()
.filter(p -> p.getOwningPlugin().equals(getPlugin())).findFirst().map(MetadataValue::asBoolean).orElse(false);
.filter(p -> getPlugin().equals(p.getOwningPlugin())).findFirst().map(MetadataValue::asBoolean).orElse(false);
if (newValue) {
user.sendMessage("commands.admin.why.turning-on", TextVariables.NAME, target.getName());
} else {

View File

@ -1,11 +1,11 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import java.util.List;
public class AdminBlueprintCopyCommand extends CompositeCommand {
public AdminBlueprintCopyCommand(AdminBlueprintCommand parent) {

View File

@ -1,9 +1,5 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintsManager;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
@ -11,6 +7,10 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintsManager;
public class AdminBlueprintListCommand extends CompositeCommand {
public AdminBlueprintListCommand(AdminBlueprintCommand parent) {

View File

@ -1,14 +1,14 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.managers.BlueprintClipboardManager;
import world.bentobox.bentobox.util.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class AdminBlueprintLoadCommand extends CompositeCommand {
public AdminBlueprintLoadCommand(AdminBlueprintCommand parent) {

View File

@ -1,14 +1,15 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import java.util.List;
public class AdminBlueprintOriginCommand extends CompositeCommand {
public AdminBlueprintOriginCommand(AdminBlueprintCommand parent) {

View File

@ -1,12 +1,12 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.blueprints.BlueprintPaster;
import java.util.List;
public class AdminBlueprintPasteCommand extends CompositeCommand {
public AdminBlueprintPasteCommand(AdminBlueprintCommand parent) {

View File

@ -1,12 +1,12 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.util.Util;
import java.util.List;
public class AdminBlueprintPos1Command extends CompositeCommand {
public AdminBlueprintPos1Command(AdminBlueprintCommand parent) {

View File

@ -1,12 +1,12 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.util.Util;
import java.util.List;
public class AdminBlueprintPos2Command extends CompositeCommand {
public AdminBlueprintPos2Command(AdminBlueprintCommand parent) {

View File

@ -1,5 +1,9 @@
package world.bentobox.bentobox.api.commands.admin.blueprints;
import java.io.File;
import java.util.List;
import java.util.Locale;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
@ -7,10 +11,6 @@ import world.bentobox.bentobox.blueprints.BlueprintClipboard;
import world.bentobox.bentobox.managers.BlueprintClipboardManager;
import world.bentobox.bentobox.managers.BlueprintsManager;
import java.io.File;
import java.util.List;
import java.util.Locale;
public class AdminBlueprintSaveCommand extends ConfirmableCommand {
public AdminBlueprintSaveCommand(AdminBlueprintCommand parent) {
@ -34,6 +34,11 @@ public class AdminBlueprintSaveCommand extends ConfirmableCommand {
BlueprintClipboard clipboard = parent.getClipboards().computeIfAbsent(user.getUniqueId(), v -> new BlueprintClipboard());
String fileName = args.get(0).toLowerCase(Locale.ENGLISH);
if (clipboard.isFull()) {
// Check if blueprint had bedrock
if (clipboard.getBlueprint().getBedrock() == null) {
user.sendMessage("commands.admin.blueprint.bedrock-required");
return false;
}
// Check if file exists
File newFile = new File(parent.getBlueprintsFolder(), fileName + BlueprintsManager.BLUEPRINT_SUFFIX);
if (newFile.exists()) {

View File

@ -1,13 +1,14 @@
package world.bentobox.bentobox.api.commands.admin.deaths;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import java.util.List;
import java.util.UUID;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
/**
* @author Poslovitch
*/

View File

@ -1,14 +1,15 @@
package world.bentobox.bentobox.api.commands.admin.deaths;
import org.apache.commons.lang.math.NumberUtils;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import java.util.List;
import java.util.UUID;
import org.apache.commons.lang.math.NumberUtils;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
/**
* @author Poslovitch
*/

View File

@ -0,0 +1,157 @@
package world.bentobox.bentobox.api.commands.admin.purge;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeletedEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
public class AdminPurgeCommand extends CompositeCommand implements Listener {
private int count;
private boolean inPurge;
private boolean toBeConfirmed;
private Iterator<String> it;
private User user;
private Set<String> islands = new HashSet<>();
public AdminPurgeCommand(CompositeCommand parent) {
super(parent, "purge");
getAddon().registerListener(this);
}
@Override
public void setup() {
setPermission("admin.purge");
setOnlyPlayer(false);
setParametersHelp("commands.admin.purge.parameters");
setDescription("commands.admin.purge.description");
new AdminPurgeStopCommand(this);
new AdminPurgeUnownedCommand(this);
new AdminPurgeProtectCommand(this);
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (inPurge) {
user.sendMessage("commands.admin.purge.purge-in-progress");
return false;
}
if (args.isEmpty()) {
// Show help
showHelp(this, user);
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.get(0).equalsIgnoreCase("confirm") && toBeConfirmed && this.user.equals(user)) {
removeIslands();
return true;
}
// Clear tbc
toBeConfirmed = false;
islands.clear();
this.user = user;
try {
Integer days = Integer.parseInt(args.get(0));
if (days < 1) {
user.sendMessage("commands.admin.purge.days-one-or-more");
return false;
}
islands = getOldIslands(days);
user.sendMessage("commands.admin.purge.purgable-islands", TextVariables.NUMBER, String.valueOf(islands.size()));
if (!islands.isEmpty()) {
toBeConfirmed = true;
user.sendMessage("commands.admin.purge.confirm", TextVariables.LABEL, this.getTopLabel());
return false;
}
} catch(Exception e) {
user.sendMessage("commands.admin.purge.number-error");
return false;
}
return true;
}
void removeIslands() {
inPurge = true;
user.sendMessage("commands.admin.purge.see-console-for-status");
it = islands.iterator();
count = 0;
// Delete first island
deleteIsland();
}
private void deleteIsland() {
if (it.hasNext()) {
getIslands().getIslandById(it.next()).ifPresent(i -> {
getIslands().deleteIsland(i, true, null);
count++;
getPlugin().log(count + " islands purged");
});
} else {
user.sendMessage("commands.admin.purge.completed");
inPurge = false;
}
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
void onIslandDeleted(IslandDeletedEvent e) {
if (inPurge) {
deleteIsland();
}
}
Set<String> getOldIslands(int days) {
return getPlugin().getIslands().getIslands().stream()
.filter(i -> !i.getPurgeProtected())
.filter(i -> i.getWorld().equals(this.getWorld()))
.filter(i -> i.getOwner() != null)
.filter(i -> i.getMembers().size() == 1)
.filter(i -> (System.currentTimeMillis() - Bukkit.getOfflinePlayer(i.getOwner()).getLastPlayed()) > days * 1000 * 24 * 3600)
.map(Island::getUniqueId)
.collect(Collectors.toSet());
}
/**
* @return the inPurge
*/
boolean isInPurge() {
return inPurge;
}
/**
* Stop the purge
*/
void stop() {
inPurge = false;
}
/**
* @param user the user to set
*/
void setUser(User user) {
this.user = user;
}
/**
* @param islands the islands to set
*/
void setIslands(Set<String> islands) {
this.islands = islands;
}
}

View File

@ -0,0 +1,53 @@
package world.bentobox.bentobox.api.commands.admin.purge;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
public class AdminPurgeProtectCommand extends CompositeCommand {
private Island island;
public AdminPurgeProtectCommand(CompositeCommand parent) {
super(parent, "protect");
}
@Override
public void setup() {
setPermission("admin.purge");
setOnlyPlayer(true);
setDescription("commands.admin.purge.protect.description");
}
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
// Show help
showHelp(this, user);
return false;
}
// Get island where the player is
if (!getIslands().getIslandAt(user.getLocation()).map(i -> {
island = i;
return true;
}).orElse(false)) {
user.sendMessage("commands.admin.purge.protect.move-to-island");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
island.setPurgeProtected(!island.getPurgeProtected());
if (island.getPurgeProtected()) {
user.sendMessage("commands.admin.purge.protect.protecting");
} else {
user.sendMessage("commands.admin.purge.protect.unprotecting");
}
return true;
}
}

View File

@ -0,0 +1,38 @@
package world.bentobox.bentobox.api.commands.admin.purge;
import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
public class AdminPurgeStopCommand extends CompositeCommand {
public AdminPurgeStopCommand(CompositeCommand parent) {
super(parent, "stop", "cancel");
}
@Override
public void setup() {
setPermission("admin.purge");
setOnlyPlayer(false);
setDescription("commands.admin.purge.stop.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
// Show help
showHelp(this, user);
return false;
}
AdminPurgeCommand parentCommand = ((AdminPurgeCommand)getParent());
if (parentCommand.isInPurge()) {
user.sendMessage("commands.admin.purge.stop.stopping");
parentCommand.stop();
return true;
} else {
user.sendMessage("commands.admin.purge.stop.no-purge-in-progress");
return false;
}
}
}

View File

@ -0,0 +1,60 @@
package world.bentobox.bentobox.api.commands.admin.purge;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
public class AdminPurgeUnownedCommand extends ConfirmableCommand {
public AdminPurgeUnownedCommand(AdminPurgeCommand parent) {
super(parent, "unowned");
}
@Override
public void setup() {
setPermission("admin.purge");
setOnlyPlayer(false);
setParametersHelp("commands.admin.purge.unowned.parameters");
setDescription("commands.admin.purge.unowned.description");
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
// Show help
showHelp(this, user);
return false;
}
AdminPurgeCommand parentCommand = ((AdminPurgeCommand)getParent());
if (parentCommand.isInPurge()) {
user.sendMessage("commands.admin.purge.purge-in-progress");
return false;
}
Set<String> unowned = getUnownedIslands();
user.sendMessage("commands.admin.purge.unowned.unowned-islands", TextVariables.NUMBER, String.valueOf(unowned.size()));
if (!unowned.isEmpty()) {
this.askConfirmation(user, () -> {
parentCommand.setUser(user);
parentCommand.setIslands(unowned);
parentCommand.removeIslands();
});
}
return true;
}
Set<String> getUnownedIslands() {
return getPlugin().getIslands().getIslands().stream()
.filter(i -> !i.getPurgeProtected())
.filter(i -> i.getWorld().equals(this.getWorld()))
.filter(i -> i.getOwner() == null)
.map(Island::getUniqueId)
.collect(Collectors.toSet());
}
}

View File

@ -1,6 +1,9 @@
package world.bentobox.bentobox.api.commands.admin.resets;
import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -24,7 +27,7 @@ public class AdminResetsResetCommand extends ConfirmableCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.isEmpty() || args.size() != 1) {
if (args.size() != 1) {
showHelp(this, user);
return false;
}

View File

@ -1,6 +1,10 @@
package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
@ -8,9 +12,6 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import java.util.List;
import java.util.UUID;
public class AdminTeamAddCommand extends CompositeCommand {
public AdminTeamAddCommand(CompositeCommand parent) {

View File

@ -1,6 +1,10 @@
package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
@ -8,9 +12,6 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import java.util.List;
import java.util.UUID;
public class AdminTeamDisbandCommand extends CompositeCommand {
public AdminTeamDisbandCommand(CompositeCommand parent) {

View File

@ -1,7 +1,11 @@
package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
@ -9,9 +13,6 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import java.util.List;
import java.util.UUID;
/**
* Kicks the specified player from the island team.
* @author tastybento

View File

@ -1,6 +1,10 @@
package world.bentobox.bentobox.api.commands.admin.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
@ -8,9 +12,6 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import java.util.List;
import java.util.UUID;
/**
* Sets the owner of an island.
* @author tastybento

View File

@ -1,9 +1,16 @@
package world.bentobox.bentobox.api.commands.island;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@ -12,13 +19,10 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
public class IslandBanCommand extends CompositeCommand {
private @Nullable User target;
public IslandBanCommand(CompositeCommand islandCommand) {
super(islandCommand, "ban");
}
@ -33,7 +37,7 @@ public class IslandBanCommand extends CompositeCommand {
}
@Override
public boolean execute(User user, String label, List<String> args) {
public boolean canExecute(User user, String label, List<String> args) {
if (args.size() != 1) {
// Show help
showHelp(this, user);
@ -47,7 +51,7 @@ public class IslandBanCommand extends CompositeCommand {
}
// Check rank to use command
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -73,12 +77,19 @@ public class IslandBanCommand extends CompositeCommand {
if (getSettings().getBanCooldown() > 0 && checkCooldown(user, island.getUniqueId(), targetUUID.toString())) {
return false;
}
User target = User.getInstance(targetUUID);
target = User.getInstance(targetUUID);
// Cannot ban ops
if (target.hasPermission(getAddon().getPermissionPrefix() + "admin.noban")) {
if (target.isOp() || (target.isOnline() && target.hasPermission(
getAddon()
.getPermissionPrefix() + "admin.noban"))) {
user.sendMessage("commands.island.ban.cannot-ban");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
// Finished error checking - start the banning
return ban(user, target);
}

View File

@ -11,6 +11,8 @@ import world.bentobox.bentobox.database.objects.Island;
public class IslandBanlistCommand extends CompositeCommand {
private Island island;
public IslandBanlistCommand(CompositeCommand islandCommand) {
super(islandCommand, "banlist", "banned", "bans");
}
@ -23,18 +25,28 @@ public class IslandBanlistCommand extends CompositeCommand {
}
@Override
public boolean execute(User user, String label, List<String> args) {
public boolean canExecute(User user, String label, List<String> args) {
if (!args.isEmpty()) {
// Show help
showHelp(this, user);
return false;
}
// Player issuing the command must have an island
if (!getIslands().hasIsland(getWorld(), user.getUniqueId())) {
user.sendMessage("general.errors.no-island");
return false;
}
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
// Player issuing the command must have an island
if (!getIslands().hasIsland(getWorld(), user.getUniqueId()) && !getIslands().inTeam(getWorld(), user.getUniqueId())) {
user.sendMessage("general.errors.no-island");
return false;
}
// Check rank to use command
island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island.getRank(user) < island.getRankCommand("ban")) {
user.sendMessage("general.errors.no-permission");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
// Show all the players banned on the island
if (island.getBanned().isEmpty()) {
user.sendMessage("commands.island.banlist.noone");

View File

@ -3,10 +3,13 @@ package world.bentobox.bentobox.api.commands.island;
import java.io.IOException;
import java.util.List;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;
import world.bentobox.bentobox.managers.island.NewIsland;
import world.bentobox.bentobox.panels.IslandCreationPanel;
@ -36,8 +39,15 @@ public class IslandCreateCommand extends CompositeCommand {
@Override
public boolean canExecute(User user, String label, List<String> args) {
if (getIslands().hasIsland(getWorld(), user.getUniqueId())
|| getIslands().inTeam(getWorld(), user.getUniqueId())) {
// Check if the island is reserved
@Nullable
Island island = getIslands().getIsland(getWorld(), user);
if (island != null) {
// Reserved islands can be made
if (island.isReserved()) {
return true;
}
// You cannot make an island
user.sendMessage("general.errors.already-have-island");
return false;
}

View File

@ -1,7 +1,11 @@
package world.bentobox.bentobox.api.commands.island;
import java.util.List;
import java.util.UUID;
import org.bukkit.Sound;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@ -9,9 +13,6 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import java.util.List;
import java.util.UUID;
/**
* @author tastybento
* @since 1.4.0
@ -19,7 +20,7 @@ import java.util.UUID;
public class IslandExpelCommand extends CompositeCommand {
private static final String CANNOT_EXPEL = "commands.island.expel.cannot-expel";
private static final String SUCCESS = "general.success";
private static final String SUCCESS = "commands.island.expel.success";
private @Nullable User target;
@ -50,7 +51,8 @@ public class IslandExpelCommand extends CompositeCommand {
return false;
}
// Check rank to use command
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -110,13 +112,13 @@ public class IslandExpelCommand extends CompositeCommand {
island.getWorld().playSound(target.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1F, 1F);
if (getIslands().hasIsland(getWorld(), target)) {
// Success
user.sendMessage(SUCCESS);
user.sendMessage(SUCCESS, TextVariables.NAME, target.getName());
// Teleport home
getIslands().homeTeleport(getWorld(), target.getPlayer());
return true;
} else if (getIslands().getSpawn(getWorld()).isPresent()){
// Success
user.sendMessage(SUCCESS);
user.sendMessage(SUCCESS, TextVariables.NAME, target.getName());
getIslands().spawnTeleport(getWorld(), target.getPlayer());
return true;
} else if (getIWM().getAddon(getWorld())
@ -126,7 +128,7 @@ public class IslandExpelCommand extends CompositeCommand {
.orElse(false)
&& target.performCommand(this.getTopLabel() + " create")) {
getAddon().logWarning("Expel: " + target.getName() + " had no island, so one was created");
user.sendMessage(SUCCESS);
user.sendMessage(SUCCESS, TextVariables.NAME, target.getName());
return true;
}

View File

@ -1,18 +1,20 @@
package world.bentobox.bentobox.api.commands.island;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.math.NumberUtils;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.commands.DelayedTeleportCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags;
/**
* @author tastybento
*/
public class IslandGoCommand extends CompositeCommand {
public class IslandGoCommand extends DelayedTeleportCommand {
public IslandGoCommand(CompositeCommand islandCommand) {
super(islandCommand, "go", "home", "h");
@ -27,27 +29,38 @@ public class IslandGoCommand extends CompositeCommand {
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (getIslands().getIsland(getWorld(), user.getUniqueId()) == null) {
public boolean canExecute(User user, String label, List<String> args) {
// Check if the island is reserved
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island == null) {
user.sendMessage("general.errors.no-island");
return false;
}
if (island.isReserved()) {
// Send player to create an island
getParent().getSubCommand("create").ifPresent(createCmd -> createCmd.call(user, createCmd.getLabel(), Collections.emptyList()));
return false;
}
if ((getIWM().inWorld(user.getWorld()) && Flags.PREVENT_TELEPORT_WHEN_FALLING.isSetForWorld(user.getWorld()))
&& user.getPlayer().getFallDistance() > 0) {
// We're sending the "hint" to the player to tell them they cannot teleport while falling.
&& user.getPlayer().getFallDistance() > 0) {
// We're sending the "hint" to the player to tell them they cannot teleport while falling.
user.sendMessage(Flags.PREVENT_TELEPORT_WHEN_FALLING.getHintReference());
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
if (!args.isEmpty() && NumberUtils.isDigits(args.get(0))) {
int homeValue = Integer.parseInt(args.get(0));
int maxHomes = user.getPermissionValue(getPermissionPrefix() + "island.maxhomes", getIWM().getMaxHomes(getWorld()));
if (homeValue > 1 && homeValue <= maxHomes) {
getIslands().homeTeleport(getWorld(), user.getPlayer(), homeValue);
user.sendMessage("commands.island.go.tip", TextVariables.LABEL, getTopLabel());
this.delayCommand(user, () -> getIslands().homeTeleport(getWorld(), user.getPlayer(), homeValue));
return true;
}
}
getIslands().homeTeleport(getWorld(), user.getPlayer());
this.delayCommand(user, () -> getIslands().homeTeleport(getWorld(), user.getPlayer()));
return true;
}

View File

@ -4,8 +4,8 @@ import java.io.IOException;
import java.util.List;
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;

View File

@ -60,7 +60,7 @@ public class IslandSetnameCommand extends CompositeCommand {
}
// Set the name
if (user.hasPermission(this.getPermissionPrefix() + ".island.name.format")) {
if (user.hasPermission(this.getPermissionPrefix() + "island.name.format")) {
getIslands().getIsland(getWorld(), playerUUID).setName(ChatColor.translateAlternateColorCodes('&', name));
} else {
getIslands().getIsland(getWorld(), playerUUID).setName(name);

View File

@ -4,12 +4,14 @@ import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.panels.builders.TabbedPanelBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.panels.SettingsPanel;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.panels.settings.SettingsTab;
import world.bentobox.bentobox.util.Util;
/**
* @author Poslovitch
* @author tastybento
*/
public class IslandSettingsCommand extends CompositeCommand {
@ -37,7 +39,15 @@ public class IslandSettingsCommand extends CompositeCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
SettingsPanel.openPanel(getPlugin(), user, Flag.Type.PROTECTION, getWorld(), 0);
Island island = getIslands().getIslandAt(user.getLocation()).orElse(getIslands().getIsland(user.getWorld(), user.getUniqueId()));
new TabbedPanelBuilder()
.user(user)
.world(getWorld())
.tab(1, new SettingsTab(getWorld(), user, island, Flag.Type.PROTECTION))
.tab(2, new SettingsTab(getWorld(), user, island, Flag.Type.SETTING))
.startingSlot(1)
.size(54)
.build().openPanel();
return true;
}
}

View File

@ -1,5 +1,10 @@
package world.bentobox.bentobox.api.commands.island;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@ -8,11 +13,6 @@ import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
public class IslandUnbanCommand extends CompositeCommand {
public IslandUnbanCommand(CompositeCommand islandCommand) {
@ -42,7 +42,8 @@ public class IslandUnbanCommand extends CompositeCommand {
return false;
}
// Check rank to use command
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}

View File

@ -49,7 +49,7 @@ public class IslandTeamCoopCommand extends CompositeCommand {
}
// Check rank to use command
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -81,7 +81,7 @@ public class IslandTeamCoopCommand extends CompositeCommand {
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island != null) {
island.setRank(target, RanksManager.COOP_RANK);
user.sendMessage("general.success");
user.sendMessage("commands.island.team.coop.success", TextVariables.NAME, target.getName());
target.sendMessage("commands.island.team.coop.you-are-a-coop-member", TextVariables.NAME, user.getName());
return true;
} else {

View File

@ -89,7 +89,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
getIslands().homeTeleport(getWorld(), user.getPlayer());
// Delete the old island
if (island != null) {
getIslands().deleteIsland(island, true);
getIslands().deleteIsland(island, true, user.getUniqueId());
}
// TODO Set the cooldown
// Reset deaths

View File

@ -17,6 +17,7 @@ import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.team.TeamEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
public class IslandTeamInviteCommand extends CompositeCommand {
@ -36,19 +37,21 @@ public class IslandTeamInviteCommand extends CompositeCommand {
setConfigurableRankCommand();
}
@Override
public boolean execute(User user, String label, List<String> args) {
UUID playerUUID = user.getUniqueId();
public boolean canExecute(User user, String label, List<String> args) {
// Player issuing the command must have an island or be in a team
if (!getIslands().inTeam(getWorld(), user.getUniqueId()) && !getIslands().hasIsland(getWorld(), user.getUniqueId())) {
user.sendMessage("general.errors.no-island");
return false;
}
// Check rank to use command
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
UUID playerUUID = user.getUniqueId();
if (args.isEmpty() || args.size() > 1) {
// Invite label with no name, i.e., /island invite - tells the player who has invited them so far
if (inviteList.containsKey(playerUUID)) {
@ -59,34 +62,41 @@ public class IslandTeamInviteCommand extends CompositeCommand {
// Show help
showHelp(this, user);
return false;
} else {
// Only online players can be invited
UUID invitedPlayerUUID = getPlayers().getUUID(args.get(0));
if (invitedPlayerUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
User invitedPlayer = User.getInstance(invitedPlayerUUID);
if (!invitedPlayer.isOnline()) {
user.sendMessage("general.errors.offline-player");
return false;
}
// Player cannot invite themselves
if (playerUUID.equals(invitedPlayerUUID)) {
user.sendMessage("commands.island.team.invite.errors.cannot-invite-self");
return false;
}
// Check cool down
if (getSettings().getInviteCooldown() > 0 && checkCooldown(user, getIslands().getIsland(getWorld(), user).getUniqueId(), invitedPlayerUUID.toString())) {
return false;
}
// Player cannot invite someone already on a team
if (getIslands().inTeam(getWorld(), invitedPlayerUUID)) {
user.sendMessage("commands.island.team.invite.errors.already-on-team");
return false;
}
return invite(user,invitedPlayer);
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args) {
UUID playerUUID = user.getUniqueId();
// Only online players can be invited
UUID invitedPlayerUUID = getPlayers().getUUID(args.get(0));
if (invitedPlayerUUID == null) {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false;
}
User invitedPlayer = User.getInstance(invitedPlayerUUID);
if (!invitedPlayer.isOnline()) {
user.sendMessage("general.errors.offline-player");
return false;
}
// Player cannot invite themselves
if (playerUUID.equals(invitedPlayerUUID)) {
user.sendMessage("commands.island.team.invite.errors.cannot-invite-self");
return false;
}
// Check cool down
if (getSettings().getInviteCooldown() > 0 && checkCooldown(user, getIslands().getIsland(getWorld(), user).getUniqueId(), invitedPlayerUUID.toString())) {
return false;
}
// Player cannot invite someone already on a team
if (getIslands().inTeam(getWorld(), invitedPlayerUUID)) {
user.sendMessage("commands.island.team.invite.errors.already-on-team");
return false;
}
return invite(user,invitedPlayer);
}
private boolean invite(User user, User invitedPlayer) {

View File

@ -1,6 +1,10 @@
package world.bentobox.bentobox.api.commands.island.team;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
@ -9,9 +13,6 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import java.util.List;
import java.util.UUID;
public class IslandTeamKickCommand extends ConfirmableCommand {
@ -38,6 +39,12 @@ public class IslandTeamKickCommand extends ConfirmableCommand {
user.sendMessage("general.errors.not-owner");
return false;
}
// Check rank to use command
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
// If args are not right, show help
if (args.size() != 1) {
showHelp(this, user);

View File

@ -94,7 +94,7 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand {
// Notify how many resets are left
showResets(user);
}
user.sendMessage("general.success");
user.sendMessage("commands.island.team.leave.success");
// Fire event
IslandBaseEvent e = TeamEvent.builder()
.island(island)
@ -103,5 +103,4 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand {
.build();
Bukkit.getServer().getPluginManager().callEvent(e);
}
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.RanksManager;
public class IslandTeamPromoteCommand extends CompositeCommand {
@ -24,6 +25,7 @@ public class IslandTeamPromoteCommand extends CompositeCommand {
setParametersHelp("commands.island.team.demote.parameters");
setDescription("commands.island.team.demote.description");
}
this.setConfigurableRankCommand();
}
@Override
@ -33,7 +35,8 @@ public class IslandTeamPromoteCommand extends CompositeCommand {
return true;
}
// Check rank to use command
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -49,6 +52,11 @@ public class IslandTeamPromoteCommand extends CompositeCommand {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return true;
}
// Check if the user is not trying to promote/ demote himself
if (target == user) {
user.sendMessage("commands.island.team.demote.errors.cant-demote-yourself");
return true;
}
if (!inTeam(getWorld(), target) || !getOwner(getWorld(), user).equals(getOwner(getWorld(), target))) {
user.sendMessage("general.errors.not-in-team");
return true;

View File

@ -45,7 +45,7 @@ public class IslandTeamTrustCommand extends CompositeCommand {
}
// Check rank to use command
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -77,7 +77,7 @@ public class IslandTeamTrustCommand extends CompositeCommand {
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island != null) {
island.setRank(target, RanksManager.TRUSTED_RANK);
user.sendMessage("general.success");
user.sendMessage("commands.island.team.trust.success", TextVariables.NAME, target.getName());
target.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, user.getName());
return true;
} else {

View File

@ -48,7 +48,8 @@ public class IslandTeamUncoopCommand extends CompositeCommand {
return false;
}
// Check rank to use command
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -81,7 +82,7 @@ public class IslandTeamUncoopCommand extends CompositeCommand {
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island != null) {
island.removeMember(targetUUID);
user.sendMessage("general.success");
user.sendMessage("commands.island.team.uncoop.success", TextVariables.NAME, target.getName());
target.sendMessage("commands.island.team.uncoop.you-are-no-longer-a-coop-member", TextVariables.NAME, user.getName());
// Set cooldown
if (getSettings().getCoopCooldown() > 0 && getParent() != null) {

View File

@ -48,7 +48,8 @@ public class IslandTeamUntrustCommand extends CompositeCommand {
return false;
}
// Check rank to use command
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
Island island = getIslands().getIsland(getWorld(), user);
if (island.getRank(user) < island.getRankCommand(getUsage())) {
user.sendMessage("general.errors.no-permission");
return false;
}
@ -81,7 +82,7 @@ public class IslandTeamUntrustCommand extends CompositeCommand {
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
if (island != null) {
island.removeMember(targetUUID);
user.sendMessage("general.success");
user.sendMessage("commands.island.team.untrust.success", TextVariables.NAME, target.getName());
target.sendMessage("commands.island.team.untrust.you-are-no-longer-trusted", TextVariables.NAME, user.getName());
// Set cooldown
if (getSettings().getTrustCooldown() > 0 && getParent() != null) {

View File

@ -171,11 +171,6 @@ public interface WorldSettings extends ConfigObject {
*/
boolean isNetherIslands();
/**
* @return the netherTrees
*/
boolean isNetherTrees();
/**
* @return the onJoinResetEnderChest
*/
@ -251,6 +246,12 @@ public interface WorldSettings extends ConfigObject {
*/
boolean isDeathsCounted();
/**
* @return true if deaths in the world are reset when the player has a new island
* @since 1.6.0
*/
boolean isDeathsResetOnNewIsland();
/**
* @return whether a player can set their home in the Nether or not.
*/

View File

@ -13,8 +13,8 @@ public class OfflineMessageEvent extends BentoBoxEvent {
private final String message;
/**
* @param offlinePlayer
* @param message
* @param offlinePlayer - offline player
* @param message message to send offline player
*/
public OfflineMessageEvent(UUID offlinePlayer, String message) {
this.offlinePlayer = offlinePlayer;

View File

@ -1,30 +0,0 @@
package world.bentobox.bentobox.api.events;
import org.bukkit.event.Event;
/**
* Provides the default methods expected when extending {@link Event}.
* @deprecated As of 1.5.3, for removal. Use {@link BentoBoxEvent} instead.
*/
@Deprecated
public abstract class PremadeEvent extends BentoBoxEvent {
/**
* The default constructor is defined for cleaner code.
* This constructor assumes the PremadeEvent is synchronous.
*/
public PremadeEvent() {
this(false);
}
/**
* This constructor is used to explicitly declare an PremadeEvent as synchronous or asynchronous.
* @param async - true indicates the event will fire asynchronously, false
* by default from default constructor
* @since 1.5.2
*/
public PremadeEvent(boolean async) {
super(async);
}
}

View File

@ -0,0 +1,40 @@
package world.bentobox.bentobox.api.events.flags;
import world.bentobox.bentobox.api.events.BentoBoxEvent;
import world.bentobox.bentobox.api.flags.Flag;
import java.util.UUID;
/**
*
* @author Poslovitch
* @since 1.6.0
*/
public abstract class FlagChangeEvent extends BentoBoxEvent {
private final UUID player;
private final Flag editedFlag;
/**
* @param player - player changing the flag
* @param editedFlag - flag that has changed
*/
public FlagChangeEvent(UUID player, Flag editedFlag) {
this.player = player;
this.editedFlag = editedFlag;
}
/**
* @return the player
*/
public UUID getPlayer() {
return player;
}
/**
* @return the editedFlag
*/
public Flag getEditedFlag() {
return editedFlag;
}
}

View File

@ -0,0 +1,44 @@
package world.bentobox.bentobox.api.events.flags;
import java.util.UUID;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.objects.Island;
/**
* @author tastybento
* @since 1.6.0
*/
public class FlagProtectionChangeEvent extends FlagChangeEvent {
private final Island island;
private final int setTo;
/**
* Event that fires when an island protection flag is changed
* @param island - island
* @param player - player changing the flag
* @param editedFlag - flag that has changed
* @param setTo - value it was set to
*/
public FlagProtectionChangeEvent(Island island, UUID player, Flag editedFlag, int setTo) {
super(player, editedFlag);
this.island = island;
this.setTo = setTo;
}
/**
* @return the island
*/
public Island getIsland() {
return island;
}
/**
* @return the setTo
*/
public int getSetTo() {
return setTo;
}
}

View File

@ -0,0 +1,44 @@
package world.bentobox.bentobox.api.events.flags;
import java.util.UUID;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.objects.Island;
/**
* @author tastybento
* @since 1.6.0
*/
public class FlagSettingChangeEvent extends FlagChangeEvent {
private final Island island;
private final boolean setTo;
/**
* Event that fires when an island setting flag is changed
* @param island - island
* @param player - player changing the flag
* @param editedFlag - flag that has changed
* @param setTo - value it was set to
*/
public FlagSettingChangeEvent(Island island, UUID player, Flag editedFlag, boolean setTo) {
super(player, editedFlag);
this.island = island;
this.setTo = setTo;
}
/**
* @return the island
*/
public Island getIsland() {
return island;
}
/**
* @return the setTo
*/
public boolean isSetTo() {
return setTo;
}
}

View File

@ -0,0 +1,45 @@
package world.bentobox.bentobox.api.events.flags;
import java.util.UUID;
import org.bukkit.World;
import world.bentobox.bentobox.api.flags.Flag;
/**
* @author tastybento
* @since 1.6.0
*/
public class FlagWorldSettingChangeEvent extends FlagChangeEvent {
private final World world;
private final boolean setTo;
/**
* Event that fires when a world setting is changed
* @param world - world
* @param player - player changing the flag
* @param editedFlag - flag that has changed
* @param setTo - value it was set to
*/
public FlagWorldSettingChangeEvent(World world, UUID player, Flag editedFlag, boolean setTo) {
super(player, editedFlag);
this.world = world;
this.setTo = setTo;
}
/**
* @return the world
*/
public World getWorld() {
return world;
}
/**
* @return the setTo
*/
public boolean isSetTo() {
return setTo;
}
}

View File

@ -1,54 +0,0 @@
package world.bentobox.bentobox.api.events.island;
import java.util.UUID;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.objects.Island;
/**
* This event is fired when a player changes a flag on his island
* <p>
* Canceling this event will result in canceling the change.
*
* @author Poslovitch
*/
public class FlagChangeEvent extends IslandBaseEvent {
private final UUID player;
private final Flag editedFlag;
private final boolean setTo;
/**
* @param island - island
* @param player - the player
* @param editedFlag - flag edited
* @param setTo - new value
*/
public FlagChangeEvent(Island island, UUID player, Flag editedFlag, boolean setTo) {
super(island);
this.player = player;
this.editedFlag = editedFlag;
this.setTo = setTo;
}
/**
* @return the player
*/
public UUID getPlayer() {
return player;
}
/**
* @return the edited flag
*/
public Flag getFlag() {
return editedFlag;
}
/**
* @return enabled/disabled
*/
public boolean getSetTo() {
return setTo;
}
}

View File

@ -4,8 +4,10 @@ import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.database.objects.IslandDeletion;
import world.bentobox.bentobox.lists.Flags;
@ -122,7 +124,12 @@ public class IslandEvent extends IslandBaseEvent {
* Player was expelled
* @since 1.4.0
*/
EXPEL
EXPEL,
/**
* The island was reserved and now is being pasted.
* @since 1.6.0
*/
RESERVED
}
public static IslandEventBuilder builder() {
@ -177,9 +184,27 @@ public class IslandEvent extends IslandBaseEvent {
*
*/
public static class IslandCreateEvent extends IslandBaseEvent {
private IslandCreateEvent(Island island, UUID player, boolean admin, Location location) {
private @NonNull BlueprintBundle blueprintBundle;
private IslandCreateEvent(Island island, UUID player, boolean admin, Location location, @NonNull BlueprintBundle blueprintBundle) {
// Final variables have to be declared in the constructor
super(island, player, admin, location);
this.blueprintBundle = blueprintBundle;
}
/**
* @since 1.6.0
*/
@NonNull
public BlueprintBundle getBlueprintBundle() {
return blueprintBundle;
}
/**
* @since 1.6.0
*/
public void setBlueprintBundle(@NonNull BlueprintBundle blueprintBundle) {
this.blueprintBundle = blueprintBundle;
}
}
/**
@ -222,7 +247,10 @@ public class IslandEvent extends IslandBaseEvent {
}
}
/**
* Fired when an island is deleted.
* Fired when island blocks are going to be deleted.
* If canceled, the island blocks will not be deleted. Note that by the time this is called
* the ownership of the island may have been removed. This event is just for detecting
* that the island blocks are going to be removed.
*
*/
public static class IslandDeletedEvent extends IslandBaseEvent {
@ -304,9 +332,27 @@ public class IslandEvent extends IslandBaseEvent {
* May be cancelled.
*/
public static class IslandResetEvent extends IslandBaseEvent {
private IslandResetEvent(Island island, UUID player, boolean admin, Location location) {
private @NonNull BlueprintBundle blueprintBundle;
private IslandResetEvent(Island island, UUID player, boolean admin, Location location, @NonNull BlueprintBundle blueprintBundle) {
// Final variables have to be declared in the constructor
super(island, player, admin, location);
this.blueprintBundle = blueprintBundle;
}
/**
* @since 1.6.0
*/
@NonNull
public BlueprintBundle getBlueprintBundle() {
return blueprintBundle;
}
/**
* @since 1.6.0
*/
public void setBlueprintBundle(@NonNull BlueprintBundle blueprintBundle) {
this.blueprintBundle = blueprintBundle;
}
}
/**
@ -338,6 +384,7 @@ public class IslandEvent extends IslandBaseEvent {
private boolean admin;
private Location location;
private IslandDeletion deletedIslandInfo;
private BlueprintBundle blueprintBundle;
public IslandEventBuilder island(Island island) {
this.island = island;
@ -382,6 +429,15 @@ public class IslandEvent extends IslandBaseEvent {
return this;
}
/**
* @since 1.6.0
*/
@NonNull
public IslandEventBuilder blueprintBundle(@NonNull BlueprintBundle blueprintBundle) {
this.blueprintBundle = blueprintBundle;
return this;
}
public IslandBaseEvent build() {
// Call the generic event for developers who just want one event and use the Reason enum
Bukkit.getServer().getPluginManager().callEvent(new IslandEvent(island, player, admin, location, reason));
@ -396,7 +452,7 @@ public class IslandEvent extends IslandBaseEvent {
Bukkit.getServer().getPluginManager().callEvent(ban);
return ban;
case CREATE:
IslandCreateEvent create = new IslandCreateEvent(island, player, admin, location);
IslandCreateEvent create = new IslandCreateEvent(island, player, admin, location, blueprintBundle);
Bukkit.getServer().getPluginManager().callEvent(create);
return create;
case CREATED:
@ -428,7 +484,7 @@ public class IslandEvent extends IslandBaseEvent {
Bukkit.getServer().getPluginManager().callEvent(lock);
return lock;
case RESET:
IslandResetEvent reset = new IslandResetEvent(island, player, admin, location);
IslandResetEvent reset = new IslandResetEvent(island, player, admin, location, blueprintBundle);
Bukkit.getServer().getPluginManager().callEvent(reset);
return reset;
case RESETTED:

View File

@ -1,10 +1,16 @@
package world.bentobox.bentobox.api.flags;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
@ -18,18 +24,11 @@ import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class Flag implements Comparable<Flag> {
/**
* Defines the behavior and operation of the flag, as well as its category in the {@link world.bentobox.bentobox.panels.SettingsPanel}.
* Defines the behavior and operation of the flag.
*/
public enum Type {
/**
@ -63,6 +62,61 @@ public class Flag implements Comparable<Flag> {
}
}
/**
* Defines the flag mode
* @author tastybento
* @since 1.6.0
*/
public enum Mode {
/**
* Flag should be shown in the basic settings
*/
BASIC,
/**
* Flag should be shown in the advanced settings
*/
ADVANCED,
/**
* Flag should be shown in the expert settings
*/
EXPERT,
/**
* Flag should be shown in the top row if applicable
*/
TOP_ROW;
/**
* Get the next ranking mode above this one. If at the top, it cycles back to the bottom mode
* @return next ranking mode
*/
public Mode getNext() {
switch(this) {
case ADVANCED:
return EXPERT;
case BASIC:
return ADVANCED;
default:
return BASIC;
}
}
/**
* Get a list of ranks that are ranked greater than this rank
* @param rank - rank to compare
* @return true if ranked greater
*/
public boolean isGreaterThan(Mode rank) {
switch(this) {
case EXPERT:
return rank.equals(BASIC) || rank.equals(ADVANCED);
case ADVANCED:
return rank.equals(BASIC);
default:
return false;
}
}
}
private static final String PROTECTION_FLAGS = "protection.flags.";
private final String id;
@ -70,12 +124,13 @@ public class Flag implements Comparable<Flag> {
private final Listener listener;
private final Type type;
private boolean setting;
private Map<World, Boolean> defaultWorldSettings = new HashMap<>();
private final int defaultRank;
private final PanelItem.ClickHandler clickHandler;
private final boolean subPanel;
private Set<GameModeAddon> gameModes = new HashSet<>();
private final Addon addon;
private final int cooldown;
private final Mode mode;
private Flag(Builder builder) {
this.id = builder.id;
@ -89,7 +144,9 @@ public class Flag implements Comparable<Flag> {
if (builder.gameModeAddon != null) {
this.gameModes.add(builder.gameModeAddon);
}
this.cooldown = builder.cooldown;
this.addon = builder.addon;
this.mode = builder.mode;
}
public String getID() {
@ -104,6 +161,13 @@ public class Flag implements Comparable<Flag> {
return Optional.ofNullable(listener);
}
/**
* @return the cooldown
*/
public int getCooldown() {
return cooldown;
}
/**
* Check if a setting is set in this world
* @param world - world
@ -111,17 +175,17 @@ public class Flag implements Comparable<Flag> {
* If world is not a game world, then the result will always be false!
*/
public boolean isSetForWorld(World world) {
if (type.equals(Type.WORLD_SETTING)) {
WorldSettings ws = BentoBox.getInstance().getIWM().getWorldSettings(world);
if (ws != null) {
ws.getWorldFlags().putIfAbsent(getID(), setting);
return ws.getWorldFlags().get(getID());
WorldSettings ws = BentoBox.getInstance().getIWM().getWorldSettings(world);
if (ws == null) return false;
if (type.equals(Type.WORLD_SETTING) || type.equals(Type.PROTECTION)) {
if (!ws.getWorldFlags().containsKey(getID())) {
ws.getWorldFlags().put(getID(), setting);
// Save config file
BentoBox.getInstance().getIWM().getAddon(world).ifPresent(GameModeAddon::saveWorldSettings);
}
return false;
} else {
// Setting
return defaultWorldSettings.getOrDefault(Util.getWorld(world), setting);
return ws.getWorldFlags().get(getID());
}
return setting;
}
/**
@ -130,13 +194,20 @@ public class Flag implements Comparable<Flag> {
* @param setting - true or false
*/
public void setSetting(World world, boolean setting) {
if (getType().equals(Type.WORLD_SETTING)) {
BentoBox.getInstance().getIWM().getWorldSettings(world).getWorldFlags().put(getID(), setting);
if (getType().equals(Type.WORLD_SETTING) || type.equals(Type.PROTECTION)) {
BentoBox.getInstance()
.getIWM()
.getWorldSettings(world)
.getWorldFlags()
.put(getID(), setting);
// Save config file
BentoBox.getInstance().getIWM().getAddon(world).ifPresent(GameModeAddon::saveWorldSettings);
}
}
/**
* Set the status of this flag for locations outside of island spaces
* Set the original status of this flag for locations outside of island spaces.
* May be overriden by the the setting for this world.
* @param defaultSetting - true means it is allowed. false means it is not allowed
*/
public void setDefaultSetting(boolean defaultSetting) {
@ -144,11 +215,19 @@ public class Flag implements Comparable<Flag> {
}
/**
* Set the status of this flag for locations outside of island spaces for a specific world
* Set the status of this flag for locations outside of island spaces for a specific world.
* World must exist and be registered before this method can be called.
* @param defaultSetting - true means it is allowed. false means it is not allowed
*/
public void setDefaultSetting(World world, boolean defaultSetting) {
this.defaultWorldSettings.put(world, defaultSetting);
WorldSettings ws = BentoBox.getInstance().getIWM().getWorldSettings(world);
if (ws == null ) {
BentoBox.getInstance().logError("Attempt to set default world setting for unregistered world. Register flags in onEnable.");
return;
}
ws.getWorldFlags().put(getID(), defaultSetting);
// Save config file
BentoBox.getInstance().getIWM().getAddon(world).ifPresent(GameModeAddon::saveWorldSettings);
}
/**
@ -276,10 +355,12 @@ public class Flag implements Comparable<Flag> {
* Converts a flag to a panel item. The content of the flag will change depending on who the user is and where they are.
* @param plugin - plugin
* @param user - user that will see this flag
* @param island - target island, if any
* @param invisible - true if this flag is not visible to players
* @return - PanelItem for this flag or null if item is inivisible to user
* @return - PanelItem for this flag or null if item is invisible to user
*/
public PanelItem toPanelItem(BentoBox plugin, User user, boolean invisible) {
@Nullable
public PanelItem toPanelItem(BentoBox plugin, User user, @Nullable Island island, boolean invisible) {
// Invisibility
if (!user.isOp() && invisible) {
return null;
@ -294,7 +375,6 @@ public class Flag implements Comparable<Flag> {
pib.description(user.getTranslation("protection.panel.flag-item.menu-layout", TextVariables.DESCRIPTION, user.getTranslation(getDescriptionReference())));
return pib.build();
}
Island island = plugin.getIslands().getIslandAt(user.getLocation()).orElse(plugin.getIslands().getIsland(user.getWorld(), user.getUniqueId()));
switch(getType()) {
case PROTECTION:
return createProtectionFlag(plugin, user, island, pib).build();
@ -321,6 +401,9 @@ public class Flag implements Comparable<Flag> {
: user.getTranslation("protection.panel.flag-item.setting-disabled");
pib.description(user.getTranslation("protection.panel.flag-item.setting-layout", TextVariables.DESCRIPTION, user.getTranslation(getDescriptionReference())
, "[setting]", islandSetting));
if (this.cooldown > 0 && island.isCooldown(this)) {
pib.description(user.getTranslation("protection.panel.flag-item.setting-cooldown"));
}
}
return pib;
}
@ -344,6 +427,14 @@ public class Flag implements Comparable<Flag> {
}
/**
* @return the mode
* @since 1.6.0
*/
public Mode getMode() {
return mode;
}
@Override
public String toString() {
return "Flag [id=" + id + "]";
@ -383,6 +474,12 @@ public class Flag implements Comparable<Flag> {
private GameModeAddon gameModeAddon;
private Addon addon;
// Cooldown
private int cooldown;
// Mode
public Mode mode = Mode.EXPERT;
/**
* Builder for making flags
* @param id - a unique id that MUST be the same as the enum of the flag
@ -456,7 +553,7 @@ public class Flag implements Comparable<Flag> {
/**
* Make this flag specific to this gameMode
* @param gameModeAddon
* @param gameModeAddon game mode addon
* @return Builder
*/
public Builder setGameMode(GameModeAddon gameModeAddon) {
@ -466,7 +563,7 @@ public class Flag implements Comparable<Flag> {
/**
* The addon registering this flag. Ensure this is set to enable the addon to be reloaded.
* @param addon
* @param addon addon
* @return Builder
* @since 1.5.0
*/
@ -475,6 +572,29 @@ public class Flag implements Comparable<Flag> {
return this;
}
/**
* Set a cooldown for {@link Type#SETTING} flag. Only applicable for settings.
* @param cooldown in seconds
* @return Builder
* @since 1.6.0
*/
public Builder cooldown(int cooldown) {
this.cooldown = cooldown;
return this;
}
/**
* Set the flag difficulty mode.
* Defaults to {@link Flag.Mode#EXPERT}.
* @param mode
* @return Builder
* @since 1.6.0
*/
public Builder mode(Mode mode) {
this.mode = mode;
return this;
}
/**
* Build the flag
* @return Flag

View File

@ -79,7 +79,7 @@ public abstract class FlagListener implements Listener {
* @param flag - the flag that has been checked
*/
public void noGo(@NonNull Event e, @NonNull Flag flag) {
noGo(e, flag, false);
noGo(e, flag, false, "protection.protected");
}
/**
@ -87,14 +87,15 @@ public abstract class FlagListener implements Listener {
* @param e - event
* @param flag - the flag that has been checked
* @param silent - if true, message is not sent
* @param string - translation reference
*/
public void noGo(@NonNull Event e, @NonNull Flag flag, boolean silent) {
public void noGo(@NonNull Event e, @NonNull Flag flag, boolean silent, String string) {
if (e instanceof Cancellable) {
((Cancellable)e).setCancelled(true);
}
if (user != null) {
if (!silent) {
user.notify("protection.protected", TextVariables.DESCRIPTION, user.getTranslation(flag.getHintReference()));
user.notify(string, TextVariables.DESCRIPTION, user.getTranslation(flag.getHintReference()));
}
user.updateInventory();
}
@ -153,8 +154,8 @@ public abstract class FlagListener implements Listener {
// Protection flag
// Ops or "bypass everywhere" moderators can do anything
if (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypassprotect")
|| user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypass." + flag.getID() + ".everywhere")) {
if (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypassprotect")
|| user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypass." + flag.getID() + ".everywhere")) {
if (user.isOp()) {
report(user, e, loc, flag, Why.OP);
} else {
@ -170,7 +171,7 @@ public abstract class FlagListener implements Listener {
return true;
}
report(user, e, loc, flag, Why.NOT_ALLOWED_IN_WORLD);
noGo(e, flag, silent);
noGo(e, flag, silent, "protection.world-protected");
return false;
}
@ -182,12 +183,12 @@ public abstract class FlagListener implements Listener {
if (island.get().isAllowed(user, flag)) {
report(user, e, loc, flag, Why.RANK_ALLOWED);
return true;
} else if (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypass." + flag.getID() + ".island")) {
} else if (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypass." + flag.getID() + ".island")) {
report(user, e, loc, flag, Why.BYPASS_ISLAND);
return true;
}
report(user, e, loc, flag, Why.NOT_ALLOWED_ON_ISLAND);
noGo(e, flag, silent);
noGo(e, flag, silent, "protection.protected");
return false;
}
// The player is in the world, but not on an island, so general world settings apply
@ -196,7 +197,7 @@ public abstract class FlagListener implements Listener {
return true;
} else {
report(user, e, loc, flag, Why.NOT_ALLOWED_IN_WORLD);
noGo(e, flag, silent);
noGo(e, flag, silent, "protection.world-protected");
return false;
}
}

View File

@ -1,15 +1,20 @@
package world.bentobox.bentobox.api.flags.clicklisteners;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.event.inventory.ClickType;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.flags.FlagProtectionChangeEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.TabbedPanel;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.panels.settings.SettingsTab;
import world.bentobox.bentobox.util.Util;
/**
@ -38,9 +43,9 @@ public class CycleClick implements PanelItem.ClickHandler {
/**
* Construct a cycle clicker with a min and max rank
* @param id
* @param minRank
* @param maxRank
* @param id flag id
* @param minRank minimum rank value
* @param maxRank maximum rank value
*/
public CycleClick(String id, int minRank, int maxRank) {
this.id = id;
@ -50,16 +55,19 @@ public class CycleClick implements PanelItem.ClickHandler {
@Override
public boolean onClick(Panel panel, User user, ClickType click, int slot) {
// This click listener is used with TabbedPanel and SettingsTabs only
TabbedPanel tp = (TabbedPanel)panel;
SettingsTab st = (SettingsTab)tp.getActiveTab();
// Get the island for this tab
island = st.getIsland();
this.user = user;
changeOccurred = false;
// Get the world
if (!plugin.getIWM().inWorld(user.getLocation())) {
user.sendMessage("general.errors.wrong-world");
return true;
}
String reqPerm = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld())) + ".settings." + id;
String allPerms = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld())) + ".settings.*";
if (!user.hasPermission(reqPerm) && !user.hasPermission(allPerms)) {
// Permission prefix
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld()));
String reqPerm = prefix + "settings." + id;
String allPerms = prefix + "settings.*";
if (!user.hasPermission(reqPerm) && !user.hasPermission(allPerms)
&& !user.isOp() && !user.hasPermission(prefix + "admin.settings")) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, reqPerm);
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
return true;
@ -67,15 +75,10 @@ public class CycleClick implements PanelItem.ClickHandler {
// Left clicking increases the rank required
// Right clicking decreases the rank required
// Shift Left Click toggles player visibility
// Get the user's island
island = plugin.getIslands().getIslandAt(user.getLocation()).orElse(plugin.getIslands().getIsland(user.getWorld(), user.getUniqueId()));
if (island != null && (user.isOp() || user.getUniqueId().equals(island.getOwner()))) {
if (island != null && (user.isOp() || user.getUniqueId().equals(island.getOwner()) || user.hasPermission(prefix + "admin.settings"))) {
changeOccurred = true;
RanksManager rm = plugin.getRanksManager();
plugin.getFlagsManager().getFlag(id).ifPresent(flag -> {
// Flag visibility
boolean invisible = false;
// Rank
int currentRank = island.getFlag(flag);
if (click.equals(ClickType.LEFT)) {
@ -85,6 +88,8 @@ public class CycleClick implements PanelItem.ClickHandler {
island.setFlag(flag, rm.getRankUpValue(currentRank));
}
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_OFF, 1F, 1F);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));
} else if (click.equals(ClickType.RIGHT)) {
if (currentRank <= minRank) {
island.setFlag(flag, maxRank);
@ -92,9 +97,10 @@ public class CycleClick implements PanelItem.ClickHandler {
island.setFlag(flag, rm.getRankDownValue(currentRank));
}
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));
} else if (click.equals(ClickType.SHIFT_LEFT) && user.isOp()) {
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
invisible = true;
plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
} else {
@ -104,8 +110,6 @@ public class CycleClick implements PanelItem.ClickHandler {
// Save changes
plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
}
// Apply change to panel
panel.getInventory().setItem(slot, flag.toPanelItem(plugin, user, invisible).getItem());
});
} else {
// Player is not the owner of the island.

View File

@ -10,16 +10,16 @@ import world.bentobox.bentobox.api.events.island.IslandEvent;
public class IslandLockClick extends CycleClick {
/**
* @param id
* @param id flag id
*/
public IslandLockClick(String id) {
super(id);
}
/**
* @param id
* @param minRank
* @param maxRank
* @param id flag id
* @param minRank minimum rank
* @param maxRank maximum rank
*/
public IslandLockClick(String id, int minRank, int maxRank) {
super(id, minRank, maxRank);

View File

@ -1,14 +1,19 @@
package world.bentobox.bentobox.api.flags.clicklisteners;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.event.inventory.ClickType;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.flags.FlagSettingChangeEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.TabbedPanel;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.panels.settings.SettingsTab;
import world.bentobox.bentobox.util.Util;
/**
@ -30,27 +35,26 @@ public class IslandToggleClick implements ClickHandler {
@Override
public boolean onClick(Panel panel, User user, ClickType click, int slot) {
// Get the world
if (!plugin.getIWM().inWorld(user.getLocation())) {
user.sendMessage("general.errors.wrong-world");
return true;
}
String reqPerm = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld())) + ".settings." + id;
if (!user.hasPermission(reqPerm)) {
// This click listener is used with TabbedPanel and SettingsTabs only
TabbedPanel tp = (TabbedPanel)panel;
SettingsTab st = (SettingsTab)tp.getActiveTab();
// Permission prefix
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld()));
String reqPerm = prefix + "settings." + id;
String allPerms = prefix + "settings.*";
if (!user.hasPermission(reqPerm) && !user.hasPermission(allPerms)
&& !user.isOp() && !user.hasPermission(prefix + "admin.settings")) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, reqPerm);
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
return true;
}
// Get the user's island or where they are standing
Island island = plugin.getIslands().getIslandAt(user.getLocation()).orElse(plugin.getIslands().getIsland(user.getWorld(), user.getUniqueId()));
if (island != null && (user.isOp() || user.getUniqueId().equals(island.getOwner()))) {
// Get the island for this tab
Island island = st.getIsland();
if (island != null && (user.isOp() || user.getUniqueId().equals(island.getOwner()) || user.hasPermission(prefix + "admin.settings"))) {
plugin.getFlagsManager().getFlag(id).ifPresent(flag -> {
// Visibility
boolean invisible = false;
if (click.equals(ClickType.SHIFT_LEFT) && user.isOp()) {
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
invisible = true;
plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
} else {
@ -60,12 +64,20 @@ public class IslandToggleClick implements ClickHandler {
// Save changes
plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings);
} else {
// Check cooldown
if (!user.isOp() && island.isCooldown(flag)) {
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_BEACON_DEACTIVATE, 1F, 1F);
user.notify("protection.panel.flag-item.setting-cooldown");
return;
}
// Toggle flag
island.toggleFlag(flag);
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
// Set cooldown
island.setCooldown(flag);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagSettingChangeEvent(island, user.getUniqueId(), flag, island.isAllowed(flag)));
}
// Apply change to panel
panel.getInventory().setItem(slot, flag.toPanelItem(plugin, user, invisible).getItem());
});
} else {
// Player is not the owner of the island.

View File

@ -1,10 +1,12 @@
package world.bentobox.bentobox.api.flags.clicklisteners;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.event.inventory.ClickType;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.flags.FlagWorldSettingChangeEvent;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
@ -18,8 +20,8 @@ import world.bentobox.bentobox.util.Util;
*/
public class WorldToggleClick implements ClickHandler {
private BentoBox plugin = BentoBox.getInstance();
private String id;
private final BentoBox plugin = BentoBox.getInstance();
private final String id;
/**
* @param id - the flag ID that this click listener is associated with
@ -35,7 +37,7 @@ public class WorldToggleClick implements ClickHandler {
user.sendMessage("general.errors.wrong-world");
return true;
}
String reqPerm = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld())) + ".admin.world.settings." + id;
String reqPerm = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld())) + "admin.world.settings." + id;
if (!user.hasPermission(reqPerm)) {
user.sendMessage("general.errors.no-permission", TextVariables.PERMISSION, reqPerm);
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
@ -43,11 +45,8 @@ public class WorldToggleClick implements ClickHandler {
}
// Get flag
plugin.getFlagsManager().getFlag(id).ifPresent(flag -> {
// Visibility
boolean invisible = false;
if (click.equals(ClickType.SHIFT_LEFT) && user.isOp()) {
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
invisible = true;
plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F);
} else {
@ -60,9 +59,9 @@ public class WorldToggleClick implements ClickHandler {
// Toggle flag
flag.setSetting(user.getWorld(), !flag.isSetForWorld(user.getWorld()));
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagWorldSettingChangeEvent(user.getWorld(), user.getUniqueId(), flag, flag.isSetForWorld(user.getWorld())));
}
// Apply change to panel
panel.getInventory().setItem(slot, flag.toPanelItem(plugin, user, invisible).getItem());
// Save world settings
plugin.getIWM().getAddon(Util.getWorld(user.getWorld())).ifPresent(GameModeAddon::saveWorldSettings);

View File

@ -6,6 +6,7 @@ import java.util.Locale;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.util.ItemParser;
@ -96,7 +97,7 @@ public class BentoBoxLocale {
* Merges a language YAML file to this locale
* @param toBeMerged the YamlConfiguration of the language file
*/
public void merge(YamlConfiguration toBeMerged) {
public void merge(@NonNull YamlConfiguration toBeMerged) {
for (String key : toBeMerged.getKeys(true)) {
if (!key.startsWith("meta") && !config.contains(key)) {
config.set(key, toBeMerged.get(key));
@ -105,6 +106,17 @@ public class BentoBoxLocale {
updateAuthors(toBeMerged);
}
/**
* Sets a reference and its value in the locale.
* If the reference already exists, it will overwrite its value.
* @param reference the reference to add, not null.
* @param value the value to set, not null.
* @since 1.6.0
*/
public void set(@NonNull String reference, @NonNull String value) {
config.set(reference, value);
}
public boolean contains(String reference) {
return config.contains(reference);
}

View File

@ -17,4 +17,8 @@ public class TextVariables {
public static final String SPAWN_HERE = "[spawn_here]";
public static final String VERSION = "[version]";
public static final String START_TEXT = "[start]";
/**
* @since 1.6.0
*/
public static final String NEXT = "[next]";
}

View File

@ -11,49 +11,48 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.listeners.PanelListenerManager;
import world.bentobox.bentobox.util.heads.HeadGetter;
import world.bentobox.bentobox.util.heads.HeadRequester;
/**
* A GUI panel that uses the Bukkit inventory API
* @author tastybento
*
*/
public class Panel implements HeadRequester, InventoryHolder {
private Inventory inventory;
private Map<Integer, PanelItem> items;
private PanelListener listener;
private User user;
private final String name;
private String name;
public Panel(String name, Map<Integer, PanelItem> items, int size, User user, PanelListener listener) {
makePanel(name, items, size, user, listener);
}
public Panel() {}
protected void makePanel(String name, Map<Integer, PanelItem> items, int size, User user,
PanelListener listener) {
this.name = name;
this.items = items;
// If size is undefined (0) then use the number of items
if (size == 0) {
size = items.keySet().size();
}
size = fixSize(size);
// Create panel
if (size > 0) {
// Make sure size is a multiple of 9 and is 54 max.
size = size + 8;
size -= (size % 9);
if (size > 54) size = 54;
inventory = Bukkit.createInventory(null, size, name);
// Fill the inventory and return
for (Map.Entry<Integer, PanelItem> en: items.entrySet()) {
//TODO allow multi-paging
if (en.getKey() < 54) {
inventory.setItem(en.getKey(), en.getValue().getItem());
// Get player head async
if (en.getValue().isPlayerHead()) {
HeadGetter.getHead(en.getValue(), this);
}
inventory = Bukkit.createInventory(null, size, name);
// Fill the inventory and return
for (Map.Entry<Integer, PanelItem> en: items.entrySet()) {
if (en.getKey() < 54) {
inventory.setItem(en.getKey(), en.getValue().getItem());
// Get player head async
if (en.getValue().isPlayerHead()) {
HeadGetter.getHead(en.getValue(), this);
}
}
} else {
inventory = Bukkit.createInventory(null, 9, name);
}
this.listener = listener;
// If the listener is defined, then run setup
@ -64,6 +63,22 @@ public class Panel implements HeadRequester, InventoryHolder {
if (user != null) this.open(user);
}
private int fixSize(int size) {
// If size is undefined (0) then use the number of items
if (size == 0) {
size = items.keySet().size();
}
if (size > 0) {
// Make sure size is a multiple of 9 and is 54 max.
size = size + 8;
size -= (size % 9);
if (size > 54) size = 54;
} else {
return 9;
}
return size;
}
@NonNull
@Override
public Inventory getInventory() {
@ -145,7 +160,7 @@ public class Panel implements HeadRequester, InventoryHolder {
ItemStack it = inventory.getItem(i);
if (it != null && it.getType().equals(Material.PLAYER_HEAD)) {
ItemMeta meta = it.getItemMeta();
if (item.getName().equals(meta.getLocalizedName())) {
if (meta != null && item.getName().equals(meta.getLocalizedName())) {
inventory.setItem(i, item.getItem());
// If one is found, we are done
return;

View File

@ -12,6 +12,11 @@ import org.bukkit.inventory.meta.ItemMeta;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
/**
* Represents an item in a {@link Panel}
* @author tastybento
*
*/
public class PanelItem {
public static PanelItem empty() {
@ -24,7 +29,7 @@ public class PanelItem {
private String name;
private boolean glow;
private ItemMeta meta;
private boolean playerHead;
private final boolean playerHead;
private boolean invisible;
public PanelItem(PanelItemBuilder builtItem) {
@ -104,6 +109,14 @@ public class PanelItem {
return Optional.ofNullable(clickHandler);
}
/**
* @param clickHandler the clickHandler to set
* @since 1.6.0
*/
public void setClickHandler(ClickHandler clickHandler) {
this.clickHandler = clickHandler;
}
public boolean isGlow() {
return glow;
}
@ -142,8 +155,8 @@ public class PanelItem {
public void setHead(ItemStack itemStack) {
this.icon = itemStack;
// Get the meta
meta = icon.getItemMeta();
if (meta != null) {
meta = icon.getItemMeta();
// Set flags to neaten up the view
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
meta.addItemFlags(ItemFlag.HIDE_DESTROYS);

View File

@ -5,6 +5,11 @@ import org.bukkit.event.inventory.InventoryCloseEvent;
import world.bentobox.bentobox.api.user.User;
/**
* This will be called if registered and if a player clicks on a panel
* @author tastybento
*
*/
public interface PanelListener {
/**
@ -16,4 +21,10 @@ public interface PanelListener {
void onInventoryClick(User user, InventoryClickEvent event);
/**
* Called after a user has clicked on a panel item.
* Used to refresh the panel in its entirety
* @since 1.6.0
*/
default void refreshPanel() {}
}

View File

@ -0,0 +1,44 @@
package world.bentobox.bentobox.api.panels;
import org.eclipse.jdt.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Represents a tab in a {@link TabbedPanel}. Contains {@link PanelItem}'s.
*
* @author tastybento
* @since 1.6.0
*
*/
public interface Tab {
// The icon that should be shown at the top of the tabbed panel
PanelItem getIcon();
/**
* @return the name of this tab
*/
String getName();
/**
* Return the panel items for this tab
* @return a list of items in slot order
*/
List<@Nullable PanelItem> getPanelItems();
/**
* @return the permission required to view this tab or empty if no permission required
*/
String getPermission();
/**
* @return Map of icons to be shown in the tab row when the tab is active
* Make sure these do not overlap any tabs that are in the tab row
*/
default Map<Integer, PanelItem> getTabIcons() {
return Collections.emptyMap();
}
}

View File

@ -0,0 +1,195 @@
package world.bentobox.bentobox.api.panels;
import java.security.InvalidParameterException;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.panels.builders.TabbedPanelBuilder;
import world.bentobox.bentobox.api.user.User;
/**
* Represents a panel with tabs. The top row of the panel is made up of up to 9 icons that are made of {@link world.bentobox.bentobox.api.panels.Tab}s.
* Only the active tab is shown. The panel will auto-refresh when a panel item is clicked, so panel item
* click listeners do not have to actively update the panel. Viewers of the panel who do not have permission
* to see a {@link world.bentobox.bentobox.api.panels.Tab} will not be shown it.
*
* @author tastybento
* @since 1.6.0
*/
public class TabbedPanel extends Panel implements PanelListener {
private static final String PROTECTION_PANEL = "protection.panel.";
private final TabbedPanelBuilder tpb;
private @NonNull BentoBox plugin = BentoBox.getInstance();
private int activeTab;
private int activePage;
private boolean closed;
/**
* Construct the tabbed panel
* @param tpb - tabbed panel builder
*/
public TabbedPanel(TabbedPanelBuilder tpb) {
this.tpb = tpb;
}
/* (non-Javadoc)
* @see world.bentobox.bentobox.api.panels.PanelListener#refreshPanel()
*/
@Override
public void refreshPanel() {
if (closed) return;
// Called when a player clicks on the panel
openPanel(activeTab, activePage);
// Reset the closed flag
closed = false;
}
/**
* Open the tabbed panel at the starting slot
*/
public void openPanel() {
openPanel(tpb.getStartingSlot(), 0);
}
/**
* Open the tabbed panel
* @param activeTab - the tab to show referenced by the slot (0 through 8)
* @param page - the page of the tab to show (if multi paged)
*/
public void openPanel(int activeTab, int page) {
if (!tpb.getTabs().containsKey(activeTab)) {
// Request to open a non-existent tab
throw new InvalidParameterException("Attempt to open a non-existent tab in a tabbed panel. Missing tab #" + activeTab);
}
if (page < 0) {
// Request to open a non-existent tab
throw new InvalidParameterException("Attempt to open a tab in a tabbed panel to a negative page! " + page);
}
this.activeTab = activeTab;
this.activePage = page;
// The items in the panel
TreeMap<Integer, PanelItem> items = new TreeMap<>();
// Get the tab
Tab tab = tpb.getTabs().get(activeTab);
// Set up the tabbed header
setupHeader(tab, items);
// Show the active tab
if (tpb.getTabs().containsKey(activeTab)) {
List<PanelItem> panelItems = tab.getPanelItems();
panelItems.stream().filter(Objects::nonNull).skip(page * 43L).limit(page * 43L + 43L).forEach(i -> items.put(items.lastKey() + 1, i));
// Add forward and backward icons
if (page > 0) {
// Previous page icon
items.put(items.lastKey() + 1, new PanelItemBuilder().icon(Material.ARROW).name(tpb.getUser().getTranslation(PROTECTION_PANEL + "previous")).clickHandler((panel, user1, clickType, slot1) -> {
this.activePage--;
this.refreshPanel();
return true;
}).build());
}
if ((page + 1) * 45 < items.size()) {
// Next page icon
items.put(items.lastKey() + 1, new PanelItemBuilder().icon(Material.ARROW).name(tpb.getUser().getTranslation(PROTECTION_PANEL + "next")).clickHandler((panel, user1, clickType, slot1) -> {
this.activePage++;
this.refreshPanel();
return true;
}).build());
}
} else {
throw new InvalidParameterException("Unknown tab slot number " + activeTab);
}
// Show it to the player
this.makePanel(tab.getName(), items, tpb.getSize(), tpb.getUser(), this);
}
/**
* Shows the top row of icons
* @param tab - active tab
* @param items - panel builder
*/
private void setupHeader(Tab tab, TreeMap<Integer, PanelItem> items) {
// Set up top
for (int i = 0; i < 9; i++) {
items.put(i, new PanelItemBuilder().icon(Material.LIGHT_BLUE_STAINED_GLASS_PANE).name("").build());
}
// Add icons
for (Entry<Integer, Tab> tabPanel : tpb.getTabs().entrySet()) {
// Add the icon to the top row
if (tabPanel.getValue().getPermission().isEmpty() || tpb.getUser().hasPermission(tabPanel.getValue().getPermission()) || tpb.getUser().isOp()) {
PanelItem activeIcon = tabPanel.getValue().getIcon();
// Set the glow of the active tab
activeIcon.setGlow(tabPanel.getValue().equals(tab));
items.put(tabPanel.getKey(), activeIcon);
}
}
// Add any subsidiary icons
tab.getTabIcons().forEach(items::put);
}
@Override
public void setup() {
// Not used
}
@Override
public void onInventoryClose(InventoryCloseEvent event) {
// This flag is set every time the inventory is closed or refreshed (closed and opened)
closed = true;
}
@Override
public void onInventoryClick(User user, InventoryClickEvent event) {
// Trap top row tab clicks
if (event.isLeftClick() && tpb.getTabs().containsKey(event.getRawSlot())
&& (tpb.getTabs().get(event.getRawSlot()).getPermission().isEmpty()
|| tpb.getUser().hasPermission(tpb.getTabs().get(event.getRawSlot()).getPermission()) || tpb.getUser().isOp())) {
event.setCancelled(true);
this.openPanel(event.getRawSlot(), 0);
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_OFF, 1F, 1F);
// Reset the closed flag
closed = false;
}
}
/**
* @return the active tab being shown to the user
*/
public Tab getActiveTab() {
return tpb.getTabs().get(activeTab);
}
/**
* @return the activePage
*/
public int getActivePage() {
return activePage;
}
/**
* @param activePage the activePage to set
*/
public void setActivePage(int activePage) {
this.activePage = activePage;
}
/**
* @param activeTab the activeTab to set
*/
public void setActiveTab(int activeTab) {
this.activeTab = activeTab;
}
}

View File

@ -1,8 +1,10 @@
package world.bentobox.bentobox.api.panels.builders;
import org.bukkit.ChatColor;
import java.util.SortedMap;
import java.util.TreeMap;
import org.bukkit.ChatColor;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.PanelListener;
@ -15,7 +17,7 @@ import world.bentobox.bentobox.api.user.User;
*/
public class PanelBuilder {
private String name;
private TreeMap<Integer, PanelItem> items = new TreeMap<>();
private final SortedMap<Integer, PanelItem> items = new TreeMap<>();
private int size;
private User user;
private PanelListener listener;
@ -108,4 +110,39 @@ public class PanelBuilder {
// items.lastKey() is a slot position, so the panel size is this value + 1
return new Panel(name, items, Math.max(size, items.isEmpty() ? size : items.lastKey() + 1), user, listener);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the items
*/
public SortedMap<Integer, PanelItem> getItems() {
return items;
}
/**
* @return the size
*/
public int getSize() {
return size;
}
/**
* @return the user
*/
public User getUser() {
return user;
}
/**
* @return the listener
*/
public PanelListener getListener() {
return listener;
}
}

View File

@ -1,17 +1,18 @@
package world.bentobox.bentobox.api.panels.builders;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
public class PanelItemBuilder {
private ItemStack icon = new ItemStack(Material.AIR);
private @Nullable String name = "";

View File

@ -0,0 +1,131 @@
package world.bentobox.bentobox.api.panels.builders;
import java.security.InvalidParameterException;
import java.util.Map;
import java.util.TreeMap;
import org.bukkit.World;
import world.bentobox.bentobox.api.panels.Tab;
import world.bentobox.bentobox.api.panels.TabbedPanel;
import world.bentobox.bentobox.api.user.User;
/**
* Builds {@link TabbedPanel}'s
* @author tastybento
* @since 1.6.0
*/
public class TabbedPanelBuilder {
private int size;
private final Map<Integer, Tab> tabs = new TreeMap<>();
private int startingSlot;
private World world;
private User user;
/**
* Forces panel to be a specific number of slots.
* @param size - size to be
* @return PanelBuilder - PanelBuilder
*/
public TabbedPanelBuilder size(int size) {
this.size = size;
return this;
}
/**
* Sets the user who will get this panel. This will open it immediately when it is built
* @param user - the User
* @return PanelBuilder
*/
public TabbedPanelBuilder user(User user) {
this.user = user;
return this;
}
/**
* @param world - world that applies to this tab
* @return TabbedPanelBuilder
*/
public TabbedPanelBuilder world(World world) {
this.world = world;
return this;
}
/**
* Add a tab to the panel
* @param slot - slot of panel (0 to 9)
* @param tab - tab to show
* @return TabbedPanelBuilder
*/
public TabbedPanelBuilder tab(int slot, Tab tab) {
if (slot < 0 || slot > 9) {
throw new InvalidParameterException("Slot must be between 0 and 9");
}
tabs.put(slot, tab);
return this;
}
/**
* The default tab to show
* @param slot - slot value between 0 and 9
* @return TabbedPanelBuilder
*/
public TabbedPanelBuilder startingSlot(int slot) {
if (slot < 0 || slot > 9) {
throw new InvalidParameterException("Slot must be between 0 and 9");
}
startingSlot = slot;
return this;
}
/**
* Build the panel
* @return Panel
*/
public TabbedPanel build() {
// Set starting slot
if (!tabs.isEmpty() && !tabs.containsKey(startingSlot)) {
startingSlot = ((TreeMap<Integer, Tab>)tabs).firstKey();
}
return new TabbedPanel(this);
}
/**
* @return the tabs
*/
public Map<Integer, Tab> getTabs() {
return tabs;
}
/**
* @return the startingSlot
*/
public int getStartingSlot() {
return startingSlot;
}
/**
* @return the world
*/
public World getWorld() {
return world;
}
/**
* @return the size
*/
public int getSize() {
return size;
}
/**
* @return the user
*/
public User getUser() {
return user;
}
}

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.api.placeholders;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.api.placeholders;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.user.User;
@FunctionalInterface

View File

@ -1,15 +1,16 @@
package world.bentobox.bentobox.api.placeholders.placeholderapi;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
import world.bentobox.bentobox.api.user.User;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.bukkit.entity.Player;
import org.eclipse.jdt.annotation.NonNull;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
import world.bentobox.bentobox.api.user.User;
/**
* @author Poslovitch
*/

View File

@ -1,5 +1,13 @@
package world.bentobox.bentobox.api.user;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.lang.math.NumberUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -16,18 +24,11 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.events.OfflineMessageEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Combines {@link Player}, {@link OfflinePlayer} and {@link CommandSender} to provide convenience methods related to
* localization and generic interactions.
@ -245,7 +246,7 @@ public class User {
*/
public boolean removePerm(String name) {
for (PermissionAttachmentInfo p : player.getEffectivePermissions()) {
if (p.getPermission().equals(name)) {
if (p.getPermission().equals(name) && p.getAttachment() != null) {
player.removeAttachment(p.getAttachment());
break;
}
@ -290,6 +291,9 @@ public class User {
* @return max value
*/
public int getPermissionValue(String permissionPrefix, int defaultValue) {
// If requester is console, then return the default value
if (!isPlayer()) return defaultValue;
int value = defaultValue;
// If there is a dot at the end of the permissionPrefix, remove it
@ -421,7 +425,7 @@ public class User {
}
/**
* Sends a message to sender if message is not empty and if the same wasn't sent within the previous {@link Notifier#NOTIFICATION_DELAY} seconds.
* Sends a message to sender if message is not empty and if the same wasn't sent within the previous Notifier.NOTIFICATION_DELAY seconds.
* @param reference - language file reference
* @param variables - CharSequence target, replacement pairs
*
@ -435,7 +439,7 @@ public class User {
}
/**
* Sends a message to sender if message is not empty and if the same wasn't sent within the previous {@link Notifier#NOTIFICATION_DELAY} seconds.
* Sends a message to sender if message is not empty and if the same wasn't sent within the previous Notifier.NOTIFICATION_DELAY seconds.
* @param world - the world the translation should come from
* @param reference - language file reference
* @param variables - CharSequence target, replacement pairs

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.blueprints;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.bukkit.Material;
@ -49,7 +50,8 @@ public class Blueprint {
* @return the name
*/
public String getName() {
return name;
// Force lower case
return name.toLowerCase(Locale.ENGLISH);
}
/**
* @param name the name to set

View File

@ -1,5 +1,15 @@
package world.bentobox.bentobox.blueprints;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@ -24,6 +34,7 @@ import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
@ -31,16 +42,6 @@ import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintCreatureSpawner;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* The clipboard provides the holding spot for an active blueprint that is being
* manipulated by a user. It supports copying from the world and setting of coordinates
@ -63,6 +64,7 @@ public class BlueprintClipboard {
private Map<Vector, List<BlueprintEntity>> bpEntities = new LinkedHashMap<>();
private Map<Vector, BlueprintBlock> bpAttachable = new LinkedHashMap<>();
private Map<Vector, BlueprintBlock> bpBlocks = new LinkedHashMap<>();
private BentoBox plugin = BentoBox.getInstance();
/**
* Create a clipboard for blueprint
@ -114,49 +116,49 @@ public class BlueprintClipboard {
blueprint.setySize((int)toCopy.getHeight());
blueprint.setzSize((int)toCopy.getWidthZ());
BentoBox plugin = BentoBox.getInstance();
final int speed = plugin.getSettings().getPasteSpeed();
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
final List<Vector> vectorsToCopy = getVectors(toCopy);
copying = false;
copyTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
if (copying) {
return;
}
copying = true;
vectorsToCopy.stream().skip(index).limit(speed).forEach(v -> {
List<LivingEntity> ents = world.getLivingEntities().stream()
.filter(Objects::nonNull)
.filter(e -> !(e instanceof Player))
.filter(e -> new Vector(Math.rint(e.getLocation().getX()),
Math.rint(e.getLocation().getY()),
Math.rint(e.getLocation().getZ())).equals(v))
.collect(Collectors.toList());
if (copyBlock(v.toLocation(world), origin, copyAir, ents)) {
count++;
}
});
index += speed;
int percent = (int)(index * 100 / (double)vectorsToCopy.size());
if (percent != lastPercentage && percent % 10 == 0) {
user.sendMessage("commands.admin.blueprint.copied-percent", TextVariables.NUMBER, String.valueOf(percent));
lastPercentage = percent;
}
if (index > vectorsToCopy.size()) {
copyTask.cancel();
blueprint.setAttached(bpAttachable);
blueprint.setBlocks(bpBlocks);
blueprint.setEntities(bpEntities);
user.sendMessage("general.success");
user.sendMessage("commands.admin.blueprint.copied-blocks", TextVariables.NUMBER, String.valueOf(count));
}
copying = false;
}, 0L, 1L);
});
int speed = plugin.getSettings().getPasteSpeed();
List<Vector> vectorsToCopy = getVectors(toCopy);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> copyAsync(world, user, vectorsToCopy, speed, copyAir));
return true;
}
private void copyAsync(World world, User user, List<Vector> vectorsToCopy, int speed, boolean copyAir) {
copying = false;
copyTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
if (copying) {
return;
}
copying = true;
vectorsToCopy.stream().skip(index).limit(speed).forEach(v -> {
List<LivingEntity> ents = world.getLivingEntities().stream()
.filter(Objects::nonNull)
.filter(e -> !(e instanceof Player))
.filter(e -> new Vector(Math.rint(e.getLocation().getX()),
Math.rint(e.getLocation().getY()),
Math.rint(e.getLocation().getZ())).equals(v))
.collect(Collectors.toList());
if (copyBlock(v.toLocation(world), origin, copyAir, ents)) {
count++;
}
});
index += speed;
int percent = (int)(index * 100 / (double)vectorsToCopy.size());
if (percent != lastPercentage && percent % 10 == 0) {
user.sendMessage("commands.admin.blueprint.copied-percent", TextVariables.NUMBER, String.valueOf(percent));
lastPercentage = percent;
}
if (index > vectorsToCopy.size()) {
copyTask.cancel();
blueprint.setAttached(bpAttachable);
blueprint.setBlocks(bpBlocks);
blueprint.setEntities(bpEntities);
user.sendMessage("general.success");
user.sendMessage("commands.admin.blueprint.copied-blocks", TextVariables.NUMBER, String.valueOf(count));
}
copying = false;
}, 0L, 1L);
}
/**
* Get all the x,y,z coords that must be copied
* @param b - bounding box

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