Final fixes for 1.2.0 release.

* Fix user custom flag GUI init not showing USER group.
* Fix item frame protection during explosions.
* Fix entity-spawn not being triggered with slime splits.
* Fix 'SouthCorners' lang translation in /claiminfo.
* Fix 'explosion-entity' flag.
* Fix shovel visual not hitting leaves.
* Add explosion pre support.
* Add extra teleport check for claim corners.
* Add additional overlay/style for custom flags.
* Add javadocs for PermissionProvider.
* Add many improvements to custom flag GUI.
This commit is contained in:
bloodshot 2019-08-25 04:19:31 -04:00
parent 0520c502c9
commit e9377d4935
28 changed files with 1439 additions and 234 deletions

View File

@ -56,6 +56,7 @@
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.permission.GDPermissions;
import com.griefdefender.permission.flag.CustomFlagData;
import com.griefdefender.permission.flag.GDActiveFlagData;
import com.griefdefender.permission.flag.GDCustomFlagDefinition;
import com.griefdefender.permission.ui.ClaimClickData;
import com.griefdefender.permission.ui.FlagData;
@ -160,8 +161,20 @@ public void execute(Player player, String[] args) throws InvalidCommandArgument
if (claim != null) {
if (flag == null && value == null && player.hasPermission(GDPermissions.COMMAND_LIST_CLAIM_FLAGS)) {
final String defaultTab = GriefDefenderPlugin.getGlobalConfig().getConfig().customFlags.getGroups().keySet().stream().findFirst().orElse(null);
showCustomFlags(src, claim, defaultTab);
String defaultGroup = "";
for (Entry<String, CustomFlagGroupCategory> groupEntry : GriefDefenderPlugin.getGlobalConfig().getConfig().customFlags.getGroups().entrySet()) {
final String permission = groupEntry.getValue().isAdminGroup() ? GDPermissions.FLAG_CUSTOM_ADMIN_BASE : GDPermissions.FLAG_CUSTOM_USER_BASE;
if (!player.hasPermission(permission + "." + groupEntry.getKey()) && !src.getInternalPlayerData().canIgnoreClaim(claim)) {
continue;
}
defaultGroup = groupEntry.getKey();
break;
}
if (!defaultGroup.isEmpty()) {
showCustomFlags(src, claim, defaultGroup);
} else {
TextAdapter.sendComponent(player, MessageCache.getInstance().PERMISSION_FLAG_USE);
}
return;
} else if (flag != null && value != null) {
GDCauseStackManager.getInstance().pushCause(player);
@ -497,13 +510,63 @@ private void addFilteredContexts(Map<String, FlagData> filteredContextMap, Set<C
}
private Component getCustomFlagText(GDCustomFlagDefinition customFlag) {
final Component baseFlagText = TextComponent.builder().color(TextColor.GREEN).append(customFlag.getDisplayName() + " ")
TextComponent definitionType = TextComponent.empty();
TextColor flagColor = TextColor.GREEN;
for (Context context : customFlag.getDefinitionContexts()) {
if (context.getKey().contains("default")) {
definitionType = TextComponent.builder()
.append("\n")
.append(MessageCache.getInstance().LABEL_TYPE.color(TextColor.AQUA))
.append(" : ", TextColor.WHITE)
.append("DEFAULT", TextColor.LIGHT_PURPLE)
.append(" ")
.append(context.getValue().toUpperCase(), TextColor.GRAY)
.build();
flagColor = TextColor.LIGHT_PURPLE;
} else if (context.getKey().contains("override")) {
definitionType = TextComponent.builder()
.append("\n")
.append(MessageCache.getInstance().LABEL_TYPE.color(TextColor.AQUA))
.append(" : ", TextColor.WHITE)
.append("OVERRIDE", TextColor.RED)
.append(" ")
.append(context.getValue().toUpperCase(), TextColor.GRAY)
.build();
flagColor = TextColor.RED;
}
}
if (definitionType == TextComponent.empty()) {
definitionType = TextComponent.builder()
.append("\n")
.append(MessageCache.getInstance().LABEL_TYPE.color(TextColor.AQUA))
.append(" : ", TextColor.WHITE)
.append("CLAIM", TextColor.YELLOW)
.build();
}
final Component baseFlagText = TextComponent.builder()
.append(customFlag.getDisplayName(), flagColor)
.append(" ")
.hoverEvent(HoverEvent.showText(TextComponent.builder()
.append(customFlag.getDescription())
.append(definitionType)
.build())).build();
return baseFlagText;
}
private TextColor getCustomFlagColor(GDCustomFlagDefinition customFlag) {
TextColor flagColor = TextColor.GREEN;
for (Context context : customFlag.getDefinitionContexts()) {
if (context.getKey().contains("default")) {
flagColor = TextColor.LIGHT_PURPLE;
break;
} else if (context.getKey().contains("override")) {
flagColor = TextColor.RED;
break;
}
}
return flagColor;
}
private Component getFlagText(Flag flag, Set<Context> contexts) {
boolean customContext = UIHelper.containsCustomContext(contexts);
@ -515,42 +578,84 @@ private Component getFlagText(Flag flag, Set<Context> contexts) {
}
private Component getCustomClickableText(GDPermissionUser src, GDClaim claim, GDCustomFlagDefinition customFlag, String flagGroup) {
Component hoverEventText = TextComponent.empty();
boolean hasHover = false;
TextComponent.Builder hoverBuilder = TextComponent.builder();
final Player player = src.getOnlinePlayer();
boolean hasEditPermission = true;
Component denyReason = claim.allowEdit(player);
if (denyReason != null) {
hoverEventText = denyReason;
hoverBuilder.append(denyReason).append("\n");
hasEditPermission = false;
hasHover = true;
}
final boolean isAdminGroup = GriefDefenderPlugin.getGlobalConfig().getConfig().customFlags.getGroups().get(flagGroup).isAdminGroup();
final String permission = isAdminGroup ? GDPermissions.FLAG_CUSTOM_ADMIN_BASE : GDPermissions.FLAG_CUSTOM_USER_BASE;
// check flag perm
if (!player.hasPermission(permission + "." + flagGroup + "." + customFlag.getDisplayName())) {
hoverEventText = MessageCache.getInstance().PERMISSION_FLAG_USE;
hoverBuilder.append(MessageCache.getInstance().PERMISSION_FLAG_USE).append("\n");
hasEditPermission = false;
hasHover = true;
}
Map<CustomFlagData, Tristate> dataResults = new HashMap<>();
List<GDActiveFlagData> dataResults = new ArrayList<>();
boolean hasGDContext = false;
Set<Context> definitionContexts = new HashSet<>(customFlag.getDefinitionContexts());
for (Context context : customFlag.getDefinitionContexts()) {
if (context.getKey().contains("gd_claim")) {
hasGDContext = true;
break;
}
}
if (!hasGDContext) {
definitionContexts.add(claim.getContext());
}
for (CustomFlagData flagData : customFlag.getFlagData()) {
Set<Context> newContexts = new HashSet<>(flagData.getContexts());
boolean hasGDContext = false;
for (Context context : newContexts) {
final Set<Context> filteredContexts = new HashSet<>();
for (Context context : definitionContexts) {
if (context.getKey().contains("gd_claim")) {
hasGDContext = true;
break;
continue;
}
filteredContexts.add(context);
}
if (!hasGDContext) {
newContexts.add(claim.getContext());
// Check override
filteredContexts.addAll(flagData.getContexts());
Set<Context> newContexts = new HashSet<>(filteredContexts);
newContexts.add(ClaimContexts.GLOBAL_OVERRIDE_CONTEXT);
newContexts.add(claim.getOverrideTypeContext());
newContexts.add(claim.getOverrideClaimContext());
Tristate result = PermissionUtil.getInstance().getPermissionValueWithRequiredContexts(claim, GriefDefenderPlugin.DEFAULT_HOLDER, flagData.getFlag().getPermission(), newContexts, "gd_claim");
if (result != Tristate.UNDEFINED) {
dataResults.add(new GDActiveFlagData(flagData, result, GDActiveFlagData.Type.OVERRIDE));
continue;
}
Tristate result = PermissionUtil.getInstance().getPermissionValue(claim, GriefDefenderPlugin.DEFAULT_HOLDER, flagData.getFlag().getPermission(), newContexts);
dataResults.put(flagData, result);
// Check claim
newContexts = new HashSet<>(filteredContexts);
newContexts.add(claim.getContext());
result = PermissionUtil.getInstance().getPermissionValueWithRequiredContexts(claim, GriefDefenderPlugin.DEFAULT_HOLDER, flagData.getFlag().getPermission(), newContexts, "gd_claim");
if (result != Tristate.UNDEFINED) {
dataResults.add(new GDActiveFlagData(flagData, result, GDActiveFlagData.Type.CLAIM));
continue;
}
// Check default
newContexts = new HashSet<>(filteredContexts);
newContexts.add(ClaimContexts.GLOBAL_DEFAULT_CONTEXT);
newContexts.add(claim.getDefaultTypeContext());
result = PermissionUtil.getInstance().getPermissionValueWithRequiredContexts(claim, GriefDefenderPlugin.DEFAULT_HOLDER, flagData.getFlag().getPermission(), newContexts, "gd_claim");
if (result != Tristate.UNDEFINED) {
dataResults.add(new GDActiveFlagData(flagData, result, GDActiveFlagData.Type.DEFAULT));
continue;
}
dataResults.add(new GDActiveFlagData(flagData, result, GDActiveFlagData.Type.UNDEFINED));
}
boolean properResult = true;
Tristate lastResult = null;
for (Tristate result : dataResults.values()) {
for (GDActiveFlagData activeFlagData : dataResults) {
final Tristate result = activeFlagData.getValue();
if (lastResult == null) {
lastResult = result;
} else if (lastResult != result) {
@ -561,12 +666,15 @@ private Component getCustomClickableText(GDPermissionUser src, GDClaim claim, GD
TextComponent.Builder valueBuilder = TextComponent.builder();
if (!properResult) {
TextComponent.Builder hoverBuilder = TextComponent.builder();
for (Map.Entry<CustomFlagData, Tristate> entry : dataResults.entrySet()) {
hoverBuilder.append(entry.getKey().getCustomPermission() + " (" + entry.getValue() + ")\n");
if (hasEditPermission) {
hoverBuilder.append("Active Data : \n");
for (GDActiveFlagData activeFlagData : dataResults) {
hoverBuilder.append(activeFlagData.getComponent())
.append("\n");
}
hasHover = true;
}
valueBuilder.append("partial")
.hoverEvent(HoverEvent.showText(hoverBuilder.build()));
valueBuilder.append("partial");
lastResult = null;
} else {
TextColor valueColor = TextColor.GRAY;
@ -575,8 +683,43 @@ private Component getCustomClickableText(GDPermissionUser src, GDClaim claim, GD
} else if (lastResult == Tristate.FALSE) {
valueColor = TextColor.RED;
}
valueBuilder
.append(String.valueOf(lastResult).toLowerCase(), valueColor);
valueBuilder.append(String.valueOf(lastResult).toLowerCase(), valueColor);
}
if (hasEditPermission) {
if (lastResult == null || lastResult == Tristate.UNDEFINED) {
hoverBuilder.append(MessageCache.getInstance().FLAG_UI_CLICK_ALLOW);
} else if (lastResult == Tristate.TRUE) {
hoverBuilder.append(MessageCache.getInstance().FLAG_UI_CLICK_DENY);
} else {
hoverBuilder.append(MessageCache.getInstance().FLAG_UI_CLICK_REMOVE);
}
if (!customFlag.getDefinitionContexts().isEmpty()) {
hoverBuilder.append("\nContexts: ");
}
for (Context context : customFlag.getDefinitionContexts()) {
hoverBuilder.append("\n");
final String key = context.getKey();
final String value = context.getValue();
TextColor keyColor = TextColor.AQUA;
if (key.contains("default")) {
keyColor = TextColor.LIGHT_PURPLE;
} else if (key.contains("override")) {
keyColor = TextColor.RED;
} else if (key.contains("server")) {
keyColor = TextColor.GRAY;
}
hoverBuilder.append(key, keyColor)
.append("=", TextColor.WHITE)
.append(value.replace("minecraft:", ""), TextColor.GRAY);
}
hasHover = true;
}
if (hasHover) {
valueBuilder.hoverEvent(HoverEvent.showText(hoverBuilder.build()));
}
TextComponent.Builder textBuilder = null;
if (hasEditPermission) {
@ -587,7 +730,6 @@ private Component getCustomClickableText(GDPermissionUser src, GDClaim claim, GD
} else {
textBuilder = TextComponent.builder()
.append(valueBuilder
.hoverEvent(HoverEvent.showText(hoverEventText))
.build());
}
@ -728,32 +870,37 @@ private Consumer<CommandSender> createCustomFlagConsumer(GDPermissionUser src, G
final Player player = src.getOnlinePlayer();
return consumer -> {
GDCauseStackManager.getInstance().pushCause(player);
boolean hasGDContext = false;
Set<Context> definitionContexts = new HashSet<>(customFlag.getDefinitionContexts());
for (Context context : customFlag.getDefinitionContexts()) {
if (context.getKey().contains("gd_claim")) {
hasGDContext = true;
break;
}
}
if (!hasGDContext) {
definitionContexts.add(claim.getContext());
}
for (CustomFlagData flagData : customFlag.getFlagData()) {
final Set<Context> contexts = flagData.getContexts();
final Set<Context> newContexts = new HashSet<>(definitionContexts);
newContexts.addAll(flagData.getContexts());
Tristate newValue = Tristate.UNDEFINED;
if (currentValue == null || currentValue == Tristate.UNDEFINED) {
newValue = Tristate.FALSE;
} else if (currentValue == Tristate.FALSE) {
newValue = Tristate.TRUE;
} else if (currentValue == Tristate.TRUE) {
newValue = Tristate.FALSE;
} else {
newValue = Tristate.UNDEFINED;
}
PermissionResult result = null;
for (Flag flag : customFlag.getFlags()) {
GDFlagPermissionEvent.Set event = new GDFlagPermissionEvent.Set(this.subject, flagData.getFlag(), newValue, contexts);
GDFlagPermissionEvent.Set event = new GDFlagPermissionEvent.Set(this.subject, flagData.getFlag(), newValue, newContexts);
GriefDefender.getEventManager().post(event);
if (event.cancelled()) {
return;
}
final Set<Context> newContexts = new HashSet<>();
for (Context context : flagData.getContexts()) {
if (!context.getKey().contains("gd_claim")) {
newContexts.add(context);
}
}
newContexts.add(claim.getContext());
result = GriefDefenderPlugin.getInstance().getPermissionProvider().setPermissionValue(GriefDefenderPlugin.DEFAULT_HOLDER, flag, newValue, newContexts);
}
}

View File

@ -156,11 +156,9 @@ public void execute(Player player, String[] args) throws InvalidCommandArgument
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().PERMISSION_GLOBAL_OPTION);
return;
}
} else {
if (!player.hasPermission(GDPermissions.USER_CLAIM_OPTIONS +"." + option.getPermission().toLowerCase())) {
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().PERMISSION_PLAYER_OPTION);
return;
}
} else if (!player.hasPermission(GDPermissions.USER_CLAIM_OPTIONS +"." + option.getPermission().toLowerCase())) {
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().PERMISSION_PLAYER_OPTION);
return;
}
}
@ -361,8 +359,10 @@ protected void showOptionPermissions(GDPermissionUser src, GDClaim claim, MenuTy
this.addFilteredContexts(src, filteredContextMap, contextSet, MenuType.DEFAULT, mapEntry.getValue());
}
if (displayType != MenuType.DEFAULT) {
if (contextSet.contains(claim.getContext())) {
this.addFilteredContexts(src, filteredContextMap, contextSet, MenuType.CLAIM, mapEntry.getValue());
if (claim.isTown() || isAdmin) {
if (contextSet.contains(claim.getContext())) {
this.addFilteredContexts(src, filteredContextMap, contextSet, MenuType.CLAIM, mapEntry.getValue());
}
}
if (contextSet.contains(ClaimContexts.GLOBAL_OVERRIDE_CONTEXT)) {
this.addFilteredContexts(src, filteredContextMap, contextSet, MenuType.OVERRIDE, mapEntry.getValue());
@ -393,13 +393,13 @@ protected void showOptionPermissions(GDPermissionUser src, GDClaim claim, MenuTy
for (Entry<String, OptionData> mapEntry : filteredContextMap.entrySet()) {
final OptionData optionData = mapEntry.getValue();
final Option option = optionData.option;
if (option.getName().contains("tax") && !GriefDefenderPlugin.getGlobalConfig().getConfig().claim.bankTaxSystem) {
continue;
}
for (OptionContextHolder optionHolder : optionData.optionContextMap.values()) {
if (displayType != MenuType.CLAIM && optionHolder.getType() != displayType) {
continue;
}
if (option.getName().contains("tax") && !GriefDefenderPlugin.getGlobalConfig().getConfig().claim.bankTaxSystem) {
continue;
}
final Set<Context> contexts = optionHolder.getAllContexts();
Component optionText = getClickableOptionComponent(src, claim, option, optionHolder, contexts, displayType);

View File

@ -180,25 +180,25 @@ public void execute(CommandSender src, String[] args) {
claim = claim.getTown().get();
}
final GDClaim gpClaim = (GDClaim) claim;
final GDClaim gdClaim = (GDClaim) claim;
final GDPermissionUser owner = PermissionHolderCache.getInstance().getOrCreateUser(claim.getOwnerUniqueId());
final UUID ownerUniqueId = claim.getOwnerUniqueId();
if (!isAdmin) {
isAdmin = playerData.canIgnoreClaim(gpClaim);
isAdmin = playerData.canIgnoreClaim(gdClaim);
}
// if not owner of claim, validate perms
if (!isAdmin && !player.getUniqueId().equals(claim.getOwnerUniqueId())) {
if (!gpClaim.getInternalClaimData().getContainers().contains(player.getUniqueId())
&& !gpClaim.getInternalClaimData().getBuilders().contains(player.getUniqueId())
&& !gpClaim.getInternalClaimData().getManagers().contains(player.getUniqueId())
if (!gdClaim.getInternalClaimData().getContainers().contains(player.getUniqueId())
&& !gdClaim.getInternalClaimData().getBuilders().contains(player.getUniqueId())
&& !gdClaim.getInternalClaimData().getManagers().contains(player.getUniqueId())
&& !player.hasPermission(GDPermissions.COMMAND_CLAIM_INFO_OTHERS)) {
TextAdapter.sendComponent(player, MessageCache.getInstance().CLAIM_NOT_YOURS);
return;
}
}
final Component allowEdit = gpClaim.allowEdit(player);
final Component allowEdit = gdClaim.allowEdit(player);
List<Component> textList = new ArrayList<>();
Component name = claim.getName().orElse(null);
@ -213,15 +213,16 @@ public void execute(CommandSender src, String[] args) {
String containerGroups = "";
String managerGroups = "";
final int minClaimLevel = gpClaim.getOwnerMinClaimLevel();
double claimY = gpClaim.getOwnerPlayerData() == null ? 65.0D : (minClaimLevel > 65.0D ? minClaimLevel : 65);
if (gpClaim.isCuboid()) {
claimY = gpClaim.lesserBoundaryCorner.getY();
final int minClaimLevel = gdClaim.getOwnerMinClaimLevel();
double claimY = gdClaim.getOwnerPlayerData() == null ? 65.0D : (minClaimLevel > 65.0D ? minClaimLevel : 65);
if (gdClaim.isCuboid()) {
claimY = gdClaim.lesserBoundaryCorner.getY();
}
Location southWest = new Location(gpClaim.getWorld(), gpClaim.lesserBoundaryCorner.getX(), claimY, gpClaim.greaterBoundaryCorner.getZ());
Location northWest = new Location(gpClaim.getWorld(), gpClaim.lesserBoundaryCorner.getX(), claimY, gpClaim.lesserBoundaryCorner.getZ());
Location southEast = new Location(gpClaim.getWorld(), gpClaim.greaterBoundaryCorner.getX(), claimY, gpClaim.greaterBoundaryCorner.getZ());
Location northEast = new Location(gpClaim.getWorld(), gpClaim.greaterBoundaryCorner.getX(), claimY, gpClaim.lesserBoundaryCorner.getZ());
Location southWest = new Location(gdClaim.getWorld(), gdClaim.lesserBoundaryCorner.getX(), claimY, gdClaim.greaterBoundaryCorner.getZ());
Location northWest = new Location(gdClaim.getWorld(), gdClaim.lesserBoundaryCorner.getX(), claimY, gdClaim.lesserBoundaryCorner.getZ());
Location southEast = new Location(gdClaim.getWorld(), gdClaim.greaterBoundaryCorner.getX(), claimY, gdClaim.greaterBoundaryCorner.getZ());
Location northEast = new Location(gdClaim.getWorld(), gdClaim.greaterBoundaryCorner.getX(), claimY, gdClaim.lesserBoundaryCorner.getZ());
// String southWestCorner =
Date created = null;
Date lastActive = null;
@ -268,7 +269,7 @@ public void execute(CommandSender src, String[] args) {
Component worldName = TextComponent.builder()
.append(MessageCache.getInstance().LABEL_WORLD.color(TextColor.YELLOW))
.append(" : ")
.append(gpClaim.getWorld().getName(), TextColor.GRAY).build();
.append(gdClaim.getWorld().getName(), TextColor.GRAY).build();
if (!claim.isWilderness() && !claim.isAdminClaim()) {
claimName = TextComponent.builder()
.append(claimName)
@ -278,10 +279,10 @@ public void execute(CommandSender src, String[] args) {
.append(claimCost).build();
}
// users
final List<UUID> accessorList = gpClaim.getUserTrustList(TrustTypes.ACCESSOR, true);
final List<UUID> builderList = gpClaim.getUserTrustList(TrustTypes.BUILDER, true);
final List<UUID> containerList = gpClaim.getUserTrustList(TrustTypes.CONTAINER, true);
final List<UUID> managerList = gpClaim.getUserTrustList(TrustTypes.MANAGER, true);
final List<UUID> accessorList = gdClaim.getUserTrustList(TrustTypes.ACCESSOR, true);
final List<UUID> builderList = gdClaim.getUserTrustList(TrustTypes.BUILDER, true);
final List<UUID> containerList = gdClaim.getUserTrustList(TrustTypes.CONTAINER, true);
final List<UUID> managerList = gdClaim.getUserTrustList(TrustTypes.MANAGER, true);
for (UUID uuid : accessorList) {
final GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(uuid);
final String userName = user.getFriendlyName();
@ -312,16 +313,16 @@ public void execute(CommandSender src, String[] args) {
}
// groups
for (String group : gpClaim.getGroupTrustList(TrustTypes.ACCESSOR, true)) {
for (String group : gdClaim.getGroupTrustList(TrustTypes.ACCESSOR, true)) {
accessorGroups += group + " ";
}
for (String group : gpClaim.getGroupTrustList(TrustTypes.BUILDER, true)) {
for (String group : gdClaim.getGroupTrustList(TrustTypes.BUILDER, true)) {
builderGroups += group + " ";
}
for (String group : gpClaim.getGroupTrustList(TrustTypes.CONTAINER, true)) {
for (String group : gdClaim.getGroupTrustList(TrustTypes.CONTAINER, true)) {
containerGroups += group + " ";
}
for (String group : gpClaim.getGroupTrustList(TrustTypes.MANAGER, true)) {
for (String group : gdClaim.getGroupTrustList(TrustTypes.MANAGER, true)) {
managerGroups += group + " ";
}
@ -347,7 +348,7 @@ public void execute(CommandSender src, String[] args) {
if (isAdmin) {
Component adminSettings = TextComponent.builder()
.append(MessageCache.getInstance().CLAIMINFO_UI_ADMIN_SETTINGS).decoration(TextDecoration.ITALIC, true).color(TextColor.RED)
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createSettingsConsumer(src, claim, generateAdminSettings(src, gpClaim), ClaimTypes.ADMIN))))
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createSettingsConsumer(src, claim, generateAdminSettings(src, gdClaim), ClaimTypes.ADMIN))))
.hoverEvent(HoverEvent.showText(MessageCache.getInstance().CLAIMINFO_UI_CLICK_ADMIN))
.build();
textList.add(adminSettings);
@ -356,11 +357,11 @@ public void execute(CommandSender src, String[] args) {
Component bankInfo = null;
Component forSaleText = null;
if (GriefDefenderPlugin.getInstance().getVaultProvider() != null) {
if (GriefDefenderPlugin.getActiveConfig(gpClaim.getWorld().getUID()).getConfig().claim.bankTaxSystem) {
if (GriefDefenderPlugin.getActiveConfig(gdClaim.getWorld().getUID()).getConfig().claim.bankTaxSystem) {
bankInfo = TextComponent.builder()
.append(MessageCache.getInstance().CLAIMINFO_UI_BANK_INFO.color(TextColor.GOLD).decoration(TextDecoration.ITALIC, true))
.hoverEvent(HoverEvent.showText(MessageCache.getInstance().CLAIMINFO_UI_BANK_INFO))
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(Consumer -> { CommandHelper.displayClaimBankInfo(src, gpClaim, gpClaim.isTown() ? true : false, true); })))
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(Consumer -> { CommandHelper.displayClaimBankInfo(src, gdClaim, gdClaim.isTown() ? true : false, true); })))
.build();
}
forSaleText = TextComponent.builder()
@ -398,7 +399,7 @@ public void execute(CommandSender src, String[] args) {
final Component whiteCloseBracket = TextComponent.of("]");
Component defaultTypeText = TextComponent.builder()
.append(whiteOpenBracket)
.append(gpClaim.getFriendlyNameType(true))
.append(gdClaim.getFriendlyNameType(true))
.append(whiteCloseBracket).build();
if (allowEdit != null && !isAdmin) {
adminShowText = allowEdit;
@ -546,11 +547,11 @@ public void execute(CommandSender src, String[] args) {
Component claimRaid = TextComponent.builder()
.append("Raid", TextColor.YELLOW)
.append(" : ")
.append(getClickableInfoText(src, claim, RAID_OVERRIDE, GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Boolean.class), owner, Options.RAID, gpClaim) == true ? TextComponent.of("ON", TextColor.GREEN) : TextComponent.of("OFF", TextColor.RED))).build();
.append(getClickableInfoText(src, claim, RAID_OVERRIDE, GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Boolean.class), owner, Options.RAID, gdClaim) == true ? TextComponent.of("ON", TextColor.GREEN) : TextComponent.of("OFF", TextColor.RED))).build();
Component claimSpawn = null;
if (claim.getData().getSpawnPos().isPresent()) {
Vector3i spawnPos = claim.getData().getSpawnPos().get();
Location spawnLoc = new Location(gpClaim.getWorld(), spawnPos.getX(), spawnPos.getY(), spawnPos.getZ());
Location spawnLoc = new Location(gdClaim.getWorld(), spawnPos.getX(), spawnPos.getY(), spawnPos.getZ());
claimSpawn = TextComponent.builder()
.append(MessageCache.getInstance().LABEL_SPAWN.color(TextColor.GREEN))
.append(" : ")
@ -578,7 +579,7 @@ public void execute(CommandSender src, String[] args) {
ImmutableMap.of("direction", TextComponent.of("SE").color(TextColor.AQUA)))))
.build();
Component southCorners = TextComponent.builder()
.append("SouthCorners", TextColor.YELLOW)
.append(MessageCache.getInstance().CLAIMINFO_UI_SOUTH_CORNERS.color(TextColor.YELLOW))
.append(" : ")
.append(southWestCorner)
.append(southEastCorner).build();
@ -632,7 +633,7 @@ public void execute(CommandSender src, String[] args) {
Component dateCreated = TextComponent.builder()
.append(MessageCache.getInstance().LABEL_CREATED.color(TextColor.YELLOW))
.append(" : ")
.append(created != null ? created.toString() : "Unknown", TextColor.GRAY).build();
.append(created != null ? TextComponent.of(created.toString(), TextColor.GRAY) : MessageCache.getInstance().LABEL_UNKNOWN.color(TextColor.GRAY)).build();
Component dateLastActive = TextComponent.builder()
.append(MessageCache.getInstance().CLAIMINFO_UI_LAST_ACTIVE.color(TextColor.YELLOW))
.append(" : ")

View File

@ -27,6 +27,7 @@
import java.util.HashMap;
import java.util.Map;
import com.griefdefender.api.claim.ClaimContexts;
import com.griefdefender.permission.flag.GDCustomFlagDefinition;
import com.griefdefender.permission.flag.GDCustomFlagTypes;
@ -60,6 +61,7 @@ public void initDefaults() {
}
if (adminGroup.isEnabled() && adminGroup.getFlagDefinitions().isEmpty()) {
for (GDCustomFlagDefinition definition : GDCustomFlagTypes.ADMIN_FLAGS) {
definition.getDefinitionContexts().add(ClaimContexts.GLOBAL_DEFAULT_CONTEXT);
adminGroup.getFlagDefinitions().put(definition.getDisplayName(), definition);
}
adminGroup.isAdmin = true;

View File

@ -93,18 +93,31 @@ public DefaultPermissionCategory() {
this.defaultUserOptions.put(Options.PLAYER_WALK_SPEED.getName(), "-1");
this.defaultUserOptions.put(Options.PLAYER_WEATHER.getName(), "undefined");
//this.defaultTownOptions.put(Options.ABANDON_RETURN_RATIO.getName(), "1.0");
this.defaultTownOptions.put(Options.CREATE_LIMIT.getName(), "-1");
this.defaultTownOptions.put(Options.MIN_LEVEL.getName(), "-1");
this.defaultBasicOptions.put(Options.MIN_SIZE_X.getName(), "5");
this.defaultBasicOptions.put(Options.MIN_SIZE_Y.getName(), "5");
this.defaultBasicOptions.put(Options.MIN_SIZE_Z.getName(), "5");
this.defaultBasicOptions.put(Options.MAX_SIZE_X.getName(), "0");
this.defaultBasicOptions.put(Options.MAX_SIZE_Y.getName(), "256");
this.defaultBasicOptions.put(Options.MAX_SIZE_Z.getName(), "0");
this.defaultSubdivisionOptions.put(Options.MIN_SIZE_X.getName(), "1");
this.defaultSubdivisionOptions.put(Options.MIN_SIZE_Y.getName(), "1");
this.defaultSubdivisionOptions.put(Options.MIN_SIZE_Z.getName(), "1");
this.defaultSubdivisionOptions.put(Options.MAX_SIZE_X.getName(), "1000");
this.defaultSubdivisionOptions.put(Options.MAX_SIZE_Y.getName(), "256");
this.defaultSubdivisionOptions.put(Options.MAX_SIZE_Z.getName(), "1000");
this.defaultTownOptions.put(Options.CREATE_LIMIT.getName(), "1");
this.defaultTownOptions.put(Options.MIN_LEVEL.getName(), "0");
this.defaultTownOptions.put(Options.MIN_SIZE_X.getName(), "32");
this.defaultTownOptions.put(Options.MIN_SIZE_Y.getName(), "32");
this.defaultTownOptions.put(Options.MIN_SIZE_Z.getName(), "32");
this.defaultTownOptions.put(Options.MAX_LEVEL.getName(), "-1");
this.defaultTownOptions.put(Options.MAX_SIZE_X.getName(), "-1");
this.defaultTownOptions.put(Options.MAX_SIZE_Y.getName(), "-1");
this.defaultTownOptions.put(Options.MAX_SIZE_Z.getName(), "-1");
this.defaultTownOptions.put(Options.TAX_EXPIRATION.getName(), "-1");
this.defaultTownOptions.put(Options.TAX_EXPIRATION_DAYS_KEEP.getName(), "-1");
this.defaultTownOptions.put(Options.MAX_LEVEL.getName(), "255");
this.defaultTownOptions.put(Options.MAX_SIZE_X.getName(), "0");
this.defaultTownOptions.put(Options.MAX_SIZE_Y.getName(), "256");
this.defaultTownOptions.put(Options.MAX_SIZE_Z.getName(), "0");
this.defaultTownOptions.put(Options.TAX_EXPIRATION.getName(), "7");
this.defaultTownOptions.put(Options.TAX_EXPIRATION_DAYS_KEEP.getName(), "7");
this.defaultTownOptions.put(Options.TAX_RATE.getName(), "1.0");
}

View File

@ -31,7 +31,7 @@
public class MessageCategory extends ConfigCategory {
@Setting(value = "locale", comment = "Set the locale to use for GD messages. (Default: en_US)\n" +
"Available languages: en_US, de_DE, fr_FR, ru_RU, zh_CN. The data is stored under assets in jar.\n" +
"Available languages: en_US, fr_FR, ru_RU. The data is stored under assets in jar.\n" +
"Note: The language code must be lowercase and the country code must be uppercase.")
public String locale = "en_US";

View File

@ -47,26 +47,22 @@
public class CustomFlagSerializer implements TypeSerializer<GDCustomFlagDefinition> {
private static final String INVALID_GD_CONTEXT = "Invalid 'gd-context' specified."
+ "\nAccepted values are : "
+ "\ngd_claim:<UUID>"
+ "\ngd_claim_default:<type>"
+ "\ngd_claim_override:<type>|<UUID>";
//private static final Pattern DATA_PATTERN = Pattern.compile("^?\\[ *((?:[\\w.-]+=[\\#\\w.-]+(?::[\\#\\w\\/.-]+)? *(?:, *(?!\\]$)|(?=\\]$)))+) *\\]$");
//private static final Pattern DATA_PATTERN = Pattern.compile("^?\\( *((?:[\\w.-]+=[\\w.-]+(?::[\\w\\/.-]+)? *(?:, *(?!\\)$)|(?=\\)$)))+) *\\)$");
@Override
public GDCustomFlagDefinition deserialize(TypeToken<?> type, ConfigurationNode node) throws ObjectMappingException {
final String flagDisplayName = node.getKey().toString();
final boolean enabled = node.getNode("enabled").getBoolean();
final String gdContext = node.getNode("gd-context").getString();
final String descr = node.getNode("description").getString();
Component description = TextComponent.empty();
if (descr != null) {
description = LegacyComponentSerializer.legacy().deserialize(descr, '&');
}
List<String> contextList = node.getNode("contexts").getList(TypeToken.of(String.class));
List<String> permissionList = node.getNode("permissions").getList(TypeToken.of(String.class));
if (permissionList == null) {
throw new ObjectMappingException("No permissions found for flag definition '" + flagDisplayName + "'. You must specify at least 1 or more permissions.");
}
List<CustomFlagData> flagDataList = new ArrayList<>();
for (String permissionEntry : permissionList) {
String permission = permissionEntry.replace(" ", "");
@ -114,44 +110,42 @@ public GDCustomFlagDefinition deserialize(TypeToken<?> type, ConfigurationNode n
}
final GDCustomFlagDefinition flagDefinition = new GDCustomFlagDefinition(flagDataList, flagDisplayName, description);
flagDefinition.setIsEnabled(enabled);
if (gdContext != null) {
final String parts[] = gdContext.split(":");
if (parts.length <= 1) {
throw new ObjectMappingException(INVALID_GD_CONTEXT);
}
final String key = parts[0];
final String value = parts[1];
switch (key) {
case "gd_claim" :
UUID uuid = null;
try {
uuid = UUID.fromString(value);
} catch (IllegalArgumentException e) {
throw new ObjectMappingException(INVALID_GD_CONTEXT);
}
break;
case "gd_claim_default" :
Set<Context> contexts = new HashSet<>();
if (contextList != null) {
for (String context : contextList) {
final String parts[] = context.split("=");
if (parts.length <= 1) {
throw new ObjectMappingException("Invalid context '" + context + "' for flag definition '" + flagDisplayName + "'. Skipping...");
}
final String key = parts[0];
final String value = parts[1];
if (key.equalsIgnoreCase("default") || key.equalsIgnoreCase("gd_claim_default")) {
if (!value.equalsIgnoreCase("global") && !value.equalsIgnoreCase("basic") && !value.equalsIgnoreCase("admin")
&& !value.equalsIgnoreCase("subdivision") && !value.equalsIgnoreCase("town")) {
throw new ObjectMappingException(INVALID_GD_CONTEXT);
throw new ObjectMappingException("Invalid context '" + key + "' with value '" + value + "'.");
}
break;
case "gd_claim_override" :
contexts.add(new Context("gd_claim_default", value));
} else if (key.equalsIgnoreCase("override") || key.equalsIgnoreCase("gd_claim_override")) {
if (!value.equalsIgnoreCase("global") && !value.equalsIgnoreCase("basic") && !value.equalsIgnoreCase("admin")
&& !value.equalsIgnoreCase("subdivision") && !value.equalsIgnoreCase("town")) {
// try UUID
uuid = null;
try {
uuid = UUID.fromString(value);
} catch (IllegalArgumentException e) {
throw new ObjectMappingException(INVALID_GD_CONTEXT);
if (value.length() == 36) {
UUID uuid = null;
try {
uuid = UUID.fromString(value);
} catch (IllegalArgumentException e) {
throw new ObjectMappingException("Invalid context '" + key + "' with value '" + value + "'.");
}
} else {
throw new ObjectMappingException("Invalid context '" + key + "' with value '" + value + "'.");
}
}
break;
default :
throw new ObjectMappingException(INVALID_GD_CONTEXT);
contexts.add(new Context("gd_claim_override", value));
} else {
contexts.add(new Context(key, value));
}
}
flagDefinition.setGDContext(new Context(key, value));
flagDefinition.setDefinitionContexts(contexts);
}
return flagDefinition;
}
@ -164,15 +158,21 @@ public void serialize(TypeToken<?> type, GDCustomFlagDefinition obj, Configurati
description = LegacyComponentSerializer.legacy().serialize((Component) obj.getDescription(), '&');
node.getNode("description").setValue(description);
}
if (obj.getGDContext() != null) {
node.getNode("gd-context").setValue(obj.getGDContext().getKey() + ":" + obj.getGDContext().getValue());
if (!obj.getDefinitionContexts().isEmpty()) {
List<String> contextList = new ArrayList<>();
ConfigurationNode contextNode = node.getNode("contexts");
for (Context context : obj.getDefinitionContexts()) {
contextList.add(context.getKey().toLowerCase() + "=" + context.getValue().toLowerCase());
}
contextNode.setValue(contextList);
}
ConfigurationNode permissionNode = node.getNode("permissions");
List<String> permissions = new ArrayList<>();
for (CustomFlagData flagData : obj.getFlagData()) {
int count = 0;
final Flag flag = flagData.getFlag();
final Set<Context> contexts = flagData.getContexts();
final Set<Context> dataContexts = flagData.getContexts();
String permission = "";
if (count > 0) {
permission += ", ";
@ -180,10 +180,11 @@ public void serialize(TypeToken<?> type, GDCustomFlagDefinition obj, Configurati
permission += "flag=" + flag.getName().toLowerCase();
count++;
for (Context context : contexts) {
for (Context context : dataContexts) {
String key = context.getKey();
permission += ", " + key + "=" + context.getValue();
}
permissions.add(permission);
}
permissionNode.setValue(permissions);

View File

@ -25,7 +25,6 @@
package com.griefdefender.configuration.type;
import com.griefdefender.configuration.category.CustomFlagGroupDefinitionCategory;
import com.griefdefender.configuration.category.CustomFlagGroupCategory;
import com.griefdefender.configuration.category.DefaultPermissionCategory;
import com.griefdefender.configuration.category.EconomyCategory;
import com.griefdefender.configuration.category.MessageCategory;
@ -45,9 +44,9 @@ public class GlobalConfig extends ConfigBase {
+ "\n admin-group=<true|false>: Whether this group is considered for admin use only."
+ "\n hover=<text>: The hover text to be displayed when hovering over group name in GUI."
+ "\n title=<text>: The title text to be used for TAB display."
+ "\n override=<type>: This is used to force a permission to a specific claim type or global. Accepted values are : 'admin', 'basic', subdivision', 'town', 'global', 'claim UUID'"
+ "\n default=<type>: This is used to set a default permission "
+ "\n value=<true|false>: This is used to set a default value for the flag definition. It is only used in conjunction with 'override=<type>, default=<type> settings."
+ "\n contexts=[\"key=value\"]: A list of optional definition contexts that will be applied to all permissions."
+ "\nNote: This is primary used with 'default' and 'override' contexts. Ex. contexts=[\"default=global\"]"
+ "\nEach group will have an associated permission in order to be viewable."
+ "\nThe 'user' group will use the permission : 'griefdefender.custom.flag.group.user'"
+ "\nThe 'admin' group will use the permission : 'griefdefender.custom.flag.group.admin'"

View File

@ -413,26 +413,18 @@ public void onExplosionEvent(BlockExplodeEvent event) {
}
Block source = event.getBlock();
GDCauseStackManager.getInstance().pushCause(source);
if (GriefDefenderPlugin.isSourceIdBlacklisted(Flags.EXPLOSION_BLOCK.toString(), source, world.getUID())) {
return;
}
final GDPermissionUser user = CauseContextHelper.getEventUser(event.getBlock().getLocation());
if (user == null) {
// Cancel if no user found
event.setCancelled(true);
return;
}
GDTimings.EXPLOSION_EVENT.startTiming();
GDClaim targetClaim = null;
final List<Block> filteredLocations = new ArrayList<>();
for (Block block : event.blockList()) {
final Location location = block.getLocation();
targetClaim = GriefDefenderPlugin.getInstance().dataStore.getClaimAt(location, targetClaim);
/*if (GDFlags.EXPLOSION_SURFACE && location.getPosition().getY() > ((net.minecraft.world.World) world).getSeaLevel()) {
result = GPPermissionHandler.getClaimPermission(event, location, targetClaim, GPPermissions.EXPLOSION_SURFACE, source, location.getBlock(), user, true);
} else {*/
Tristate result = GDPermissionManager.getInstance().getFinalPermission(event, location, targetClaim, GDPermissions.EXPLOSION_BLOCK, source, location.getBlock(), user, true);
if (result == Tristate.FALSE) {
// Avoid lagging server from large explosions.
@ -443,7 +435,7 @@ public void onExplosionEvent(BlockExplodeEvent event) {
filteredLocations.add(block);
}
}
// Workaround for SpongeForge bug
if (event.isCancelled()) {
event.blockList().clear();
} else if (!filteredLocations.isEmpty()) {

View File

@ -24,11 +24,13 @@
*/
package com.griefdefender.listener;
import com.flowpowered.math.vector.Vector3i;
import com.google.common.reflect.TypeToken;
import com.griefdefender.GDPlayerData;
import com.griefdefender.GDTimings;
import com.griefdefender.GriefDefenderPlugin;
import com.griefdefender.api.Tristate;
import com.griefdefender.api.claim.Claim;
import com.griefdefender.api.claim.TrustType;
import com.griefdefender.api.claim.TrustTypes;
import com.griefdefender.api.permission.Context;
@ -37,6 +39,7 @@
import com.griefdefender.cache.MessageCache;
import com.griefdefender.cache.PermissionHolderCache;
import com.griefdefender.claim.GDClaim;
import com.griefdefender.claim.GDClaimManager;
import com.griefdefender.event.GDCauseStackManager;
import com.griefdefender.internal.tracking.EntityTracker;
import com.griefdefender.internal.tracking.entity.GDEntity;
@ -47,14 +50,15 @@
import com.griefdefender.permission.flag.GDFlags;
import com.griefdefender.storage.BaseStorage;
import com.griefdefender.util.CauseContextHelper;
import com.griefdefender.util.PermissionUtil;
import com.griefdefender.util.PlayerUtil;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Item;
@ -62,6 +66,7 @@
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -78,7 +83,10 @@
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntitySpawnEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.SlimeSplitEvent;
import org.bukkit.event.entity.SpawnerSpawnEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
@ -152,6 +160,45 @@ public void onEntityChangeBlockEvent(EntityChangeBlockEvent event) {
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onExplosionPrimeEvent(ExplosionPrimeEvent event) {
final World world = event.getEntity().getLocation().getWorld();
if (!GDFlags.EXPLOSION_BLOCK && !GDFlags.EXPLOSION_ENTITY) {
return;
}
if (!GriefDefenderPlugin.getInstance().claimsEnabledForWorld(world.getUID())) {
return;
}
GDCauseStackManager.getInstance().pushCause(event.getEntity());
GDTimings.ENTITY_EXPLOSION_PRE_EVENT.startTiming();
final GDEntity gdEntity = EntityTracker.getCachedEntity(event.getEntity().getEntityId());
GDPermissionUser user = null;
if (gdEntity != null) {
user = PermissionHolderCache.getInstance().getOrCreateUser(gdEntity.getOwnerUUID());
} else {
user = CauseContextHelper.getEventUser(event.getEntity().getLocation());
}
final Location location = event.getEntity().getLocation();
final GDClaim radiusClaim = NMSUtil.getInstance().createClaimFromCenter(location, event.getRadius());
final GDClaimManager claimManager = GriefDefenderPlugin.getInstance().dataStore.getClaimWorldManager(location.getWorld().getUID());
final Set<Claim> surroundingClaims = claimManager.findOverlappingClaims(radiusClaim);
if (surroundingClaims.size() == 0) {
return;
}
for (Claim claim : surroundingClaims) {
// Use any location for permission check
final Vector3i pos = claim.getLesserBoundaryCorner();
Location targetLocation = new Location(location.getWorld(), pos.getX(), pos.getY(), pos.getZ());
Tristate result = GDPermissionManager.getInstance().getFinalPermission(event, location, claim, GDPermissions.EXPLOSION_BLOCK, event.getEntity(), targetLocation, user, true);
if (result == Tristate.FALSE) {
event.setCancelled(true);
break;
}
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onEntityExplodeEvent(EntityExplodeEvent event) {
final World world = event.getEntity().getLocation().getWorld();
@ -159,6 +206,7 @@ public void onEntityExplodeEvent(EntityExplodeEvent event) {
return;
}
GDCauseStackManager.getInstance().pushCause(event.getEntity());
// check entity tracker
final GDEntity gdEntity = EntityTracker.getCachedEntity(event.getEntity().getEntityId());
GDPermissionUser user = null;
@ -249,11 +297,22 @@ public void onEntityDamage(EntityDamageByBlockEvent event) {
}
@EventHandler(priority = EventPriority.LOWEST)
public void onEntityDamage(EntityDamageByEntityEvent event) {
/*if (event.getDamager() instanceof Projectile) {
return;
}*/
public void onHangingBreakEvent(HangingBreakEvent event) {
GDTimings.ENTITY_DAMAGE_EVENT.startTiming();
Object source = event.getCause().name();
final Object causeSource = GDCauseStackManager.getInstance().getCurrentCause().first(Entity.class).orElse(null);
if (causeSource != null) {
source = causeSource;
}
if (protectEntity(event, source, event.getEntity())) {
event.setCancelled(true);
}
GDTimings.ENTITY_DAMAGE_EVENT.stopTiming();
}
@EventHandler(priority = EventPriority.LOWEST)
public void onEntityDamage(EntityDamageByEntityEvent event) {
if (event.getDamager() instanceof Player) {
final Player player = (Player) event.getDamager();
GDCauseStackManager.getInstance().pushCause(player);
@ -268,6 +327,7 @@ public void onEntityDamage(EntityDamageByEntityEvent event) {
}
}
GDTimings.ENTITY_DAMAGE_EVENT.startTiming();
if (protectEntity(event, event.getDamager(), event.getEntity())) {
event.setCancelled(true);
}
@ -322,6 +382,13 @@ public boolean protectEntity(Event event, Object source, Entity targetEntity) {
return false;
}
if (source instanceof Creeper || source instanceof TNTPrimed) {
final Tristate result = GDPermissionManager.getInstance().getFinalPermission(event, targetEntity.getLocation(), claim, GDPermissions.EXPLOSION_ENTITY, source, targetEntity, user, true);
if (result == Tristate.FALSE) {
return true;
}
}
GDPlayerData playerData = null;
if (user != null) {
playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(targetEntity.getWorld(), user.getUniqueId());
@ -379,12 +446,17 @@ public boolean protectEntity(Event event, Object source, Entity targetEntity) {
@EventHandler(priority = EventPriority.LOWEST)
public void onCreatureSpawn(CreatureSpawnEvent event) {
handleEntitySpawn(event, event.getSpawnReason());
handleEntitySpawn(event, event.getSpawnReason(), event.getEntity());
}
@EventHandler(priority = EventPriority.LOWEST)
public void onSpawnerSpawn(SpawnerSpawnEvent event) {
handleEntitySpawn(event, event.getSpawner());
handleEntitySpawn(event, event.getSpawner(), event.getEntity());
}
@EventHandler(priority = EventPriority.LOWEST)
public void onSlimeSplitEvent(SlimeSplitEvent event) {
handleEntitySpawn(event, event.getEntity(), event.getEntity());
}
@EventHandler(priority = EventPriority.LOWEST)
@ -397,26 +469,26 @@ public void onEntitySpawn(EntitySpawnEvent event) {
gdEntity.setNotifierUUID(user.getUniqueId());
EntityTracker.addTempEntity(gdEntity);
}
handleEntitySpawn(event, null);
handleEntitySpawn(event, null, event.getEntity());
}
//@EventHandler(priority = EventPriority.LOWEST)
//public void onEntitySpawn(EntitySpawnEvent event) {
//}
public void handleEntitySpawn(EntitySpawnEvent event, Object source) {
public void handleEntitySpawn(Event event, Object source, Entity entity) {
if (!GDFlags.ENTITY_SPAWN) {
return;
}
final World world = event.getEntity().getWorld();
final World world = entity.getWorld();
if (!GriefDefenderPlugin.getInstance().claimsEnabledForWorld(world.getUID())) {
return;
}
if (GriefDefenderPlugin.isSourceIdBlacklisted(Flags.ENTITY_SPAWN.getName(), source, world.getUID())) {
return;
}
if (event.getEntity() instanceof FallingBlock) {
if (entity instanceof FallingBlock) {
return;
}
@ -439,7 +511,6 @@ public void handleEntitySpawn(EntitySpawnEvent event, Object source) {
}
}
final Entity entity = event.getEntity();
// Player drops are handled in PlayerDropItemEvent
if (source instanceof GDPermissionUser && entity instanceof Item) {
GDTimings.ENTITY_SPAWN_EVENT.stopTiming();
@ -475,7 +546,7 @@ public void handleEntitySpawn(EntitySpawnEvent event, Object source) {
}
if (GDPermissionManager.getInstance().getFinalPermission(event, entity.getLocation(), targetClaim, permission, source, entity, user, TrustTypes.ACCESSOR, true) == Tristate.FALSE) {
event.setCancelled(true);
((Cancellable) event).setCancelled(true);
}
GDTimings.ENTITY_SPAWN_EVENT.stopTiming();

View File

@ -30,6 +30,7 @@ public class ContextGroupKeys {
public static final String ANIMAL = "#animal";
public static final String AQUATIC = "#aquatic";
public static final String FOOD = "#food";
public static final String MISC = "#misc";
public static final String MONSTER = "#monster";
public static final String VEHICLE = "#vehicle";
}

View File

@ -33,11 +33,13 @@ public class ContextGroups {
public static final Context SOURCE_AMBIENT = new Context(ContextKeys.SOURCE, ContextGroupKeys.AMBIENT);
public static final Context SOURCE_ANIMAL = new Context(ContextKeys.SOURCE, ContextGroupKeys.ANIMAL);
public static final Context SOURCE_AQUATIC = new Context(ContextKeys.SOURCE, ContextGroupKeys.AQUATIC);
public static final Context SOURCE_MISC = new Context(ContextKeys.SOURCE, ContextGroupKeys.MISC);
public static final Context SOURCE_MONSTER = new Context(ContextKeys.SOURCE, ContextGroupKeys.MONSTER);
public static final Context SOURCE_VEHICLE = new Context(ContextKeys.SOURCE, ContextGroupKeys.VEHICLE);
public static final Context TARGET_AMBIENT = new Context(ContextKeys.TARGET, ContextGroupKeys.AMBIENT);
public static final Context TARGET_ANIMAL = new Context(ContextKeys.TARGET, ContextGroupKeys.ANIMAL);
public static final Context TARGET_AQUATIC = new Context(ContextKeys.TARGET, ContextGroupKeys.AQUATIC);
public static final Context TARGET_MISC = new Context(ContextKeys.TARGET, ContextGroupKeys.MISC);
public static final Context TARGET_MONSTER = new Context(ContextKeys.TARGET, ContextGroupKeys.MONSTER);
public static final Context TARGET_VEHICLE = new Context(ContextKeys.TARGET, ContextGroupKeys.VEHICLE);

View File

@ -333,16 +333,7 @@ private Tristate getFlagDefaultPermission(Claim claim, String permission) {
}
}
if (claim.isAdminClaim()) {
contexts.add(ClaimContexts.ADMIN_DEFAULT_CONTEXT);
} else if (claim.isBasicClaim() || claim.isSubdivision()) {
contexts.add(ClaimContexts.BASIC_DEFAULT_CONTEXT);
} else if (claim.isTown()) {
contexts.add(ClaimContexts.TOWN_DEFAULT_CONTEXT);
} else { // wilderness
contexts.add(ClaimContexts.WILDERNESS_DEFAULT_CONTEXT);
}
contexts.add(claim.getDefaultTypeContext());
contexts.add(ClaimContexts.GLOBAL_DEFAULT_CONTEXT);
//contexts.add(claim.getWorld().getContext());
contexts.addAll(this.eventContexts);
@ -689,12 +680,18 @@ public void addCustomEntityTypeContexts(Entity targetEntity, Set<Context> contex
} else {
contexts.add(ContextGroups.TARGET_MONSTER);
}
} else {
} else if (creatureType.contains("ambient")) {
if (isSource) {
contexts.add(ContextGroups.SOURCE_AMBIENT);
} else {
contexts.add(ContextGroups.TARGET_AMBIENT);
}
} else {
if (isSource) {
contexts.add(ContextGroups.SOURCE_MISC);
} else {
contexts.add(ContextGroups.TARGET_MISC);
}
}
}

View File

@ -24,11 +24,8 @@
*/
package com.griefdefender.permission.flag;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.griefdefender.api.Tristate;
import com.griefdefender.api.permission.Context;
import com.griefdefender.api.permission.flag.Flag;
@ -65,21 +62,4 @@ public boolean matches(Flag otherFlag, Set<Context> otherContexts) {
}
return true;
}
public String getCustomPermission() {
int count = 0;
final Flag flag = this.getFlag();
final Set<Context> contexts = this.getContexts();
String permission = "";
if (count > 0) {
permission += ", ";
}
permission += "flag=" + flag.getName().toLowerCase();
count++;
for (Context context : contexts) {
String key = context.getKey();
permission += ", " + key + "=" + context.getValue();
}
return permission;
}
}

View File

@ -0,0 +1,94 @@
/*
* This file is part of GriefDefender, licensed under the MIT License (MIT).
*
* Copyright (c) bloodmc
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.griefdefender.permission.flag;
import com.griefdefender.api.Tristate;
import com.griefdefender.api.permission.Context;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
public class GDActiveFlagData {
public enum Type {
CLAIM,
DEFAULT,
OVERRIDE,
UNDEFINED
}
private final CustomFlagData flagData;
private final Tristate value;
private final Type type;
public GDActiveFlagData(CustomFlagData flagData, Tristate value, Type type) {
this.flagData = flagData;
this.value = value;
this.type = type;
}
public CustomFlagData getFlagData() {
return this.flagData;
}
public Tristate getValue() {
return this.value;
}
public TextColor getColor() {
if (this.type == Type.CLAIM) {
return TextColor.YELLOW;
}
if (this.type == Type.OVERRIDE) {
return TextColor.RED;
}
if (this.type == Type.DEFAULT) {
return TextColor.LIGHT_PURPLE;
}
return TextColor.GRAY;
}
public Component getComponent() {
TextComponent.Builder contextBuilder = TextComponent.builder();
int count = 0;
for (Context context : this.flagData.getContexts()) {
if (count > 0) {
contextBuilder.append(", ");
}
contextBuilder.append(context.getKey().replace("gd_claim_", "").replace("gd_claim", ""), TextColor.GREEN)
.append("=")
.append(context.getValue(), TextColor.GRAY);
}
TextComponent.Builder builder = TextComponent.builder();
builder
.append(this.flagData.getFlag().getName().toLowerCase(), this.getColor())
.append("=", TextColor.WHITE)
.append(this.value.toString().toLowerCase(), TextColor.GOLD)
.append(" ")
.append(contextBuilder.build());
return builder.build();
}
}

View File

@ -44,7 +44,7 @@
public class GDCustomFlagDefinition {
private boolean enabled = true;
private Context gdContext;
private Set<Context> definitionContexts = new HashSet<>();
private List<CustomFlagData> data = new ArrayList<>();
private String displayName;
private Tristate defaultValue = Tristate.UNDEFINED;
@ -82,12 +82,12 @@ public Component getDescription() {
return this.description;
}
public Context getGDContext() {
return this.gdContext;
public Set<Context> getDefinitionContexts() {
return this.definitionContexts;
}
public void setGDContext(Context context) {
this.gdContext = context;
public void setDefinitionContexts(Set<Context> contexts) {
this.definitionContexts = contexts;
}
public String getDisplayName() {

View File

@ -45,25 +45,21 @@
public class GDOption<T> implements Option<T> {
private static final List<Option> GLOBAL_OPTIONS = Arrays.asList(
Options.ABANDON_RETURN_RATIO, Options.BLOCKS_ACCRUED_PER_HOUR, Options.CHEST_EXPIRATION, Options.ECONOMY_BLOCK_COST,
Options.ECONOMY_BLOCK_SELL_RETURN, Options.EXPIRATION, Options.INITIAL_BLOCKS, Options.MAX_ACCRUED_BLOCKS, Options.RADIUS_LIST,
Options.RADIUS_LIST);
private static final List<String> GLOBAL_OPTIONS = Arrays.asList(
"abandon-return-ratio", "blocks-accrued-per-hour", "chest-expiration", "economy-block-cost",
"economy-block-sell-return", "expiration", "initial-blocks", "max-accrued-blocks", "radius-list",
"radius-list");
private static final List<String> ADMIN_OPTIONS = Arrays.asList(
"player-command", "player-deny-godmode", "player-deny-hunger", "player-gamemode",
"player-health-regen", "player-keep-inventory", "player-keep-level", "player-walk-speed",
"radius-list", "radius-inspect");
private static final List<Option> TOWN_OPTIONS = Arrays.asList(
Options.ABANDON_RETURN_RATIO, Options.BLOCKS_ACCRUED_PER_HOUR, Options.CHEST_EXPIRATION, Options.ECONOMY_BLOCK_COST,
Options.ECONOMY_BLOCK_SELL_RETURN, Options.EXPIRATION, Options.INITIAL_BLOCKS, Options.MAX_ACCRUED_BLOCKS,
Options.TAX_EXPIRATION, Options.TAX_EXPIRATION_DAYS_KEEP, Options.TAX_RATE);
"player-command", "player-deny-godmode", "player-deny-hunger", "player-gamemode",
"player-health-regen", "player-keep-inventory", "player-keep-level", "player-walk-speed",
"radius-inspect", "radius-list");
private final String id;
private final String name;
private final Class<T> allowed;
private Component description;
private boolean isGlobal;
private boolean isAdmin;
private Boolean isGlobal;
private Boolean isAdmin;
GDOption(OptionBuilder<T> builder) {
this(builder.id, builder.name, builder.typeClass);
@ -73,8 +69,8 @@ public GDOption(String id, String name, Class<T> allowed) {
this.id = id;
this.name = name;
this.allowed = allowed;
this.isGlobal = GLOBAL_OPTIONS.contains(name);
this.isAdmin = ADMIN_OPTIONS.contains(name);
this.isGlobal = GLOBAL_OPTIONS.contains(name);
}
@Override

View File

@ -373,13 +373,13 @@ public Map<Set<Context>, Map<String, Boolean>> getPermanentPermissions(GDClaim c
Set<Context> contexts = null;
if (contextMap.get(node.getContexts()) == null) {
contexts = getGPContexts(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
contextMap.put(node.getContexts(), contexts);
} else {
contexts = contextMap.get(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
}
@ -417,13 +417,13 @@ public Map<Set<Context>, Map<String, Boolean>> getTransientPermissions(GDClaim c
Set<Context> contexts = null;
if (contextMap.get(node.getContexts()) == null) {
contexts = getGPContexts(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
contextMap.put(node.getContexts(), contexts);
} else {
contexts = contextMap.get(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
}
@ -459,13 +459,13 @@ public Map<Set<Context>, Map<String, String>> getPermanentOptions(GDPermissionHo
Set<Context> contexts = null;
if (contextMap.get(node.getContexts()) == null) {
contexts = getGPContexts(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
contextMap.put(node.getContexts(), contexts);
} else {
contexts = contextMap.get(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
}
@ -501,13 +501,13 @@ public Map<Set<Context>, Map<String, String>> getTransientOptions(GDPermissionHo
Set<Context> contexts = null;
if (contextMap.get(node.getContexts()) == null) {
contexts = getGPContexts(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
contextMap.put(node.getContexts(), contexts);
} else {
contexts = contextMap.get(node.getContexts());
if (serverName != null) {
if (serverName != null && !serverName.equalsIgnoreCase("undefined")) {
contexts.add(new Context("server", serverName));
}
}
@ -645,7 +645,6 @@ public Tristate getPermissionValue(GDClaim claim, GDPermissionHolder holder, Str
}
boolean match = true;
for (Context context : entry.getKey()) {
boolean found = false;
if (!contexts.contains(context)) {
match = false;
break;
@ -698,6 +697,41 @@ public Tristate getPermissionValue(GDClaim claim, GDPermissionHolder holder, Str
return Tristate.UNDEFINED;
}
public Tristate getPermissionValueWithRequiredContexts(GDClaim claim, GDPermissionHolder holder, String permission, Set<Context> contexts, String contextFilter) {
Map<Set<Context>, Map<String, Boolean>> permanentPermissions = getPermanentPermissions(claim, holder);
for (Entry<Set<Context>, Map<String, Boolean>> entry : permanentPermissions.entrySet()) {
if (entry.getKey().isEmpty()) {
continue;
}
boolean match = true;
for (Context context : entry.getKey()) {
if (!contexts.contains(context)) {
match = false;
break;
}
}
// Check for required contexts
for (Context context : contexts) {
if (!context.getKey().contains(contextFilter)) {
if (!entry.getKey().contains(context)) {
match = false;
break;
}
}
}
if (match) {
for (Map.Entry<String, Boolean> permEntry : entry.getValue().entrySet()) {
if (FilenameUtils.wildcardMatch(permission, permEntry.getKey())) {
final Tristate value = Tristate.fromBoolean(permEntry.getValue());
return value;
}
}
}
}
return Tristate.UNDEFINED;
}
public Tristate getPermissionValue(GDPermissionHolder holder, String permission, Set<Context> contexts) {
ImmutableContextSet contextSet = ImmutableContextSet.fromEntries(contexts);
return this.getPermissionValue(holder, permission, contextSet);

View File

@ -30,6 +30,7 @@
import java.util.UUID;
import org.bukkit.OfflinePlayer;
import org.checkerframework.checker.nullness.qual.Nullable;
import com.griefdefender.GDPlayerData;
import com.griefdefender.api.Tristate;
@ -41,67 +42,312 @@
import com.griefdefender.claim.GDClaim;
import com.griefdefender.permission.GDPermissionHolder;
/**
* Represents a provider of permission data.
*
* <p>This is the interface that a permissions plugin must implement and
* to provide permissions lookups for GriefDefender.</p>
*/
public interface PermissionProvider {
/**
* Checks if the group identifier exists.
*
* @param identifier The group identifier
* @return whether the group exists
*/
boolean hasGroupSubject(String identifier);
UUID lookupUserUniqueId(String name);
/**
* Performs a lookup for a UUID with matching
* username.
*
* @param name The username to search with
* @return The user uuid if available
*/
@Nullable UUID lookupUserUniqueId(String name);
/**
* Retrieves an immutable list of all loaded player
* names that exist in permissions.
*
* @return An immutable list of player names or empty if none.
*/
List<String> getAllLoadedPlayerNames();
/**
* Retrieves an immutable list of all loaded group
* names that exist in permissions.
*
* @return An immutable list of group names or empty if none.
*/
List<String> getAllLoadedGroupNames();
/**
* Appends all active contexts to passed context set currently
* active on permission holder.
*
* @param contexts The set to append to
* @param permissionHolder The holder to check active contexts
*/
void addActiveContexts(Set<Context> contexts, GDPermissionHolder permissionHolder);
/**
* Appends all active contexts to passed context set currently
* active on permission holder.
*
* @param contexts The set to append to
* @param permissionHolder The holder to check active contexts
* @param playerData The player data
* @param claim The claim
*/
void addActiveContexts(Set<Context> contexts, GDPermissionHolder permissionHolder, GDPlayerData playerData, Claim claim);
/**
* Clears all permissions that contain {@link Claim#getContext()}
* from passed {@link Claim}.
*
* @param claim The claim
*/
void clearPermissions(GDClaim claim);
/**
* Clears all permissions that contain {@link Context}
* from passed player.
*
* @param claim The claim
*/
void clearPermissions(OfflinePlayer player, Context context);
/**
* Clears all permissions that contain {@link Context}
* from passed holder.
*
* @param claim The claim
*/
void clearPermissions(GDPermissionHolder holder, Context context);
/**
* Clears all permissions that contain {@link Context}'s
* from passed player.
*
* @param claim The claim
*/
void clearPermissions(GDPermissionHolder holder, Set<Context> contexts);
/**
* Checks if holder has permission.
*
* @param permission The permission
* @return whether the holder has permission
*/
boolean holderHasPermission(GDPermissionHolder holder, String permission);
/**
* Gets all cached permissions of holder that contain specific {@link Context}'s.
*
* @param holder The holder
* @param contexts The contexts required
* @return An immutable map of cached permissions or empty if none.
*/
Map<String, Boolean> getPermissions(GDPermissionHolder holder, Set<Context> contexts);
/**
* Gets all cached options of holder that contain specific {@link Context}'s.
*
* @param holder The holder
* @param contexts The contexts required
* @return An immutable map of cached options or empty if none.
*/
Map<String, String> getOptions(GDPermissionHolder holder, Set<Context> contexts);
/**
* Gets all persisted permissions with associated contexts of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of persisted permissions or empty if none.
*/
Map<Set<Context>, Map<String, Boolean>> getPermanentPermissions(GDClaim claim, GDPermissionHolder holder);
/**
* Gets all transient permissions with associated contexts of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of transient permissions or empty if none.
*/
Map<Set<Context>, Map<String, Boolean>> getTransientPermissions(GDClaim claim, GDPermissionHolder holder);
/**
* Gets all persisted options with associated contexts of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of persisted options or empty if none.
*/
Map<Set<Context>, Map<String, String>> getPermanentOptions(GDPermissionHolder holder);
/**
* Gets all transient options with associated contexts of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of transient options or empty if none.
*/
Map<Set<Context>, Map<String, String>> getTransientOptions(GDPermissionHolder holder);
/**
* Gets all persisted options and associated values of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of persisted options or empty if none.
*/
Map<String, String> getPermanentOptions(GDClaim claim, GDPermissionHolder holder, Set<Context> contexts);
/**
* Gets all transient options and associated values of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of transient options or empty if none.
*/
Map<String, String> getTransientOptions(GDClaim claim, GDPermissionHolder holder, Set<Context> contexts);
/**
* Gets all persisted permissions, including inherited nodes, with associated contexts of holder.
*
* @param claim The current claim
* @param holder The holder
* @return An immutable map of persisted permissions or empty if none.
*/
Map<Set<Context>, Map<String, Boolean>> getAllPermissions(GDClaim claim, GDPermissionHolder holder);
/**
* Gets the current value of a permission assigned to a holder.
*
* @param holder The holder
* @param permission The permission to check
* @return The permission value
*/
Tristate getPermissionValue(GDPermissionHolder holder, String permission);
/**
* Gets the current value of a permission assigned to a holder.
*
* @param claim The current claim
* @param holder The holder
* @param permission The permission to check
* @param contexts The contexts
* @return The permission value
*/
Tristate getPermissionValue(GDClaim claim, GDPermissionHolder holder, String permission, Set<Context> contexts);
/**
* Gets the current value of a permission assigned to a holder.
*
* @param claim The current claim
* @param holder The holder
* @param permission The permission to check
* @param contexts The contexts
* @param checkTransient Whether to check transient permissions
* @return The permission value
*/
Tristate getPermissionValue(GDClaim claim, GDPermissionHolder holder, String permission, Set<Context> contexts, boolean checkTransient);
/**
* Gets the current value of a permission assigned to a holder.
*
* @param holder The holder
* @param permission The permission to check
* @param contexts The contexts
* @return The permission value
*/
Tristate getPermissionValue(GDPermissionHolder holder, String permission, Set<Context> contexts);
/**
* Gets the current value of a permission that contains all passed contexts
* assigned to a holder.
*
* @param claim The current claim
* @param holder The holder
* @param permission The permission to check
* @param contexts The contexts required
* @param contextFilter The context key to ignore for required contexts
* @return The permission value
*/
Tristate getPermissionValueWithRequiredContexts(GDClaim claim, GDPermissionHolder holder, String permission, Set<Context> contexts, String contextFilter);
/**
* Gets the current value of an option assigned to a holder.
*
* @param holder The holder
* @param permission The permission to check
* @param contexts The contexts
* @return The option value
*/
String getOptionValue(GDPermissionHolder holder, Option option, Set<Context> contexts);
/**
* Sets an option and value with contexts to a holder.
*
* @param holder The holder
* @param permission The permission
* @param value The value
* @param contexts The contexts
* @return The permission result
*/
PermissionResult setOptionValue(GDPermissionHolder holder, String permission, String value, Set<Context> contexts);
/**
* Sets a permission and value with contexts to a holder.
*
* @param holder The holder
* @param flag The flag to use for permission
* @param value The value
* @param contexts The contexts
* @return The permission result
*/
PermissionResult setPermissionValue(GDPermissionHolder holder, Flag flag, Tristate value, Set<Context> contexts);
/**
* Sets a permission and value with contexts to a holder.
*
* @param holder The holder
* @param permission The permission
* @param value The value
* @param contexts The contexts
* @return Whether the set permission operation was successful
*/
boolean setPermissionValue(GDPermissionHolder holder, String permission, Tristate value, Set<Context> contexts);
/**
* Sets a transient option and value with contexts to a holder.
*
* @param holder The holder
* @param permission The permission
* @param value The value
* @param contexts The contexts
* @return Whether the set permission operation was successful
*/
void setTransientOption(GDPermissionHolder holder, String permission, String value, Set<Context> contexts);
/**
* Sets a transient permission and value with contexts to a holder.
*
* @param holder The holder
* @param permission The permission
* @param value The value
* @param contexts The contexts
* @return Whether the set permission operation was successful
*/
void setTransientPermission(GDPermissionHolder holder, String permission, Boolean value, Set<Context> contexts);
/**
* Refreshes all cached permission data of holder.
*
* @param holder The holder
*/
void refreshCachedData(GDPermissionHolder holder);
}

View File

@ -391,6 +391,13 @@ public Tristate getPermissionValue(GDPermissionHolder holder, String permission,
return tristateFromInt(holderToPEXSubject(holder).getPermission(contextsGDToPEX(contexts), permission));
}
@Override
public Tristate getPermissionValueWithRequiredContexts(GDClaim claim, GDPermissionHolder holder, String permission,
Set<Context> contexts, String contextFilter) {
// TODO
return tristateFromInt(holderToPEXSubject(holder).getPermission(contextsGDToPEX(contexts), permission));
}
@Override
public String getOptionValue(GDPermissionHolder holder, Option option, Set<Context> contexts) {
return holderToPEXSubject(holder).getOption(contextsGDToPEX(contexts), option.getPermission()).orElse(null);

View File

@ -177,6 +177,10 @@ public Tristate getPermissionValue(GDPermissionHolder holder, String permission,
return PERMISSION_PROVIDER.getPermissionValue(holder, permission, contexts);
}
public Tristate getPermissionValueWithRequiredContexts(GDClaim claim, GDPermissionHolder holder, String permission, Set<Context> contexts, String contextFilter) {
return PERMISSION_PROVIDER.getPermissionValueWithRequiredContexts(claim, holder, permission, contexts, contextFilter);
}
public String getOptionValue(GDPermissionHolder holder, Option option, Set<Context> contexts) {
return PERMISSION_PROVIDER.getOptionValue(holder, option, contexts);
}

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:adapter:1.12.2",
"sha1": "49a2722e73f2dae2ae30905a1c34f8ecbe6ac84c",
"path": "com/griefdefender/adapter/1.12.2-SNAPSHOT/adapter-1.12.2-20190824.054201-17.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.12.2-SNAPSHOT/adapter-1.12.2-20190824.054201-17.jar"
"sha1": "1e2864c2f4f191a91ec94a457b7c23b67cc3cad8",
"path": "com/griefdefender/adapter/1.12.2-SNAPSHOT/adapter-1.12.2-20190825.074610-19.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.12.2-SNAPSHOT/adapter-1.12.2-20190825.074610-19.jar"
},
{
"name": "com.griefdefender:api:1.0.0",

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:adapter:1.13.2",
"sha1": "392cab759abcf0adfc73d4bad702583d5471645c",
"path": "com/griefdefender/adapter/1.13.2-SNAPSHOT/adapter-1.13.2-20190824.054317-16.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.13.2-SNAPSHOT/adapter-1.13.2-20190824.054317-16.jar"
"sha1": "2edc122ff64351cd85a8b1d509f25dbca3abdfea",
"path": "com/griefdefender/adapter/1.13.2-SNAPSHOT/adapter-1.13.2-20190825.074424-18.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.13.2-SNAPSHOT/adapter-1.13.2-20190825.074424-18.jar"
},
{
"name": "com.griefdefender:api:1.0.0",

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:adapter:1.14.2",
"sha1": "233717ff2c34f5a26c68d6d7e36c2d288454b677",
"path": "com/griefdefender/adapter/1.14.2-SNAPSHOT/adapter-1.14.2-20190824.054513-16.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.14.2-SNAPSHOT/adapter-1.14.2-20190824.054513-16.jar"
"sha1": "cfc9fb3065a7c135f064a57fcd1c444a1ec3e828",
"path": "com/griefdefender/adapter/1.14.2-SNAPSHOT/adapter-1.14.2-20190825.074341-18.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.14.2-SNAPSHOT/adapter-1.14.2-20190825.074341-18.jar"
},
{
"name": "com.griefdefender:api:1.0.0",

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:adapter:1.14.3",
"sha1": "f850a336ea29e1f926e7b6e7220bd03174418e49",
"path": "com/griefdefender/adapter/1.14.3-SNAPSHOT/adapter-1.14.3-20190824.054551-17.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.14.3-SNAPSHOT/adapter-1.14.3-20190824.054551-17.jar"
"sha1": "263ac2510d35b21493cb0d7247bee0f3536f6bc5",
"path": "com/griefdefender/adapter/1.14.3-SNAPSHOT/adapter-1.14.3-20190825.074256-19.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.14.3-SNAPSHOT/adapter-1.14.3-20190825.074256-19.jar"
},
{
"name": "com.griefdefender:api:1.0.0",

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:adapter:1.14.4",
"sha1": "bd0432df546af6c352a09836b4116887e5b596e3",
"path": "com/griefdefender/adapter/1.14.4-SNAPSHOT/adapter-1.14.4-20190824.054634-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.14.4-SNAPSHOT/adapter-1.14.4-20190824.054634-14.jar"
"sha1": "35fdaf76357368ae604a38ecfaca60b128922318",
"path": "com/griefdefender/adapter/1.14.4-SNAPSHOT/adapter-1.14.4-20190825.074211-16.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.14.4-SNAPSHOT/adapter-1.14.4-20190825.074211-16.jar"
},
{
"name": "com.griefdefender:api:1.0.0",

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:adapter:1.8.8",
"sha1": "b6abc129566822a55c70760f39c8b053ebe2ce22",
"path": "com/griefdefender/adapter/1.8.8-SNAPSHOT/adapter-1.8.8-20190824.054037-17.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.8.8-SNAPSHOT/adapter-1.8.8-20190824.054037-17.jar"
"sha1": "880f48231949acb4941024b7836c4bcbba10da49",
"path": "com/griefdefender/adapter/1.8.8-SNAPSHOT/adapter-1.8.8-20190825.074658-19.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/adapter/1.8.8-SNAPSHOT/adapter-1.8.8-20190825.074658-19.jar"
},
{
"name": "com.griefdefender:api:1.0.0",

View File

@ -0,0 +1,618 @@
GriefDefender {
descriptions {
abandon-all="Abandonne l'ENSEMBLE de tes protections."
abandon-claim="Abandonne une protection."
abandon-top="Abandonne la protection de plus haut niveau."
buy-blocks="Achète des blocs supplémentaires avec l'argent du serveur.\nNote: Nécessite un plug-in d'économie."
callback="Exécute un rappel définis comme faisant partie d'un objet textuel. Utilisée principalement pour un usage interne."
claim-bank="Utilisée pour retirer ou déposer de l'argent pour une utilisation dans la protection."
claim-clear="Permet de nettoyer les entités dans une ou plusieurs protection(s)."
claim-debug="Active/Désactive le mode débug pour les flags de protection."
claim-farewell="Définis le message de sortie de la protection."
claim-greeting="Définis le message d'accueil de la protection."
claim-ignore="Active/Désactive le mode pour ignorer les protections."
claim-info="Affiche l'ensemble des informations connues pour la protection dans laquelle tu te trouves.."
claim-inherit="Active/Désactive l'héritage des permissions depuis une protection parente."
claim-list="Liste l'ensemble des protections connues dans la zone."
claim-name="Définis le nom de la protection."
claim-restore="Restaure la protection à son état naturel. À utiliser avec prudence."
claim-setspawn="Définis le point d'apparition pour les joueurs."
claim-spawn="Te téléportes au point d'apparition si disponible."
claim-transfer="Transfert une protection basique ou admin à un autre joueur."
claim-worldedit="Utilise la sélection WordEdit pour créer une protection."
cuboid="Active/Désactive le mode protection cuboid."
debug="Capture l'ensemble des actions GD à des fins de débuggage."
delete-all="Supprime l'ensemble des protections d'un autre joueur."
delete-all-admin="supprime l'ensemble des protections admin."
delete-claim="Supprime la protection dans laquelle tu es, même si elle ne t'appartiens pas."
delete-top="Supprime la protection de plus haut niveau dans laquelle tu es, même si elle ne t'appartiens pas."
flag-claim="Récupère/Définis les flags de la protection dans laquelle tu es."
flag-group="Récupère/Définis les flags de permission pour un groupe dans la protection dans laquelle tu es."
flag-player="Récupère/Définis les flags de permission pour un joueur dans la protection dans laquelle tu es."
flag-reset="Remets par défaut les flags dans une protection."
mode-admin="Bascule l'outil pelle en mode protection admin."
mode-basic="Re-bascule l'outil pelle en mode protection basique."
mode-nature="Bascule l'outil pelle en mode restauration."
mode-subdivision="Bascule l'outil pelle en mode sous-division, utilisé pour sous-diviser les protections."
mode-town="Bascule l'outil pelle en mode protection Village."
option-claim="Récupère/Définis les options dans la protection dans laquelle tu es."
permission-group="Définis une permission sur un groupe avec un contexte de protection."
permission-player="Définis une permission sur un joueur avec un contexte de protection."
player-adjust-bonus-blocks="Mets à jour le nombre total de bloc de protection bonus pour un joueur."
player-info="Affiche les informations concernant un joueur."
player-set-accrued-blocks="Met à jour le nombre total de bloc gagné par un joueur."
reload="Recharge la configuration des paramètres de GriefDefender."
schematic="Gère les patrons de protection. Utilises '/claimschematic create <nom>' pour créer directement une copie de la protection."
sell-blocks="Vends tes blocs de protection contre de l'argent serveur.\nNote: Nécessite un plug-in d'économie."
sell-claim="Mets en vente ta protection. Utilises /claimsell <montant>.\nNote: Nécessite un plug-in d'économie."
town-chat="Active/Désactive le chat du Village."
town-tag="Définis le blason du village."
trust-group="Donne à un groupe accès à ta protection.\nAccessor: Permet d'intéragir avec l'ensemble des blocs sans inventaire.\nContainer: Permet d'intéragir avec l'ensemble des blocs avec inventaire.\nBuilder: Permet la même chose qu'au dessus avec en plus la possibilité de placer et casser des blocs.\nManager: Permet la même chose qu'au dessus avec en plus la possibilité de gérer les paramètres de la protection."
trust-group-all="Donne à un groupe l'accès à l'ENSEMBLE de tes protections.\nAccessor: Permet d'intéragir avec l'ensemble des blocs sans inventaire.\nContainer: Permet d'intéragir avec l'ensemble des blocs avec inventaire.\nBuilder: Permet la même chose qu'au dessus avec en plus la possibilité de placer et casser des blocs.\nManager: Permet la même chose qu'au dessus avec en plus la possibilité de gérer les paramètres de la protection."
trust-player="Donne à un joueur accès à ta protection.\nAccessor: Permet d'intéragir avec l'ensemble des blocs sans inventaire.\nContainer: Permet d'intéragir avec l'ensemble des blocs avec inventaire.\nBuilder: Permet la même chose qu'au dessus avec en plus la possibilité de placer et casser des blocs.\nManager: Permet la même chose qu'au dessus avec en plus la possibilité de gérer les paramètres de la protection."
trust-player-all="Donne à un joueur accès à l'ENSEMBLE de tes protections.\nAccessor: Permet d'intéragir avec l'ensemble des blocs sans inventaire.\nContainer: Permet d'intéragir avec l'ensemble des blocs avec inventaire.\nBuilder: Permet la même chose qu'au dessus avec en plus la possibilité de placer et casser des blocs.\nManager: Permet la même chose qu'au dessus avec en plus la possibilité de gérer les paramètres de la protection."
untrust-group="Supprime les accès d'un groupe à ta protection."
untrust-group-all="Supprime les accès d'un groupe à l'ENSEMBLE de tes protections."
untrust-player="Supprime les accès d'un joueur à ta protection."
untrust-player-all="Supprime les accès d'un joueur à l'ENSEMBLE de tes protections."
version="Affiche les informations sur la version de GriefDefender."
}
messages {
abandon-all-warning="&6Es-tu sûr de vouloir abandonner &cTOUTES&6 tes protections ?"
abandon-claim-delay-warning="&aCette protection a été créée récemment et ne peut pas être abandonnée avec le &6{date}&a."
abandon-claim-failed="&aN'a pas réussi à abandonner la protection. Résultat de la protection était: &f{result}&a."
abandon-claim-missing="&cPas de protection trouvée. Va dans la protection que tu veux abandonner ou envisages &f/abandonall&c."
abandon-other-success="La protection de &6{player}&a a été abandonnée. &6{player}&a dispose de maintenant &6{amount}&a blocs de protection disponibles."
abandon-success="&aProtection abandonnée. Tu as maintenant &6{amount}&a blocs de protection disponibles."
abandon-top-level="&cCette protection ne peut être abandonnée car elle contient une ou plusieurs protection(s) enfant(s). Pour abandonner une protection avec enfant, tu dois utiliser &f/abandontop&c à la place."
abandon-town-children="&cTu n'as pas la permission pour abandonner un village contenant des protections enfants qui ne t'appartiennent pas. Utilises &f/ignoreclaims&c ou fais en sorte que le propriétaire des protections enfant les abandonnent d'abord. Si tu veux abandonner le village sans affecter les protections enfant, utilises &f/abandon&c à la place."
abandon-warning="&6Es-tu sûr de vouloir abandonner cette protection ? Elle ne sera plus protégée contre les dégâts."
adjust-accrued-blocks-success="&aAjustement du nombre de blocs gagnés par &6{player}&a de &6{amount}&a. Nouveau total de blocs gagnés: &6{total}&a."
adjust-bonus-blocks-success="&aAjustement du nombre de blocs bonus &6{player}&a de &6{amount}&a. Nouveau total de blocs bonus: &6{total}&a."
bank-click-view-transactions="Clique ici pour voir les transactions bancaires"
bank-deposit="&aDépôt de &6{amount}&a avec succès dans la banque."
bank-deposit-no-funds="&cTu n'as pas suffisamment de fond pour faire un dépôt en banque."
bank-info="&aSolde: &6{balance}&a \nTaxe: &6{tax-amount}&f prélevée au &7{time-remaining}&a \nTaxe due: &6{tax-balance}."
bank-no-permission="&cTu n'as pas la permission de gérer la banque de protection de &6{player}&c."
bank-tax-system-disabled="&cLa banque/système de taxe n'est pas activé. Si tu veux l'activer, paramètre 'bank-tax-system' à true dans le fichier de configuration."
bank-title-transactions="Transactions Bancaire"
bank-withdraw="&aRetrait de &6{amount}&a de la banque avec succès."
bank-withdraw-no-funds="&cLa banque de protection a un solde de &a{balance}&c et n'a pas suffisamment de fond pour un retrait de &a{amount}&c."
block-claimed="&aCe bloc a été protégé par &6{player}&a."
block-not-claimed="&cPersonne n'a protégé ce bloc."
block-sale-value="&aChaque bloc de protection vaut &6{amount}&a. Tu as &6{total}&a disponible pour la vente."
claim-above-level="&cImpossible de protéger le bloc car il est au-dessus de niveau maximum limite de &a{limit}&c."
claim-action-not-available="&cCette action n'est pas disponible dans {type}&c."
claim-automatic-notification="&cCe coffre et les blocs à proximités sont protégés."
claim-below-level="&cImpossible de protéger le bloc car il est en-dessous du niveau minimum limite de &a{limit}&c."
claim-chest-confirmation="&cCe coffre est protégé."
claim-chest-outside-level="&cCe coffre ne peut pas être protégé car sa position est en dehors du niveau limite de protection de &a{min-level}&c et &a{max-level}&c."
claim-children-warning="&6Cette protection contient des protections enfants. Si tu es sûr de vouloir la supprimer, utilises &f/deleteclaim&6 à nouveau."
claim-context-not-found="&cContexte &f{context}&c non trouvé."
claim-disabled-world="&cLes protections sont désactivées dans ce monde."
claim-farewell="&aDéfini le message de sortie à {farewell}&a."
claim-farewell-clear="&aLe message de sortie a été supprimé."
claim-farewell-invalid="&cLe flag de protection &f{flag}&c n'est pas valide."
claim-greeting="&aDéfinis le message d'accueil sur {greeting}&a."
claim-greeting-clear="&aLe message de d'accueil a été supprimé."
claim-ignore="&aIgnore maintenant les protections."
claim-last-active="&aDernière activité de la protection le &6{date}&a."
claim-name="&aDéfinis le nom de la protection à {name}&a."
claim-no-claims="&cTu n'as aucune protection de zone."
claim-no-set-home="&cTu dois avoir la confiance pour utiliser /sethome ici."
claim-not-found="&cIl n'y a pas de protection ici."
claim-not-yours="&cCe n'est pas ta protection."
claim-owner-already="&cTu es déjà le propriétaire de cette protection."
claim-owner-only="&cSeulement &6{player}&c peut modifier cette protection."
claim-protected-entity="&cCela appartient à &6{player}&c."
claim-respecting="&aRespecte maintenant les protections."
claim-restore-success="&aRestauration de la protection avec succès."
claim-show-nearby="&aTrouvé &6{amount}&a protections à proximité."
claim-size-max="&cLa taille de &6{axis}&c sur &a{size}&c de la protection excède la taille maximum de &a{max-size}&c.\nLa zone a besoin d'être un minimum de &a{min-area}&c et de maximum &a{max-area}"
claim-size-min="&cLa taille de &6{axis}&c sur &a{size}&c de la protection est sous la taille minimum de &a{min-size}&c.\nLa zone a besoin d'être un minimum de &a{min-area}&c et de maximum &a{max-area}"
claim-size-need-blocks-2d="&cTu n'as pas suffisamment de blocs pour une protection de cette taille.\nTu as besoin de &a{block-amount}&c blocs supplémentaires."
claim-size-need-blocks-3d="&cTu n'as pas suffisamment de blocs pour une protection de cette taille.\nTu as besoin de &a{chunk-amount}&c chunks supplémentaires. &f({block-amount})"
claim-size-too-small="&cLa taille de la zone de protection sélectionnée de &a{width}&fx&a{length}&c sera trop petite. Une protection doit être à minimum &a{min-width}&fx&a{min-length}&c en taille."
claim-start="{type}&a coin défini ! Utilise la pelle au coin opposé pour protéger un rectangle de terre. Pour annuler, met la pelle de côté."
claim-too-far="&cC'est trop loin."
claim-transfer-exceeds-limit="&cLa protection ne peut pas être transférée car cela dépassera la limite de création du nouveau propriétaire."
claim-transfer-success="&aProtection transférée."
claim-type-not-found="&cPas de protection {type}&c trouvée."
claiminfo-ui-admin-settings="Paramètres Admin"
claiminfo-ui-bank-info="Information Bancaire"
claiminfo-ui-claim-expiration="Expiration de la protection"
claiminfo-ui-click-admin="Clique ici pour voir les paramètres admin"
claiminfo-ui-click-bank="Clique ici pour vérifier les informations bancaire"
claiminfo-ui-click-change-claim="Clique ici pour changer la protection à {type}"
claiminfo-ui-click-toggle="Clique ici pour basculer la valeur"
claiminfo-ui-deny-messages="Messages de refus"
claiminfo-ui-flag-overrides="Flag outrepassant"
claiminfo-ui-for-sale="À Vendre"
claiminfo-ui-inherit-parent="Héritage parent"
claiminfo-ui-last-active="Dernière activité"
claiminfo-ui-north-corners="Coin nord"
claiminfo-ui-pvp-override="Outrepasser PvP"
claiminfo-ui-requires-claim-blocks="Blocs de protection nécessaire"
claiminfo-ui-return-bankinfo="Retour au information bancaire"
claiminfo-ui-return-claiminfo="Retour au information de protection"
claiminfo-ui-return-settings="Retour au information standard"
claiminfo-ui-size-restrictions="Restriction de taille"
claiminfo-ui-south-corners="Coin sud"
claiminfo-ui-teleport-direction="Clique ici pour te téléporter au coin {direction}&f de la protection"
claiminfo-ui-teleport-feature="Tu n'as pas la permission pour utiliser la fonction de téléportation dans cette protection"
claiminfo-ui-teleport-spawn="Clique ici pour te téléporter au point d'appartition de la protection"
claiminfo-ui-title-claiminfo="Information de la protection"
claiminfo-ui-town-settings="Paramètre de la ville"
claimlist-ui-click-info="Clique ici pour voir plus d'informations"
claimlist-ui-click-purchase="Clique ici pour acheter la protection"
claimlist-ui-click-teleport-target="Clique ici pour te téléporter à {name}&f {target}&f dans &6{world}"
claimlist-ui-click-toggle-value="Clique ici pour basculer la valeur {type}"
claimlist-ui-click-view-children="Clique ici pour lister les protections enfant"
claimlist-ui-click-view-claims="Clique ici pour voir les protections qui t'appartiennent"
claimlist-ui-no-claims-found="Pas de protection trouvé dans ce monde."
claimlist-ui-return-claimlist="Retourne à la liste des protections"
claimlist-ui-title="Liste les protections"
claimlist-ui-title-child-claims="Protections enfant"
command-blocked="&cLa commande &f{command}&c a été bloquée par le propriétaire de la protection &6{player}&c."
command-claimban-success-block="&cBANNISSEMENT&a du bloc avec l'id {id}&a avec succès."
command-claimban-success-entity="&cBANNISSEMENT&a de l'entité avec l'id {id}&a avec succès."
command-claimban-success-item="&cBANNISSEMENT&a de l'objet avec l'id {id}&a avec succès."
command-claimbuy-title="&bProtection à vendre"
command-claimclear-killed="&cTué &6{amount}&a entités de type {type}&f."
command-claimclear-no-entities="&cImpossible de localiser une entité de type {type}&c."
command-claimclear-uuid-deny="&cSeulement les admins peuvent nettoyer les protections par UUID."
command-claimflagdebug-disabled="Mode débug de flag de protection &cOFF"
command-claimflagdebug-enabled="Mode débug de flag de protection &aON"
command-claiminfo-not-found="&cPas de joueur valide ou de protection avec cet UUID trouvé."
command-claiminfo-uuid-required="&cUUID de la protection nécessaire si exécuté depuis une source non joueur."
command-claiminherit-disabled="Héritage protection parente &cOFF"
command-claiminherit-enabled="Héritage protection parente &aON"
command-claimunban-success-block="&cDÉBANISSEMENT&a du bloc avec l'id {id}&a avec succès."
command-claimunban-success-entity="&cDÉBANISSEMENT&a de l'entité avec l'id {id}&a avec succès."
command-claimunban-success-item="&cDÉBANISSEMENT&a de l'objet avec l'id {id}&a avec succès."
command-cuboid-disabled="&aProtège maintenant en mode &d2D&a."
command-cuboid-enabled="&aProtège maintenant en mode &d3D&a."
command-execute-failed="&cÉchec de l'exécution de la commande '{command} {args}'"
command-giveblocks-confirmation="&6Es-tu sûr de vouloir donner à {player}&6 {amount}&6 blocs de protection ?"
command-inherit-only-child="&cCette commande ne peut être utilisée que dans des protections enfant."
command-invalid="&cPas de commande valide entrée."
command-invalid-amount="&cMontant invalide &6{amount}&c entré."
command-invalid-claim="&cCette commande ne peut être utilisée dans les protections de type {type}&c."
command-invalid-group="&cGroupe &6{group}&c n'est pas valide."
command-invalid-player="&cJoueur &6{player}&c n'est pas valide."
command-invalid-player-group="&cPas un joueur ou groupe valide."
command-invalid-type="&cType {type}&c invalide spécifié."
command-not-available-economy="&cCette commande n'est pas disponible quand le serveur est en mode économie."
command-option-exceeds-admin="&cLa valeur &a'{value}&c' de l'option dépasse la valeur admin de '&a{admin-value}&c'. Ajustement à la valeur admin..."
command-pet-confirmation="&aAnimal transféré."
command-pet-invalid="&cL'animal de type {type} n'est pas actuellement transférable."
command-pet-transfer-cancel="&aTransfert animal annulé."
command-pet-transfer-ready="&aPrêt pour le transfert! Fait un clique droit sur l'animal que tu veux donner, ou annule avec un clique gauche."
command-player-not-found="&cJoueur '&6{player}&c' non trouvable."
command-world-not-found="&cMonde '&6{world}&c' non trouvable."
command-worldedit-missing="&cCette commande a besoin que WorldEdit soi installé sur le serveur."
create-cancel="&cLa création de cette protection a été annulée."
create-cuboid-disabled="&cLa création de protection en mode &d3D&c a été désactivées par un administrateur.\nTu peux uniquement créer une protection en mode &d3D&c en tant qu'Admin ou dans une protection en mode &d2D&c qui t'appartient."
create-failed-claim-limit="&cTu as atteint la limite de &a{limit}&c pour les protections de type {type}&c. Utilises &f/abandon&c pour en supprimer une avant d'en créer une nouvelle."
create-failed-result="&aLa création de la protection a échoué à cause de : &6{reason}&a."
create-insufficient-blocks-2d="&cTu n'as pas suffisamment de blocs pour protéger cette zone.\nTu as besoin de &a{amount}&c blocs supplémentaires."
create-insufficient-blocks-3d="&cTu n'as pas suffisamment de blocs pour protéger cette zone.\nTu as besoin de &a{amount}&c chunks supplémentaires. &f({block-amount})"
create-overlap="&cTu ne peut pas créer une protection ici car elle chevaucherait ton autre protection. Utilises &f/abandonclaim&c pour la supprimer ou utilise la pelle dans un coin pour la redimensionner."
create-overlap-player="&cTu ne peut pas créer une protection ici car elle chevaucherait la protection de &6{player}&c."
create-overlap-short="&cPas de protection existante sur le coin sélectionné. Clique sur un bloc valide à l'intérieur d'une protection parente afin de créer une sous-division."
create-subdivision-fail="&cPAs de protection existante au coin sélectionné. Cliques sur un bloc valide dans une zone à l'intérieur de la protection parente pour créer la sous-division."
create-subdivision-only="&cImpossible de créer la protection. Seulement les sous-divisions peuvent être créée à l'endroit d'un bloc unique."
create-success="{type}&a créée ! Utilises &f/trust&a pour la partager avec tes amis."
debug-error-upload="&cErreur d'envoi du contenu {content}&c."
debug-no-records="&cPas d'enregistrement de débug à coller !"
debug-paste-success="&aCollage avec succès !"
debug-record-end="Fin d'enregistrement"
debug-record-start="Démarrage d'enregistrement"
debug-time-elapsed="Temps passé"
delete-all-player-failed="&aNe peut pas supprimer l'ENSEMBLE des protections de &6{player}&a. Résultat de protection était &f{result}&a."
delete-all-player-success="&aSuppression de l'ENSEMBLE des protections de &6{player}&a avec succès."
delete-all-player-warning="&6Es-tu sûr de vouloir supprimer l'ENSEMBLE des protections de &6{player}&6 ?"
delete-all-type-deny="&cImpossible de supprimer l'ensemble des protections de type {type}&c. Un plug-in l'a refusé."
delete-all-type-success="&&cSuppression de l'ensemble des protections {type}&c."
delete-all-type-warning="&6Es-tu sûr de vouloir supprimer l'ENSEMBLE des protections de type {type}&6 ?"
delete-claim-failed="&aNe peut pas supprimer la protection. Le résultat de la protection était : &f{result}&a."
delete-claim-success="&aSuppression des protections de {player}&a."
delete-claim-warning="&6Es-tu sûr de vouloir supprimer les protections de {player}&6 ?"
economy-balance="&aVotre nouveau solde est de &6{balance}&a."
economy-block-available-purchase-2d="&aTu as suffisamment de fonds pour créer une protection jusqu'à &6{block-amount} &ablocs supplémentaires."
economy-block-available-purchase-3d="&aTu as suffisamment de fonds pour créer une protection jusqu'à &6{chunk-amount} &achunks supplémentaires. &f({block-amount})"
economy-block-buy-invalid="&cLe nombre de bloc doit être supérieur à 0."
economy-block-buy-sell-disabled="&cDésolé, l'achat et la vente de blocs de protection est désactivé."
economy-block-cost="&aChaque bloc de protection coût &6{amount}&a."
economy-block-not-available="&cTu n'as pas autant de blocs disponible pour la vente."
economy-block-only-buy="&cLes blocs de protection ne peuvent qu'être achetés, pas vendus."
economy-block-only-sell="&cLes blocs de protection ne peuvent qu'être vendus, pas achetés."
economy-block-purchase-confirmation="&aRetrait de &6{amount}&a depuis ton compte. Tu as maintenant &6{balance}&a blocs de protection disponible."
economy-block-purchase-cost="&aChaque bloc de protection coût &6{amount}&a. Ton solde est de &6{balance}&a."
economy-block-purchase-limit="&cLe nouveau nombre de bloc de protection total de &a{total}&c va dépasser la limite de bloc maximum de &a{limit}&c. La transaction a été annulée."
economy-block-sale-confirmation="&aDéposé &6{deposit}&a sur ton compte. Tu as maintenant &6{amount}&a blocs de protection disponible."
economy-block-sell-error="&cImpossible de vendre les blocs. Raison: &f{reason}&c."
economy-claim-abandon-success="&aProtection abandonnée. Tu as été remboursé d'un total de '&6{amount}&a'."
economy-claim-buy-cancelled="&cAchat annulé ! Impossible d'acheter la protection de &6{player}&c. Resultat est &a{result}"
economy-claim-buy-confirmation="&6Es-tu sûr de vouloir acheter cette protection pour &a{amount}&6 ? Clique confirm pour procéder."
economy-claim-buy-confirmed="&aTu as acheté la protection avec succès pour un montant de &6{amount}&a."
economy-claim-buy-not-enough-funds="&cTu n'as pas suffisamment de fond pour acheter cette protection pour &a{amount}&c. Tu as actuellement un solde de &a{balance}&c et tu as besoin de &a{amount_required}&c supplémentaire pour l'achat"
economy-claim-buy-transfer-cancelled="&cTransfert de protection annulé ! Ne peut transférer du propriétaire &6{owner}&c à &6{player}&c. Resultat est &a{result}"
economy-claim-not-for-sale="&cCette protection n'est pas à vendre."
economy-claim-sale-cancelled="&aTu as annulé la vente de ta protection."
economy-claim-sale-confirmation="&6Es-tu sûr de vouloir vendre ta protection pour &a{amount}&6 ? Si la protection est vendu, l'ensemble des objets et blocs vont être transféré à l'acheteur. Clique confirm si c'est bon."
economy-claim-sale-confirmed="&aTu as mis en vente ta protection avec succès pour un montant de &6{amount}&a."
economy-claim-sale-invalid-price="&cLe prix de vente de &a{amount}&c doit être supérieur ou égal à &a0&c."
economy-claim-sold="&aTa protection est vendu ! Le montant de &6{amount}&a a été déposé sur ton compte. Ton solde total est maintenant de &6{balance}&a."
economy-mode-block-sale-confirmation="&aDépôt de &6{deposit}&a sur votre compte. Votre solde total est de &6{balance}&a. Tu as maintenant suffisamment de fonds pour protéger jusqu'à &6{amount}&a blocs supplémentaires."
economy-mode-resize-success-2d="&aProtection redimensionnée. Ton nouveau solde est de &6{balance}&a. Tu as maintenant suffisamment de fonds pour protéger jusqu'à &6{block-amount} &ablocs supplémentaires."
economy-mode-resize-success-3d="&aProtection redimensionnée. Ton nouveau solde est de &6{balance}&a. Tu as maintenant suffisamment de fonds pour protéger jusqu'à &6{chunk-amount} &achunks supplémentaires. &f({block-amount})"
economy-not-enough-funds="&cTu n'as pas suffisamment de fond pour acheter cette zone. Ton solde actuel est '&a{balance}&c' mais tu as besoin de '&a{amount}&c' pour valider l'achat."
economy-not-installed="&cPlug-in d'économie non installé !"
economy-player-not-found="&cPas de compte d'économie trouvé pour le joueur &6{player}&c."
economy-remaining-funds="&aTu as &6{amount}&a disponible pour protéger du terrain."
economy-virtual-not-supported="&cLe plug-in d'économie ne supporte pas les comptes virtuels, ce qui est nécessaire. Utilises un autre plug-in d'économie ou contact le dev du plug-in pour qu'il supporte les comptes virtuels."
economy-withdraw-error="&cImpossible de retirer des fonds. Raison: &f{reason}&c."
feature-not-available="&cCette fonctionnalité est actuellement en cours de développement et sera disponible dans une version future."
flag-description-admin-block-break="Contrôle si un bloc peut être cassé."
flag-description-admin-block-grow="Contrôle si un bloc peut pousser."
flag-description-admin-block-place="Contrôle si un bloc peut être placé."
flag-description-admin-block-spread="Contrôle si un bloc peut s'étendre."
flag-description-admin-build="Contrôle les actions autorisées contre les blocs comme le minage, placement et intéraction."
flag-description-admin-enderpearl="Contrôle si une enderpearl peut être utilisée."
flag-description-admin-exit-player="Contrôle si un joueur peut sortir de la protection."
flag-description-admin-exp-drop="Contrôle si les orbes d'expériences peuvent apparaîtres."
flag-description-admin-explosion-block="Contrôle si les explosions affectent les blocs."
flag-description-admin-explosion-entity="Contrôle si les explosions affectent les entités."
flag-description-admin-fall-damage="Contrôle si le joueur peut prendre des dégâts de chute."
flag-description-admin-interact-block="Contrôle si un joueur peut intéragir avec les blocs.\n&bNote&f: Cela n'inclut PAS les blocs avec inventaire comme les coffres."
flag-description-admin-interact-entity="Contrôle si un joueur peut intéragir avec une entité.\n&bNote&f: Cela n'inclut PAS l'accès au coffre des entités comme les chevaux."
flag-description-admin-interact-inventory="Contrôle si un joueur peut intéragir avec un inventaire."
flag-description-admin-invincible="Contrôle si un joueur est invincible contre les dégâts."
flag-description-admin-item-drop="Contrôle si un joueur peut jeter un objet."
flag-description-admin-item-pickup="Contrôle si un joueur peut ramasser un objet."
flag-description-admin-monster-damage="Contrôle si un monstre peut faire des dégâts."
flag-description-admin-pistons="Contrôle si un piston peut être utilisé."
flag-description-admin-portal-use="Contrôle si un portail peut être utilisé."
flag-description-admin-spawn-ambient="Contrôle si les environnementaux, comme les chauves-souris, peuvent apparaître."
flag-description-admin-spawn-animal="Contrôle si les animaux, comme les vaches ou cochons, peuvent apparaître."
flag-description-admin-spawn-aquatic="Contrôle si les aquatiques, comme les poulpes et gardiens, peuvent apparaître."
flag-description-admin-spawn-monster="Contrôle si les monstres, comme les creepers ou les skeletons, peuvent apparaître."
flag-description-admin-teleport-from="Contrôle si les joueurs peuvent se téléporter depuis la protection."
flag-description-admin-teleport-to="Contrôle si les joueur peuvent se téléporter vers la protection."
flag-description-admin-use="Contrôle si les joueurs peuvent utiliser des blocs sans inventaire dans la protection."
flag-description-admin-vehicle-destroy="Contrôle si un vehicule peut être détruit."
flag-description-admin-wither-damage="Contrôle si un Withers peut faire des dégâts."
flag-description-block-break="Contrôle si un bloc peut être cassé.\n&dExemple&f : Pour prévenir n'importe quelle source de casser un bloc de terre, entre\n&a/cf block-break minecraft:dirt false\n&bNote&f : minecraft représente le modid et dirt représente l'ID du bloc.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-block-grow="Contrôle si un bloc peut pousser.\n&dExemple&f : Pour prévenir un cactus de pousser, entre\n&a/cf block-grow minecraft:cactus false\n&bNote&f : minecraft représente le modid et cactus représente l'ID du bloc.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-block-modify="Contrôle si un bloc peut être modifié.\n&dExemple&f : Pour prévenir n'importe quelle source d'allumer un bloc, entre\n&a/cf block-modify minecraft:fire false\n&bNote&f : minecraft représente le modid et fire représente l'ID du bloc.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-block-place="Contrôle si un bloc peut être placé.\n&dExemple&f : Pour prévenir n'importe quelle source de placer un bloc de terre, entre\n&a/cf block-place minecraft:dirt false\n&bNote&f : minecraft représente le modid et dirt représente l'ID du bloc.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-collide-block="Contrôle si une entité peut rentrer en collision avec un bloc.\n&dExemple&f : Pour prévenir une entité d'entrer en collision avec une plaque de pression en pierre, entre\n&a/cf collide-block minecraft:stone_pressure_plate false\n&bNote&f : minecraft représente le modid et stone_pressure_plate représente l'ID du bloc.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-collide-entity="Contrôle si une entité peut rentrer en collision avec une entité.\n&dExample&f : Pour prévenir une entité d'entrer en collision avec un cadre, entre\n&a/cf collide-entity minecraft:item_frame false\n&bNote&f : minecraft représente le modid et item_frame représente l'ID du bloc.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-command-execute="Contrôle si une commande peut être exécutée.\n&dExemple&f : Pour prévenir la commande pixelmon'/shop select' d'être lancée, entre\n&a/cf command-execute pixelmon:shop[select] false\n&bNote&f : &o&6pixelmon&f représente le modid et &o&6shop&f représente la commande de base et &o&6select&f représente l'argument.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-command-execute-pvp="Contrôle si une commande peut être exécutée en état de PvP.\n&dExemple&f : Pour prévenir la commande pixelmon'/shop select' d'être lancée, entre\n&a/cf command-execute pixelmon:shop[select] false\n&bNote&f : &o&6pixelmon&f représente le modid et &o&6shop&f représente la commande de base et &o&6select&f représente l'argument.\nNe pas spécifier de modid va toujours par défaut sur minecraft."
flag-description-enter-claim="Contrôle si une entité peut rentrer dans une protection.\n&dExemple&f : Pour prévenir les joueurs de rentrer dans une protection, entre\n&a/cf enter-claim player false\n&bNote&f : Si tu veux utiliser ça sur un groupe, utilises la commande /cfg."
flag-description-entity-chunk-spawn="Contrôle si une entité sauvegardée peut apparaître pendant le chargement d'un chunk.\n&dExemple&f : Pour prévenir les chevaux d'apparaître pendant le chargement du chunk, entre\n&a/cf entity-chunk-spawn minecraft:horse false\n&bNote&f : Cela va supprimer l'ENSEMBLE des entités sauvegardées quand le chunk va charger. Si le chunk est déjà chargé, l'effet aura lieu après le rechargement. À utiliser avec une extrême prudence."
flag-description-entity-damage="Contrôle si une entité peut prendre des dégâts.\n&dExemple&f : Pour prévenir les animaux de prendre des dégâts, entre\n&a/cf entity-damage minecraft:animal false."
flag-description-entity-riding="Contrôle si une entité peut être chevauchée.\n&dExemple&f : Pour prévenir les chevaux d'être montés, entre\n&a/cf entity-riding minecraft:horse false."
flag-description-entity-spawn="Contrôle si une entité peut apparaître dans le monde.\n&dExemple&f : Pour prévenir les cochons d'apparaîtres, entre\n&a/cf entity-spawn minecraft:pig false\n&bNote&f : Cela n'inclut pas les objets d'entités. Regarde les flags item-spawn"
flag-description-entity-teleport-from="Contrôle si une entité peut se téléporter depuis une protection.\n&dExemple&f : Pour prévenir les joueurs de se téléporter depuis la protection, entre\n&a/cf entity-teleport-from player false\n&bNote&f : Si tu veux utiliser ça pour les groupes, utilises la commande /cfg."
flag-description-entity-teleport-to="Contrôle si une entité peut se téléporter dans une protection.\n&dExemple&f : Pour prévenir les joueur de se téléporter dans une protection, entre\n&a/cf entity-teleport-to player false\n&bNote&f : Si tu veux utiliser ça pour les groupes, utilises la commande /cfg."
flag-description-exit-claim="Contrôle si une entité peut sortir d'une protection.\n&dExample&f : Pour prévenir les joueurs de sortir d'une protection, entre\n&a/cf exit-claim player false\n&bNote&f : Si tu veux utiliser ça pour les groupes, utilises la commande /cfg."
flag-description-explosion-block="Contrôle si une explosion peut endommager les blocs dans la protection.\n&dExemple&f : Pour prévenir une explosion d'affecter n'importe quel bloc, entre\n&a/cf explosion-block any false"
flag-description-explosion-entity="Contrôle si une explosion peut blesser une entité dans une protection.\n&dExample&f : Pour prévenir une explosion d'affecter n'importe quel entité, entre\n&a/cf explosion-entity any false"
flag-description-fire-spread="Contrôle si le feu peut se propager dans la protection.\n&dExample&f : Pour prévenir le feu de se propager, entre\n&a/cf fire-spread any false\n&bNote&f : Cela n'empêche pas le feu initial d'être placé, seulement la propagation."
flag-description-interact-block-primary="Contrôle si un joueur peut faire un clique-gauche(attaque) un bloc.\n&dExemple&f : Pour prévenir un joueur de faire un clique-gauche sur un coffre, entre\n&a/cf interact-block-primary minecraft:chest false"
flag-description-interact-block-secondary="Contrôle si un joueur peut faire un clique-droit sur un bloc.\n&dExemple&f : Pour prévenir un joueur de faire un clique-droit(ouvrir) sur un coffre, entre\n&a/cf interact-block-secondary minecraft:chest false"
flag-description-interact-entity-primary="Contrôle si un joueur peut faire un clique-gauche(attaque) sur une entité.\n&dExemple&f : Pour prévenir un joueur de faire un clique-gauche sur une vache, entre\n&a/cf interact-entity-primary minecraft:cow false"
flag-description-interact-entity-secondary="Contrôle si un joueur peut faire un clique-droit sur une entité.\n&dExemple&f : Pour prévenir un joueur d'intéragir avec un villageois, entre\n&a/cf interact-entity-secondary minecraft:villager false"
flag-description-interact-inventory="Contrôle si un joueur peut faire un clique-droit(ouvrir) un bloc avec un inventaire comme un coffre.\n&dExemple&f : Pour prévenir un joueur d'ouvrir un coffre, entre\n&a/cf interact-inventory minecraft:chest false"
flag-description-interact-inventory-click="Contrôle si un joueur peut cliquer sur un emplacement d'inventaire.\n&dExemple&f : Pour prévenir un joueur de cliquer sur un emplacement d'inventaire qui contient un diamant, entre\n&a/cf interact-inventory-click minecraft:diamond false"
flag-description-interact-item-primary="Contrôle si un joueur peut clique-gauche(attaque) avec un objet.\n&dExemple&f : Pour prévenir un joueur de clique-gauche avec un épée en diamant, entre\n&a/cf interact-item-primary minecraft:diamond_sword false"
flag-description-interact-item-secondary="Contrôle si un joueur peut clique-droit avec un objet.\n&dExample&f : Pour prévenir un joueur de faire un clique droit avec un briquet, entre\n&a/cf interact-item-secondary minecraft:flint_and_steel false"
flag-description-item-drop="Contrôle si un objet peut être lâché dans une protection.\n&dExemple&f : Pour prévenir le diamant d'être lâché par les joueurs dans la protection, entre\n&a/cf item-drop minecraft:flint_and_steel false context[source=player]"
flag-description-item-pickup="Contrôle si un item peut être ramassé dans la protection.\n&dExemple&f : Pour prévenir un diamant d'être ramassé par les joueurs, entre\n&a/cf item-pickup minecraft:diamond false"
flag-description-item-spawn="Contrôle si un objet peut apparaître dans une protection.\n&dExemple&f : Pour prévenir les plumes d'apparaître dans la protection, entre\n&a/cf item-spawn minecraft:feather false"
flag-description-item-use="Contrôle si un objet peut être utilisé.\n&dExemple&f : Pour prévenir les pommes d'être mangées dans la protection, entre\n&a/cf item-use minecraft:apple false"
flag-description-leaf-decay="Contrôle si les feuilles peuvent dépérir dans la protection.\n&dExemple&f : Pour prévenir les feuilles de dépérir dans la protection, entre\n&a/cf leaf-decay any false"
flag-description-liquid-flow="Contrôle si un liquide, comme la lave ou l'eau, d'être autorisé à couler dans la protection.\n&dExemple&f : Pour prévenir n'importe quel type de liquide de couler dans la protection, entre\n&a/cf liquid-flow any false"
flag-description-portal-use="Contrôle si un portail peut être utilisé.\n&dExemple&f : Pour prévenir seulement les joueurs d'utiliser un portail sans affecter les non joueurs, entre\n&a/cf portal-use any false context[source=player]"
flag-description-projectile-impact-block="Contrôle si un projectile peut avoir un impact(collision) avec un bloc.\n&dExemple&f : Pour prévenir les pokéballs de pixelmon d'impacter un bloc, entre\n&a/cf projectile-impact-block any false[source=pixelmon:occupiedpokeball]\n&bNote&f : Cela concerne les choses comme les potions, flèches, lançable, pokéball pixelmon, etc."
flag-description-projectile-impact-entity="Contrôle si un projectile peut avoir un impact(collision) avec une entité.\n&dExample&f : Pour prévenir les joueurs de faire un tir de flèche pouvant impacter une entité, entre\n&a/cf projectile-impact-entity minecraft:arrow false[source=player]\n&bNote&f : Cela concerne les choses comme les potions, flèches, lançable, pokéball pixelmon, etc."
flag-description-user-chest-access="Contrôle si un joueur peut accéder à l'inventaire d'un coffre."
flag-description-user-chorus-fruit-teleport="Contrôle si un joueur peut se téléporter en utilisant un fruit chorus."
flag-description-user-crop-growth="Contrôle si les poussent peuvent grandir."
flag-description-user-damage-animals="Contrôle si les animaux peuvent prendre des dégâts."
flag-description-user-enderman-grief="Contrôle si les enderman peuvent grief."
flag-description-user-enter-player="Contrôle si un joueur peut entrer dans une protection."
flag-description-user-explosion-creeper="Contrôle si un creeper peut exploser."
flag-description-user-explosion-tnt="Contrôle si une TnT peut exploser."
flag-description-user-fire-damage="Contrôle si le feu fait des dégâts."
flag-description-user-fire-spread="Contrôle si le feu peut se répandre."
flag-description-user-grass-growth="Contrôle si l'herbe peut pousser."
flag-description-user-ice-form="Contrôle si la glace peut se former."
flag-description-user-ice-melt="Contrôle si la glace peut fondre."
flag-description-user-lava-flow="Contrôle si la lave peut couler."
flag-description-user-leaf-decay="Contrôle si les feuilles peuvent dépérir."
flag-description-user-lighter="Contrôle si un joueur peut utiliser un briquet."
flag-description-user-lightning="Contrôle si un éclair peut causer des dégâts."
flag-description-user-mushroom-growth="Contrôle si les champignons peuvent grandir."
flag-description-user-mycelium-spread="Contrôle si le mycelium peut s'étendre."
flag-description-user-pvp="Contrôle si le combat Joueur contre Joueur est autorisé."
flag-description-user-ride="Contrôle si les véhicules (incluant les animaux) peuvent être montés."
flag-description-user-sleep="Contrôle si les joueurs peuvent dormir dans les lits."
flag-description-user-snow-fall="Contrôle si la neige peut tomber."
flag-description-user-snow-melt="Contrôle si la neige peut fondre."
flag-description-user-snowman-trail="Contrôle si un bonhomme de neige peut laisser de la neige derrière lui."
flag-description-user-soil-dry="Contrôle si la terre peut sécher."
flag-description-user-vehicle-place="Contrôle si un véhicule (bateau, minecraft) peut être placé."
flag-description-user-vine-growth="Contrôle si les vignes (et les algues) peuvent grandir."
flag-description-user-water-flow="Contrôle si l'eau peut couler."
flag-invalid-context="&cContexte entré '&f{context}&c' invalide pour le flag de base &f{flag}&c."
flag-invalid-meta="&cCible meta entrée '&f{value}&c' invalide pour le flag de base &f{flag}&c."
flag-invalid-target="&cCible '&f{target}&c' entré invalide pour le flag de base &f{flag}&c."
flag-not-found="&cFlag {flag}&c introuvable."
flag-not-set="{flag}&f est actuellement non définis.\nLa valeur par défaut {value}&f de la protection sera active jusqu'à définition."
flag-overridden="&cÉchec de la définition du flag de protection. Le flag &f{flag}&c a été outrepassé par un admin."
flag-override-not-supported="&cLe type de protection {type}&c ne supporte pas les flags outrepassés."
flag-reset-success="&aFlags remit par défaut dans la protection avec succès."
flag-set-permission-target="&aDéfinis {type}&a permission &b{permission}&a avec contexte &7{contexts}&a à {value}&a sur &6{target}&a."
flag-ui-click-allow="Clique ici pour autoriser ce flag."
flag-ui-click-deny="Clique ici pour interdire ce flag."
flag-ui-click-remove="Clique ici pour supprimer ce flag."
flag-ui-click-toggle="Clique ici pour basculer la valeur de {flag}&f."
flag-ui-info-claim="La protection est vérifiée avant les valeurs par défaut. Autorise les propriétaires de protection de spécifier le paramètre de flag dans leurs protections seulement."
flag-ui-info-default="Default est le dernier à être vérifié. Protection et Outrepassant prenent la priorité sur cela."
flag-ui-info-inherit="Héritage est un flag forcé par la protection parente et ne peut être changé."
flag-ui-info-override="Outrepassant est la plus haute priorité et est vérifié avant les valeurs Default et Protection. Permet aux admins d'outrepasser l'ensemble des protections Basiques et Admins."
flag-ui-inherit-parent="Ce flag hérite depuis la protection parente {name}&f et ne peut &npas&f être changé."
flag-ui-override-no-permission="Ce flag a été outrepassé par un administrateur et ne peut &n&cPAS&f être changé."
flag-ui-override-permission="{flag}&f est actuellement &coutrepassé&f par un administrateur.\nClique ici pour supprimer ce flag."
flag-ui-return-flags="Retourne au flag"
label-accessors=Accédant
label-area=Zone
label-blocks=Blocs
label-builders=Constructeurs
label-buy=Achat
label-children=Enfant
label-confirm=Confirme
label-containers=Conteneur
label-context=Contexte
label-created=Créé
label-displaying=Affiche
label-expired=Expiré
label-farewell="Message de sortie"
label-flag=Flag
label-greeting="Message d'accueil"
label-group=Groupe
label-inherit=Héritage
label-location=Location
label-managers=Manageurs
label-name=Nom
label-no=Non
label-output=Sortie
label-owner=Propriétaire
label-permission=Permission
label-player=Joueur
label-price=Prix
label-raid=Raid
label-resizable=Redimensionnable
label-result=Résultat
label-schematic=Patron
label-source=Source
label-spawn="Point d'apparition"
label-target=Cible
label-trust=Confiance
label-type=Type
label-unknown=Inconnu
label-user=Utilisateur
label-world=Monde
label-yes=Oui
mode-admin="&aMode protection Administratif activé. Chaque protection créée sera gratuite et éditable par les autres administrateur."
mode-basic="&aMode de création protection basique activé."
mode-nature="&aPrêt pour restaurer la protection ! Clique-droit sur un bloc pour restaurer, et utilises &f/modebasic&c pour arrêter."
mode-subdivision="&aMode Sous-divions. Utilises la pelle pour créer une sous-division dans ta protection existante. Utilises &f/modebasic&a pour sortir."
mode-town="&aMode création de Village activé."
option-description-abandon-delay="&aLe nombre de jour avant qu'une nouvelle protection créée puisse être abandonnée."
option-description-abandon-return-ratio="&aLa portion de bloc de protection basique rendu au joueur quand une protection est abandonnée."
option-description-blocks-accrued-per-hour="&aBloc gagné par heure.\n&dNote&f: Regarde /playerinfo pour plus d'information."
option-description-chest-expiration="&aNombre de jour d'inactivité avant qune protection de coffre automatique expire.\n&dNote&f: Lors de l'expiration, une protection peut soit être restaurée à son état d'origine ou supprimée. Cela dépend de la configuration du serveur. Contact un administrateur pour plus d'information."
option-description-create-limit="&aNombre maximum de protection par joueur.\n&dNote&f: Mettre une valeur en dessous de 0 donnera illimité."
option-description-create-mode="&aLe mode de création de la protection (Zone = 2D, Volume = 3D).\n&dNote&f: &bZone&a affecte seulement les axes x et y.\n&bVolume&a affecte les axes x, y, et z."
option-description-economy-block-cost="&aLe montant économique chargé par bloc de protection.\n&dNote&f: La formule de calcul du prix est montant * nombre total de blocs de protection."
option-description-economy-block-sell-return="&aLe ratio de retour pour vendre des blocs de protection.\n&dNote&f: La formule de calcul est ratio de retour * nombre total de blocs de protection."
option-description-expiration="&aNombre de jour d'inactivité avant que la protection expire.\n&dNote&f: Lors de l'expiration, une protection peut soit être restaurée à son état d'origine ou supprimée. Cela dépend de la configuration du serveur. Contact un administrateur pour plus d'information."
option-description-initial-blocks="&aLe nombre de blocs de protection qu'a initialement un joueur, par défaut."
option-description-max-accrued-blocks="&aLe limite de bloc accrues (dans le temps).\n&dNote&f: Cela ne limite pas les blocs achetés ou donnés par un admin."
option-description-max-level="&aLe niveau maximum, sur l'axe y, une protection peut être créée."
option-description-max-size-x="&aLa taille maximum de blocs l'axe x peut être."
option-description-max-size-y="&aLa taille maximum de blocs l'axe y peut être."
option-description-max-size-z="&aLa taille maximum de blocs l'axe z peut être."
option-description-min-level="&aLe niveau minimum, sur l'axe y, une protection peut être créée."
option-description-min-size-x="&aLa taille minimum de blocs l'axe x peut être."
option-description-min-size-y="&aLa taille minimum de blocs l'axe y peut être."
option-description-min-size-z="&aLa taille minimum de blocs l'axe z peut être."
option-description-player-command="&aUtilisé pour exécuté une commande avec un contexte spécifique."
option-description-player-deny-flight="&aUtilisé pour déterminer si un joueur est incapable de fly dans une protection.\n&dNote&f: Cela ne donne pas l'abilité de fly au joueur, ça supprime juste l'abilité si elle a été donnée. Cela donne la meilleurs compatibilité avec les plugins."
option-description-player-deny-godmode="&aUtilisé pour déterminer si un joueur est incapable de godmode dans une protection.\n&dNote&f: Cela ne donne pas l'abilité de godmode au joueur, ça supprime juste l'abilité si elle a été donnée. Cela donne la meilleurs compatibilité avec les plugins."
option-description-player-deny-hunger="&aUtilisé pour refusé la famine dans un protection.\n&dNote&f: Cela ne donne pas l'abilité de gagner de la famine au joueur, ça supprime l'abilité de cause de la famine si défini. Cela donne la meilleurs compatibilité avec les plugins."
option-description-player-gamemode="&aUtilisé pour déterminer le gamemode d'un joueur dans un protection."
option-description-player-health-regen="&aUtilisé pour définir le nombre de vie régénéré pour un joueur dans la protection.\n&dNote&f: Si le joueur a la vie au maximum, cela n'aura pas d'effet. \n&dNote&f: Une valeur de&6-1&f désactive cette option."
option-description-player-keep-inventory="&aUtilisé pour déterminer si un joueur à le droit de garder son inventaire après la mort dans une protection."
option-description-player-keep-level="&aUtilisé pour détermine si un joueur à le droit de garder son niveau après la mort dans une protection."
option-description-player-walk-speed="&aUtilisé pour définir la vitesse de marche dans une protection.\n&dNote&f: Une valeur de &6-1&f désactive cette option."
option-description-player-weather="&aUtilisé pour définir la météo d'un joueur dans une protection."
option-description-radius-inspect="&aLe rayon de recherche pour les protections à proximité lors de l'inspection."
option-description-radius-list="&aLe rayon en blocs utilisés pour lister les protections à proximité."
option-description-tax-expiration="&aNombre de jour après ne pas avoir payé les taxes avant que la protection soi mise sous demeure.\n&dNote&f: Une mise sous demeure signifie que tu n'auras plus accès à la construction ou l'intération avec la protection jusqu'au paiement des taxes."
option-description-tax-expiration-days-keep="&aNombre de jour pour garder une protection basique mise sous demeure et avant expiration.\n&dNote&f: Lors de l'expiration, une protection peut soit être restaurée à son état d'origine ou supprimée. Cela dépend de la configuration du serveur. Contact un administrateur pour plus d'information."
option-description-tax-rate="&aLe taux de taxe de la protection.\n&dNote&f: Le taux de taxe est calculé par le nombre de blocs de protection dans les protections basiques."
option-invalid-context="&cContext '&f{context}&c' invalide entré pour l'option &f{option}&c."
option-invalid-target="&cCible '&f{target}&c' invalide entrée pour l'option &f{option}&c."
option-invalid-value="&cValeur '&6{value}&c' invalide entrée pour l'option &f{option}&c.\n&dNote&f: Cette option accepte uniquement les valeurs &f{type}&c."
option-not-found="&cL'option {option}&c n'a pas été trouvée."
option-not-set="{option}&f est actuellement non définit.\n&dNote&f: La valeur par défaut {value}&f de l'option sera active jusqu'à définition."
option-override-not-supported="&cProtection de type {type}&c ne supporte pas les options outrepassantes."
option-player-deny-flight="&cTu n'as pas accès au fly dans cette protection et a été téléporté dans une zone sécurisé au sol."
option-reset-success="&aOption de la protection remises par défaut avec succès."
option-set-target="&aDéfinis {type}&a de l'option &b{option}&a à {value}&a avec le contexte &7{contexts}&a sur la cible &6{target}&a."
option-ui-click-toggle="Clique ici pour changer la valeur de {option}&f."
option-ui-inherit-parent="Cette option est hérité depuis la protection parente {name}&f et ne peut &nPAS&f être changée."
option-ui-overridden="&cÉchec de la définition de l'option. L'option &f{option}&c a été outrepassée par un admin."
option-ui-override-no-permission="Cette option a été outrepassée par un administration et ne peut &n&cPAS&f être changée."
owner-admin="un administrateur"
permission-access="&cTu n'as pas la permission de &6{player}&c pour accéder à ça."
permission-assign-without-having="&cTu n'as pas l'autorisation d'assigner une permission que tu ne possèdes pas."
permission-ban-block="&cLe bloc {id}&c a été &l&nBANNIT&c et ne peut être utilisé."
permission-ban-entity="&cL'entité {id}&c a été &l&nBANNIT&c et ne peut être utilisé."
permission-ban-item="&cL'objet {id}&c a été &l&nBANNIT&c et ne peut être utilisé."
permission-build="&cTu n'as pas la permission de &6{player}&c pour construire."
permission-build-near-claim="&cTu n'as pas la permission de &6{player}&c de construire à proximité de protection."
permission-claim-create="&cTu n'as pas la permission de protéger une zone."
permission-claim-delete="&cTu n'as pas la permission de supprimer les protections {type}&c."
permission-claim-enter="&cTu n'as pas la permission de rentrer dans cette protection."
permission-claim-exit="&cTu n'as pas la permission de sortir de cette protection."
permission-claim-ignore="&cTu n'as pas la permission pour ignorer les protections {type}&c."
permission-claim-list="&cTu n'as pas la permission pour récupérer les informations concernants les protections d'autres joueurs."
permission-claim-manage="&cTu n'as pas la permission pour gérer les protections {type}&c."
permission-claim-reset-flags="&cTu n'as pas la permission de remettre par défaut les flags dabs les protections {type}&c."
permission-claim-reset-flags-self="&cTu n'as pas la permission pour remettre par défaut les flags dans tes protections."
permission-claim-resize="&cTu n'as pas la permission pour redimensionner cette protection."
permission-claim-sale="&cTu n'as pas la permission pour vendre cette protection."
permission-claim-transfer-admin="&cTu n'as pas la permission de transférer les protections admin."
permission-clear="&cNettoyage des permissions de cette protection. Pour le définir pour l'ENSEMBLE des protections, sort de la zone des protections."
permission-clear-all="&cSeulement le propriétaire de la protection peut nettoyer l'ensemble des permissions."
permission-command-trust="&cTu n'as pas la permission pour utiliser ce type de confiance."
permission-cuboid="&cTu n'as pas la permission pour créer/redimensionner les protections basiques en mode 3D."
permission-edit-claim="&cTu n'as pas la permission pour éditer cette protection."
permission-fire-spread="&cTu n'as pas la permission pour propager le feu dans cette protection."
permission-flag-defaults="&cTu n'as pas la permission pour gérer les flags par défaut."
permission-flag-overrides="&cTu n'as pas la permission pour gérer les flags outrepassant."
permission-flag-use="&cTu n'as pas la permission pour utiliser ce flag."
permission-flow-liquid="&cTu n'as pas la permission pour faire couler le liquide dans cette protection."
permission-global-option="&cTu n'as pas la permission pour gérer les options globals."
permission-grant="&cTu ne peut pas te donner une permission que tu ne possèdes pas toi-même."
permission-group-option="&cTu n'as pas la permission pour assigner une option à un groupe."
permission-interact-block="&cTu n'as pas la permission de &6{player}&c pour intéragir avec le bloc &d{block}&c."
permission-interact-entity="&cTu n'as pas la permission de &6{player}&c pour intéragir avec l'entité &d{entity}&c."
permission-interact-item="&cTu n'as pas la permission de &6{player}& pour intéragir avec l'objet &d{item}&c."
permission-interact-item-block="&cTu n'as pas la permission d'utiliser l'objet &d{item}&c sur &b{block}&c."
permission-interact-item-entity="&cTu n'as pas la permission d'utiliser l'objet &d{item}&c sur &b{entity}&c."
permission-inventory-open="&cTu n'as pas la permission de &6{player}&c d'ouvrir &d{block}&c."
permission-item-drop="&cTu n'as pas la permission de &6{player}&c de jeter l'objet &d{item}&c dans cette protection."
permission-item-use="&cTu ne peut pas utiliser l'objet &d{item}&c dans cette protection."
permission-option-defaults="&cTu n'as pas la permission pour gérer les options par défaut."
permission-option-overrides="&cTu n'as pas la permission pour gérer les options outrepassant."
permission-option-use="&cTu n'as pas la permission d'utiliser cette option."
permission-override-deny="&cL'action que tu essayes d'effectuer a été refusée par un flag outrepassant administrateur."
permission-player-admin-flags="&cTu n'as pas la permission de changer un flag sur un joueur admin."
permission-player-option="&cTu n'as pas la permission pour assigner une option sur un joueur."
permission-player-view-others="&cTu n'as pas la permission pour voir les autres joueurs."
permission-portal-enter="&cTu ne peut pas utiliser le portail car tu n'as pas la permission de &6{player}&c d'entrer dans la protection de destination."
permission-portal-exit="&cTu ne peut pas utiliser le portail car tu n'as pas la permission de &6{player}&c pour sortir de la protection de destination."
permission-protected-portal="&cTu n'as pas la permission d'utiliser les portails dans les protections appartenant à &6{player}&c."
permission-trust="&cTu n'as pas la permission de &6{player}&c pour gérer les permissions ici."
permission-visual-claims-nearby="&cTu n'as pas la permission pour voir les protections à proximité."
player-accrued-blocks-exceeded="&cLe joueur &6{player}&c a un total de &6{total}&c et vas dépasser le maximum autorisé de bloc de protection gagné s'il est donné un nombre additionnel de &6{amount}&c bloc.\nSoit descend le nombre ou demande un admin de donner à l'utilisateur un outrepassement."
player-remaining-blocks-2d="&aTu peut protéger jusqu'à &6{block-amount}&a blocs supplémentaires."
player-remaining-blocks-3d="&aTu peut protéger jusqu'à &6{chunk-amount}&a chunks supplémentaire. &f({block-amount})"
playerinfo-ui-abandon-return-ratio="&eAbandonné, Ratio de retour&f : &a{ratio}"
playerinfo-ui-block-accrued="&eBloc gagné&f : &a{amount}&7(&d{block_amount}&f par heure&7)"
playerinfo-ui-block-bonus="&eBloc bonus&f : &a{amount}"
playerinfo-ui-block-initial="&eBloc Initial&f : &a{amount}"
playerinfo-ui-block-max-accrued="&eMaximum de bloc gagné&f : &a{amount}"
playerinfo-ui-block-remaining="&eBlocs restant&f : &a{amount}"
playerinfo-ui-block-total="&eTotal de Blocs&f : &a{amount}"
playerinfo-ui-chunk-total="&eTotal Chunk Protectable&f : %a{amount}"
playerinfo-ui-claim-level="&eMin/Niveau de protection max&f : &a{level}"
playerinfo-ui-claim-size-limit="&eLimite de taille de protection&f : &a{limit}"
playerinfo-ui-claim-total="&eProtections Total&f : &a{amount}"
playerinfo-ui-economy-block-available-purchase="&eBlocs restant pour l'achat&f : &a{amount}"
playerinfo-ui-economy-block-cost="&ePrix de bloc de protection&f : &a{amount} par bloc"
playerinfo-ui-economy-block-sell-return="&ePrix de retour de bloc de proteciton vendu&f : &a{amount} par bloc"
playerinfo-ui-last-active="&eDernière Activité&f : {date}"
playerinfo-ui-tax-current-rate="&eTaux de taxe actuel de la protection&f : &a{rate}"
playerinfo-ui-tax-global-claim-rate="&eTaux de taxe de la protection Global&f : &a{rate}"
playerinfo-ui-tax-global-town-rate="&eTaux de taxe de Village Global&f : &a{rate}"
playerinfo-ui-tax-total="&eTaxe Total&f : &a{amount}"
playerinfo-ui-title="&bInfo joueur"
playerinfo-ui-uuid="&eUUID&f : &7{id}"
playerinfo-ui-world="&eMonde&f : &7{name}"
plugin-command-not-found="&cImpossible de localiser la commande '&a{command}&c' pour le plug-in &b{id}&a."
plugin-event-cancel="&cUn plug-in a annulé cette action."
plugin-not-found="&cImpossible de localiser le plug-in avec l'id &b{id}&c."
plugin-reload="&aGriefDefender a été rechargé."
registry-block-not-found="&cLe bloc {id} ne peut pas être trouvé dans le registre."
registry-entity-not-found="&cL'entité {id} ne peut pas être trouvé dans le registre."
registry-item-not-found="&cL'objet {id} ne peut pas être trouvé dans le registre."
resize-overlap="&cImpossible de redimensionner ici car cela chauvecherait une protection à proximité."
resize-overlap-subdivision="&cTu ne peut pas créer une sous-division ici car cela chevaucherait une autre sous-division. Considère &f/abandon&c pour la supprimer ou utilise la pelle sur un coin pour le redimensionner."
resize-same-location="&cTu dois sélectionner un bloc à un endroit différent pour redimensionner une protection."
resize-start="&aRedimensionnement de la protection. Utilise la pelle à nouveau au nouvel endroit pour ce coin."
resize-success-2d="&aProtection redimensionnée. Tu as encore &6{amount} &ablocs restant."
resize-success-3d="&aProtection redimensionnée. Tu as encore &6{amount} &achunks restant. &f({block-amount})"
result-type-change-deny="&cTu ne peut pas changer une protection en {type}."
result-type-change-not-admin="&cTu n'as pas la permission d'un administrateur pour changer le type en {type}&c."
result-type-child-same="Protection {type}&c ne peuvent pas avoir directement des protections enfant de type {type}&c."
result-type-create-deny="{type}&c ne peut pas être créé dans {target_type}."
result-type-no-children="{type}&c ne peut pas contenir de protection enfant."
result-type-only-subdivision="{type}&c peut seulement contenir des sous-division."
result-type-requires-owner="&cImpossible de convertir la protection {type} en {target_type}. Le propriétaire est requis."
schematic-abandon-all-restore-warning="&6Es-tu sûr de vouloir &nabandonner&6 &cTOUTES&6 tes protections ? &cL'ENSEMBLE DES DONNÉES SERA PERDUES&f !&6 Tes protections seront restorées à leur état d'origine lors de la confirmation."
schematic-abandon-restore-warning="&6Es-tu sûr de vouloir &nabandonner&6 cette protection ? &cL'ENSEMBLE DES DONNÉES SERA PERDUES&f !&6 Cette protection sera restorée à son état d'origine lors de la confirmation."
schematic-create="&aCréation d'un sauvegarde du patron..."
schematic-create-complete="&asauvegarde du patron complète."
schematic-create-fail="&cLe patron n'a pas pu être créé."
schematic-deleted="&aLe patron {name} a été supprimé."
schematic-none="&aIl n'y a pas de patron de sauvegarde pour cette protection."
schematic-restore-click="&aCLique ici pour restaurer le patron de la protection.\nNom: {name}\nCréé: {date}"
schematic-restore-confirmation="&6Es-tu sûr de vouloir restaurer ? Clique confirme va restaurer l'&ENSEMBLE&6 des données de la protection avec le patron. Utilisation avec prudence !"
schematic-restore-confirmed="&aTu as restauré la protection depuis le patron sauvegardé &b{name}&a avec succès."
spawn-not-set="&cPas de point d'apparition de la protection définis."
spawn-set-success="&aDéfinition du point d'apparition à &b{location}&a avec succès."
spawn-teleport="&aTéléportation au point d'apparition de la protection à &b{location}&a."
tax-claim-expired="&cCette protection a été mise en demeure à cause de taxe impayés. Le montant actuel du est '&a{amount}&c'.\nIl reste '&a{days}&c' jours pour effectuer le dépôt de paiement à la banque de protection pour lever la mise en demeure.\nL'échec de payer cette dette aura pour conséquence la suppression de la protection.\nNote: Pour déposer des fonds dans la banque de protection, utilises &f/claimbank&c deposit <nombre>."
tax-claim-paid-balance="&aLa dette de taxe de '&6{amount}&a' a été payée. La mise en demeure a été levée et la protection est disponible pour usage."
tax-claim-paid-partial="&aLa dette de taxe de '&6{amount}&a' a été partiellement payée. Pour lever la mise en demeure de la protection, le reste de la taxe due de '&6{balance}&a' doit être payé."
tax-info="&aTon prélèvement de taxe d'un montant de &6{amount}&a va être prélevé depuis ton compte le &b{date}&a."
tax-past-due="&cTu as actuellement un défaut de paiement passé de taxe de &a{balance}&c qui nécessite d'être payé pour le &b{date}&c. L'échec de paiement de cette taxe entrainera la perte de la propriété."
title-accessor=ACCÉDANT
title-all=TOUS
title-builder=CONSTRUTEUR
title-claim=PROTECTION
title-container=CONTENEUR
title-default=DEFAUT
title-inherit=HÉRITAGE
title-manager=GÉRANT
title-override=OUTREPASSANT
title-own=POSSÈDE
tool-not-equipped="&cTu n'as pas {tool}&c équipé."
town-chat-disabled="&aChat de Village désactivé."
town-chat-enabled="&aChat de Village activé."
town-create-not-enough-funds="&cTy n'as pas suffisamment de fond pour créer un village pour &a{amount}&c. Tu as actuellement un solde de &a{balance}&c et a besoin de &a{amount-needed}&c supplémentaire pour la création."
town-name="&aDéfinis le nom du village à {name}&a."
town-not-found="&cVillage non trouvé."
town-not-in="&cTu n'es pas dans un Village."
town-owner="&cCela appartient au village."
town-tag="&aDéfinis le blason du village à {tag}."
town-tag-clear="&aLe blason du village a été supprimé."
town-tax-no-claims="&cTu dois avoir une propriété dans ce village pour être taxé."
trust-already-has="&c{target} a déjà la permission {type}&c."
trust-click-show-list="Clique ici pour afficher la liste de l'ensemble des players et groupes ayant la confiance dans cette protection."
trust-grant="&aDonne à &6{target}&a la permission de {type}&a dans la protection actuelle."
trust-individual-all-claims="&aDonne &6{player}'s&a total confiance dans l'ENSEMBLE de tes protections. Pour supprimer les permissions dans l'ENSEMBLE de tes protections, utilises &f/untrustall&a."
trust-invalid="&cType de confiance invalide entré.\nLes types autorisés sont : accessor, builder, container, et manager."
trust-list-header="Permission explicite ici :"
trust-no-claims="&cTu n'as pas de protection pour donner Confiance."
trust-plugin-cancel="&cImpossible d'avoir Confiance en {target}&c. Un plug-in l'a refusé."
trust-self="&cTu ne peut pas te faire Confiance à toi-même."
tutorial-claim-basic="&eClique pour l'aide sur la protection: &ahttp://bit.ly/mcgpuser"
ui-click-confirm="Clique pour confirmer."
ui-click-filter-type="Clique ici pour filtrer par {type}&f."
untrust-individual-all-claims="&aRévoque &6{target}&a accès à l'ENSEMBLE de tes protections. Pour définir la permission pour une seule protection, va dedans et utilises &f/untrust&a."
untrust-individual-single-claim="&aRévoque &6{target}&a accès à cette protection. Pour définir la permission pour l'ENSEMBLE de tes protections, utilises &f/untrustall&a."
untrust-no-claims="&cTu n'as pas de protection où enlever la confiance."
untrust-owner="&6{owner}&a est le propriétaire et ne pas pas perdre la confiance."
untrust-self="&cTu ne peut pas te retirer la confiance toi-même."
}
}