mirror of
https://github.com/md5sha256/AreaShop.git
synced 2026-11-07 01:42:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6ae122b86 | ||
|
|
2562075b90 | ||
|
|
9fc5d8a314 | ||
|
|
e96b179c48 | ||
|
|
49bed6f655 | ||
|
|
ffc5b03a75 | ||
|
|
69fea8ab7e | ||
|
|
29fc2c4205 | ||
|
|
2dd6d4ec4a | ||
|
|
789073f6d6 | ||
|
|
d211bf2f43 | ||
|
|
a6659cb14d | ||
|
|
880218cca0 | ||
|
|
3426381273 | ||
|
|
80a73fecea | ||
|
|
590d5a4988 | ||
|
|
dda4a090fb | ||
|
|
3a415513dd | ||
|
|
8ec6a43dc8 | ||
|
|
2d81614f5f | ||
|
|
8fb035015d | ||
|
|
77088a3a72 | ||
|
|
2c2f40b0ea | ||
|
|
07406c3987 | ||
|
|
82a90b350d | ||
|
|
151fbe8000 | ||
|
|
f2a4dd71e3 | ||
|
|
d4cc70f954 | ||
|
|
8001047480 | ||
|
|
af1486a6fa | ||
|
|
36a2d054d6 | ||
|
|
7429b0a206 | ||
|
|
557d11dfb4 | ||
|
|
b9547e2c67 | ||
|
|
221785ae55 | ||
|
|
0d04676bce | ||
|
|
c8cd68c17b | ||
|
|
539887449c | ||
|
|
4cda8a9292 | ||
|
|
fe131dc157 | ||
|
|
41ced9ee6c | ||
|
|
03de0ff252 | ||
|
|
b057271394 | ||
|
|
d7cdff0b22 | ||
|
|
1035b6b41b | ||
|
|
e0bad7397c | ||
|
|
b7124e8cdd | ||
|
|
f0952c32c9 | ||
|
|
d3dfa86a65 | ||
|
|
8f73b8af3c | ||
|
|
51b24c74b4 | ||
|
|
9beb1eb61b | ||
|
|
de5fdafca0 | ||
|
|
0aea914d20 | ||
|
|
b4efe7d5bf | ||
|
|
ec7983e126 | ||
|
|
e45c353030 | ||
|
|
44b1cb0fc8 | ||
|
|
c7299fa56c | ||
|
|
12bf467714 | ||
|
|
5b327db316 | ||
|
|
b4f33589a1 | ||
|
|
530c74ccd2 | ||
|
|
fa4857cbce | ||
|
|
93fd4e96cb | ||
|
|
a6863ae782 | ||
|
|
e5e2c4ca08 | ||
|
|
b0341e2a3e | ||
|
|
c8e1ebb068 | ||
|
|
39c8eb5f73 | ||
|
|
2483cf1614 |
No files matched your search
@@ -1,6 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report a problem in the plugin
|
||||
title: ''
|
||||
labels: 'NEW, Type: Bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea
|
||||
title: ''
|
||||
labels: 'NEW, Type: Feature'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
name: Support question
|
||||
about: Ask help with the setup or usage of the plugin
|
||||
title: ''
|
||||
labels: 'NEW, Type: Support'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
name : "build"
|
||||
|
||||
on : [ "pull_request", "push" ]
|
||||
|
||||
jobs :
|
||||
build :
|
||||
strategy :
|
||||
matrix :
|
||||
java : [ 16 ]
|
||||
# java: ["1.8", "11"]
|
||||
os : [ "ubuntu-18.04" ]
|
||||
runs-on : "${{ matrix.os }}"
|
||||
steps :
|
||||
- name : "Checkout Repository"
|
||||
uses : "actions/checkout@v2.3.4"
|
||||
|
||||
- name : "Checkout submodules"
|
||||
uses : "srt32/git-actions@v0.0.3"
|
||||
with :
|
||||
args : "git submodule update --init --recursive"
|
||||
|
||||
- name : "Restore Gradle cache"
|
||||
uses : "actions/cache@v2"
|
||||
with :
|
||||
path : "~/.gradle/caches"
|
||||
key : "${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}"
|
||||
restore-keys : |
|
||||
${{ runner.os }}-gradle-
|
||||
- name : "Setup JDK ${{ matrix.java }}"
|
||||
uses : "actions/setup-java@v1.4.3"
|
||||
with :
|
||||
java-version : "${{ matrix.java }}"
|
||||
|
||||
- name : "Grant execute permission for gradlew"
|
||||
run : "chmod +x gradlew"
|
||||
|
||||
- name : "Build with Gradle"
|
||||
run : "./gradlew clean build"
|
||||
+23
-4
@@ -1,5 +1,5 @@
|
||||
# Maven stuff
|
||||
/target
|
||||
### Maven ###
|
||||
target
|
||||
|
||||
.project
|
||||
.metadata
|
||||
@@ -14,12 +14,31 @@ local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
### Locally stored "Eclipse launch configurations" ###
|
||||
*.launch
|
||||
|
||||
# IntelliJ IDEA
|
||||
### IntelliJ IDEA ###
|
||||
*.iml
|
||||
.idea
|
||||
dependency-reduced-pom.xml
|
||||
|
||||
desktop.ini
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
|
||||
### Gradle Patch ###
|
||||
**/build/
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -0,0 +1,60 @@
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
}
|
||||
|
||||
description = 'AreaShop'
|
||||
version = '2.6.3'
|
||||
|
||||
dependencies {
|
||||
// Spigot api
|
||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||
|
||||
// Libs
|
||||
implementation 'com.github.NLthijs48:InteractiveMessenger:e7749258ca'
|
||||
implementation 'co.aikar:taskchain-bukkit:3.7.2'
|
||||
implementation 'io.papermc:paperlib:1.0.6'
|
||||
|
||||
// Hooks
|
||||
implementation project(':areashop-interface')
|
||||
implementation project(':areashop-worldguard-7')
|
||||
implementation project(':areashop-worldedit-7')
|
||||
implementation project(':areashop-fawe-1-16')
|
||||
implementation project(':areashop-fawe-1-17')
|
||||
implementation project(':areashop-nms-1-16-5')
|
||||
implementation project(':areashop-nms-1-17')
|
||||
|
||||
// Runtime plugins
|
||||
compileOnly 'com.sk89q.worldedit:worldedit-bukkit:7.2.5'
|
||||
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.5'
|
||||
compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
||||
from (sourceSets.main.resources) {
|
||||
filter ReplaceTokens, tokens: [version: project.version]
|
||||
duplicatesStrategy(DuplicatesStrategy.INCLUDE)
|
||||
}
|
||||
}
|
||||
|
||||
assemble {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName.set('AreaShop')
|
||||
classifier('original')
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveBaseName.set('AreaShop')
|
||||
String relocationBase = 'me.wiefferink.areashop.shaded'
|
||||
classifier('')
|
||||
relocate('co.aikar.taskchain', "${relocationBase}.taskchain")
|
||||
relocate('me.wiefferink.interactivemessenger', "${relocationBase}.interactivemessenger")
|
||||
relocate('org.bstats', "${relocationBase}.bstats")
|
||||
relocate('io.papermc', "${relocationBase}.papermc")
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop</name>
|
||||
<version>2.5.0</version> <!-- Main plugin version -->
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- Bukkit, AreaShop aims to support 1.7.9+, but this is the lowest Bukkit version available from the Spigot repo, Bukkit repository is gone -->
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- InteractiveMessenger library -->
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>interactivemessenger</artifactId>
|
||||
<version>1.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- BukkitDo library -->
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>bukkitdo</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-5</artifactId>
|
||||
<version>WorldGuard-5</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-6</artifactId>
|
||||
<version>WorldGuard-6</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-6_1_3</artifactId>
|
||||
<version>WorldGuard-6_1_3</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-7</artifactId>
|
||||
<version>WorldGuard-7</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldedit-5</artifactId>
|
||||
<version>WorldEdit-5</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldedit-6</artifactId>
|
||||
<version>WorldEdit-6</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldedit-7</artifactId>
|
||||
<version>WorldEdit-7</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldedit</artifactId>
|
||||
<scope>system</scope>
|
||||
<version>any</version>
|
||||
<systemPath>${project.basedir}/../dependencies/worldedit-bukkit-7.0.0-beta-01.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<scope>system</scope>
|
||||
<version>any</version>
|
||||
<systemPath>${project.basedir}/../dependencies/worldguard-legacy-7.0.0-beta01.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.milkbowl.vault</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<!-- Copy the jar file to a test server, activate by using -DcopyResult="/path/to/test/server" -->
|
||||
<profile>
|
||||
<id>test-locally</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>copyResult</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<configuration>
|
||||
<target>
|
||||
<copy file="./target/${project.build.finalName}.jar"
|
||||
tofile="${copyResult}\${project.build.finalName}.jar"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Package the source files in a jar, activate by using -Dsources -->
|
||||
<profile>
|
||||
<id>package-sources</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>sources</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Produce javadoc files, activate by using -Djavadoc -->
|
||||
<profile>
|
||||
<id>generate-javadoc</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>javadoc</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<excludePackageNames>me.wiefferink.areashop.lib</excludePackageNames>
|
||||
<destDir>${javadoc}</destDir>
|
||||
<links>
|
||||
<link>https://hub.spigotmc.org/javadocs/bukkit/</link>
|
||||
<link>http://docs.sk89q.com/worldedit/apidocs/</link>
|
||||
<link>http://docs.sk89q.com/worldguard/apidocs/</link>
|
||||
</links>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<directory>target</directory>
|
||||
<finalName>AreaShop</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>plugin.yml</include>
|
||||
<include>config.yml</include>
|
||||
<include>hiddenConfig.yml</include>
|
||||
<include>default.yml</include>
|
||||
<include>README.md</include>
|
||||
<include>lang/*.yml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<!-- Relocate messaging framework -->
|
||||
<relocation>
|
||||
<pattern>me.wiefferink.interactivemessenger</pattern>
|
||||
<shadedPattern>me.wiefferink.areashop.shaded.interactivemessenger</shadedPattern>
|
||||
</relocation>
|
||||
<!-- Relocate BukkitDo -->
|
||||
<relocation>
|
||||
<pattern>me.wiefferink.bukkitdo</pattern>
|
||||
<shadedPattern>me.wiefferink.areashop.shaded.bukkitdo</shadedPattern>
|
||||
</relocation>
|
||||
<!-- Relocate bstats -->
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>me.wiefferink.areashop.shaded.bstats</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,25 +2,24 @@ package me.wiefferink.areashop.commands;
|
||||
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.events.ask.AddingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.BuyingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.RentingRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.BoughtRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.RentedRegionEvent;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import me.wiefferink.areashop.managers.FileManager;
|
||||
import me.wiefferink.areashop.regions.BuyRegion;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import me.wiefferink.areashop.regions.RentRegion;
|
||||
import me.wiefferink.areashop.tools.Utils;
|
||||
import me.wiefferink.bukkitdo.Do;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AddCommand extends CommandAreaShop {
|
||||
@@ -57,7 +56,7 @@ public class AddCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length < 2 || args[1] == null || (!"rent".equals(args[1].toLowerCase()) && !"buy".equals(args[1].toLowerCase()))) {
|
||||
if(args.length < 2 || args[1] == null || (!"rent".equalsIgnoreCase(args[1]) && !"buy".equalsIgnoreCase(args[1]))) {
|
||||
plugin.message(sender, "add-help");
|
||||
return;
|
||||
}
|
||||
@@ -79,7 +78,7 @@ public class AddCommand extends CommandAreaShop {
|
||||
}
|
||||
world = selection.getWorld();
|
||||
regions = Utils.getWorldEditRegionsInSelection(selection).stream().collect(Collectors.toMap(ProtectedRegion::getId, region -> region));
|
||||
if(regions.size() == 0) {
|
||||
if(regions.isEmpty()) {
|
||||
plugin.message(player, "cmd-noWERegionsFound");
|
||||
return;
|
||||
}
|
||||
@@ -113,24 +112,26 @@ public class AddCommand extends CommandAreaShop {
|
||||
}
|
||||
regions.put(args[2], region);
|
||||
}
|
||||
final boolean isRent = "rent".equals(args[1].toLowerCase());
|
||||
final boolean isRent = "rent".equalsIgnoreCase(args[1]);
|
||||
final Player finalPlayer = player;
|
||||
AreaShop.debug("Starting add task with " + regions.size() + " regions");
|
||||
|
||||
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
|
||||
TreeSet<GeneralRegion> regionsAlready = new TreeSet<>();
|
||||
TreeSet<GeneralRegion> regionsAlreadyOtherWorld = new TreeSet<>();
|
||||
TreeSet<GeneralRegion> regionsRentCancelled = new TreeSet<>(); // Denied by an event listener
|
||||
TreeSet<GeneralRegion> regionsBuyCancelled = new TreeSet<>(); // Denied by an event listener
|
||||
TreeSet<String> namesBlacklisted = new TreeSet<>();
|
||||
TreeSet<String> namesNoPermission = new TreeSet<>();
|
||||
Do.forAll(
|
||||
plugin.getConfig().getInt("adding.regionsPerTick"),
|
||||
regions.entrySet(),
|
||||
regionEntry -> {
|
||||
TreeSet<String> namesAddCancelled = new TreeSet<>(); // Denied by an event listener
|
||||
Utils.runAsBatches(regions.entrySet(),
|
||||
Math.min(plugin.getConfig().getInt("adding.regionsPerTick"), 1),
|
||||
(regionEntry) -> {
|
||||
String regionName = regionEntry.getKey();
|
||||
ProtectedRegion region = regionEntry.getValue();
|
||||
// Determine if the player is an owner or member of the region
|
||||
boolean isMember = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
|
||||
boolean isOwner = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
|
||||
boolean isOwner = finalPlayer != null && plugin.getWorldGuardHandler().containsOwner(region, finalPlayer.getUniqueId());
|
||||
String type;
|
||||
if(isRent) {
|
||||
type = "rent";
|
||||
@@ -154,46 +155,56 @@ public class AddCommand extends CommandAreaShop {
|
||||
List<UUID> existing = new ArrayList<>();
|
||||
existing.addAll(plugin.getWorldGuardHandler().getOwners(region).asUniqueIdList());
|
||||
existing.addAll(plugin.getWorldGuardHandler().getMembers(region).asUniqueIdList());
|
||||
|
||||
AreaShop.debug("regionAddLandlordStatus:", regionName,
|
||||
"landlord:", landlord,
|
||||
"existing:", existing,
|
||||
"isMember:", isMember,
|
||||
"isOwner:", isOwner,
|
||||
"createPermission:", sender.hasPermission("areashop.create" + type),
|
||||
"ownerPermission:", sender.hasPermission("areashop.create" + type + ".owner"),
|
||||
"memberPermission:", sender.hasPermission("areashop.create" + type + ".member"));
|
||||
|
||||
if(isRent) {
|
||||
RentRegion rent = new RentRegion(regionName, world);
|
||||
// Set landlord
|
||||
if(landlord) {
|
||||
rent.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
|
||||
}
|
||||
// Run commands
|
||||
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
|
||||
plugin.getFileManager().addRent(rent);
|
||||
|
||||
AddingRegionEvent event = plugin.getFileManager().addRegion(rent);
|
||||
if (event.isCancelled()) {
|
||||
namesAddCancelled.add(rent.getName());
|
||||
return;
|
||||
}
|
||||
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
|
||||
|
||||
rent.update();
|
||||
|
||||
// Run commands
|
||||
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
|
||||
|
||||
// Add existing owners/members if any
|
||||
if(!landlord && !existing.isEmpty()) {
|
||||
// TODO also execute rent events to notify other plugins?
|
||||
UUID rentBy = existing.remove(0);
|
||||
OfflinePlayer rentByPlayer = Bukkit.getOfflinePlayer(rentBy);
|
||||
|
||||
// Run commands
|
||||
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, true);
|
||||
RentingRegionEvent rentingRegionEvent = new RentingRegionEvent(rent, rentByPlayer, false);
|
||||
Bukkit.getPluginManager().callEvent(rentingRegionEvent);
|
||||
if(rentingRegionEvent.isCancelled()) {
|
||||
regionsRentCancelled.add(rent);
|
||||
} else {
|
||||
// Add values to the rent and send it to FileManager
|
||||
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
|
||||
rent.setRenter(rentBy);
|
||||
rent.updateLastActiveTime();
|
||||
|
||||
// Add values to the rent and send it to FileManager
|
||||
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
|
||||
rent.setRenter(existing.remove(0));
|
||||
rent.updateLastActiveTime();
|
||||
// Fire schematic event and updated times extended
|
||||
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
|
||||
|
||||
// Add others as friends
|
||||
for(UUID friend : existing) {
|
||||
rent.getFriendsFeature().addFriend(friend, null);
|
||||
// Add others as friends
|
||||
for(UUID friend : existing) {
|
||||
rent.getFriendsFeature().addFriend(friend, null);
|
||||
}
|
||||
|
||||
rent.notifyAndUpdate(new RentedRegionEvent(rent, false));
|
||||
}
|
||||
|
||||
// Fire schematic event and updated times extended
|
||||
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
|
||||
|
||||
// Notify about updates
|
||||
rent.update();
|
||||
|
||||
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, false);
|
||||
}
|
||||
|
||||
regionsSuccess.add(rent);
|
||||
@@ -203,47 +214,47 @@ public class AddCommand extends CommandAreaShop {
|
||||
if(landlord) {
|
||||
buy.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
|
||||
}
|
||||
// Run commands
|
||||
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
|
||||
|
||||
plugin.getFileManager().addBuy(buy);
|
||||
AddingRegionEvent event = plugin.getFileManager().addRegion(buy);
|
||||
if (event.isCancelled()) {
|
||||
namesAddCancelled.add(buy.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
|
||||
|
||||
buy.update();
|
||||
|
||||
// Run commands
|
||||
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
|
||||
|
||||
// Add existing owners/members if any
|
||||
if(!landlord && !existing.isEmpty()) {
|
||||
// TODO also execute buy events to notify for other plugins?
|
||||
UUID buyBy = existing.remove(0);
|
||||
OfflinePlayer buyByPlayer = Bukkit.getOfflinePlayer(buyBy);
|
||||
|
||||
// Run commands
|
||||
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, true);
|
||||
BuyingRegionEvent buyingRegionEvent = new BuyingRegionEvent(buy, buyByPlayer);
|
||||
Bukkit.getPluginManager().callEvent(buyingRegionEvent);
|
||||
if(buyingRegionEvent.isCancelled()) {
|
||||
regionsBuyCancelled.add(buy);
|
||||
} else {
|
||||
// Set the owner
|
||||
buy.setBuyer(buyBy);
|
||||
buy.updateLastActiveTime();
|
||||
|
||||
// Set the owner
|
||||
buy.setBuyer(existing.remove(0));
|
||||
buy.updateLastActiveTime();
|
||||
// Add others as friends
|
||||
for(UUID friend : existing) {
|
||||
buy.getFriendsFeature().addFriend(friend, null);
|
||||
// Update everything
|
||||
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
|
||||
|
||||
// Add others as friends
|
||||
for (UUID friend : existing) {
|
||||
buy.getFriendsFeature().addFriend(friend, null);
|
||||
}
|
||||
|
||||
buy.notifyAndUpdate(new BoughtRegionEvent(buy));
|
||||
}
|
||||
|
||||
// Notify about updates
|
||||
buy.update();
|
||||
|
||||
// Update everything
|
||||
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
|
||||
|
||||
// Run commands
|
||||
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, false);
|
||||
}
|
||||
|
||||
regionsSuccess.add(buy);
|
||||
}
|
||||
}
|
||||
},
|
||||
() -> {
|
||||
}, false).thenAccept(
|
||||
(success) -> {
|
||||
if(!regionsSuccess.isEmpty()) {
|
||||
plugin.message(sender, "add-success", args[1], Utils.combinedMessage(regionsSuccess, "region"));
|
||||
}
|
||||
@@ -253,6 +264,12 @@ public class AddCommand extends CommandAreaShop {
|
||||
if(!regionsAlreadyOtherWorld.isEmpty()) {
|
||||
plugin.message(sender, "add-failedOtherWorld", Utils.combinedMessage(regionsAlreadyOtherWorld, "region"));
|
||||
}
|
||||
if(!regionsRentCancelled.isEmpty()) {
|
||||
plugin.message(sender, "add-rentCancelled", Utils.combinedMessage(regionsRentCancelled, "region"));
|
||||
}
|
||||
if(!regionsBuyCancelled.isEmpty()) {
|
||||
plugin.message(sender, "add-buyCancelled", Utils.combinedMessage(regionsBuyCancelled, "region"));
|
||||
}
|
||||
if(!namesBlacklisted.isEmpty()) {
|
||||
plugin.message(sender, "add-blacklisted", Utils.createCommaSeparatedList(namesBlacklisted));
|
||||
}
|
||||
@@ -260,13 +277,15 @@ public class AddCommand extends CommandAreaShop {
|
||||
plugin.message(sender, "add-noPermissionRegions", Utils.createCommaSeparatedList(namesNoPermission));
|
||||
plugin.message(sender, "add-noPermissionOwnerMember");
|
||||
}
|
||||
}
|
||||
);
|
||||
if(!namesAddCancelled.isEmpty()) {
|
||||
plugin.message(sender, "add-rentCancelled", Utils.createCommaSeparatedList(namesAddCancelled));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
|
||||
List<String> result = new ArrayList<>();
|
||||
List<String> result = new LinkedList<>();
|
||||
if(toComplete == 2) {
|
||||
if(sender.hasPermission("areashop.createrent")) {
|
||||
result.add("rent");
|
||||
|
||||
@@ -3,12 +3,16 @@ package me.wiefferink.areashop.commands;
|
||||
import me.wiefferink.areashop.features.signs.RegionSign;
|
||||
import me.wiefferink.areashop.features.signs.SignsFeature;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import me.wiefferink.areashop.tools.Materials;
|
||||
import me.wiefferink.areashop.tools.Utils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Sign;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.material.Sign;
|
||||
import org.bukkit.util.BlockIterator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -17,100 +21,108 @@ import java.util.Set;
|
||||
|
||||
public class AddsignCommand extends CommandAreaShop {
|
||||
|
||||
@Override
|
||||
public String getCommandStart() {
|
||||
return "areashop addsign";
|
||||
}
|
||||
@Override
|
||||
public String getCommandStart() {
|
||||
return "areashop addsign";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.addsign")) {
|
||||
return "help-addsign";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if (target.hasPermission("areashop.addsign")) {
|
||||
return "help-addsign";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if(!sender.hasPermission("areashop.addsign")) {
|
||||
plugin.message(sender, "addsign-noPermission");
|
||||
return;
|
||||
}
|
||||
if(!(sender instanceof Player)) {
|
||||
plugin.message(sender, "cmd-onlyByPlayer");
|
||||
return;
|
||||
}
|
||||
Player player = (Player)sender;
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (!sender.hasPermission("areashop.addsign")) {
|
||||
plugin.message(sender, "addsign-noPermission");
|
||||
return;
|
||||
}
|
||||
if (!(sender instanceof Player)) {
|
||||
plugin.message(sender, "cmd-onlyByPlayer");
|
||||
return;
|
||||
}
|
||||
Player player = (Player) sender;
|
||||
|
||||
// Get the sign
|
||||
Block block = null;
|
||||
BlockIterator blockIterator = new BlockIterator(player, 100);
|
||||
while(blockIterator.hasNext() && block == null) {
|
||||
Block next = blockIterator.next();
|
||||
if(next.getType() != Material.AIR) {
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
|
||||
plugin.message(sender, "addsign-noSign");
|
||||
return;
|
||||
}
|
||||
// Get the sign
|
||||
Block block = null;
|
||||
BlockIterator blockIterator = new BlockIterator(player, 100);
|
||||
while (blockIterator.hasNext() && block == null) {
|
||||
Block next = blockIterator.next();
|
||||
if (next.getType() != Material.AIR) {
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
if (block == null || !Materials.isSign(block.getType())) {
|
||||
plugin.message(sender, "addsign-noSign");
|
||||
return;
|
||||
}
|
||||
|
||||
GeneralRegion region;
|
||||
if(args.length > 1) {
|
||||
// Get region by argument
|
||||
region = plugin.getFileManager().getRegion(args[1]);
|
||||
if(region == null) {
|
||||
plugin.message(sender, "cmd-notRegistered", args[1]);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Get region by sign position
|
||||
List<GeneralRegion> regions = Utils.getImportantRegions(block.getLocation());
|
||||
if(regions.isEmpty()) {
|
||||
plugin.message(sender, "addsign-noRegions");
|
||||
return;
|
||||
} else if(regions.size() > 1) {
|
||||
plugin.message(sender, "addsign-couldNotDetect", regions.get(0).getName(), regions.get(1).getName());
|
||||
return;
|
||||
}
|
||||
region = regions.get(0);
|
||||
}
|
||||
Sign sign = (Sign)block.getState().getData();
|
||||
String profile = null;
|
||||
if(args.length > 2) {
|
||||
profile = args[2];
|
||||
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
|
||||
if(!profiles.contains(profile)) {
|
||||
plugin.message(sender, "addsign-wrongProfile", Utils.createCommaSeparatedList(profiles), region);
|
||||
return;
|
||||
}
|
||||
}
|
||||
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
|
||||
if(regionSign != null) {
|
||||
plugin.message(sender, "addsign-alreadyRegistered", regionSign.getRegion());
|
||||
return;
|
||||
}
|
||||
GeneralRegion region;
|
||||
if (args.length > 1) {
|
||||
// Get region by argument
|
||||
region = plugin.getFileManager().getRegion(args[1]);
|
||||
if (region == null) {
|
||||
plugin.message(sender, "cmd-notRegistered", args[1]);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Get region by sign position
|
||||
List<GeneralRegion> regions = Utils.getImportantRegions(block.getLocation());
|
||||
if (regions.isEmpty()) {
|
||||
plugin.message(sender, "addsign-noRegions");
|
||||
return;
|
||||
} else if (regions.size() > 1) {
|
||||
plugin.message(sender, "addsign-couldNotDetect", regions.get(0).getName(), regions.get(1).getName());
|
||||
return;
|
||||
}
|
||||
region = regions.get(0);
|
||||
}
|
||||
String profile = null;
|
||||
if (args.length > 2) {
|
||||
profile = args[2];
|
||||
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
|
||||
if (!profiles.contains(profile)) {
|
||||
plugin.message(sender, "addsign-wrongProfile", Utils.createCommaSeparatedList(profiles), region);
|
||||
return;
|
||||
}
|
||||
}
|
||||
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
|
||||
if (regionSign != null) {
|
||||
plugin.message(sender, "addsign-alreadyRegistered", regionSign.getRegion());
|
||||
return;
|
||||
}
|
||||
|
||||
region.getSignsFeature().addSign(block.getLocation(), block.getType(), sign.getFacing(), profile);
|
||||
if(profile == null) {
|
||||
plugin.message(sender, "addsign-success", region);
|
||||
} else {
|
||||
plugin.message(sender, "addsign-successProfile", profile, region);
|
||||
}
|
||||
region.update();
|
||||
}
|
||||
final BlockData data = block.getBlockData();
|
||||
final BlockFace rotation;
|
||||
if (data instanceof Sign) {
|
||||
rotation = ((Sign) data).getRotation();
|
||||
} else if (data instanceof WallSign) {
|
||||
rotation = ((WallSign) data).getFacing();
|
||||
} else {
|
||||
rotation = null;
|
||||
}
|
||||
region.getSignsFeature().addSign(block.getLocation(), block.getType(), rotation, profile);
|
||||
if (profile == null) {
|
||||
plugin.message(sender, "addsign-success", region);
|
||||
} else {
|
||||
plugin.message(sender, "addsign-successProfile", profile, region);
|
||||
}
|
||||
region.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if(toComplete == 2) {
|
||||
result.addAll(plugin.getFileManager().getRegionNames());
|
||||
} else if(toComplete == 3) {
|
||||
result.addAll(plugin.getConfig().getStringList("signProfiles"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (toComplete == 2) {
|
||||
result.addAll(plugin.getFileManager().getRegionNames());
|
||||
} else if (toComplete == 3) {
|
||||
result.addAll(plugin.getConfig().getStringList("signProfiles"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,7 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Abstract class for generalising command classes.
|
||||
@@ -46,7 +43,7 @@ public abstract class CommandAreaShop {
|
||||
* @return A collection with all the possibilities for argument to complete
|
||||
*/
|
||||
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
|
||||
return new ArrayList<>();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,9 +86,9 @@ public abstract class CommandAreaShop {
|
||||
return false;
|
||||
}
|
||||
|
||||
private class CommandTime {
|
||||
public String command;
|
||||
public long time;
|
||||
private static class CommandTime {
|
||||
public final String command;
|
||||
public final long time;
|
||||
|
||||
CommandTime(String command, long time) {
|
||||
this.command = command;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.wiefferink.areashop.commands;
|
||||
|
||||
import me.wiefferink.areashop.events.ask.DeletingRegionEvent;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import me.wiefferink.areashop.regions.BuyRegion;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
@@ -11,6 +12,7 @@ import org.bukkit.entity.Player;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DelCommand extends CommandAreaShop {
|
||||
|
||||
@@ -50,62 +52,82 @@ public class DelCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
|
||||
if(regions == null || regions.size() == 0) {
|
||||
if(regions.isEmpty()) {
|
||||
plugin.message(player, "cmd-noRegionsFound");
|
||||
return;
|
||||
}
|
||||
// Start removing the regions that he has permission for
|
||||
ArrayList<String> namesSuccess = new ArrayList<>();
|
||||
TreeSet<GeneralRegion> namesFailed = new TreeSet<>();
|
||||
TreeSet<GeneralRegion> regionsFailed = new TreeSet<>();
|
||||
TreeSet<GeneralRegion> regionsCancelled = new TreeSet<>();
|
||||
for(GeneralRegion region : regions) {
|
||||
boolean isLandlord = region.isLandlord(((Player)sender).getUniqueId());
|
||||
if(region instanceof RentRegion) {
|
||||
if(!sender.hasPermission("areashop.destroyrent") && !(isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
|
||||
namesFailed.add(region);
|
||||
} else {
|
||||
plugin.getFileManager().removeRent((RentRegion)region, true);
|
||||
namesSuccess.add(region.getName());
|
||||
regionsFailed.add(region);
|
||||
continue;
|
||||
}
|
||||
} else if(region instanceof BuyRegion) {
|
||||
if(!sender.hasPermission("areashop.destroybuy") && !(isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
|
||||
namesFailed.add(region);
|
||||
} else {
|
||||
plugin.getFileManager().removeBuy((BuyRegion)region, true);
|
||||
namesSuccess.add(region.getName());
|
||||
regionsFailed.add(region);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DeletingRegionEvent event = plugin.getFileManager().deleteRegion(region, true);
|
||||
if (event.isCancelled()) {
|
||||
regionsCancelled.add(region);
|
||||
} else {
|
||||
namesSuccess.add(region.getName());
|
||||
}
|
||||
}
|
||||
// send messages
|
||||
if(namesSuccess.size() != 0) {
|
||||
|
||||
// Send messages
|
||||
if(!namesSuccess.isEmpty()) {
|
||||
plugin.message(sender, "del-success", Utils.createCommaSeparatedList(namesSuccess));
|
||||
}
|
||||
if(namesFailed.size() != 0) {
|
||||
plugin.message(sender, "del-failed", Utils.combinedMessage(namesFailed, "region"));
|
||||
if(!regionsFailed.isEmpty()) {
|
||||
plugin.message(sender, "del-failed", Utils.combinedMessage(regionsFailed, "region"));
|
||||
}
|
||||
if(!regionsCancelled.isEmpty()) {
|
||||
plugin.message(sender, "del-cancelled", Utils.combinedMessage(regionsCancelled, "region"));
|
||||
}
|
||||
} else {
|
||||
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
|
||||
if(region == null) {
|
||||
plugin.message(sender, "cmd-notRegistered", args[1]);
|
||||
return;
|
||||
}
|
||||
boolean isLandlord = sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId());
|
||||
if(region instanceof RentRegion) {
|
||||
// Remove the rent if the player has permission
|
||||
if(sender.hasPermission("areashop.destroyrent") || (isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
|
||||
plugin.getFileManager().removeRent((RentRegion)region, true);
|
||||
plugin.message(sender, "destroy-successRent", region);
|
||||
} else {
|
||||
plugin.message(sender, "destroy-noPermissionRent", region);
|
||||
}
|
||||
} else if(region instanceof BuyRegion) {
|
||||
// Remove the buy if the player has permission
|
||||
if(sender.hasPermission("areashop.destroybuy") || (isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
|
||||
plugin.getFileManager().removeBuy((BuyRegion)region, true);
|
||||
plugin.message(sender, "destroy-successBuy", region);
|
||||
} else {
|
||||
plugin.message(sender, "destroy-noPermissionBuy", region);
|
||||
}
|
||||
}
|
||||
CompletableFuture<GeneralRegion> future = plugin.getFileManager().getRegionUnsafe(args[1]);
|
||||
Utils.newChain()
|
||||
.future(future)
|
||||
.syncLast(region -> {
|
||||
if(region == null) {
|
||||
plugin.message(sender, "cmd-notRegistered", args[1]);
|
||||
return;
|
||||
}
|
||||
boolean isLandlord = sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId());
|
||||
if(region instanceof RentRegion) {
|
||||
// Remove the rent if the player has permission
|
||||
if(sender.hasPermission("areashop.destroyrent") || (isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
|
||||
DeletingRegionEvent event = plugin.getFileManager().deleteRegion(region, true);
|
||||
if (event.isCancelled()) {
|
||||
plugin.message(sender, "general-cancelled", event.getReason());
|
||||
} else {
|
||||
plugin.message(sender, "destroy-successRent", region);
|
||||
}
|
||||
} else {
|
||||
plugin.message(sender, "destroy-noPermissionRent", region);
|
||||
}
|
||||
} else if(region instanceof BuyRegion) {
|
||||
// Remove the buy if the player has permission
|
||||
if(sender.hasPermission("areashop.destroybuy") || (isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
|
||||
DeletingRegionEvent event = plugin.getFileManager().deleteRegion(region, true);
|
||||
if (event.isCancelled()) {
|
||||
plugin.message(sender, "general-cancelled", event.getReason());
|
||||
} else {
|
||||
plugin.message(sender, "destroy-successBuy", region);
|
||||
}
|
||||
} else {
|
||||
plugin.message(sender, "destroy-noPermissionBuy", region);
|
||||
}
|
||||
}
|
||||
}).execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.wiefferink.areashop.commands;
|
||||
|
||||
import me.wiefferink.areashop.features.signs.RegionSign;
|
||||
import me.wiefferink.areashop.features.signs.SignsFeature;
|
||||
import me.wiefferink.areashop.tools.Materials;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -47,7 +48,7 @@ public class DelsignCommand extends CommandAreaShop {
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
|
||||
if(block == null || !Materials.isSign(block.getType())) {
|
||||
plugin.message(sender, "delsign-noSign");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.bukkit.entity.Player;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class FindCommand extends CommandAreaShop {
|
||||
|
||||
@@ -82,7 +83,7 @@ public class FindCommand extends CommandAreaShop {
|
||||
}
|
||||
if(!results.isEmpty()) {
|
||||
// Draw a random one
|
||||
BuyRegion region = results.get(new Random().nextInt(results.size()));
|
||||
BuyRegion region = results.get(ThreadLocalRandom.current().nextInt(results.size()));
|
||||
Message onlyInGroup = Message.empty();
|
||||
if(group != null) {
|
||||
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
|
||||
@@ -122,7 +123,7 @@ public class FindCommand extends CommandAreaShop {
|
||||
}
|
||||
if(!results.isEmpty()) {
|
||||
// Draw a random one
|
||||
RentRegion region = results.get(new Random().nextInt(results.size()));
|
||||
RentRegion region = results.get(ThreadLocalRandom.current().nextInt(results.size()));
|
||||
Message onlyInGroup = Message.empty();
|
||||
if(group != null) {
|
||||
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
|
||||
|
||||
@@ -53,7 +53,7 @@ public class GroupaddCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
|
||||
if(regions.size() == 0) {
|
||||
if(regions.isEmpty()) {
|
||||
plugin.message(player, "cmd-noRegionsFound");
|
||||
return;
|
||||
}
|
||||
@@ -66,10 +66,10 @@ public class GroupaddCommand extends CommandAreaShop {
|
||||
regionsFailed.add(region);
|
||||
}
|
||||
}
|
||||
if(regionsSuccess.size() != 0) {
|
||||
if(!regionsSuccess.isEmpty()) {
|
||||
plugin.message(player, "groupadd-weSuccess", group.getName(), Utils.combinedMessage(regionsSuccess, "region"));
|
||||
}
|
||||
if(regionsFailed.size() != 0) {
|
||||
if(!regionsFailed.isEmpty()) {
|
||||
plugin.message(player, "groupadd-weFailed", group.getName(), Utils.combinedMessage(regionsFailed, "region"));
|
||||
}
|
||||
// Update all regions, this does it in a task, updating them without lag
|
||||
|
||||
@@ -54,7 +54,7 @@ public class GroupdelCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
|
||||
if(regions.size() == 0) {
|
||||
if(regions.isEmpty()) {
|
||||
plugin.message(player, "cmd-noRegionsFound");
|
||||
return;
|
||||
}
|
||||
@@ -67,10 +67,10 @@ public class GroupdelCommand extends CommandAreaShop {
|
||||
regionsFailed.add(region);
|
||||
}
|
||||
}
|
||||
if(regionsSuccess.size() != 0) {
|
||||
if(!regionsSuccess.isEmpty()) {
|
||||
plugin.message(player, "groupdel-weSuccess", group.getName(), Utils.combinedMessage(regionsSuccess, "region"));
|
||||
}
|
||||
if(regionsFailed.size() != 0) {
|
||||
if(!regionsFailed.isEmpty()) {
|
||||
plugin.message(player, "groupdel-weFailed", group.getName(), Utils.combinedMessage(regionsFailed, "region"));
|
||||
}
|
||||
// Update all regions, this does it in a task, updating them without lag
|
||||
|
||||
@@ -40,7 +40,7 @@ public class GroupinfoCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
Set<String> members = group.getMembers();
|
||||
if(members.size() == 0) {
|
||||
if(members.isEmpty()) {
|
||||
plugin.message(sender, "groupinfo-noMembers", group.getName());
|
||||
} else {
|
||||
plugin.message(sender, "groupinfo-members", group.getName(), Utils.createCommaSeparatedList(members));
|
||||
|
||||
@@ -28,7 +28,7 @@ public class GrouplistCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
List<String> groups = plugin.getFileManager().getGroupNames();
|
||||
if(groups.size() == 0) {
|
||||
if(groups.isEmpty()) {
|
||||
plugin.message(sender, "grouplist-noGroups");
|
||||
} else {
|
||||
plugin.message(sender, "grouplist-success", Utils.createCommaSeparatedList(groups));
|
||||
|
||||
@@ -27,11 +27,11 @@ public class ImportCommand extends CommandAreaShop {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// - Landlord?
|
||||
// - Friends
|
||||
// - Region flags?
|
||||
// - Settings from the 'permissions' section in RegionForSale/config.yml?
|
||||
// TODO:
|
||||
// - Landlord?
|
||||
// - Friends
|
||||
// - Region flags?
|
||||
// - Settings from the 'permissions' section in RegionForSale/config.yml?
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
@@ -54,7 +54,7 @@ public class ImportCommand extends CommandAreaShop {
|
||||
return;
|
||||
}
|
||||
|
||||
ImportJob importJob = new ImportJob(sender);
|
||||
new ImportJob(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.base.Charsets;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.events.ask.AddingRegionEvent;
|
||||
import me.wiefferink.areashop.features.signs.RegionSign;
|
||||
import me.wiefferink.areashop.features.signs.SignsFeature;
|
||||
import me.wiefferink.areashop.regions.BuyRegion;
|
||||
@@ -240,10 +241,13 @@ public class ImportJob {
|
||||
GeneralRegion region;
|
||||
if(rentable || (owner != null && !isBought)) {
|
||||
region = new RentRegion(regionKey, world);
|
||||
plugin.getFileManager().addRent((RentRegion)region);
|
||||
} else {
|
||||
region = new BuyRegion(regionKey, world);
|
||||
plugin.getFileManager().addBuy((BuyRegion)region);
|
||||
}
|
||||
AddingRegionEvent event = plugin.getFileManager().addRegion(region);
|
||||
if (event.isCancelled()) {
|
||||
messageNoPrefix("general-cancelled", event.getReason());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Import settings
|
||||
@@ -330,7 +334,7 @@ public class ImportJob {
|
||||
String buyPrice = from.getString("economic-settings.cost-per-unit.buy");
|
||||
String sellPrice = from.getString("economic-settings.cost-per-unit.selling-price");
|
||||
// TODO: There is no easy way to import this, setup eventCommandsProfile?
|
||||
String taxes = from.getString("economic-settings.cost-per-unit.taxes");
|
||||
// String taxes = from.getString("economic-settings.cost-per-unit.taxes");
|
||||
|
||||
// Determine unit and add that to the price
|
||||
String unitSuffix = "";
|
||||
@@ -411,8 +415,8 @@ public class ImportJob {
|
||||
}
|
||||
|
||||
private static class TimeUnit {
|
||||
public long minutes;
|
||||
public String identifier;
|
||||
public final long minutes;
|
||||
public final String identifier;
|
||||
|
||||
TimeUnit(long minutes, String identifier) {
|
||||
this.minutes = minutes;
|
||||
|
||||
@@ -113,9 +113,9 @@ public class InfoCommand extends CommandAreaShop {
|
||||
}
|
||||
// Page status
|
||||
if(totalPages > 1) {
|
||||
String pageString = "" + page;
|
||||
StringBuilder pageString = new StringBuilder("" + page);
|
||||
for(int i = pageString.length(); i < (totalPages + "").length(); i++) {
|
||||
pageString = "0" + pageString;
|
||||
pageString.insert(0, "0");
|
||||
}
|
||||
footer.append(Message.fromKey("info-pageStatus").replacements(page, totalPages));
|
||||
if(page < totalPages) {
|
||||
|
||||
@@ -19,9 +19,7 @@ public class MessageCommand extends CommandAreaShop {
|
||||
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.message")) {
|
||||
return null; // Internal command, no need to show in the help list
|
||||
}
|
||||
// Internal command, no need to show in the help list
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,14 +90,14 @@ public class SetdurationCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if(toComplete == 2) {
|
||||
result = plugin.getFileManager().getRentNames();
|
||||
} else if(toComplete == 4) {
|
||||
if(toComplete == 3) {
|
||||
result.addAll(plugin.getConfig().getStringList("minutes"));
|
||||
result.addAll(plugin.getConfig().getStringList("hours"));
|
||||
result.addAll(plugin.getConfig().getStringList("days"));
|
||||
result.addAll(plugin.getConfig().getStringList("months"));
|
||||
result.addAll(plugin.getConfig().getStringList("years"));
|
||||
} else if(toComplete == 4) {
|
||||
result = plugin.getFileManager().getRentNames();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class SetteleportCommand extends CommandAreaShop {
|
||||
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
|
||||
if(target.hasPermission("areashop.setteleportall") || target.hasPermission("areashop.setteleport")) {
|
||||
return "help-setteleport";
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package me.wiefferink.areashop.commands;
|
||||
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.events.ask.AddingRegionEvent;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import me.wiefferink.areashop.regions.BuyRegion;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
@@ -17,6 +16,7 @@ import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -104,7 +104,7 @@ public class StackCommand extends CommandAreaShop {
|
||||
plugin.message(player, "stack-unclearDirection", facing.toString().toLowerCase().replace('_', '-'));
|
||||
return;
|
||||
}
|
||||
Vector shift = new BlockVector(0, 0, 0);
|
||||
Vector shift = new Vector(0, 0, 0);
|
||||
if(facing == BlockFace.SOUTH) {
|
||||
shift = shift.setZ(-selection.getLength() - gap);
|
||||
} else if(facing == BlockFace.WEST) {
|
||||
@@ -158,33 +158,16 @@ public class StackCommand extends CommandAreaShop {
|
||||
current++;
|
||||
if(current < amount) {
|
||||
// Create the region name
|
||||
String counterName = counter + "";
|
||||
int minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
|
||||
while(counterName.length() < minimumLength) {
|
||||
counterName = "0" + counterName;
|
||||
}
|
||||
String regionName;
|
||||
if(nameTemplate.contains("#")) {
|
||||
regionName = nameTemplate.replace("#", counterName);
|
||||
} else {
|
||||
regionName = nameTemplate + counterName;
|
||||
}
|
||||
String regionName = countToName(nameTemplate, counter);
|
||||
while(manager.getRegion(regionName) != null || AreaShop.getInstance().getFileManager().getRegion(regionName) != null) {
|
||||
counter++;
|
||||
counterName = counter + "";
|
||||
minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
|
||||
while(counterName.length() < minimumLength) {
|
||||
counterName = "0" + counterName;
|
||||
}
|
||||
if(nameTemplate.contains("#")) {
|
||||
regionName = nameTemplate.replace("#", counterName);
|
||||
} else {
|
||||
regionName = nameTemplate + counterName;
|
||||
}
|
||||
regionName = countToName(nameTemplate, counter);
|
||||
}
|
||||
|
||||
// Add the region to WorldGuard (at startposition shifted by the number of this region times the blocks it should shift)
|
||||
BlockVector minimum = new BlockVector(minimumVector.add(finalShift.multiply(current)));
|
||||
BlockVector maximum = new BlockVector(maximumVector.add(finalShift.multiply(current)));
|
||||
Vector minimum = minimumVector.clone().add(finalShift.clone().multiply(current));
|
||||
Vector maximum = maximumVector.clone().add(finalShift.clone().multiply(current));
|
||||
|
||||
// Check for out of bounds
|
||||
if(minimum.getBlockY() < 0) {
|
||||
tooLow++;
|
||||
@@ -193,30 +176,28 @@ public class StackCommand extends CommandAreaShop {
|
||||
tooHigh++;
|
||||
continue;
|
||||
}
|
||||
ProtectedCuboidRegion region = new ProtectedCuboidRegion(regionName, minimum, maximum);
|
||||
ProtectedCuboidRegion region = plugin.getWorldGuardHandler().createCuboidRegion(regionName, minimum,maximum);
|
||||
manager.addRegion(region);
|
||||
|
||||
// Add the region to AreaShop
|
||||
GeneralRegion newRegion;
|
||||
if(rentRegions) {
|
||||
RentRegion rent = new RentRegion(regionName, selection.getWorld());
|
||||
if(finalGroup != null) {
|
||||
finalGroup.addMember(rent);
|
||||
}
|
||||
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
|
||||
plugin.getFileManager().addRent(rent);
|
||||
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
|
||||
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
|
||||
rent.update();
|
||||
newRegion = new RentRegion(regionName, selection.getWorld());
|
||||
|
||||
} else {
|
||||
BuyRegion buy = new BuyRegion(regionName, selection.getWorld());
|
||||
if(finalGroup != null) {
|
||||
finalGroup.addMember(buy);
|
||||
}
|
||||
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
|
||||
plugin.getFileManager().addBuy(buy);
|
||||
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
|
||||
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
|
||||
buy.update();
|
||||
newRegion = new BuyRegion(regionName, selection.getWorld());
|
||||
}
|
||||
|
||||
if(finalGroup != null) {
|
||||
finalGroup.addMember(newRegion);
|
||||
}
|
||||
AddingRegionEvent event = plugin.getFileManager().addRegion(newRegion);
|
||||
if (event.isCancelled()) {
|
||||
plugin.message(player, "general-cancelled", event.getReason());
|
||||
continue;
|
||||
}
|
||||
newRegion.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
|
||||
newRegion.update();
|
||||
}
|
||||
}
|
||||
if(current >= amount) {
|
||||
@@ -237,6 +218,26 @@ public class StackCommand extends CommandAreaShop {
|
||||
}.runTaskTimer(plugin, 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a name from a count, with the right length.
|
||||
* @param template Template to put the name in (# to put the count there, otherwise count is appended)
|
||||
* @param count Number to use
|
||||
* @return name with prepended 0's
|
||||
*/
|
||||
private String countToName(String template, int count) {
|
||||
StringBuilder counterName = new StringBuilder().append(count);
|
||||
int minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
|
||||
while(counterName.length() < minimumLength) {
|
||||
counterName.insert(0, "0");
|
||||
}
|
||||
|
||||
if(template.contains("#")) {
|
||||
return template.replace("#", counterName);
|
||||
} else {
|
||||
return template + counterName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
@@ -59,12 +59,13 @@ public class TeleportCommand extends CommandAreaShop {
|
||||
plugin.message(player, "teleport-noRentOrBuy", args[1]);
|
||||
return;
|
||||
}
|
||||
if(args.length >= 3 && (args[2].equalsIgnoreCase("sign") || args[2].equalsIgnoreCase("yes") || args[2].equalsIgnoreCase("true"))) {
|
||||
region.getTeleportFeature().teleportPlayer(player, true);
|
||||
} else {
|
||||
region.getTeleportFeature().teleportPlayer(player, false);
|
||||
}
|
||||
|
||||
boolean toSign = args.length >= 3 && (
|
||||
args[2].equalsIgnoreCase("sign")
|
||||
|| args[2].equalsIgnoreCase("yes")
|
||||
|| args[2].equalsIgnoreCase("true")
|
||||
);
|
||||
region.getTeleportFeature().teleportPlayer(player, toSign, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@ public class RegionEvent<T> extends Event {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
// Required by Bukkit/Spigot
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package me.wiefferink.areashop.events.ask;
|
||||
|
||||
import me.wiefferink.areashop.events.CancellableRegionEvent;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
|
||||
/**
|
||||
* Broadcasted when a region has been added to AreaShop.
|
||||
*/
|
||||
public class AddingRegionEvent extends CancellableRegionEvent<GeneralRegion> {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param region The region that has been added
|
||||
*/
|
||||
public AddingRegionEvent(GeneralRegion region) {
|
||||
super(region);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package me.wiefferink.areashop.events.ask;
|
||||
|
||||
import me.wiefferink.areashop.events.CancellableRegionEvent;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
|
||||
/**
|
||||
* Broadcasted when a region has been added to AreaShop.
|
||||
*/
|
||||
public class DeletingRegionEvent extends CancellableRegionEvent<GeneralRegion> {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param region The region that has been added
|
||||
*/
|
||||
public DeletingRegionEvent(GeneralRegion region) {
|
||||
super(region);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package me.wiefferink.areashop.features;
|
||||
|
||||
import me.wiefferink.areashop.events.ask.AddingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.BuyingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.DeletingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.RentingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.ResellingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.SellingRegionEvent;
|
||||
import me.wiefferink.areashop.events.ask.UnrentingRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.AddedRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.BoughtRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.DeletedRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.RentedRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.ResoldRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.SoldRegionEvent;
|
||||
import me.wiefferink.areashop.events.notify.UnrentedRegionEvent;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CommandsFeature extends RegionFeature {
|
||||
|
||||
/**
|
||||
* Run command for a certain event.
|
||||
* @param region Region to execute the events for
|
||||
* @param event The event
|
||||
* @param before The 'before' or 'after' commands
|
||||
*/
|
||||
public void runEventCommands(GeneralRegion region, GeneralRegion.RegionEvent event, boolean before) {
|
||||
ConfigurationSection eventCommandProfileSection = region.getConfigurationSectionSetting("general.eventCommandProfile", "eventCommandProfiles");
|
||||
if(eventCommandProfileSection == null) {
|
||||
return;
|
||||
}
|
||||
List<String> commands = eventCommandProfileSection.getStringList(event.getValue() + "." + (before ? "before" : "after"));
|
||||
if(commands == null || commands.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
region.runCommands(Bukkit.getConsoleSender(), commands);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void addingRegion(AddingRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.CREATED, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void addedRegion(AddedRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.CREATED, false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void deletingRegion(DeletingRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.DELETED, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void deletedRegion(DeletedRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.DELETED, false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void rentingRegion(RentingRegionEvent event) {
|
||||
// Technically the rent can still be cancelled if the payment fails...
|
||||
runEventCommands(event.getRegion(), event.isExtending() ? GeneralRegion.RegionEvent.EXTENDED : GeneralRegion.RegionEvent.RENTED, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void rentedRegion(RentedRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), event.hasExtended() ? GeneralRegion.RegionEvent.EXTENDED : GeneralRegion.RegionEvent.RENTED, false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void buyingRegion(BuyingRegionEvent event) {
|
||||
// Technically the buy can still be cancelled if the payment fails...
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.BOUGHT, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void boughtRegion(BoughtRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.BOUGHT, false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void resellingRegion(ResellingRegionEvent event) {
|
||||
// Technically the resell can still be cancelled if the payment fails...
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.RESELL, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void resoldRegion(ResoldRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.RESELL, false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void sellingRegion(SellingRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.SOLD, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void soldRegion(SoldRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.SOLD, false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void unrentingRegion(UnrentingRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.UNRENTED, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void unrentedRegion(UnrentedRegionEvent event) {
|
||||
runEventCommands(event.getRegion(), GeneralRegion.RegionEvent.UNRENTED, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class FriendsFeature extends RegionFeature {
|
||||
HashSet<String> result = new HashSet<>();
|
||||
for(UUID friend : getFriends()) {
|
||||
OfflinePlayer player = Bukkit.getOfflinePlayer(friend);
|
||||
if(player != null && player.getName() != null) {
|
||||
if(player.hasPlayedBefore() && player.getName() != null) {
|
||||
result.add(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,31 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
/*
|
||||
Possible future feature classes:
|
||||
- RestrictedToRegion feature
|
||||
- rent/buy restricted to the region itself
|
||||
- RestrictedToWorld feature
|
||||
- rent/buy restricted to the world of the region
|
||||
- CountLimitsFeature:
|
||||
- Check region limits
|
||||
- TimeLimitsFeatures:
|
||||
- maxExtends
|
||||
- maxRentTime
|
||||
- SchematicFeature
|
||||
- save/load schematics
|
||||
- CommandsFeature
|
||||
- execute commands after extend/rent/etc
|
||||
- LandlordFeature
|
||||
- manage landlords
|
||||
- ExpirationWarningsFeature
|
||||
- sending rental expiration warnings
|
||||
*/
|
||||
|
||||
public abstract class RegionFeature implements Listener {
|
||||
public static final AreaShop plugin = AreaShop.getInstance();
|
||||
|
||||
public YamlConfiguration config = plugin.getConfig();
|
||||
protected YamlConfiguration config = plugin.getConfig();
|
||||
private GeneralRegion region;
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+3
-4
@@ -42,7 +42,7 @@ public class WorldGuardRegionFlagsFeature extends RegionFeature {
|
||||
// Region flags for all states
|
||||
ConfigurationSection allFlags = flagProfileSection.getConfigurationSection("ALL");
|
||||
if(allFlags != null) {
|
||||
result = result && updateRegionFlags(region, allFlags);
|
||||
result = updateRegionFlags(region, allFlags);
|
||||
}
|
||||
|
||||
// Region flags for the current state
|
||||
@@ -52,9 +52,8 @@ public class WorldGuardRegionFlagsFeature extends RegionFeature {
|
||||
if(stateFlags == null && region.getState() == GeneralRegion.RegionState.RESELL) {
|
||||
stateFlags = flagProfileSection.getConfigurationSection("resale");
|
||||
}
|
||||
|
||||
if(stateFlags != null) {
|
||||
result = result && updateRegionFlags(region, stateFlags);
|
||||
result &= updateRegionFlags(region, stateFlags);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -256,7 +255,7 @@ public class WorldGuardRegionFlagsFeature extends RegionFeature {
|
||||
result = result.replace("&1", "&B");
|
||||
result = result.replace("&d", "&p");
|
||||
result = result.replace("&5", "&P");
|
||||
result = result.replace("&0", "&0");
|
||||
//result = result.replace("&0", "&0");
|
||||
result = result.replace("&8", "&1");
|
||||
result = result.replace("&7", "&2");
|
||||
result = result.replace("&f", "&w");
|
||||
|
||||
@@ -1,252 +1,331 @@
|
||||
package me.wiefferink.areashop.features.signs;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.managers.SignErrorLogger;
|
||||
import me.wiefferink.areashop.interfaces.BlockBehaviourHelper;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import me.wiefferink.areashop.tools.Materials;
|
||||
import me.wiefferink.areashop.tools.Utils;
|
||||
import me.wiefferink.interactivemessenger.processing.Message;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Sign that is connected to a region to display information and interact with the region.
|
||||
*/
|
||||
public class RegionSign {
|
||||
|
||||
private final SignsFeature signsFeature;
|
||||
private final String key;
|
||||
|
||||
public RegionSign(SignsFeature signsFeature, String key) {
|
||||
this.signsFeature = signsFeature;
|
||||
this.key = key;
|
||||
}
|
||||
public static final BlockBehaviourHelper behaviourHelper = AreaShop.getInstance().getNMSHelper().behaviourHelper();
|
||||
public static Level invalidSignLogLevel;
|
||||
public static boolean removeInvalidSigns;
|
||||
|
||||
/**
|
||||
* Get the location of this sign.
|
||||
* @return The location of this sign
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return Utils.configToLocation(getRegion().getConfig().getConfigurationSection("general.signs." + key + ".location"));
|
||||
}
|
||||
static {
|
||||
YamlConfiguration configuration = AreaShop.getInstance().getConfig();
|
||||
removeInvalidSigns = configuration.getBoolean("signs.removeInvalid");
|
||||
final String rawLogLevel = configuration.getString("signs.invalidSignLogLevel", "WARNING");
|
||||
try {
|
||||
assert rawLogLevel != null;
|
||||
invalidSignLogLevel = Level.parse(rawLogLevel);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
AreaShop.warn("Invalid Logging Level: " + rawLogLevel);
|
||||
invalidSignLogLevel = Level.WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Location string to be used as key in maps.
|
||||
* @return Location string
|
||||
*/
|
||||
public String getStringLocation() {
|
||||
return SignsFeature.locationToString(getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Chunk string to be used as key in maps.
|
||||
* @return Chunk string
|
||||
*/
|
||||
public String getStringChunk() {
|
||||
return SignsFeature.chunkToString(getLocation());
|
||||
}
|
||||
private static boolean canLogSignError() {
|
||||
return AreaShop.getInstance().getLogger().isLoggable(invalidSignLogLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the region this sign is linked to.
|
||||
* @return The region this sign is linked to
|
||||
*/
|
||||
public GeneralRegion getRegion() {
|
||||
return signsFeature.getRegion();
|
||||
}
|
||||
private static void logSignError(String... messages) {
|
||||
if (invalidSignLogLevel == Level.OFF) {
|
||||
return;
|
||||
}
|
||||
if (invalidSignLogLevel == Level.SEVERE) {
|
||||
AreaShop.error((Object) messages);
|
||||
} else if (invalidSignLogLevel == Level.WARNING) {
|
||||
AreaShop.warn((Object) messages);
|
||||
} else if (invalidSignLogLevel.intValue() >= Level.FINE.intValue()) {
|
||||
AreaShop.debug((Object) messages);
|
||||
} else {
|
||||
AreaShop.info((Object) messages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this sign from the region.
|
||||
*/
|
||||
public void remove() {
|
||||
getLocation().getBlock().setType(Material.AIR);
|
||||
signsFeature.getSignsRef().remove(getStringLocation());
|
||||
SignsFeature.getAllSigns().remove(getStringLocation());
|
||||
SignsFeature.getSignsByChunk().get(getStringChunk()).remove(this);
|
||||
getRegion().setSetting("general.signs." + key, null);
|
||||
}
|
||||
private final SignsFeature signsFeature;
|
||||
private final String key;
|
||||
|
||||
/**
|
||||
* Get the ConfigurationSection defining the sign layout.
|
||||
* @return The sign layout config
|
||||
*/
|
||||
public ConfigurationSection getProfile() {
|
||||
return getRegion().getConfigurationSectionSetting("general.signProfile", "signProfiles", getRegion().getConfig().get("general.signs." + key + ".profile"));
|
||||
}
|
||||
public RegionSign(SignsFeature signsFeature, String key) {
|
||||
this.signsFeature = signsFeature;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the facing of the sign.
|
||||
* @return BlockFace the sign faces, or null if unknown
|
||||
*/
|
||||
public BlockFace getFacing() {
|
||||
try {
|
||||
return BlockFace.valueOf(getRegion().getConfig().getString("general.signs." + key + ".facing"));
|
||||
} catch(NullPointerException | IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the location of this sign.
|
||||
*
|
||||
* @return The location of this sign
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return Utils.configToLocation(getRegion().getConfig().getConfigurationSection("general.signs." + key + ".location"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the material of the sign
|
||||
* @return Material of the sign, normally {@link Material#WALL_SIGN} or {@link Material#SIGN_POST}, but could be something else or null.
|
||||
*/
|
||||
public Material getMaterial() {
|
||||
try {
|
||||
return Material.valueOf(getRegion().getConfig().getString("general.signs." + key + ".signType"));
|
||||
} catch(NullPointerException | IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Location string to be used as key in maps.
|
||||
*
|
||||
* @return Location string
|
||||
*/
|
||||
public String getStringLocation() {
|
||||
return SignsFeature.locationToString(getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this sign.
|
||||
* @return true if the update was successful, otherwise false
|
||||
*/
|
||||
public boolean update() {
|
||||
// Ignore updates of signs in chunks that are not loaded
|
||||
Location signLocation = getLocation();
|
||||
if(signLocation == null
|
||||
|| signLocation.getWorld() == null
|
||||
|| !signLocation.getWorld().isChunkLoaded(signLocation.getBlockX() >> 4, signLocation.getBlockZ() >> 4)) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Chunk string to be used as key in maps.
|
||||
*
|
||||
* @return Chunk string
|
||||
*/
|
||||
public String getStringChunk() {
|
||||
return SignsFeature.chunkToString(getLocation());
|
||||
}
|
||||
|
||||
if(getRegion().isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Get the region this sign is linked to.
|
||||
*
|
||||
* @return The region this sign is linked to
|
||||
*/
|
||||
public GeneralRegion getRegion() {
|
||||
return signsFeature.getRegion();
|
||||
}
|
||||
|
||||
YamlConfiguration regionConfig = getRegion().getConfig();
|
||||
ConfigurationSection signConfig = getProfile();
|
||||
Block block = signLocation.getBlock();
|
||||
if(signConfig == null || !signConfig.isSet(getRegion().getState().getValue())) {
|
||||
block.setType(Material.AIR);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Remove this sign from the region.
|
||||
*/
|
||||
public void remove() {
|
||||
getLocation().getBlock().setType(Material.AIR);
|
||||
signsFeature.getSignsRef().remove(getStringLocation());
|
||||
SignsFeature.getAllSigns().remove(getStringLocation());
|
||||
SignsFeature.getSignsByChunk().get(getStringChunk()).remove(this);
|
||||
getRegion().setSetting("general.signs." + key, null);
|
||||
}
|
||||
|
||||
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue());
|
||||
/**
|
||||
* Get the ConfigurationSection defining the sign layout.
|
||||
*
|
||||
* @return The sign layout config
|
||||
*/
|
||||
public ConfigurationSection getProfile() {
|
||||
return getRegion().getConfigurationSectionSetting("general.signProfile", "signProfiles", getRegion().getConfig().get("general.signs." + key + ".profile"));
|
||||
}
|
||||
|
||||
// Get the lines
|
||||
String[] signLines = new String[4];
|
||||
boolean signEmpty = true;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
signLines[i] = stateConfig.getString("line" + (i + 1));
|
||||
signEmpty &= (signLines[i] == null || signLines[i].isEmpty());
|
||||
}
|
||||
if(signEmpty) {
|
||||
block.setType(Material.AIR);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Get the facing of the sign as saved in the config.
|
||||
*
|
||||
* @return BlockFace the sign faces, or null if unknown
|
||||
*/
|
||||
public BlockFace getFacing() {
|
||||
try {
|
||||
return BlockFace.valueOf(getRegion().getConfig().getString("general.signs." + key + ".facing"));
|
||||
} catch (NullPointerException | IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Sign signState = null;
|
||||
// Place the sign back (with proper rotation and type) after it has been hidden or (indirectly) destroyed
|
||||
if(block.getType() != Material.WALL_SIGN && block.getType() != Material.SIGN_POST) {
|
||||
Material signType = getMaterial();
|
||||
if(signType != Material.WALL_SIGN && signType != Material.SIGN_POST) {
|
||||
AreaShop.debug("Setting sign", key, "of region", getRegion().getName(), "failed, could not set sign block back");
|
||||
return false;
|
||||
}
|
||||
block.setType(signType);
|
||||
signState = (Sign)block.getState();
|
||||
org.bukkit.material.Sign signData = (org.bukkit.material.Sign)signState.getData();
|
||||
BlockFace signFace = getFacing();
|
||||
if(signFace != null) {
|
||||
signData.setFacingDirection(signFace);
|
||||
signState.setData(signData);
|
||||
}
|
||||
}
|
||||
if(signState == null) {
|
||||
signState = (Sign)block.getState();
|
||||
}
|
||||
/**
|
||||
* Get the material of the sign as saved in the config.
|
||||
*
|
||||
* @return Material of the sign, usually, a sign or {@link Material#AIR} if none.
|
||||
*/
|
||||
public Material getMaterial() {
|
||||
String name = getRegion().getConfig().getString("general.signs." + key + ".signType");
|
||||
Material result = Materials.signNameToMaterial(name);
|
||||
return result == null ? Material.AIR : result;
|
||||
}
|
||||
|
||||
// Save current rotation and type
|
||||
org.bukkit.material.Sign signData = (org.bukkit.material.Sign)signState.getData();
|
||||
if(!regionConfig.isString("general.signs." + key + ".signType")) {
|
||||
getRegion().setSetting("general.signs." + key + ".signType", signState.getType().toString());
|
||||
}
|
||||
if(!regionConfig.isString("general.signs." + key + ".facing")) {
|
||||
getRegion().setSetting("general.signs." + key + ".facing", signData.getFacing().toString());
|
||||
}
|
||||
/**
|
||||
* Update this sign.
|
||||
*
|
||||
* @return true if the update was successful, otherwise false
|
||||
*/
|
||||
public boolean update() {
|
||||
// Ignore updates of signs in chunks that are not loaded
|
||||
Location signLocation = getLocation();
|
||||
if (signLocation == null
|
||||
|| signLocation.getWorld() == null
|
||||
|| !signLocation.getWorld().isChunkLoaded(signLocation.getBlockX() >> 4, signLocation.getBlockZ() >> 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply replacements and color and then set it on the sign
|
||||
for(int i = 0; i < signLines.length; i++) {
|
||||
if(signLines[i] == null) {
|
||||
signState.setLine(i, "");
|
||||
continue;
|
||||
}
|
||||
signLines[i] = Message.fromString(signLines[i]).replacements(getRegion()).getSingle();
|
||||
signLines[i] = Utils.applyColors(signLines[i]);
|
||||
signState.setLine(i, signLines[i]);
|
||||
}
|
||||
signState.update();
|
||||
return true;
|
||||
}
|
||||
if (getRegion().isDeleted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the sign needs to update periodically.
|
||||
* @return true if it needs periodic updates, otherwise false
|
||||
*/
|
||||
public boolean needsPeriodicUpdate() {
|
||||
ConfigurationSection signConfig = getProfile();
|
||||
if(signConfig == null || !signConfig.isSet(getRegion().getState().getValue().toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue().toLowerCase());
|
||||
// Check the lines for the timeleft tag
|
||||
for(int i = 1; i <= 4; i++) {
|
||||
String line = stateConfig.getString("line" + i);
|
||||
if(line != null && !line.isEmpty() && line.contains(Message.VARIABLE_START + AreaShop.tagTimeLeft + Message.VARIABLE_END)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
YamlConfiguration regionConfig = getRegion().getConfig();
|
||||
ConfigurationSection signConfig = getProfile();
|
||||
Block block = signLocation.getBlock();
|
||||
if (signConfig == null || !signConfig.isSet(getRegion().getState().getValue())) {
|
||||
block.setType(Material.AIR);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run commands when a player clicks a sign.
|
||||
* @param clicker The player that clicked the sign
|
||||
* @param clickType The type of clicking
|
||||
* @return true if the commands ran successfully, false if any of them failed
|
||||
*/
|
||||
public boolean runSignCommands(Player clicker, GeneralRegion.ClickType clickType) {
|
||||
ConfigurationSection signConfig = getProfile();
|
||||
if(signConfig == null) {
|
||||
return false;
|
||||
}
|
||||
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue().toLowerCase());
|
||||
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue());
|
||||
assert stateConfig != null;
|
||||
// Get the lines
|
||||
String[] signLines = new String[4];
|
||||
boolean signEmpty = true;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
signLines[i] = stateConfig.getString("line" + (i + 1));
|
||||
signEmpty &= (signLines[i] == null || signLines[i].isEmpty());
|
||||
}
|
||||
if (signEmpty) {
|
||||
block.setType(Material.AIR);
|
||||
return true;
|
||||
}
|
||||
final BlockStateSnapshotResult snapshot = PaperLib.getBlockState(block, false);
|
||||
final BlockState blockState = snapshot.getState();
|
||||
final BlockData blockData = blockState.getBlockData();
|
||||
final SignErrorLogger errorLogger = AreaShop.getInstance().getSignErrorLogger();
|
||||
Material signType = getMaterial();
|
||||
// Place the sign back (with proper rotation and type) after it has been hidden or (indirectly) destroyed
|
||||
if (!Materials.isSign(blockState.getType())) {
|
||||
// Don't do physics here, we first need to update the direction
|
||||
blockState.setType(signType);
|
||||
if (blockData instanceof WallSign) {
|
||||
((WallSign) blockData).setFacing(getFacing());
|
||||
} else if (blockData instanceof Sign) {
|
||||
((org.bukkit.block.data.type.Sign) blockData).setRotation(getFacing());
|
||||
}
|
||||
blockState.setBlockData(blockData);
|
||||
blockState.update(false, true);
|
||||
// Check if the sign has popped
|
||||
if (!Materials.isSign(block.getType())) {
|
||||
final String message = String.format("Setting sign of $1%s of region $2%s failed, could not set sign block back", key, getRegion().getName());
|
||||
errorLogger.submitWarning(message);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
final String message = "Setting sign $1%s of region $2%s failed, RegionSign material was: $3%s";
|
||||
errorLogger.submitWarning(String.format(message, key, getRegion().getName(), signType.name()));
|
||||
}
|
||||
|
||||
// Run player commands if specified
|
||||
List<String> playerCommands = new ArrayList<>();
|
||||
for(String command : stateConfig.getStringList(clickType.getValue() + "Player")) {
|
||||
// TODO move variable checking code to InteractiveMessenger?
|
||||
playerCommands.add(command.replace(Message.VARIABLE_START + AreaShop.tagClicker + Message.VARIABLE_END, clicker.getName()));
|
||||
}
|
||||
getRegion().runCommands(clicker, playerCommands);
|
||||
// Save current rotation and type
|
||||
if (!regionConfig.isString("general.signs." + key + ".signType")) {
|
||||
getRegion().setSetting("general.signs." + key + ".signType", block.getType().name());
|
||||
}
|
||||
if (!regionConfig.isString("general.signs." + key + ".facing")) {
|
||||
final BlockFace rotation;
|
||||
if (Materials.isSign(block.getType())) {
|
||||
BlockData data = blockState.getBlockData();
|
||||
if (data instanceof org.bukkit.block.data.type.Sign) {
|
||||
rotation = ((org.bukkit.block.data.type.Sign) block.getBlockData()).getRotation();
|
||||
} else if (data instanceof WallSign) {
|
||||
rotation = ((WallSign) data).getFacing();
|
||||
} else {
|
||||
rotation = null;
|
||||
}
|
||||
} else {
|
||||
rotation = null;
|
||||
}
|
||||
getRegion().setSetting("general.signs." + key + ".facing", rotation == null ? null : rotation.toString());
|
||||
}
|
||||
|
||||
// Run console commands if specified
|
||||
List<String> consoleCommands = new ArrayList<>();
|
||||
for(String command : stateConfig.getStringList(clickType.getValue() + "Console")) {
|
||||
consoleCommands.add(command.replace(Message.VARIABLE_START + AreaShop.tagClicker + Message.VARIABLE_END, clicker.getName()));
|
||||
}
|
||||
getRegion().runCommands(Bukkit.getConsoleSender(), consoleCommands);
|
||||
// Apply replacements and color and then set it on the sign
|
||||
Sign signState = (Sign) blockState;
|
||||
for (int i = 0; i < signLines.length; i++) {
|
||||
if (signLines[i] == null) {
|
||||
signState.setLine(i, "");
|
||||
continue;
|
||||
}
|
||||
signLines[i] = Message.fromString(signLines[i]).replacements(getRegion()).getSingle();
|
||||
signLines[i] = Utils.applyColors(signLines[i]);
|
||||
signState.setLine(i, signLines[i]);
|
||||
}
|
||||
// BlockState#update *should* return true here.
|
||||
return blockState.update(true, false);
|
||||
}
|
||||
|
||||
return !playerCommands.isEmpty() || !consoleCommands.isEmpty();
|
||||
}
|
||||
/**
|
||||
* Check if the sign needs to update periodically.
|
||||
*
|
||||
* @return true if it needs periodic updates, otherwise false
|
||||
*/
|
||||
public boolean needsPeriodicUpdate() {
|
||||
ConfigurationSection signConfig = getProfile();
|
||||
if (signConfig == null || !signConfig.isSet(getRegion().getState().getValue().toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof RegionSign && ((RegionSign)object).getRegion().equals(this.getRegion()) && ((RegionSign)object).key.equals(this.key);
|
||||
}
|
||||
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue().toLowerCase());
|
||||
if (stateConfig == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(key, getRegion().getName());
|
||||
}
|
||||
// Check the lines for the timeleft tag
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
String line = stateConfig.getString("line" + i);
|
||||
if (line != null && !line.isEmpty() && line.contains(Message.VARIABLE_START + AreaShop.tagTimeLeft + Message.VARIABLE_END)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run commands when a player clicks a sign.
|
||||
*
|
||||
* @param clicker The player that clicked the sign
|
||||
* @param clickType The type of clicking
|
||||
* @return true if the commands ran successfully, false if any of them failed
|
||||
*/
|
||||
public boolean runSignCommands(Player clicker, GeneralRegion.ClickType clickType) {
|
||||
ConfigurationSection signConfig = getProfile();
|
||||
if (signConfig == null) {
|
||||
return false;
|
||||
}
|
||||
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue().toLowerCase());
|
||||
|
||||
// Run player commands if specified
|
||||
List<String> playerCommands = new ArrayList<>();
|
||||
for (String command : stateConfig.getStringList(clickType.getValue() + "Player")) {
|
||||
// TODO move variable checking code to InteractiveMessenger?
|
||||
playerCommands.add(command.replace(Message.VARIABLE_START + AreaShop.tagClicker + Message.VARIABLE_END, clicker.getName()));
|
||||
}
|
||||
getRegion().runCommands(clicker, playerCommands);
|
||||
|
||||
// Run console commands if specified
|
||||
List<String> consoleCommands = new ArrayList<>();
|
||||
for (String command : stateConfig.getStringList(clickType.getValue() + "Console")) {
|
||||
consoleCommands.add(command.replace(Message.VARIABLE_START + AreaShop.tagClicker + Message.VARIABLE_END, clicker.getName()));
|
||||
}
|
||||
getRegion().runCommands(Bukkit.getConsoleSender(), consoleCommands);
|
||||
|
||||
return !playerCommands.isEmpty() || !consoleCommands.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof RegionSign && ((RegionSign) object).getRegion().equals(this.getRegion()) && ((RegionSign) object).key.equals(this.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(key, getRegion().getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package me.wiefferink.areashop.features.signs;
|
||||
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.events.notify.UpdateRegionEvent;
|
||||
import me.wiefferink.areashop.tools.Utils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SignCache implements Listener {
|
||||
|
||||
private final Map<String, RegionSign> allSigns = new HashMap<>();
|
||||
private final Map<String, List<RegionSign>> signsByChunk = new HashMap<>();
|
||||
|
||||
public void registerListeners() {
|
||||
Bukkit.getPluginManager().registerEvents(this, AreaShop.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a location to a string to use as map key.
|
||||
*
|
||||
* @param location The location to get the key for
|
||||
* @return A string to use in a map for a location
|
||||
*/
|
||||
public static String locationToString(Location location) {
|
||||
return location.getWorld().getName() + ";" + location.getBlockX() + ";" + location.getBlockY() + ";" + location.getBlockZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a chunk to a string to use as map key.
|
||||
*
|
||||
* @param location The location to get the key for
|
||||
* @return A string to use in a map for a chunk
|
||||
*/
|
||||
public static String chunkToString(Location location) {
|
||||
return location.getWorld().getName() + ";" + (location.getBlockX() >> 4) + ";" + (location.getBlockZ() >> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a chunk to a string to use as map key.
|
||||
* Use a Location argument to prevent chunk loading!
|
||||
*
|
||||
* @param chunk The location to get the key for
|
||||
* @return A string to use in a map for a chunk
|
||||
*/
|
||||
public static String chunkToString(Chunk chunk) {
|
||||
return chunk.getWorld().getName() + ";" + chunk.getX() + ";" + chunk.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sign by a location.
|
||||
*
|
||||
* @param location The location to get the sign for
|
||||
* @return The RegionSign that is at the location, or null if none
|
||||
*/
|
||||
public RegionSign getSignByLocation(Location location) {
|
||||
return allSigns.get(locationToString(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map with all signs.
|
||||
*
|
||||
* @return Map with all signs: locationString -> RegionSign
|
||||
*/
|
||||
public Map<String, RegionSign> getAllSigns() {
|
||||
return allSigns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map with signs by chunk.
|
||||
*
|
||||
* @return Map with signs by chunk: chunkString -> List<RegionSign>
|
||||
*/
|
||||
public Map<String, List<RegionSign>> getSignsByChunk() {
|
||||
return signsByChunk;
|
||||
}
|
||||
|
||||
public void addSign(RegionSign regionSign) {
|
||||
signsByChunk.computeIfAbsent(regionSign.getStringChunk(), (unused) -> new ArrayList<>()).add(regionSign);
|
||||
}
|
||||
|
||||
public void removeSign(RegionSign regionSign) {
|
||||
final List<RegionSign> signs = signsByChunk.get(regionSign.getStringChunk());
|
||||
if (signs != null) {
|
||||
signs.remove(regionSign);
|
||||
}
|
||||
allSigns.remove(regionSign.getStringLocation());
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
HandlerList.unregisterAll(this);
|
||||
signsByChunk.clear();
|
||||
allSigns.clear();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void regionUpdate(UpdateRegionEvent event) {
|
||||
event.getRegion().getSignsFeature().update();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
List<RegionSign> chunkSigns = signsByChunk.get(chunkToString(event.getChunk()));
|
||||
if (chunkSigns == null) {
|
||||
return;
|
||||
}
|
||||
int batchSize = Math.max(chunkSigns.size() / 10, 10);
|
||||
Utils.runAsBatches(chunkSigns, batchSize, RegionSign::update, false);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,769 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Tyler Blair. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and contributors and should not be interpreted as representing official policies,
|
||||
* either expressed or implied, of anybody else.
|
||||
*/
|
||||
|
||||
package me.wiefferink.areashop.lib;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class Metrics {
|
||||
|
||||
/**
|
||||
* The current revision number.
|
||||
*/
|
||||
private static final int REVISION = 7;
|
||||
|
||||
/**
|
||||
* The base url of the metrics domain.
|
||||
*/
|
||||
private static final String BASE_URL = "http://report.mcstats.org";
|
||||
|
||||
/**
|
||||
* The url used to report a server's status.
|
||||
*/
|
||||
private static final String REPORT_URL = "/plugin/%s";
|
||||
|
||||
/**
|
||||
* Interval of time to ping (in minutes).
|
||||
*/
|
||||
private static final int PING_INTERVAL = 15;
|
||||
|
||||
/**
|
||||
* The plugin this metrics submits for.
|
||||
*/
|
||||
private final Plugin plugin;
|
||||
|
||||
/**
|
||||
* All of the custom graphs to submit to metrics.
|
||||
*/
|
||||
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
|
||||
|
||||
/**
|
||||
* The plugin configuration file.
|
||||
*/
|
||||
private final YamlConfiguration configuration;
|
||||
|
||||
/**
|
||||
* The plugin configuration file.
|
||||
*/
|
||||
private final File configurationFile;
|
||||
|
||||
/**
|
||||
* Unique server id.
|
||||
*/
|
||||
private final String guid;
|
||||
|
||||
/**
|
||||
* Debug mode.
|
||||
*/
|
||||
private final boolean debug;
|
||||
|
||||
/**
|
||||
* Lock for synchronization.
|
||||
*/
|
||||
private final Object optOutLock = new Object();
|
||||
|
||||
/**
|
||||
* The scheduled task.
|
||||
*/
|
||||
private volatile BukkitTask task = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param plugin The plugin to report stats for
|
||||
* @throws IOException When the plugin or configuration is wrong
|
||||
*/
|
||||
public Metrics(final Plugin plugin) throws IOException {
|
||||
if(plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null");
|
||||
}
|
||||
|
||||
this.plugin = plugin;
|
||||
|
||||
// load the config
|
||||
configurationFile = getConfigFile();
|
||||
configuration = YamlConfiguration.loadConfiguration(configurationFile);
|
||||
|
||||
// add some defaults
|
||||
configuration.addDefault("opt-out", false);
|
||||
configuration.addDefault("guid", UUID.randomUUID().toString());
|
||||
configuration.addDefault("debug", false);
|
||||
|
||||
// Do we need to create the file?
|
||||
if(configuration.get("guid", null) == null) {
|
||||
configuration.options().header("http://mcstats.org").copyDefaults(true);
|
||||
configuration.save(configurationFile);
|
||||
}
|
||||
|
||||
// Load the guid then
|
||||
guid = configuration.getString("guid");
|
||||
debug = configuration.getBoolean("debug", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
|
||||
* website. Plotters can be added to the graph object returned.
|
||||
* @param name The name of the graph
|
||||
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
|
||||
*/
|
||||
public Graph createGraph(final String name) {
|
||||
if(name == null) {
|
||||
throw new IllegalArgumentException("Graph name cannot be null");
|
||||
}
|
||||
|
||||
// Construct the graph object
|
||||
final Graph graph = new Graph(name);
|
||||
|
||||
// Now we can add our graph
|
||||
graphs.add(graph);
|
||||
|
||||
// and return back
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend.
|
||||
* @param graph The name of the graph
|
||||
*/
|
||||
public void addGraph(final Graph graph) {
|
||||
if(graph == null) {
|
||||
throw new IllegalArgumentException("Graph cannot be null");
|
||||
}
|
||||
|
||||
graphs.add(graph);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
|
||||
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
|
||||
* ticks.
|
||||
* @return True if statistics measuring is running, otherwise false.
|
||||
*/
|
||||
public boolean start() {
|
||||
synchronized(optOutLock) {
|
||||
// Did we opt out?
|
||||
if(isOptOut()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is metrics already running?
|
||||
if(task != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Begin hitting the server with glorious data
|
||||
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
|
||||
|
||||
private boolean firstPost = true;
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
// This has to be synchronized or it can collide with the disable method.
|
||||
synchronized(optOutLock) {
|
||||
// Disable Task, if it is running and the server owner decided to opt-out
|
||||
if(isOptOut() && task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
// Tell all plotters to stop gathering information.
|
||||
for(Graph graph : graphs) {
|
||||
graph.onOptOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We use the inverse of firstPost because if it is the first time we are posting,
|
||||
// it is not a interval ping, so it evaluates to FALSE
|
||||
// Each time thereafter it will evaluate to TRUE, i.e PING!
|
||||
postPlugin(!firstPost);
|
||||
|
||||
// After the first post we set firstPost to false
|
||||
// Each post thereafter will be a ping
|
||||
firstPost = false;
|
||||
} catch(IOException e) {
|
||||
if(debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, PING_INTERVAL * 1200);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the server owner denied plugin metrics.
|
||||
* @return true if metrics should be opted out of it
|
||||
*/
|
||||
public boolean isOptOut() {
|
||||
synchronized(optOutLock) {
|
||||
try {
|
||||
// Reload the metrics file
|
||||
configuration.load(getConfigFile());
|
||||
} catch(IOException ex) {
|
||||
if(debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
return true;
|
||||
} catch(InvalidConfigurationException ex) {
|
||||
if(debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return configuration.getBoolean("opt-out", false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
|
||||
* @throws IOException when saving the config file fails
|
||||
*/
|
||||
public void enable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the task.
|
||||
synchronized(optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set it.
|
||||
if(isOptOut()) {
|
||||
configuration.set("opt-out", false);
|
||||
configuration.save(configurationFile);
|
||||
}
|
||||
|
||||
// Enable Task, if it is not running
|
||||
if(task == null) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
|
||||
* @throws IOException when saving the config file fails
|
||||
*/
|
||||
public void disable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the task.
|
||||
synchronized(optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set it.
|
||||
if(!isOptOut()) {
|
||||
configuration.set("opt-out", true);
|
||||
configuration.save(configurationFile);
|
||||
}
|
||||
|
||||
// Disable Task, if it is running
|
||||
if(task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status.
|
||||
* @return the File object for the config file
|
||||
*/
|
||||
public File getConfigFile() {
|
||||
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
|
||||
// is to abuse the plugin object we already have
|
||||
// plugin.getDataFolder() => base/plugins/PluginA/
|
||||
// pluginsFolder => base/plugins/
|
||||
// The base is not necessarily relative to the startup directory.
|
||||
File pluginsFolder = plugin.getDataFolder().getParentFile();
|
||||
|
||||
// return => base/plugins/PluginMetrics/config.yml
|
||||
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the online player (backwards compatibility).
|
||||
* @return online player amount
|
||||
*/
|
||||
private int getOnlinePlayers() {
|
||||
try {
|
||||
Method onlinePlayerMethod = Server.class.getMethod("getOnlinePlayers");
|
||||
if(onlinePlayerMethod.getReturnType().equals(Collection.class)) {
|
||||
return ((Collection<?>)onlinePlayerMethod.invoke(Bukkit.getServer())).size();
|
||||
} else {
|
||||
return ((Player[])onlinePlayerMethod.invoke(Bukkit.getServer())).length;
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
if(debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method that posts a plugin to the metrics website.
|
||||
*/
|
||||
private void postPlugin(final boolean isPing) throws IOException {
|
||||
// Server software specific section
|
||||
PluginDescriptionFile description = plugin.getDescription();
|
||||
String pluginName = description.getName();
|
||||
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
|
||||
String pluginVersion = description.getVersion();
|
||||
String serverVersion = Bukkit.getVersion();
|
||||
int playersOnline = this.getOnlinePlayers();
|
||||
|
||||
// END server software specific section -- all code below does not use any code outside of this class / Java
|
||||
|
||||
// Construct the post data
|
||||
StringBuilder json = new StringBuilder(1024);
|
||||
json.append('{');
|
||||
|
||||
// The plugin's description file containg all of the plugin data such as name, version, author, etc
|
||||
appendJsonPair(json, "guid", guid);
|
||||
appendJsonPair(json, "plugin_version", pluginVersion);
|
||||
appendJsonPair(json, "server_version", serverVersion);
|
||||
appendJsonPair(json, "players_online", Integer.toString(playersOnline));
|
||||
|
||||
// New data as of R6
|
||||
String osname = System.getProperty("os.name");
|
||||
String osarch = System.getProperty("os.arch");
|
||||
String osversion = System.getProperty("os.version");
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
// normalize os arch .. amd64 -> x86_64
|
||||
if(osarch.equals("amd64")) {
|
||||
osarch = "x86_64";
|
||||
}
|
||||
|
||||
appendJsonPair(json, "osname", osname);
|
||||
appendJsonPair(json, "osarch", osarch);
|
||||
appendJsonPair(json, "osversion", osversion);
|
||||
appendJsonPair(json, "cores", Integer.toString(coreCount));
|
||||
appendJsonPair(json, "auth_mode", onlineMode ? "1" : "0");
|
||||
appendJsonPair(json, "java_version", javaVersion);
|
||||
|
||||
// If we're pinging, append it
|
||||
if(isPing) {
|
||||
appendJsonPair(json, "ping", "1");
|
||||
}
|
||||
|
||||
if(graphs.size() > 0) {
|
||||
synchronized(graphs) {
|
||||
json.append(',');
|
||||
json.append('"');
|
||||
json.append("graphs");
|
||||
json.append('"');
|
||||
json.append(':');
|
||||
json.append('{');
|
||||
|
||||
boolean firstGraph = true;
|
||||
|
||||
final Iterator<Graph> iter = graphs.iterator();
|
||||
|
||||
while(iter.hasNext()) {
|
||||
Graph graph = iter.next();
|
||||
|
||||
StringBuilder graphJson = new StringBuilder();
|
||||
graphJson.append('{');
|
||||
|
||||
for(Plotter plotter : graph.getPlotters()) {
|
||||
appendJsonPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue()));
|
||||
}
|
||||
|
||||
graphJson.append('}');
|
||||
|
||||
if(!firstGraph) {
|
||||
json.append(',');
|
||||
}
|
||||
|
||||
json.append(escapeJson(graph.getName()));
|
||||
json.append(':');
|
||||
json.append(graphJson);
|
||||
|
||||
firstGraph = false;
|
||||
}
|
||||
|
||||
json.append('}');
|
||||
}
|
||||
}
|
||||
|
||||
// close json
|
||||
json.append('}');
|
||||
|
||||
// Create the url
|
||||
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
|
||||
|
||||
// Connect to the website
|
||||
URLConnection connection;
|
||||
|
||||
// Mineshafter creates a socks proxy, so we can safely bypass it
|
||||
// It does not reroute POST requests so we need to go around it
|
||||
if(isMineshafterPresent()) {
|
||||
connection = url.openConnection(Proxy.NO_PROXY);
|
||||
} else {
|
||||
connection = url.openConnection();
|
||||
}
|
||||
|
||||
|
||||
byte[] uncompressed = json.toString().getBytes();
|
||||
byte[] compressed = gzip(json.toString());
|
||||
|
||||
// Headers
|
||||
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
|
||||
connection.addRequestProperty("Content-Type", "application/json");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
|
||||
connection.setDoOutput(true);
|
||||
|
||||
if(debug) {
|
||||
System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
|
||||
}
|
||||
|
||||
// Write the data
|
||||
OutputStream os = connection.getOutputStream();
|
||||
os.write(compressed);
|
||||
os.flush();
|
||||
|
||||
// Now read the response
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String response = reader.readLine();
|
||||
|
||||
// close resources
|
||||
os.close();
|
||||
reader.close();
|
||||
|
||||
if(response == null || response.startsWith("ERR") || response.startsWith("7")) {
|
||||
if(response == null) {
|
||||
response = "null";
|
||||
} else if(response.startsWith("7")) {
|
||||
response = response.substring(response.startsWith("7,") ? 2 : 1);
|
||||
}
|
||||
|
||||
throw new IOException(response);
|
||||
} else {
|
||||
// Is this the first update this hour?
|
||||
if(response.equals("1") || response.contains("This is your first update this hour")) {
|
||||
synchronized(graphs) {
|
||||
final Iterator<Graph> iter = graphs.iterator();
|
||||
|
||||
while(iter.hasNext()) {
|
||||
final Graph graph = iter.next();
|
||||
|
||||
for(Plotter plotter : graph.getPlotters()) {
|
||||
plotter.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GZip compress a string of bytes.
|
||||
* @param input Content to gzip
|
||||
* @return byte[] of the gzipped input
|
||||
*/
|
||||
public static byte[] gzip(String input) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzos = null;
|
||||
|
||||
try {
|
||||
gzos = new GZIPOutputStream(baos);
|
||||
gzos.write(input.getBytes(StandardCharsets.UTF_8));
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(gzos != null) {
|
||||
try {
|
||||
gzos.close();
|
||||
} catch(IOException ignore) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
|
||||
* @return true if mineshafter is installed on the server
|
||||
*/
|
||||
private boolean isMineshafterPresent() {
|
||||
try {
|
||||
Class.forName("mineshafter.MineServer");
|
||||
return true;
|
||||
} catch(Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a json encoded key/value pair to the given string builder.
|
||||
*/
|
||||
private static void appendJsonPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
|
||||
boolean isValueNumeric = false;
|
||||
|
||||
try {
|
||||
if(value.equals("0") || !value.endsWith("0")) {
|
||||
Double.parseDouble(value);
|
||||
isValueNumeric = true;
|
||||
}
|
||||
} catch(NumberFormatException e) {
|
||||
isValueNumeric = false;
|
||||
}
|
||||
|
||||
if(json.charAt(json.length() - 1) != '{') {
|
||||
json.append(',');
|
||||
}
|
||||
|
||||
json.append(escapeJson(key));
|
||||
json.append(':');
|
||||
|
||||
if(isValueNumeric) {
|
||||
json.append(value);
|
||||
} else {
|
||||
json.append(escapeJson(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string to create a valid JSON string.
|
||||
*/
|
||||
private static String escapeJson(String text) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append('"');
|
||||
for(int index = 0; index < text.length(); index++) {
|
||||
char chr = text.charAt(index);
|
||||
|
||||
switch(chr) {
|
||||
case '"':
|
||||
case '\\':
|
||||
builder.append('\\');
|
||||
builder.append(chr);
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
default:
|
||||
if(chr < ' ') {
|
||||
String t = "000" + Integer.toHexString(chr);
|
||||
builder.append("\\u" + t.substring(t.length() - 4));
|
||||
} else {
|
||||
builder.append(chr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
builder.append('"');
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode text as UTF-8.
|
||||
* @param text the text to encode
|
||||
* @return the encoded text, as UTF-8
|
||||
*/
|
||||
private static String urlEncode(final String text) throws UnsupportedEncodingException {
|
||||
return URLEncoder.encode(text, "UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom graph on the website.
|
||||
*/
|
||||
public static class Graph {
|
||||
|
||||
/**
|
||||
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
|
||||
* rejected.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The set of plotters that are contained within this graph.
|
||||
*/
|
||||
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
|
||||
|
||||
private Graph(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the graph's name.
|
||||
* @return the Graph's name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plotter to the graph, which will be used to plot entries.
|
||||
* @param plotter the plotter to add to the graph
|
||||
*/
|
||||
public void addPlotter(final Plotter plotter) {
|
||||
plotters.add(plotter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a plotter from the graph.
|
||||
* @param plotter the plotter to remove from the graph
|
||||
*/
|
||||
public void removePlotter(final Plotter plotter) {
|
||||
plotters.remove(plotter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph.
|
||||
* @return an unmodifiable {@link java.util.Set} of the plotter objects
|
||||
*/
|
||||
public Set<Plotter> getPlotters() {
|
||||
return Collections.unmodifiableSet(plotters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if(!(object instanceof Graph)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Graph graph = (Graph)object;
|
||||
return graph.name.equals(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
|
||||
*/
|
||||
protected void onOptOut() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to collect custom data for a plugin.
|
||||
*/
|
||||
public abstract static class Plotter {
|
||||
|
||||
/**
|
||||
* The plot's name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Construct a plotter with the default plot name.
|
||||
*/
|
||||
public Plotter() {
|
||||
this("Default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a plotter with a specific plot name.
|
||||
* @param name the name of the plotter to use, which will show up on the website
|
||||
*/
|
||||
public Plotter(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current value for the plotted point. Since this function defers to an external function it may or may
|
||||
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
|
||||
* from any thread so care should be taken when accessing resources that need to be synchronized.
|
||||
* @return the current value for the point to be plotted.
|
||||
*/
|
||||
public abstract int getValue();
|
||||
|
||||
/**
|
||||
* Get the column name for the plotted point.
|
||||
* @return the plotted point's column name
|
||||
*/
|
||||
public String getColumnName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the website graphs have been updated.
|
||||
*/
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getColumnName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if(!(object instanceof Plotter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Plotter plotter = (Plotter)object;
|
||||
return plotter.name.equals(name) && plotter.getValue() == getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
-98
@@ -5,7 +5,6 @@ import me.wiefferink.areashop.regions.BuyRegion;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import me.wiefferink.areashop.regions.RentRegion;
|
||||
import me.wiefferink.areashop.tools.Utils;
|
||||
import me.wiefferink.bukkitdo.Do;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -22,112 +21,109 @@ import java.util.List;
|
||||
* Notify region expiry and track activity time.
|
||||
*/
|
||||
public final class PlayerLoginLogoutListener implements Listener {
|
||||
private final AreaShop plugin;
|
||||
private final AreaShop plugin;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param plugin The AreaShop plugin
|
||||
*/
|
||||
public PlayerLoginLogoutListener(AreaShop plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param plugin The AreaShop plugin
|
||||
*/
|
||||
public PlayerLoginLogoutListener(AreaShop plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a sign is changed.
|
||||
* @param event The event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
if(event.getResult() != Result.ALLOWED) {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
/**
|
||||
* Called when a sign is changed.
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
if (event.getResult() != Result.ALLOWED) {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
// Schedule task to check for notifications, prevents a lag spike at login
|
||||
Do.syncTimerLater(25, 25, () -> {
|
||||
// Delay until all regions are loaded
|
||||
if(!plugin.isReady()) {
|
||||
return true;
|
||||
}
|
||||
if(!player.isOnline()) {
|
||||
return false;
|
||||
}
|
||||
// Notify for rents that almost run out
|
||||
for(RentRegion region : plugin.getFileManager().getRents()) {
|
||||
if(region.isRenter(player)) {
|
||||
String warningSetting = region.getStringSetting("rent.warningOnLoginTime");
|
||||
if(warningSetting == null || warningSetting.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
long warningTime = Utils.durationStringToLong(warningSetting);
|
||||
if(region.getTimeLeft() < warningTime) {
|
||||
// Send the warning message later to let it appear after general MOTD messages
|
||||
AreaShop.getInstance().message(player, "rent-expireWarning", region);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Schedule task to check for notifications, prevents a lag spike at login
|
||||
Utils.runCancellingTaskTimer(() -> {
|
||||
// Delay until all regions are loaded
|
||||
if (!plugin.isReady()) {
|
||||
return true;
|
||||
}
|
||||
if (!player.isOnline()) {
|
||||
return false;
|
||||
}
|
||||
// Notify for rents that almost run out
|
||||
for (RentRegion region : plugin.getFileManager().getRents()) {
|
||||
if (region.isRenter(player)) {
|
||||
String warningSetting = region.getStringSetting("rent.warningOnLoginTime");
|
||||
if (warningSetting == null || warningSetting.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
long warningTime = Utils.durationStringToLong(warningSetting);
|
||||
if (region.getTimeLeft() < warningTime) {
|
||||
// Send the warning message later to let it appear after general MOTD messages
|
||||
AreaShop.getInstance().message(player, "rent-expireWarning", region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify admins for plugin updates
|
||||
AreaShop.getInstance().notifyUpdate(player);
|
||||
return false;
|
||||
});
|
||||
// Notify admins for plugin updates
|
||||
AreaShop.getInstance().notifyUpdate(player);
|
||||
return false;
|
||||
}, 25, 25, false);
|
||||
|
||||
// Check if the player has regions that use an old name of him and update them
|
||||
Do.syncTimerLater(22, 10, () -> {
|
||||
if(!plugin.isReady()) {
|
||||
return true;
|
||||
}
|
||||
// Check if the player has regions that use an old name of him and update them
|
||||
Utils.runCancellingTaskTimer(() -> {
|
||||
if (!plugin.isReady()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<GeneralRegion> regions = new ArrayList<>();
|
||||
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
|
||||
if(region.isOwner(player)) {
|
||||
regions.add(region);
|
||||
}
|
||||
}
|
||||
List<GeneralRegion> regions = new ArrayList<>();
|
||||
for (GeneralRegion region : plugin.getFileManager().getRegions()) {
|
||||
if (region.isOwner(player)) {
|
||||
regions.add(region);
|
||||
}
|
||||
}
|
||||
final String name = player.getName();
|
||||
Utils.runAsBatches(regions,
|
||||
plugin.getConfig().getInt("nameupdate.regionsPerTick"),
|
||||
(region) -> {
|
||||
if (region instanceof BuyRegion || region instanceof RentRegion) {
|
||||
String key = region instanceof BuyRegion ? "buy.buyerName" : "rent.renterName";
|
||||
if (!name.equals(region.getStringSetting("buy.buyerName"))) {
|
||||
region.setSetting(key, player.getName());
|
||||
region.update();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
return false;
|
||||
}, 22, 10, false);
|
||||
}
|
||||
|
||||
Do.forAll(
|
||||
plugin.getConfig().getInt("nameupdate.regionsPerTick"),
|
||||
regions,
|
||||
region -> {
|
||||
if(region instanceof BuyRegion) {
|
||||
if(!player.getName().equals(region.getStringSetting("buy.buyerName"))) {
|
||||
region.setSetting("buy.buyerName", player.getName());
|
||||
region.update();
|
||||
}
|
||||
} else if(region instanceof RentRegion) {
|
||||
if(!player.getName().equals(region.getStringSetting("rent.renterName"))) {
|
||||
region.setSetting("rent.renterName", player.getName());
|
||||
region.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
// Active time updates
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLogout(PlayerQuitEvent event) {
|
||||
updateLastActive(event.getPlayer());
|
||||
}
|
||||
|
||||
// Active time updates
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLogout(PlayerQuitEvent event) {
|
||||
updateLastActive(event.getPlayer());
|
||||
}
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerKick(PlayerKickEvent event) {
|
||||
updateLastActive(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerKick(PlayerKickEvent event) {
|
||||
updateLastActive(event.getPlayer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the last active time for all regions the player is owner off.
|
||||
* @param player The player to update the active times for
|
||||
*/
|
||||
private void updateLastActive(Player player) {
|
||||
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
|
||||
if(region.isOwner(player)) {
|
||||
region.updateLastActiveTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update the last active time for all regions the player is owner off.
|
||||
*
|
||||
* @param player The player to update the active times for
|
||||
*/
|
||||
private void updateLastActive(Player player) {
|
||||
for (GeneralRegion region : plugin.getFileManager().getRegions()) {
|
||||
if (region.isOwner(player)) {
|
||||
region.updateLastActiveTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,17 +34,11 @@ import me.wiefferink.areashop.commands.StackCommand;
|
||||
import me.wiefferink.areashop.commands.StopresellCommand;
|
||||
import me.wiefferink.areashop.commands.TeleportCommand;
|
||||
import me.wiefferink.areashop.commands.UnrentCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.command.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
|
||||
public class CommandManager extends Manager implements CommandExecutor, TabCompleter {
|
||||
public class CommandManager extends Manager implements TabExecutor {
|
||||
private final ArrayList<CommandAreaShop> commands;
|
||||
|
||||
/**
|
||||
@@ -88,14 +82,13 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl
|
||||
|
||||
// Register commands in bukkit
|
||||
plugin.getCommand("AreaShop").setExecutor(this);
|
||||
plugin.getCommand("AreaShop").setTabCompleter(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list with AreaShop commands.
|
||||
* @return The list with AreaShop commands
|
||||
*/
|
||||
public ArrayList<CommandAreaShop> getCommands() {
|
||||
public List<CommandAreaShop> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
@@ -114,7 +107,7 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl
|
||||
plugin.message(target, "help-alias");
|
||||
for(CommandAreaShop command : commands) {
|
||||
String help = command.getHelp(target);
|
||||
if(help != null && help.length() != 0) {
|
||||
if(help != null && !help.isEmpty()) {
|
||||
messages.add(help);
|
||||
}
|
||||
}
|
||||
@@ -130,11 +123,13 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl
|
||||
plugin.message(sender, "general-notReady");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Redirect `/as info player <player>` to `/as me <player>`
|
||||
if(args.length == 3 && "info".equals(args[0]) && "player".equals(args[1])) {
|
||||
args[0] = "me";
|
||||
args[1] = args[2];
|
||||
}
|
||||
|
||||
// Execute command
|
||||
boolean executed = false;
|
||||
for(int i = 0; i < commands.size() && !executed; i++) {
|
||||
@@ -143,25 +138,30 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl
|
||||
executed = true;
|
||||
}
|
||||
}
|
||||
if(!executed && args.length == 0) {
|
||||
this.showHelp(sender);
|
||||
} else if(!executed && args.length > 0) {
|
||||
// Indicate that the '/as updaterents' and '/as updatebuys' commands are removed
|
||||
if("updaterents".equalsIgnoreCase(args[0]) || "updatebuys".equalsIgnoreCase(args[0])) {
|
||||
plugin.message(sender, "reload-updateCommandChanged");
|
||||
|
||||
// Show help
|
||||
if (!executed) {
|
||||
if (args.length == 0) {
|
||||
this.showHelp(sender);
|
||||
} else {
|
||||
plugin.message(sender, "cmd-notValid");
|
||||
// Indicate that the '/as updaterents' and '/as updatebuys' commands are removed
|
||||
if("updaterents".equalsIgnoreCase(args[0]) || "updatebuys".equalsIgnoreCase(args[0])) {
|
||||
plugin.message(sender, "reload-updateCommandChanged");
|
||||
} else {
|
||||
plugin.message(sender, "cmd-notValid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if(!sender.hasPermission("areashop.tabcomplete")) {
|
||||
return result;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> result = new ArrayList<>();
|
||||
int toCompleteNumber = args.length;
|
||||
String toCompletePrefix = args[args.length - 1].toLowerCase();
|
||||
//AreaShop.debug("toCompleteNumber=" + toCompleteNumber + ", toCompletePrefix=" + toCompletePrefix + ", length=" + toCompletePrefix.length());
|
||||
@@ -181,7 +181,7 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl
|
||||
}
|
||||
}
|
||||
// Filter and sort the results
|
||||
if(result.size() > 0) {
|
||||
if(!result.isEmpty()) {
|
||||
SortedSet<String> set = new TreeSet<>();
|
||||
for(String suggestion : result) {
|
||||
if(suggestion.toLowerCase().startsWith(toCompletePrefix)) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.wiefferink.areashop.managers;
|
||||
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.features.CommandsFeature;
|
||||
import me.wiefferink.areashop.features.DebugFeature;
|
||||
import me.wiefferink.areashop.features.FriendsFeature;
|
||||
import me.wiefferink.areashop.features.RegionFeature;
|
||||
@@ -25,7 +26,8 @@ public class FeatureManager extends Manager {
|
||||
SignsFeature.class,
|
||||
FriendsFeature.class,
|
||||
WorldGuardRegionFlagsFeature.class,
|
||||
TeleportFeature.class
|
||||
TeleportFeature.class,
|
||||
CommandsFeature.class
|
||||
));
|
||||
// One instance of each feature, registered for event handling
|
||||
private final Set<RegionFeature> globalFeatures;
|
||||
@@ -40,13 +42,11 @@ public class FeatureManager extends Manager {
|
||||
for(Class<? extends RegionFeature> clazz : featureClasses) {
|
||||
try {
|
||||
Constructor<? extends RegionFeature> constructor = clazz.getConstructor();
|
||||
try {
|
||||
RegionFeature feature = constructor.newInstance();
|
||||
feature.listen();
|
||||
globalFeatures.add(feature);
|
||||
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
|
||||
AreaShop.error("Failed to instantiate global feature:", clazz, e);
|
||||
}
|
||||
RegionFeature feature = constructor.newInstance();
|
||||
feature.listen();
|
||||
globalFeatures.add(feature);
|
||||
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
|
||||
AreaShop.error("Failed to instantiate global feature:", clazz, e);
|
||||
} catch(NoSuchMethodException e) {
|
||||
// Feature does not have a global part
|
||||
}
|
||||
@@ -68,6 +68,8 @@ public class FeatureManager extends Manager {
|
||||
for(RegionFeature feature : globalFeatures) {
|
||||
feature.shutdown();
|
||||
}
|
||||
// FIXME make this system less hacky!
|
||||
SignsFeature.shutdownGlobalState();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +82,7 @@ public class FeatureManager extends Manager {
|
||||
try {
|
||||
return regionFeatureConstructors.get(featureClazz).newInstance(region);
|
||||
} catch(InstantiationException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
|
||||
AreaShop.error("Failed to instanciate feature", featureClazz, "for region", region, e, e.getCause());
|
||||
AreaShop.error("Failed to instantiate feature", featureClazz, "for region", region, e, e.getCause());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,79 @@
|
||||
package me.wiefferink.areashop.managers;
|
||||
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Date;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class SignErrorLogger {
|
||||
|
||||
public static final String PREFIX_WARN = "[Warning] [Sign Feature] ";
|
||||
public static final DateFormat FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
|
||||
|
||||
private final List<String> cache = new LinkedList<>();
|
||||
private final AtomicBoolean needsSaving = new AtomicBoolean(false);
|
||||
|
||||
private final File file;
|
||||
|
||||
public SignErrorLogger(File file) {
|
||||
this.file = Objects.requireNonNull(file);
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
synchronized (this.cache) {
|
||||
this.cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public SignErrorLogger submitWarning(String message) {
|
||||
final String actual = FORMAT.format(Date.from(Instant.now())) + PREFIX_WARN + message;
|
||||
synchronized (this.cache) {
|
||||
this.cache.add(actual);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void queueSave() {
|
||||
this.needsSaving.set(true);
|
||||
}
|
||||
|
||||
public void saveIfDirty() {
|
||||
if (this.needsSaving.get()) {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void save() {
|
||||
AreaShop.debugTask("[Sign Feature] Dumping sign errors to disk...");
|
||||
final String[] copy;
|
||||
synchronized (this.cache) {
|
||||
copy = cache.toArray(new String[0]);
|
||||
}
|
||||
final StringJoiner joiner = new StringJoiner(System.lineSeparator());
|
||||
for (String s : copy) {
|
||||
joiner.add(s);
|
||||
}
|
||||
try (OutputStream os = new FileOutputStream(file);
|
||||
OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
|
||||
writer.write(joiner.toString());
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
AreaShop.error("Failed to update the sign error log!");
|
||||
} finally {
|
||||
AreaShop.debugTask("[Sign Feature] Error dump complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,16 @@ package me.wiefferink.areashop.managers;
|
||||
import me.wiefferink.areashop.features.signs.RegionSign;
|
||||
import me.wiefferink.areashop.features.signs.SignsFeature;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import me.wiefferink.areashop.tools.Materials;
|
||||
import me.wiefferink.areashop.tools.Utils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Sign;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -17,7 +21,6 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.material.Sign;
|
||||
import org.bukkit.util.BlockIterator;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -120,7 +123,7 @@ public class SignLinkerManager extends Manager implements Listener {
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
|
||||
if(block == null || !Materials.isSign(block.getType())) {
|
||||
plugin.message(player, "linksigns-noSign");
|
||||
return;
|
||||
}
|
||||
@@ -130,8 +133,16 @@ public class SignLinkerManager extends Manager implements Listener {
|
||||
plugin.message(player, "linksigns-alreadyRegistered", regionSign.getRegion());
|
||||
return;
|
||||
}
|
||||
Sign sign = (Sign)block.getState().getData();
|
||||
linker.setSign(block.getLocation(), block.getType(), sign.getFacing());
|
||||
final BlockData blockData = block.getBlockData();
|
||||
final BlockFace rotation;
|
||||
if (blockData instanceof Sign) {
|
||||
rotation = ((Sign) blockData).getRotation();
|
||||
} else if (blockData instanceof WallSign) {
|
||||
rotation = ((WallSign) blockData).getFacing();
|
||||
} else {
|
||||
rotation = null;
|
||||
}
|
||||
linker.setSign(block.getLocation(), block.getType(), rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,189 +259,187 @@ public class BuyRegion extends GeneralRegion {
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean buy(OfflinePlayer offlinePlayer) {
|
||||
// Check if the player has permission
|
||||
if(plugin.hasPermission(offlinePlayer, "areashop.buy")) {
|
||||
if(plugin.getEconomy() == null) {
|
||||
message(offlinePlayer, "general-noEconomy");
|
||||
if(!plugin.hasPermission(offlinePlayer, "areashop.buy")) {
|
||||
message(offlinePlayer, "buy-noPermission");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(plugin.getEconomy() == null) {
|
||||
message(offlinePlayer, "general-noEconomy");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isInResellingMode()) {
|
||||
if(!plugin.hasPermission(offlinePlayer, "areashop.buyresell")) {
|
||||
message(offlinePlayer, "buy-noPermissionResell");
|
||||
return false;
|
||||
}
|
||||
if(isInResellingMode()) {
|
||||
if(!plugin.hasPermission(offlinePlayer, "areashop.buyresell")) {
|
||||
message(offlinePlayer, "buy-noPermissionResell");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(!plugin.hasPermission(offlinePlayer, "areashop.buynormal")) {
|
||||
message(offlinePlayer, "buy-noPermissionNoResell");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(getWorld() == null) {
|
||||
message(offlinePlayer, "general-noWorld");
|
||||
return false;
|
||||
}
|
||||
if(getRegion() == null) {
|
||||
message(offlinePlayer, "general-noRegion");
|
||||
return false;
|
||||
}
|
||||
if(!isSold() || (isInResellingMode() && !isBuyer(offlinePlayer))) {
|
||||
boolean isResell = isInResellingMode();
|
||||
|
||||
// Only relevant if the player is online
|
||||
Player player = offlinePlayer.getPlayer();
|
||||
if(player != null) {
|
||||
// Check if the players needs to be in the region for buying
|
||||
if(restrictedToRegion() && (!player.getWorld().getName().equals(getWorldName())
|
||||
|| !getRegion().contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
|
||||
message(offlinePlayer, "buy-restrictedToRegion");
|
||||
return false;
|
||||
}
|
||||
// Check if the players needs to be in the world for buying
|
||||
if(restrictedToWorld() && !player.getWorld().getName().equals(getWorldName())) {
|
||||
message(offlinePlayer, "buy-restrictedToWorld", player.getWorld().getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check region limits
|
||||
LimitResult limitResult = this.limitsAllow(RegionType.BUY, offlinePlayer);
|
||||
AreaShop.debug("LimitResult: " + limitResult.toString());
|
||||
if(!limitResult.actionAllowed()) {
|
||||
if(limitResult.getLimitingFactor() == LimitType.TOTAL) {
|
||||
message(offlinePlayer, "total-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
if(limitResult.getLimitingFactor() == LimitType.BUYS) {
|
||||
message(offlinePlayer, "buy-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
// Should not be reached, but is safe like this
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the player has enough money
|
||||
if((!isResell && plugin.getEconomy().has(offlinePlayer, getWorldName(), getPrice())) || (isResell && plugin.getEconomy().has(offlinePlayer, getWorldName(), getResellPrice()))) {
|
||||
UUID oldOwner = getBuyer();
|
||||
if(isResell && oldOwner != null) {
|
||||
// Broadcast and check event
|
||||
ResellingRegionEvent event = new ResellingRegionEvent(this, offlinePlayer);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if(event.isCancelled()) {
|
||||
message(offlinePlayer, "general-cancelled", event.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
getFriendsFeature().clearFriends();
|
||||
double resellPrice = getResellPrice();
|
||||
// Transfer the money to the previous owner
|
||||
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), getResellPrice());
|
||||
if(!r.transactionSuccess()) {
|
||||
message(offlinePlayer, "buy-payError");
|
||||
AreaShop.debug("Something went wrong with getting money from " + offlinePlayer.getName() + " while buying " + getName() + ": " + r.errorMessage);
|
||||
return false;
|
||||
}
|
||||
r = null;
|
||||
OfflinePlayer oldOwnerPlayer = Bukkit.getOfflinePlayer(oldOwner);
|
||||
String oldOwnerName = getPlayerName();
|
||||
if(oldOwnerPlayer != null && oldOwnerPlayer.getName() != null) {
|
||||
r = plugin.getEconomy().depositPlayer(oldOwnerPlayer, getWorldName(), getResellPrice());
|
||||
oldOwnerName = oldOwnerPlayer.getName();
|
||||
} else if(oldOwnerName != null) {
|
||||
r = plugin.getEconomy().depositPlayer(oldOwnerName, getWorldName(), getResellPrice());
|
||||
}
|
||||
if(r == null || !r.transactionSuccess()) {
|
||||
AreaShop.warn("Something went wrong with paying '" + oldOwnerName + "' " + getFormattedPrice() + " for his resell of region " + getName() + " to " + offlinePlayer.getName());
|
||||
}
|
||||
// Resell is done, disable that now
|
||||
disableReselling();
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.RESELL, true);
|
||||
// Set the owner
|
||||
setBuyer(offlinePlayer.getUniqueId());
|
||||
updateLastActiveTime();
|
||||
|
||||
// Update everything
|
||||
handleSchematicEvent(RegionEvent.RESELL);
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new ResoldRegionEvent(this, oldOwner));
|
||||
|
||||
// Send message to the player
|
||||
message(offlinePlayer, "buy-successResale", oldOwnerName);
|
||||
Player seller = Bukkit.getPlayer(oldOwner);
|
||||
if(seller != null) {
|
||||
message(seller, "buy-successSeller", resellPrice);
|
||||
}
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.RESELL, false);
|
||||
} else {
|
||||
// Broadcast and check event
|
||||
BuyingRegionEvent event = new BuyingRegionEvent(this, offlinePlayer);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if(event.isCancelled()) {
|
||||
message(offlinePlayer, "general-cancelled", event.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Substract the money from the players balance
|
||||
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), getPrice());
|
||||
if(!r.transactionSuccess()) {
|
||||
message(offlinePlayer, "buy-payError");
|
||||
return false;
|
||||
}
|
||||
// Optionally give money to the landlord
|
||||
OfflinePlayer landlordPlayer = null;
|
||||
if(getLandlord() != null) {
|
||||
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
|
||||
}
|
||||
String landlordName = getLandlordName();
|
||||
if(landlordName != null) {
|
||||
if(landlordPlayer != null && landlordPlayer.getName() != null) {
|
||||
r = plugin.getEconomy().depositPlayer(landlordPlayer, getWorldName(), getPrice());
|
||||
} else {
|
||||
r = plugin.getEconomy().depositPlayer(landlordName, getWorldName(), getPrice());
|
||||
}
|
||||
if(r != null && !r.transactionSuccess()) {
|
||||
AreaShop.warn("Something went wrong with paying '" + landlordName + "' " + getFormattedPrice() + " for his sell of region " + getName() + " to " + offlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.BOUGHT, true);
|
||||
// Set the owner
|
||||
setBuyer(offlinePlayer.getUniqueId());
|
||||
updateLastActiveTime();
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new BoughtRegionEvent(this));
|
||||
|
||||
// Update everything
|
||||
handleSchematicEvent(RegionEvent.BOUGHT);
|
||||
|
||||
// Send message to the player
|
||||
message(offlinePlayer, "buy-succes");
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.BOUGHT, false);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// Player has not enough money
|
||||
if(isResell) {
|
||||
message(offlinePlayer, "buy-lowMoneyResell", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
} else {
|
||||
message(offlinePlayer, "buy-lowMoney", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(isBuyer(offlinePlayer)) {
|
||||
message(offlinePlayer, "buy-yours");
|
||||
} else {
|
||||
message(offlinePlayer, "buy-someoneElse");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
message(offlinePlayer, "buy-noPermission");
|
||||
if(!plugin.hasPermission(offlinePlayer, "areashop.buynormal")) {
|
||||
message(offlinePlayer, "buy-noPermissionNoResell");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
if(getWorld() == null) {
|
||||
message(offlinePlayer, "general-noWorld");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(getRegion() == null) {
|
||||
message(offlinePlayer, "general-noRegion");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSold() && !(isInResellingMode() && !isBuyer(offlinePlayer))) {
|
||||
if(isBuyer(offlinePlayer)) {
|
||||
message(offlinePlayer, "buy-yours");
|
||||
} else {
|
||||
message(offlinePlayer, "buy-someoneElse");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isResell = isInResellingMode();
|
||||
|
||||
// Only relevant if the player is online
|
||||
Player player = offlinePlayer.getPlayer();
|
||||
if(player != null) {
|
||||
// Check if the players needs to be in the region for buying
|
||||
if(restrictedToRegion() && (!player.getWorld().getName().equals(getWorldName())
|
||||
|| !getRegion().contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
|
||||
message(offlinePlayer, "buy-restrictedToRegion");
|
||||
return false;
|
||||
}
|
||||
// Check if the players needs to be in the world for buying
|
||||
if(restrictedToWorld() && !player.getWorld().getName().equals(getWorldName())) {
|
||||
message(offlinePlayer, "buy-restrictedToWorld", player.getWorld().getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check region limits
|
||||
LimitResult limitResult = this.limitsAllow(RegionType.BUY, offlinePlayer);
|
||||
AreaShop.debug("LimitResult: " + limitResult.toString());
|
||||
if(!limitResult.actionAllowed()) {
|
||||
if(limitResult.getLimitingFactor() == LimitType.TOTAL) {
|
||||
message(offlinePlayer, "total-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
if(limitResult.getLimitingFactor() == LimitType.BUYS) {
|
||||
message(offlinePlayer, "buy-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
// Should not be reached, but is safe like this
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the player has enough money
|
||||
if (isResell && !plugin.getEconomy().has(offlinePlayer, getWorldName(), getResellPrice())) {
|
||||
message(offlinePlayer, "buy-lowMoneyResell", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
return false;
|
||||
}
|
||||
if (!isResell && !plugin.getEconomy().has(offlinePlayer, getWorldName(), getPrice())) {
|
||||
message(offlinePlayer, "buy-lowMoney", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
return false;
|
||||
}
|
||||
|
||||
UUID oldOwner = getBuyer();
|
||||
if(isResell && oldOwner != null) {
|
||||
// Broadcast and check event
|
||||
ResellingRegionEvent event = new ResellingRegionEvent(this, offlinePlayer);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if(event.isCancelled()) {
|
||||
message(offlinePlayer, "general-cancelled", event.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
getFriendsFeature().clearFriends();
|
||||
double resellPrice = getResellPrice();
|
||||
// Transfer the money to the previous owner
|
||||
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), getResellPrice());
|
||||
if(!r.transactionSuccess()) {
|
||||
message(offlinePlayer, "buy-payError");
|
||||
AreaShop.debug("Something went wrong with getting money from " + offlinePlayer.getName() + " while buying " + getName() + ": " + r.errorMessage);
|
||||
return false;
|
||||
}
|
||||
r = null;
|
||||
OfflinePlayer oldOwnerPlayer = Bukkit.getOfflinePlayer(oldOwner);
|
||||
String oldOwnerName = getPlayerName();
|
||||
if(oldOwnerPlayer.hasPlayedBefore() && oldOwnerPlayer.getName() != null) {
|
||||
r = plugin.getEconomy().depositPlayer(oldOwnerPlayer, getWorldName(), getResellPrice());
|
||||
oldOwnerName = oldOwnerPlayer.getName();
|
||||
} else if(oldOwnerName != null) {
|
||||
r = plugin.getEconomy().depositPlayer(oldOwnerName, getWorldName(), getResellPrice());
|
||||
}
|
||||
if(r == null || !r.transactionSuccess()) {
|
||||
AreaShop.warn("Something went wrong with paying '" + oldOwnerName + "' " + getFormattedPrice() + " for his resell of region " + getName() + " to " + offlinePlayer.getName());
|
||||
}
|
||||
// Resell is done, disable that now
|
||||
disableReselling();
|
||||
|
||||
// Set the owner
|
||||
setBuyer(offlinePlayer.getUniqueId());
|
||||
updateLastActiveTime();
|
||||
|
||||
// Update everything
|
||||
handleSchematicEvent(RegionEvent.RESELL);
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new ResoldRegionEvent(this, oldOwner));
|
||||
|
||||
// Send message to the player
|
||||
message(offlinePlayer, "buy-successResale", oldOwnerName);
|
||||
Player seller = Bukkit.getPlayer(oldOwner);
|
||||
if(seller != null) {
|
||||
message(seller, "buy-successSeller", resellPrice);
|
||||
}
|
||||
} else {
|
||||
// Broadcast and check event
|
||||
BuyingRegionEvent event = new BuyingRegionEvent(this, offlinePlayer);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if(event.isCancelled()) {
|
||||
message(offlinePlayer, "general-cancelled", event.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Substract the money from the players balance
|
||||
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), getPrice());
|
||||
if(!r.transactionSuccess()) {
|
||||
message(offlinePlayer, "buy-payError");
|
||||
return false;
|
||||
}
|
||||
// Optionally give money to the landlord
|
||||
OfflinePlayer landlordPlayer = null;
|
||||
if(getLandlord() != null) {
|
||||
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
|
||||
}
|
||||
String landlordName = getLandlordName();
|
||||
if(landlordName != null) {
|
||||
if(landlordPlayer != null && landlordPlayer.getName() != null) {
|
||||
r = plugin.getEconomy().depositPlayer(landlordPlayer, getWorldName(), getPrice());
|
||||
} else {
|
||||
r = plugin.getEconomy().depositPlayer(landlordName, getWorldName(), getPrice());
|
||||
}
|
||||
if(r != null && !r.transactionSuccess()) {
|
||||
AreaShop.warn("Something went wrong with paying '" + landlordName + "' " + getFormattedPrice() + " for his sell of region " + getName() + " to " + offlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Set the owner
|
||||
setBuyer(offlinePlayer.getUniqueId());
|
||||
updateLastActiveTime();
|
||||
|
||||
// Send message to the player
|
||||
message(offlinePlayer, "buy-succes");
|
||||
|
||||
// Update everything
|
||||
handleSchematicEvent(RegionEvent.BOUGHT);
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new BoughtRegionEvent(this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -483,9 +481,6 @@ public class BuyRegion extends GeneralRegion {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.SOLD, true);
|
||||
|
||||
disableReselling();
|
||||
// Give part of the buying price back
|
||||
double moneyBack = getMoneyBackAmount();
|
||||
@@ -528,11 +523,12 @@ public class BuyRegion extends GeneralRegion {
|
||||
}
|
||||
}
|
||||
|
||||
message(executor, "sell-sold");
|
||||
|
||||
// Handle schematic save/restore (while %uuid% is still available)
|
||||
handleSchematicEvent(RegionEvent.SOLD);
|
||||
|
||||
// Send message: before actual removal of the buyer so that it is still available for variables
|
||||
message(executor, "sell-sold");
|
||||
|
||||
// Remove friends and the owner
|
||||
getFriendsFeature().clearFriends();
|
||||
UUID oldBuyer = getBuyer();
|
||||
@@ -541,9 +537,6 @@ public class BuyRegion extends GeneralRegion {
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new SoldRegionEvent(this, oldBuyer, Math.max(moneyBack, 0)));
|
||||
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.SOLD, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -148,8 +148,8 @@ public class RegionGroup {
|
||||
*/
|
||||
public Set<GeneralRegion> getMemberRegions() {
|
||||
Set<GeneralRegion> result = new HashSet<>();
|
||||
for(String name : getMembers()) {
|
||||
result.add(plugin.getFileManager().getRegion(name));
|
||||
for(String playerName : getMembers()) {
|
||||
result.add(plugin.getFileManager().getRegion(playerName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ public class RentRegion extends GeneralRegion {
|
||||
*/
|
||||
public double getMoneyBackAmount() {
|
||||
Long currentTime = Calendar.getInstance().getTimeInMillis();
|
||||
Double timeLeft = (double)((getRentedUntil() - currentTime));
|
||||
Double timeLeft = (double)(getRentedUntil() - currentTime);
|
||||
double percentage = (getMoneyBackPercentage()) / 100.0;
|
||||
Double timePeriod = (double)(getDuration());
|
||||
double periods = timeLeft / timePeriod;
|
||||
@@ -347,10 +347,8 @@ public class RentRegion extends GeneralRegion {
|
||||
long now = Calendar.getInstance().getTimeInMillis();
|
||||
if(!isDeleted() && isRented() && now > getRentedUntil()) {
|
||||
// Extend rent if configured for that
|
||||
if(getBooleanSetting("rent.autoExtend")) {
|
||||
if(extend()) {
|
||||
return false;
|
||||
}
|
||||
if(getBooleanSetting("rent.autoExtend") && extend()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send message to the player if online
|
||||
@@ -434,200 +432,190 @@ public class RentRegion extends GeneralRegion {
|
||||
message(offlinePlayer, "general-noEconomy");
|
||||
return false;
|
||||
}
|
||||
//Check if the player has permission
|
||||
if(plugin.hasPermission(offlinePlayer, "areashop.rent")) {
|
||||
if(getWorld() == null) {
|
||||
message(offlinePlayer, "general-noWorld");
|
||||
|
||||
// Check if the player has permission
|
||||
if(!plugin.hasPermission(offlinePlayer, "areashop.rent")) {
|
||||
message(offlinePlayer, "rent-noPermission");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check location restrictions
|
||||
if(getWorld() == null) {
|
||||
message(offlinePlayer, "general-noWorld");
|
||||
return false;
|
||||
}
|
||||
if(getRegion() == null) {
|
||||
message(offlinePlayer, "general-noRegion");
|
||||
return false;
|
||||
}
|
||||
boolean extend = false;
|
||||
if(getRenter() != null && offlinePlayer.getUniqueId().equals(getRenter())) {
|
||||
extend = true;
|
||||
}
|
||||
|
||||
// Check if available or extending
|
||||
if (isRented() && !extend) {
|
||||
message(offlinePlayer, "rent-someoneElse");
|
||||
return false;
|
||||
}
|
||||
|
||||
// These checks are only relevant for online players doing the renting/buying themselves
|
||||
Player player = offlinePlayer.getPlayer();
|
||||
if(player != null) {
|
||||
// Check if the players needs to be in the region for renting
|
||||
if(restrictedToRegion() && (!player.getWorld().getName().equals(getWorldName())
|
||||
|| !getRegion().contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
|
||||
message(offlinePlayer, "rent-restrictedToRegion");
|
||||
return false;
|
||||
}
|
||||
if(getRegion() == null) {
|
||||
message(offlinePlayer, "general-noRegion");
|
||||
|
||||
// Check if the players needs to be in the world for renting
|
||||
if(restrictedToWorld() && !player.getWorld().getName().equals(getWorldName())) {
|
||||
message(offlinePlayer, "rent-restrictedToWorld", player.getWorld().getName());
|
||||
return false;
|
||||
}
|
||||
boolean extend = false;
|
||||
if(getRenter() != null && offlinePlayer.getUniqueId().equals(getRenter())) {
|
||||
extend = true;
|
||||
}
|
||||
|
||||
// Check region limits if this is not extending
|
||||
if(!(extend && config.getBoolean("allowRegionExtendsWhenAboveLimits"))) {
|
||||
|
||||
LimitResult limitResult;
|
||||
if(extend) {
|
||||
limitResult = this.limitsAllow(RegionType.RENT, offlinePlayer, true);
|
||||
} else {
|
||||
limitResult = this.limitsAllow(RegionType.RENT, offlinePlayer);
|
||||
}
|
||||
// Check if the region is available for renting or if the player wants to extend the rent
|
||||
if(!isRented() || extend) {
|
||||
// These checks are only relevant for online players doing the renting/buying themselves
|
||||
Player player = offlinePlayer.getPlayer();
|
||||
if(player != null) {
|
||||
// Check if the players needs to be in the region for renting
|
||||
if(restrictedToRegion() && (!player.getWorld().getName().equals(getWorldName())
|
||||
|| !getRegion().contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
|
||||
message(offlinePlayer, "rent-restrictedToRegion");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the players needs to be in the world for renting
|
||||
if(restrictedToWorld() && !player.getWorld().getName().equals(getWorldName())) {
|
||||
message(offlinePlayer, "rent-restrictedToWorld", player.getWorld().getName());
|
||||
return false;
|
||||
}
|
||||
AreaShop.debug("LimitResult: " + limitResult.toString());
|
||||
if(!limitResult.actionAllowed()) {
|
||||
if(limitResult.getLimitingFactor() == LimitType.TOTAL) {
|
||||
message(offlinePlayer, "total-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check region limits if this is not extending
|
||||
if(!(extend && config.getBoolean("allowRegionExtendsWhenAboveLimits"))) {
|
||||
|
||||
LimitResult limitResult;
|
||||
if(extend) {
|
||||
limitResult = this.limitsAllow(RegionType.RENT, offlinePlayer, true);
|
||||
} else {
|
||||
limitResult = this.limitsAllow(RegionType.RENT, offlinePlayer);
|
||||
}
|
||||
AreaShop.debug("LimitResult: " + limitResult.toString());
|
||||
if(!limitResult.actionAllowed()) {
|
||||
if(limitResult.getLimitingFactor() == LimitType.TOTAL) {
|
||||
message(offlinePlayer, "total-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
if(limitResult.getLimitingFactor() == LimitType.RENTS) {
|
||||
message(offlinePlayer, "rent-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
if(limitResult.getLimitingFactor() == LimitType.EXTEND) {
|
||||
message(offlinePlayer, "rent-maximumExtend", limitResult.getMaximum(), limitResult.getCurrent() + 1, limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(limitResult.getLimitingFactor() == LimitType.RENTS) {
|
||||
message(offlinePlayer, "rent-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the player can still extend this rent
|
||||
if(extend && !plugin.hasPermission(offlinePlayer, "areashop.rentextendbypass")) {
|
||||
if(getMaxExtends() >= 0 && getTimesExtended() >= getMaxExtends()) {
|
||||
message(offlinePlayer, "rent-maxExtends");
|
||||
return false;
|
||||
}
|
||||
if(limitResult.getLimitingFactor() == LimitType.EXTEND) {
|
||||
message(offlinePlayer, "rent-maximumExtend", limitResult.getMaximum(), limitResult.getCurrent() + 1, limitResult.getLimitingGroup());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is enough time left before hitting maxRentTime
|
||||
boolean extendToMax = false;
|
||||
double price = getPrice();
|
||||
long timeNow = Calendar.getInstance().getTimeInMillis();
|
||||
long timeRented = 0;
|
||||
long maxRentTime = getMaxRentTime();
|
||||
if(isRented()) {
|
||||
timeRented = getRentedUntil() - timeNow;
|
||||
}
|
||||
if((timeRented + getDuration()) > (maxRentTime)
|
||||
&& !plugin.hasPermission(offlinePlayer, "areashop.renttimebypass")
|
||||
&& maxRentTime != -1) {
|
||||
// Extend to the maximum instead of adding a full period
|
||||
if(getBooleanSetting("rent.extendToFullWhenAboveMaxRentTime")) {
|
||||
if(timeRented >= maxRentTime) {
|
||||
message(offlinePlayer, "rent-alreadyAtFull");
|
||||
return false;
|
||||
} else {
|
||||
long toRentPart = maxRentTime - timeRented;
|
||||
extendToMax = true;
|
||||
price = ((double)toRentPart) / getDuration() * price;
|
||||
}
|
||||
} else {
|
||||
message(offlinePlayer, "rent-maxRentTime");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check if the player can still extend this rent
|
||||
if(extend && !plugin.hasPermission(offlinePlayer, "areashop.rentextendbypass")) {
|
||||
if(getMaxExtends() >= 0 && getTimesExtended() >= getMaxExtends()) {
|
||||
message(offlinePlayer, "rent-maxExtends");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(plugin.getEconomy().has(offlinePlayer, getWorldName(), price)) {
|
||||
// Broadcast and check event
|
||||
RentingRegionEvent event = new RentingRegionEvent(this, offlinePlayer, extend);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if(event.isCancelled()) {
|
||||
message(offlinePlayer, "general-cancelled", event.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Substract the money from the players balance
|
||||
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), price);
|
||||
if(!r.transactionSuccess()) {
|
||||
message(offlinePlayer, "rent-payError");
|
||||
AreaShop.debug("Something went wrong with getting money from " + offlinePlayer.getName() + " while renting " + getName() + ": " + r.errorMessage);
|
||||
return false;
|
||||
}
|
||||
// Optionally give money to the landlord
|
||||
OfflinePlayer landlordPlayer = null;
|
||||
if(getLandlord() != null) {
|
||||
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
|
||||
}
|
||||
String landlordName = getLandlordName();
|
||||
if(landlordName != null) {
|
||||
if(landlordPlayer != null && landlordPlayer.getName() != null) {
|
||||
r = plugin.getEconomy().depositPlayer(landlordPlayer, getWorldName(), price);
|
||||
} else {
|
||||
r = plugin.getEconomy().depositPlayer(landlordName, getWorldName(), price);
|
||||
}
|
||||
if(r == null || !r.transactionSuccess()) {
|
||||
AreaShop.warn("Something went wrong with paying '" + landlordName + "' " + Utils.formatCurrency(price) + " for his rent of region " + getName() + " to " + offlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if(!extend) {
|
||||
// Run commands
|
||||
runEventCommands(RegionEvent.RENTED, true);
|
||||
} else {
|
||||
// Run commands
|
||||
runEventCommands(RegionEvent.EXTENDED, true);
|
||||
}
|
||||
|
||||
// Get the time until the region will be rented
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
if(extendToMax) {
|
||||
calendar.setTimeInMillis(calendar.getTimeInMillis() + getMaxRentTime());
|
||||
} else if(extend) {
|
||||
calendar.setTimeInMillis(getRentedUntil() + getDuration());
|
||||
} else {
|
||||
calendar.setTimeInMillis(calendar.getTimeInMillis() + getDuration());
|
||||
}
|
||||
|
||||
// Add values to the rent and send it to FileManager
|
||||
setRentedUntil(calendar.getTimeInMillis());
|
||||
setRenter(offlinePlayer.getUniqueId());
|
||||
updateLastActiveTime();
|
||||
|
||||
// Fire schematic event and updated times extended
|
||||
if(!extend) {
|
||||
this.handleSchematicEvent(RegionEvent.RENTED);
|
||||
setTimesExtended(0);
|
||||
} else {
|
||||
setTimesExtended(getTimesExtended() + 1);
|
||||
}
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new RentedRegionEvent(this, extend));
|
||||
|
||||
// Send message to the player
|
||||
if(extendToMax) {
|
||||
message(offlinePlayer, "rent-extendedToMax");
|
||||
} else if(extend) {
|
||||
message(offlinePlayer, "rent-extended");
|
||||
} else {
|
||||
message(offlinePlayer, "rent-rented");
|
||||
}
|
||||
if(!extend) {
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.RENTED, false);
|
||||
} else {
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.EXTENDED, false);
|
||||
}
|
||||
return true;
|
||||
// Check if there is enough time left before hitting maxRentTime
|
||||
boolean extendToMax = false;
|
||||
double price = getPrice();
|
||||
long timeNow = Calendar.getInstance().getTimeInMillis();
|
||||
long timeRented = 0;
|
||||
long maxRentTime = getMaxRentTime();
|
||||
if(isRented()) {
|
||||
timeRented = getRentedUntil() - timeNow;
|
||||
}
|
||||
if((timeRented + getDuration()) > (maxRentTime)
|
||||
&& !plugin.hasPermission(offlinePlayer, "areashop.renttimebypass")
|
||||
&& maxRentTime != -1) {
|
||||
// Extend to the maximum instead of adding a full period
|
||||
if(getBooleanSetting("rent.extendToFullWhenAboveMaxRentTime")) {
|
||||
if(timeRented >= maxRentTime) {
|
||||
message(offlinePlayer, "rent-alreadyAtFull");
|
||||
return false;
|
||||
} else {
|
||||
// Player has not enough money
|
||||
if(extend) {
|
||||
message(offlinePlayer, "rent-lowMoneyExtend", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
} else {
|
||||
message(offlinePlayer, "rent-lowMoneyRent", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
}
|
||||
long toRentPart = maxRentTime - timeRented;
|
||||
extendToMax = true;
|
||||
price = ((double)toRentPart) / getDuration() * price;
|
||||
}
|
||||
} else {
|
||||
message(offlinePlayer, "rent-someoneElse");
|
||||
message(offlinePlayer, "rent-maxRentTime");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
message(offlinePlayer, "rent-noPermission");
|
||||
}
|
||||
return false;
|
||||
|
||||
// Check if the player has enough money
|
||||
if(!plugin.getEconomy().has(offlinePlayer, getWorldName(), price)) {
|
||||
if(extend) {
|
||||
message(offlinePlayer, "rent-lowMoneyExtend", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
} else {
|
||||
message(offlinePlayer, "rent-lowMoneyRent", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Broadcast and check event
|
||||
RentingRegionEvent event = new RentingRegionEvent(this, offlinePlayer, extend);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if(event.isCancelled()) {
|
||||
message(offlinePlayer, "general-cancelled", event.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Substract the money from the players balance
|
||||
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), price);
|
||||
if(!r.transactionSuccess()) {
|
||||
message(offlinePlayer, "rent-payError");
|
||||
AreaShop.debug("Something went wrong with getting money from " + offlinePlayer.getName() + " while renting " + getName() + ": " + r.errorMessage);
|
||||
return false;
|
||||
}
|
||||
// Optionally give money to the landlord
|
||||
OfflinePlayer landlordPlayer = null;
|
||||
if(getLandlord() != null) {
|
||||
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
|
||||
}
|
||||
String landlordName = getLandlordName();
|
||||
if(landlordName != null) {
|
||||
if(landlordPlayer != null && landlordPlayer.getName() != null) {
|
||||
r = plugin.getEconomy().depositPlayer(landlordPlayer, getWorldName(), price);
|
||||
} else {
|
||||
r = plugin.getEconomy().depositPlayer(landlordName, getWorldName(), price);
|
||||
}
|
||||
if(r == null || !r.transactionSuccess()) {
|
||||
AreaShop.warn("Something went wrong with paying '" + landlordName + "' " + Utils.formatCurrency(price) + " for his rent of region " + getName() + " to " + offlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Get the time until the region will be rented
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
if(extendToMax) {
|
||||
calendar.setTimeInMillis(calendar.getTimeInMillis() + getMaxRentTime());
|
||||
} else if(extend) {
|
||||
calendar.setTimeInMillis(getRentedUntil() + getDuration());
|
||||
} else {
|
||||
calendar.setTimeInMillis(calendar.getTimeInMillis() + getDuration());
|
||||
}
|
||||
|
||||
// Add values to the rent and send it to FileManager
|
||||
setRentedUntil(calendar.getTimeInMillis());
|
||||
setRenter(offlinePlayer.getUniqueId());
|
||||
updateLastActiveTime();
|
||||
|
||||
// Fire schematic event and updated times extended
|
||||
if(!extend) {
|
||||
this.handleSchematicEvent(RegionEvent.RENTED);
|
||||
setTimesExtended(0);
|
||||
} else {
|
||||
setTimesExtended(getTimesExtended() + 1);
|
||||
}
|
||||
|
||||
// Send message to the player
|
||||
if(extendToMax) {
|
||||
message(offlinePlayer, "rent-extendedToMax");
|
||||
} else if(extend) {
|
||||
message(offlinePlayer, "rent-extended");
|
||||
} else {
|
||||
message(offlinePlayer, "rent-rented");
|
||||
}
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new RentedRegionEvent(this, extend));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -662,8 +650,7 @@ public class RentRegion extends GeneralRegion {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.UNRENTED, true);
|
||||
// Do a payback
|
||||
double moneyBack = getMoneyBackAmount();
|
||||
if(moneyBack > 0 && giveMoneyBack) {
|
||||
boolean noPayBack = false;
|
||||
@@ -704,12 +691,12 @@ public class RentRegion extends GeneralRegion {
|
||||
}
|
||||
}
|
||||
|
||||
// Send messages
|
||||
message(executor, "unrent-unrented");
|
||||
|
||||
// Handle schematic save/restore (while %uuid% is still available)
|
||||
handleSchematicEvent(RegionEvent.UNRENTED);
|
||||
|
||||
// Send message: before actual removal of the renter so that it is still available for variables
|
||||
message(executor, "unrent-unrented");
|
||||
|
||||
// Remove friends, the owner and renteduntil values
|
||||
getFriendsFeature().clearFriends();
|
||||
UUID oldRenter = getRenter();
|
||||
@@ -720,9 +707,6 @@ public class RentRegion extends GeneralRegion {
|
||||
|
||||
// Notify about updates
|
||||
this.notifyAndUpdate(new UnrentedRegionEvent(this, oldRenter, Math.max(0, moneyBack)));
|
||||
|
||||
// Run commands
|
||||
this.runEventCommands(RegionEvent.UNRENTED, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
package me.wiefferink.areashop.tools;
|
||||
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import me.wiefferink.areashop.regions.BuyRegion;
|
||||
import me.wiefferink.areashop.regions.GeneralRegion;
|
||||
import me.wiefferink.areashop.regions.RentRegion;
|
||||
import org.bstats.Metrics;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Analytics {
|
||||
|
||||
/**
|
||||
* Start analytics tracking.
|
||||
*/
|
||||
public static void start() {
|
||||
// Legacy MCstats statistics (remove at some point)
|
||||
try {
|
||||
new me.wiefferink.areashop.lib.Metrics(AreaShop.getInstance()).start();
|
||||
AreaShop.debug("Started mcstats.org statistics service");
|
||||
} catch(Exception e) {
|
||||
AreaShop.debug("Could not start mcstats.org statistics service");
|
||||
}
|
||||
|
||||
// bStats statistics
|
||||
try {
|
||||
Metrics metrics = new Metrics(AreaShop.getInstance());
|
||||
|
||||
// Number of regions
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return AreaShop.getInstance().getFileManager().getRegions().size();
|
||||
}
|
||||
});
|
||||
|
||||
// Number of rental regions
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("rental_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return AreaShop.getInstance().getFileManager().getRents().size();
|
||||
}
|
||||
});
|
||||
|
||||
// Number of buy regions
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("buy_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return AreaShop.getInstance().getFileManager().getBuys().size();
|
||||
}
|
||||
});
|
||||
|
||||
// Language
|
||||
metrics.addCustomChart(new Metrics.SimplePie("language") {
|
||||
@Override
|
||||
public String getValue() {
|
||||
return AreaShop.getInstance().getConfig().getString("language");
|
||||
}
|
||||
});
|
||||
|
||||
// Pie with region states
|
||||
metrics.addCustomChart(new Metrics.AdvancedPie("region_state") {
|
||||
@Override
|
||||
public HashMap<String, Integer> getValues(HashMap<String, Integer> result) {
|
||||
RegionStateStats stats = getStateStats();
|
||||
result.put("For Rent", stats.forrent);
|
||||
result.put("Rented", stats.rented);
|
||||
result.put("For Sale", stats.forsale);
|
||||
result.put("Sold", stats.sold);
|
||||
result.put("Reselling", stats.reselling);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
// Time series of each region state
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("forrent_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getStateStats().forrent;
|
||||
}
|
||||
});
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("rented_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getStateStats().rented;
|
||||
}
|
||||
});
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("forsale_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getStateStats().forsale;
|
||||
}
|
||||
});
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("sold_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getStateStats().sold;
|
||||
}
|
||||
});
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("reselling_region_count") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getStateStats().reselling;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO track rent/buy/unrent/sell/resell actions (so that it can be reported per collection interval)
|
||||
|
||||
AreaShop.debug("Started bstats.org statistics service");
|
||||
} catch(Exception e) {
|
||||
AreaShop.debug("Could not start bstats.org statistics service");
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegionStateStats {
|
||||
int forrent = 0;
|
||||
int forsale = 0;
|
||||
int rented = 0;
|
||||
int sold = 0;
|
||||
int reselling = 0;
|
||||
}
|
||||
|
||||
private static RegionStateStats getStateStats() {
|
||||
RegionStateStats result = new RegionStateStats();
|
||||
for(GeneralRegion region : AreaShop.getInstance().getFileManager().getRegions()) {
|
||||
if(region instanceof RentRegion) {
|
||||
RentRegion rent = (RentRegion)region;
|
||||
if(rent.isAvailable()) {
|
||||
result.forrent++;
|
||||
} else {
|
||||
result.rented++;
|
||||
}
|
||||
} else if(region instanceof BuyRegion) {
|
||||
BuyRegion buy = (BuyRegion)region;
|
||||
if(buy.isAvailable()) {
|
||||
result.forsale++;
|
||||
} else if(buy.isInResellingMode()) {
|
||||
result.reselling++;
|
||||
} else {
|
||||
result.sold++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package me.wiefferink.areashop.tools;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@@ -18,234 +18,242 @@ import java.util.logging.Logger;
|
||||
|
||||
public class GithubUpdateCheck {
|
||||
|
||||
public static final String API_HOST = "https://api.github.com/repos";
|
||||
public static final String API_LATEST_RELEASE = "releases/latest";
|
||||
public static final String USER_AGENT = "GithubUpdateCheck by NLThijs48";
|
||||
public static final boolean DEBUG = false;
|
||||
public static final String API_HOST = "https://api.github.com/repos";
|
||||
public static final String API_LATEST_RELEASE = "releases/latest";
|
||||
public static final String USER_AGENT = "GithubUpdateCheck by NLThijs48";
|
||||
public static final boolean DEBUG = false;
|
||||
private static final Gson GSON = new GsonBuilder().create();
|
||||
|
||||
private final String author;
|
||||
private final String repository;
|
||||
private final Plugin plugin;
|
||||
private final Logger logger;
|
||||
private URL url;
|
||||
private VersionComparator versionComparator;
|
||||
private final String author;
|
||||
private final String repository;
|
||||
private final Plugin plugin;
|
||||
private final Logger logger;
|
||||
private final String currentVersion;
|
||||
private URL url;
|
||||
private VersionComparator versionComparator;
|
||||
// Status
|
||||
private boolean checking;
|
||||
private boolean error;
|
||||
private boolean hasUpdate;
|
||||
private String latestVersion;
|
||||
|
||||
// Status
|
||||
private boolean checking;
|
||||
private boolean error;
|
||||
private boolean hasUpdate;
|
||||
private String latestVersion;
|
||||
private final String currentVersion;
|
||||
/**
|
||||
* Create a new GithubUpdateCheck with the required information.
|
||||
*
|
||||
* @param plugin The plugin to create it for (used for logging and checking version)
|
||||
* @param author The author of the plugin as used on Github
|
||||
* @param repository The repository name of the plugin on Github
|
||||
*/
|
||||
public GithubUpdateCheck(Plugin plugin, String author, String repository) {
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
this.author = author;
|
||||
this.repository = repository;
|
||||
this.currentVersion = plugin.getDescription().getVersion();
|
||||
this.versionComparator = (latest, current) ->
|
||||
!latest.equalsIgnoreCase(current);
|
||||
|
||||
/**
|
||||
* Create a new GithubUpdateCheck with the required information.
|
||||
* @param plugin The plugin to create it for (used for logging and checking version)
|
||||
* @param author The author of the plugin as used on Github
|
||||
* @param repository The repository name of the plugin on Github
|
||||
*/
|
||||
public GithubUpdateCheck(Plugin plugin, String author, String repository) {
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
this.author = author;
|
||||
this.repository = repository;
|
||||
this.currentVersion = plugin.getDescription().getVersion();
|
||||
this.versionComparator = (latestVersion, currentVersion) ->
|
||||
!latestVersion.equalsIgnoreCase(currentVersion);
|
||||
this.checking = false;
|
||||
this.error = false;
|
||||
this.hasUpdate = false;
|
||||
}
|
||||
|
||||
this.checking = false;
|
||||
this.error = false;
|
||||
this.hasUpdate = false;
|
||||
}
|
||||
/**
|
||||
* Change the version comparator.
|
||||
*
|
||||
* @param versionComparator VersionComparator to use for checking if one version is newer than the other
|
||||
* @return this
|
||||
*/
|
||||
public GithubUpdateCheck withVersionComparator(VersionComparator versionComparator) {
|
||||
this.versionComparator = versionComparator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the version comparator.
|
||||
* @param versionComparator VersionComparator to use for checking if one version is newer than the other
|
||||
* @return this
|
||||
*/
|
||||
public GithubUpdateCheck withVersionComparator(VersionComparator versionComparator) {
|
||||
this.versionComparator = versionComparator;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Check if an update is available.
|
||||
*/
|
||||
public void checkUpdate() {
|
||||
checkUpdate(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an update is available.
|
||||
*/
|
||||
public void checkUpdate() {
|
||||
checkUpdate(null);
|
||||
}
|
||||
/**
|
||||
* Check if an update is available.
|
||||
*
|
||||
* @param callback Callback to execute when the update check is done
|
||||
* @return GithubUpdateCheck containing the status of the check
|
||||
*/
|
||||
public GithubUpdateCheck checkUpdate(UpdateCallback callback) {
|
||||
checking = true;
|
||||
final GithubUpdateCheck self = this;
|
||||
// Check for update on async thread
|
||||
Utils.newChain()
|
||||
.async(() -> {
|
||||
try {
|
||||
try {
|
||||
String rawUrl = API_HOST + "/" + author + "/" + repository + "/" + API_LATEST_RELEASE;
|
||||
url = new URL(rawUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
logger.severe("Invalid url: '" + url + "', are the author '" + author + "' and repository '" + repository + "' correct?");
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an update is available.
|
||||
* @param callback Callback to execute when the update check is done
|
||||
* @return GithubUpdateCheck containing the status of the check
|
||||
*/
|
||||
public GithubUpdateCheck checkUpdate(UpdateCallback callback) {
|
||||
checking = true;
|
||||
final GithubUpdateCheck self = this;
|
||||
// Check for update on asyn thread
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
try {
|
||||
String rawUrl = API_HOST + "/" + author + "/" + repository + "/" + API_LATEST_RELEASE;
|
||||
url = new URL(rawUrl);
|
||||
} catch(MalformedURLException e) {
|
||||
logger.severe("Invalid url: '" + url + "', are the author '" + author + "' and repository '" + repository + "' correct?");
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
// Give up after 15 seconds
|
||||
conn.setConnectTimeout(15000);
|
||||
// Identify ourselves
|
||||
conn.addRequestProperty("User-Agent", USER_AGENT);
|
||||
// Make sure we access the correct api version
|
||||
conn.addRequestProperty("Accept", "application/vnd.github.v3+json");
|
||||
// We want to read the result
|
||||
conn.setDoOutput(true);
|
||||
// Open connection
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
|
||||
String response = reader.readLine();
|
||||
debug("Response:", response);
|
||||
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
// Give up after 15 seconds
|
||||
conn.setConnectTimeout(15000);
|
||||
// Identify ourselves
|
||||
conn.addRequestProperty("User-Agent", USER_AGENT);
|
||||
// Make sure we access the correct api version
|
||||
conn.addRequestProperty("Accept", "application/vnd.github.v3+json");
|
||||
// We want to read the result
|
||||
conn.setDoOutput(true);
|
||||
// Open connection
|
||||
try(BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
|
||||
String response = reader.readLine();
|
||||
debug("Response:", response);
|
||||
JsonObject latestRelease = GSON.fromJson(response, JsonObject.class);
|
||||
|
||||
JSONObject latestRelease = (JSONObject)JSONValue.parse(response);
|
||||
if (latestRelease.isJsonNull()) {
|
||||
logger.warning("Failed to get api response from " + url);
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
debug("json: " + latestRelease.getAsString());
|
||||
|
||||
if(latestRelease.isEmpty()) {
|
||||
logger.warning("Failed to get api response from " + url);
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
debug("json: " + latestRelease.toJSONString());
|
||||
// Latest version
|
||||
latestVersion = latestRelease.get("tag_name").getAsString();
|
||||
debug("Tag name:", latestVersion);
|
||||
|
||||
// Latest version
|
||||
latestVersion = (String)latestRelease.get("tag_name");
|
||||
debug("Tag name:", latestVersion);
|
||||
// Current version
|
||||
debug("Plugin version:", currentVersion);
|
||||
|
||||
// Current version
|
||||
debug("Plugin version:", currentVersion);
|
||||
// Compare version
|
||||
hasUpdate = versionComparator.isNewer(latestVersion, currentVersion);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.severe("Failed to get latest release:" + ExceptionUtils
|
||||
.getStackTrace(e));
|
||||
error = true;
|
||||
} catch (ClassCastException e) {
|
||||
logger.info("Unexpected structure of the result, failed to parse it");
|
||||
error = true;
|
||||
}
|
||||
} finally {
|
||||
checking = false;
|
||||
debug("result:", self);
|
||||
}
|
||||
}
|
||||
).syncLast(x -> {
|
||||
if (callback != null) {
|
||||
callback.run(this);
|
||||
}
|
||||
}).execute();
|
||||
return this;
|
||||
}
|
||||
|
||||
// Compare version
|
||||
hasUpdate = versionComparator.isNewer(latestVersion, currentVersion);
|
||||
}
|
||||
} catch(IOException e) {
|
||||
logger.severe("Failed to get latest release:" + ExceptionUtils.getStackTrace(e));
|
||||
error = true;
|
||||
} catch(ClassCastException e) {
|
||||
logger.info("Unexpected structure of the result, failed to parse it");
|
||||
error = true;
|
||||
}
|
||||
} finally {
|
||||
checking = false;
|
||||
debug("result:", self);
|
||||
if(callback != null) {
|
||||
// Switch back to main thread and call the callback
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.run(self);
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskAsynchronously(plugin);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Check if an update check is running.
|
||||
*
|
||||
* @return true if an update check is running
|
||||
*/
|
||||
public boolean isChecking() {
|
||||
return checking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an update check is running.
|
||||
* @return true if an update check is running
|
||||
*/
|
||||
public boolean isChecking() {
|
||||
return checking;
|
||||
}
|
||||
/**
|
||||
* Check if the update check failed.
|
||||
*
|
||||
* @return true if the update check failed (an error message has been logged)
|
||||
*/
|
||||
public boolean hasFailed() {
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the update check failed.
|
||||
* @return true if the update check failed (an error message has been logged)
|
||||
*/
|
||||
public boolean hasFailed() {
|
||||
return error;
|
||||
}
|
||||
/**
|
||||
* Check if an update has been found.
|
||||
*
|
||||
* @return true if an update has been found
|
||||
*/
|
||||
public boolean hasUpdate() {
|
||||
return hasUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an update has been found.
|
||||
* @return true if an update has been found
|
||||
*/
|
||||
public boolean hasUpdate() {
|
||||
return hasUpdate;
|
||||
}
|
||||
/**
|
||||
* Get the repository that this update checker is checking.
|
||||
*
|
||||
* @return Used repository
|
||||
*/
|
||||
public String getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the repository that this update checker is checking.
|
||||
* @return Used repository
|
||||
*/
|
||||
public String getRepository() {
|
||||
return repository;
|
||||
}
|
||||
/**
|
||||
* Get the author that this update checker is checking.
|
||||
*
|
||||
* @return Used author
|
||||
*/
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the author that this update checker is checking.
|
||||
* @return Used author
|
||||
*/
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
/**
|
||||
* Get the current version.
|
||||
*
|
||||
* @return Current version of the plugin
|
||||
*/
|
||||
public String getCurrentVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current version.
|
||||
* @return Current version of the plugin
|
||||
*/
|
||||
public String getCurrentVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
/**
|
||||
* Get the latest version.
|
||||
*
|
||||
* @return Latest version of the plugin (if checking is complete)
|
||||
*/
|
||||
public String getLatestVersion() {
|
||||
return latestVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest version.
|
||||
* @return Latest version of the plugin (if checking is complete)
|
||||
*/
|
||||
public String getLatestVersion() {
|
||||
return latestVersion;
|
||||
}
|
||||
/**
|
||||
* Print a debug message if DEBUG is enabled.
|
||||
*
|
||||
* @param message Message to print
|
||||
*/
|
||||
private void debug(Object... message) {
|
||||
if (DEBUG) {
|
||||
logger.info("[" + this.getClass().getSimpleName() + "] [DEBUG] " + StringUtils
|
||||
.join(message, " "));
|
||||
}
|
||||
}
|
||||
|
||||
public interface VersionComparator {
|
||||
/**
|
||||
* Check if a version should be considered 'newer' than another.
|
||||
* @param latestVersion Version that is available on Github
|
||||
* @param currentVersion Version of the current plugin
|
||||
* @return true if the latestVersion is newer than the localVersion, otherwise false
|
||||
*/
|
||||
boolean isNewer(String latestVersion, String currentVersion);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GithubUpdateCheck(" + StringUtils.join(Arrays.asList(
|
||||
"author=" + author,
|
||||
"repository=" + repository,
|
||||
"plugin=" + plugin.getName(),
|
||||
"checking=" + checking,
|
||||
"hasUpdate=" + hasUpdate,
|
||||
"error=" + error,
|
||||
"currentVersion=" + currentVersion,
|
||||
"latestVersion=" + latestVersion
|
||||
), ", ") + ")";
|
||||
}
|
||||
|
||||
public interface UpdateCallback {
|
||||
void run(GithubUpdateCheck result);
|
||||
}
|
||||
public interface VersionComparator {
|
||||
/**
|
||||
* Check if a version should be considered 'newer' than another.
|
||||
*
|
||||
* @param latestVersion Version that is available on Github
|
||||
* @param currentVersion Version of the current plugin
|
||||
* @return true if the latestVersion is newer than the localVersion, otherwise false
|
||||
*/
|
||||
boolean isNewer(String latestVersion, String currentVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a debug message if DEBUG is enabled.
|
||||
* @param message Message to print
|
||||
*/
|
||||
private void debug(Object... message) {
|
||||
if(DEBUG) {
|
||||
logger.info("[" + this.getClass().getSimpleName() + "] [DEBUG] " + StringUtils.join(message, " "));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GithubUpdateCheck(" + StringUtils.join(Arrays.asList(
|
||||
"author=" + author,
|
||||
"repository=" + repository,
|
||||
"plugin=" + plugin.getName(),
|
||||
"checking=" + checking,
|
||||
"hasUpdate=" + hasUpdate,
|
||||
"error=" + error,
|
||||
"currentVersion=" + currentVersion,
|
||||
"latestVersion=" + latestVersion
|
||||
), ", ") + ")";
|
||||
}
|
||||
public interface UpdateCallback {
|
||||
void run(GithubUpdateCheck result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package me.wiefferink.areashop.tools;
|
||||
|
||||
import me.wiefferink.areashop.AreaShop;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class Materials {
|
||||
|
||||
private Materials() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get material based on a sign material name.
|
||||
* @param name Name of the sign material
|
||||
* @return null if not a sign, otherwise the material matching the name (when the material is not available on the current minecraft version, it returns the base type)
|
||||
*/
|
||||
public static Material signNameToMaterial(String name) {
|
||||
// Expected null case
|
||||
if (!isSign(name)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Material.matchMaterial(name);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
AreaShop.debug("Materials.get() null result:", name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Material is a sign (of either the wall or floor type).
|
||||
* @param material Material to check
|
||||
* @return true if the given material is a sign
|
||||
*/
|
||||
public static boolean isSign(Material material) {
|
||||
return Tag.SIGNS.isTagged(material) || Tag.WALL_SIGNS.isTagged(material);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Material is a sign (of either the wall or floor type).
|
||||
* @param name String to check
|
||||
* @return true if the given material is a sign
|
||||
*/
|
||||
public static boolean isSign(String name) {
|
||||
try {
|
||||
return isSign(Material.matchMaterial(name));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
AreaShop.debug("Invalid Material: " + name + " passed when performing sign check.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,29 +2,29 @@ package me.wiefferink.areashop.tools;
|
||||
|
||||
public class Value<T> {
|
||||
|
||||
private T value;
|
||||
private T content;
|
||||
|
||||
/**
|
||||
* Create a container with a default value.
|
||||
* @param value The value to set
|
||||
* Create a container with a default content.
|
||||
* @param content The content to set
|
||||
*/
|
||||
public Value(T value) {
|
||||
this.value = value;
|
||||
public Value(T content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored value.
|
||||
* @return The stored value
|
||||
* Get the stored content.
|
||||
* @return The stored content
|
||||
*/
|
||||
public T get() {
|
||||
return value;
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value.
|
||||
* @param value The new value
|
||||
* Set the content.
|
||||
* @param value The new content
|
||||
*/
|
||||
public void set(T value) {
|
||||
this.value = value;
|
||||
this.content = value;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ general:
|
||||
# The y location within the region to start searching for safe teleport locations (x and z are in the middle of the region).
|
||||
# Possible values: 'bottom', 'middle', 'top' or a number indicating an exact y coordinate.
|
||||
teleportLocationY: bottom
|
||||
# If true the teleportation algorithm only allows telportation to inside the region, otherwise it will expand
|
||||
# If true the teleportation algorithm only allows teleportation to inside the region, otherwise it will expand
|
||||
# a cube from the starting point to check for safe spots (then it could end outside of the region).
|
||||
teleportIntoRegion: true
|
||||
# Same as above, but then for when you teleport to the sign of a region instead of the region itself.
|
||||
|
||||
@@ -414,6 +414,9 @@ add-success: "Added as %0%: [gray]%1%."
|
||||
add-failed: "Already registered: [gray]%0%."
|
||||
add-failedOtherWorld: "Already registered from another world: [gray]%0%."
|
||||
add-blacklisted: "On the blacklist: [gray]%0%."
|
||||
add-rentCancelled: "Rent cancelled: [gray]%0%."
|
||||
add-buyCancelled: "Buy cancelled: [gray]%0%."
|
||||
add-addCancelled: "Add cancelled: [gray]%0%."
|
||||
add-specifyWorld: "Specify the world of the region when using from console."
|
||||
add-incorrectWorld: "World '%0%' not found, try again (case-sensitive)."
|
||||
add-noPermissionRegions: "No permission to add: [gray]%0%."
|
||||
@@ -422,6 +425,7 @@ add-noPermissionOwnerMember: "[gray]You either are not a member/owner of these r
|
||||
del-noPermission: "You don't have permission to remove regions."
|
||||
del-success: "Removed regions: [gray]%0%."
|
||||
del-failed: "No permission to remove or not registered: [gray]%0%."
|
||||
del-cancelled: "Delete cancelled: [gray]%0%."
|
||||
|
||||
addsign-help: "/as addsign [region] [profile]."
|
||||
addsign-noSign: "You are not looking at a sign."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||
# ║ Language file of the AreaShop plugin created by NLThijs48, Github can be found at https://github.com/NLthijs48/AreaShop
|
||||
# ║ Spanish language file, plugin version 2.5.0, 424/428 messages are translated (99%)
|
||||
# ║ Spanish language file, plugin version 2.5.0, 426/428 messages are translated (100%)
|
||||
# ║
|
||||
# ║ This file will be overwritten at each startup/reload of the plugin, if you want to change anything then do the following:
|
||||
# ║ 1: Make a copy of this file
|
||||
@@ -138,6 +138,7 @@
|
||||
"sell-sold": "La región %lang:region%, de %lang:player%, ha sido vendida."
|
||||
"sell-noPermission": "No tienes permiso para vender regiones."
|
||||
"sell-noPermissionOther": "No tienes permiso para vender regiones ajenas."
|
||||
"sell-disabled": "La venta fue desactivada para esta región."
|
||||
"reload-reloading": "Todos los archivos han sido recargados, comprobando alquileres y actualizando regiones..."
|
||||
"reload-noPermission": "No tienes permiso para recargar los archivos de configuración."
|
||||
"reload-updateCommandChanged": "Los comandos '/as updaterents' y '/as updatebuys' han sido borrados, '/as reload' actualizará las regiones. Puedes usar este comando en vez de los 2 primeros."
|
||||
@@ -432,6 +433,7 @@
|
||||
"resell-success": "%lang:region% está en modo reventa por %resellprice%."
|
||||
"resell-noPermission": "No tienes permiso para cambiar tu región a modo reventa."
|
||||
"resell-noPermissionOther": "No tienes permiso para cambiar las regiones a modo reventa."
|
||||
"resell-disabled": "La reventa fue deshabilitada para esta región."
|
||||
"stopresell-help": "/as stopresell [región], la región en la que estás se usará si no se especifican nombres."
|
||||
"stopresell-notRegistered": "La región especificada no es válida: %0%."
|
||||
"stopresell-notResell": "No puedes parar la reventa de %lang:region% porque no está en modo reventa."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||
# ║ Language file of the AreaShop plugin created by NLThijs48, Github can be found at https://github.com/NLthijs48/AreaShop
|
||||
# ║ French language file, plugin version 2.5.0, 399/428 messages are translated (93%)
|
||||
# ║ French language file, plugin version 2.5.0, 428/428 messages are translated (100%)
|
||||
# ║
|
||||
# ║ This file will be overwritten at each startup/reload of the plugin, if you want to change anything then do the following:
|
||||
# ║ 1: Make a copy of this file
|
||||
@@ -178,6 +178,10 @@
|
||||
"info-pageNoPrevious":
|
||||
- " [darkgray][bold]◄Précédent[/bold] "
|
||||
- " hover: C'est déjà la premier page"
|
||||
"info-pageNext":
|
||||
- "[gold][bold]Suivant►[/bold]"
|
||||
- "hover: %lang:action|Page suivante|%"
|
||||
- "commande: /areashop "
|
||||
"info-pageNoNext":
|
||||
- " [darkgray][bold]Suivaznt►[/bold]"
|
||||
- " hover: C'est déjà la dernière page"
|
||||
@@ -290,6 +294,7 @@
|
||||
"setduration-successRemoved": "La durée de location de %lang:region% a été supprimé, maintenant celle-ci utilisera le durée de location du group ou du fichier default.yml, nouvelle durée de location : %duration%."
|
||||
"setup-noRegion": "Vous n'avez pas spécifié de région à la seconde ligne."
|
||||
"setup-alreadyRentSign": "La région que vous avez spécifiée a déjà été ajoutée à AreaShop en tant qu'une région louable, ajoutez un panneau avec [as] sur le première ligne ou tapez '/as addsign'."
|
||||
"setup-alreadyOtherWorld": "La région que vous avez spécifiée est déjà ajoutée à AreaShop dans un autre monde. Les régions de différents mondes ont toujours besoin de noms différents."
|
||||
"setup-alreadyBuySign": "La région que vous avez spécifiée a déjà été ajoutée à AreaShop en tant qu'une région achetable, ajoutez un panneau avec [as] sur le première ligne ou tapez '/as addsign'."
|
||||
"setup-noDuration": "A la troisième ligne, vous n'avez pas spécifié la durée de location de la région."
|
||||
"setup-wrongDuration": "Le temps spécifié n'est pas au bon format. Exemple : 1 day."
|
||||
@@ -368,6 +373,7 @@
|
||||
"add-noPermission": "Vous n'avez pas la permission d'ajouter une région à AreaShop."
|
||||
"add-success": "Ajoutée comme %0% : [gray]%1%."
|
||||
"add-failed": "Déjà enregistré: [gray]%0%."
|
||||
"add-failedOtherWorld": "Déjà inscrit d'un autre monde: [gray]%0%."
|
||||
"add-blacklisted": "Dans la liste noir: [gray]%0%."
|
||||
"add-specifyWorld": "Spécifiez le monde de la région lors de l'utilisation de la console."
|
||||
"add-incorrectWorld": "Le monde '%0%' est introuvable, essayez de nouveau (attention à la casse)."
|
||||
@@ -379,6 +385,7 @@
|
||||
"addsign-help": "/as addsign [region] [profile]"
|
||||
"addsign-noSign": "Vous ne regardez pas de panneau."
|
||||
"addsign-noRegions": "Aucune région trouvée autour du panneau."
|
||||
"addSign-notRegistered": "La région spécifiée n'est pas enregistrée dans AreaShop: %0% (elle doit d'abord être ajoutée à AreaShop avant qu'un signe puisse être ajouté)."
|
||||
"addsign-couldNotDetect": "Plusieurs régions ont été trouvées à proximité du panneau. Spécifiez la région en argument supplémentaire (2 des régions trouvées: %lang:tRegion|%0%|% et %lang:tRegion|%1%|%)."
|
||||
"addsign-couldNotDetectSign": "Plusieurs régions ont été trouvées à proximité du panneau. Spécifiez la région à la deuxième ligne (2 des régions trouvées: %lang:tRegion|%0%|% et %lang:tRegion|%1%|%)."
|
||||
"addsign-wrongProfile": "Le profil spécifié n'existe pas, utilisez l'un de la liste suivante (Vérifiez la config): [gray]%0%."
|
||||
@@ -428,6 +435,7 @@
|
||||
"resell-success": "%lang:region% a été mise en revente avec succès pour un prix de %resellprice%."
|
||||
"resell-noPermission": "Vous n'avez pas la permission de mettre votre région en revente."
|
||||
"resell-noPermissionOther": "Vous n'avez pas la permission de mettre des régions en revente."
|
||||
"resell-disabled": "La revente a été désactivée pour cette région."
|
||||
"stopresell-help": "/as stropresell [région], la région où vous vous trouvez sera utilisée si vous ne spécifiez pas de région."
|
||||
"stopresell-notRegistered": "La région spécifiée n'est pas enregistrée : %0%."
|
||||
"stopresell-notResell": "Vous ne pouvez pas stopper la revente %lang:region% car elle n'est pas en mode revente."
|
||||
@@ -486,6 +494,30 @@
|
||||
"message-help": "/as message <joueur> <message...>"
|
||||
"message-noPermission": "Vous n'avez pas la permission d'envoyer des messages AreaShop."
|
||||
"message-notOnline": "%0% n'est pas connecté."
|
||||
"import-help": "/as import RegionAVendre"
|
||||
"import-wrongSource": "Spécifiez d'où vous voulez importer les données, les options: RegionAVendre"
|
||||
"import-noPluginFolder": "Impossible de trouver le dossier %0%, êtes-vous sûr que vous importez de la bonne source?"
|
||||
"import-noWorldsFolder": "Il n'y a pas de dossier 'plugins/RegionForSale/worlds' donc rien ne peut être importé."
|
||||
"import-confirm": "Êtes-vous sûr de vouloir importer toutes les régions de RegionAVendre?"
|
||||
"import-start": "Début de l'importation des données RegionAVendre :"
|
||||
"import-doWorld": "[darkgreen][bold]► Monde %0% :"
|
||||
"import-noBukkitWorld": "[red]Impossible de trouver le monde dans Bukkit."
|
||||
"import-noRegionManager": "[red]Impossible d’obtenir RegionManager de WorldGuard, les régions sont-elles activées dans ce monde?"
|
||||
"import-noRegions": "[red]Pas de fichier regions.yml trouvé."
|
||||
"import-loadRegionsFailed": "[red]Impossible de charger regions.yml de : %0%"
|
||||
"import-invalidRegionSection": "[red]Mauvaise section dans regions.yml : %0%."
|
||||
"import-noWorldGuardRegion": "[red]La région de WorldGuard n'a pas été trouvée :%0%."
|
||||
"import-noWorldGuardRegionParent": "[red]La région de WorldGuard pour la région parent n'a pas été trouvé : %0%"
|
||||
"import-buyAndRent": "[gold] %0% peuvent être achetés et loués, seulement en ajoutant comme achat dans AreaShop (ne peuvent pas être les deux)."
|
||||
"import-noBuyAndNoRent": "[red]%0% ne peut pas être acheté ni être loué sans importer."
|
||||
"import-imported": "[green]%lang:tRegion|%0% importé."
|
||||
"import-loadWorldConfigFailed": "[red} Chargement de world-specific config.yml échoué : %0%."
|
||||
"import-improperParentRegion": "[red]Region parent %0% n'a pas de réglages lisible."
|
||||
"import-alreadyAdded": "[red]Region '%0%' a déjà été ajoutée."
|
||||
"import-alreadyAddedOtherWorld": "[red]Region '%0%' a déjà été ajoutée dans le monde %1%, les régions de différents mondes ne peuvent pas avoir le même nom dans AreaShop."
|
||||
"import-invalidSignLocation": "[red]Echec d'importation de la pancarte de la région '%0%', location invalide '%1%'."
|
||||
"import-signAlreadyAdded": "[red] Ignoré l'ajout de la pancarte à la location '%1%' de la région '%0%', il est déjà ajouté à la région '%2%'."
|
||||
"import-moneyBackFailed": "[red] Échec de l'analyse du prix d'achat '%0%' et du prix de vente '%1%' pour définir le pourcentage de remboursement."
|
||||
"confirm-rent":
|
||||
- "%lang:prefix%Êtes-vous sur de vouloir louer %lang:tRegion|%0%|%?[break]"
|
||||
- "[darkgreen][bold]►[reset] %lang:button|Cliquez ici pour louer %0%|%"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||
# ║ Language file of the AreaShop plugin created by NLThijs48, Github can be found at https://github.com/NLthijs48/AreaShop
|
||||
# ║ Russian language file, plugin version 2.5.0, 395/428 messages are translated (92%)
|
||||
# ║ Russian language file, plugin version 2.5.0, 403/428 messages are translated (94%)
|
||||
# ║
|
||||
# ║ This file will be overwritten at each startup/reload of the plugin, if you want to change anything then do the following:
|
||||
# ║ 1: Make a copy of this file
|
||||
@@ -136,6 +136,7 @@
|
||||
"sell-sold": "%lang:region% был продан %lang:player%."
|
||||
"sell-noPermission": "У Вас нет прав для продажи региона."
|
||||
"sell-noPermissionOther": "У Вас нет прав для продажи другого региона."
|
||||
"sell-disabled": "Продажа была отключена для этого региона"
|
||||
"reload-reloading": "Перезагружены все конфигурации и файлы регионов."
|
||||
"reload-noPermission": "Недостаточно полномочий для того, чтобы перезагрузить конфиги плагина."
|
||||
"reload-updateCommandChanged": "'/as updaterents' и '/as updatebuys' были удалены, '/as reload' теперь будет также обновлять регионы, используйте взамен эту команду."
|
||||
@@ -283,6 +284,7 @@
|
||||
"setduration-successRemoved": "Длительность аренды в %lang:region% было удалено, использование новой длительности аренды из группы или файла default.yml, новая длительность: %duration%."
|
||||
"setup-noRegion": "Вы не указали регион на второй строке."
|
||||
"setup-alreadyRentSign": "Регион уже добавлен в AreaShop в виде аренды региона, добавьте табличку с [as] на первой строке, или '/as addsign'."
|
||||
"setup-alreadyOtherWorld": "Регион который ты выбрал уже добавлен в AreaShop в другом мире, регионы из разных миров должы иметь разные названия"
|
||||
"setup-alreadyBuySign": "Регион уже добавлен в AreaShop в виде покупного региона, добавьте табличку с [as] на первой строке, или '/as addsign'."
|
||||
"setup-noDuration": "Вы не указали, на сколько времени этот регион можно арендовать, сделайте это на третьей строчке."
|
||||
"setup-wrongDuration": "Время указано не в правильном формате, например: 1 day."
|
||||
@@ -361,6 +363,7 @@
|
||||
"add-noPermission": "У вас нет разрешения добавлять регионы в AreaShop."
|
||||
"add-success": "Добавлен в %0%: [gray]%1%."
|
||||
"add-failed": "Уже зарегистрирован: [gray]%0%."
|
||||
"add-failedOtherWorld": "Уже зарегистрирован в другом мире: [gray]"
|
||||
"add-blacklisted": "Включен в черный список : [gray]%0%."
|
||||
"add-specifyWorld": "Укажите мир региона при использовании из консоли."
|
||||
"add-incorrectWorld": "Мир '%0%' не найден, попробуйте еще раз (с учетом регистра)."
|
||||
@@ -372,6 +375,7 @@
|
||||
"addsign-help": "/as addsign [регион] [профиль]."
|
||||
"addsign-noSign": "Вы не смотрите на табличку."
|
||||
"addsign-noRegions": "Не найдено регионов вокруг таблички."
|
||||
"addSign-notRegistered": "Данный регион не зарегистрирован в AreaShop%0% (сначало нужно добавить регион в AreaShop прежде чем создавать табичку)"
|
||||
"addsign-couldNotDetect": "Найдено несколько регионов вокруг таблички, укажите регион в качестве дополнительного аргумента (2 из регионов, которые были найдены: %lang:tRegion|%0%|% и %lang:tRegion|%1%|%)."
|
||||
"addsign-couldNotDetectSign": "Найдено несколько регионов вокруг таблички, укажите регион на второй строке (2 из регионов, которые были найдены: %lang:tRegion|%0%|% и %lang:tRegion|%1%|%)."
|
||||
"addsign-wrongProfile": "Указанный профиль не существует, используйте одно из следующих действий (проверьте конфиг.): [gray]%0%."
|
||||
@@ -421,6 +425,7 @@
|
||||
"resell-success": "%lang:region% был успешно выставлен в режим перепродажи за %resellprice%."
|
||||
"resell-noPermission": "У Вас нет прав что бы установить ваш регион в режим перепродажи."
|
||||
"resell-noPermissionOther": "У Вас нет прав что бы установить регион в режим перепродажи."
|
||||
"resell-disabled": "Перепродажа была отключенна для этого региона"
|
||||
"stopresell-help": "/as stopresell [имярегиона], если не указано имя, будет выбран регион в котором вы находитесь."
|
||||
"stopresell-notRegistered": "Указанный регион не зарегистрирован: %0%."
|
||||
"stopresell-notResell": "Вы не можете остановить перепродажу %lang:region% потому что регион не в режиме перепродажи."
|
||||
@@ -479,6 +484,9 @@
|
||||
"message-help": "/as message <игрок> <сообщение...>"
|
||||
"message-noPermission": "У вас нет разрешения на отправку AreaShop сообщений."
|
||||
"message-notOnline": "%0% не в сети."
|
||||
"import-help": "/as import RegionForSale"
|
||||
"import-confirm": "Вы действительно хотите импортировать все регионы из RegionForSale?"
|
||||
"import-noWorldGuardRegion": "[red]WorldGuard регион не найден:"
|
||||
"confirm-rent":
|
||||
- "%lang:prefix%Вы уверены, что вы хотите арендовать %lang:tRegion|%0%|%?[break]"
|
||||
- "[darkgreen][bold]►[reset] %lang:button|Нажмите, чтобы арендовать %0%|%"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
name: AreaShop
|
||||
main: me.wiefferink.areashop.AreaShop
|
||||
version: "${project.version}${build.number}"
|
||||
version: "@version@"
|
||||
description: "Selling and renting WorldGuard regions to your players, highly configurable."
|
||||
depend: [Vault, WorldGuard, WorldEdit]
|
||||
softdepend: [Multiverse-Core]
|
||||
softdepend: [Multiverse-Core, FastAsyncWorldEdit]
|
||||
author: NLThijs48
|
||||
website: https://github.com/NLthijs48/AreaShop
|
||||
commands:
|
||||
@@ -13,6 +13,7 @@ commands:
|
||||
aliases: [as]
|
||||
awareness:
|
||||
- !@UTF8
|
||||
api-version: 1.13
|
||||
permissions:
|
||||
areashop.*:
|
||||
description: Give access to all commands of AreaShop
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,38 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop Interface</name>
|
||||
<version>AreaShopInterface</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldedit</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,22 +0,0 @@
|
||||
package me.wiefferink.areashop.interfaces;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public abstract class WorldEditInterface {
|
||||
protected final AreaShopInterface pluginInterface;
|
||||
|
||||
public WorldEditInterface(AreaShopInterface pluginInterface) {
|
||||
this.pluginInterface = pluginInterface;
|
||||
}
|
||||
|
||||
// Different way to restore blocks per implementation, newer ones support entities as well
|
||||
public abstract boolean restoreRegionBlocks(File file, GeneralRegionInterface regionInterface);
|
||||
|
||||
// Different way to save blocks per implementation, newer ones support entities as well
|
||||
public abstract boolean saveRegionBlocks(File file, GeneralRegionInterface regionInterface);
|
||||
|
||||
public abstract WorldEditSelection getPlayerSelection(Player player);
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
[►Request a feature, report a bug or ask support](https://github.com/NLthijs48/AreaShop/issues/new/choose)
|
||||
[►Open issues](https://github.com/NLthijs48/AreaShop/issues)<br/>
|
||||
**Development:**
|
||||
[►Changelog](https://github.com/NLthijs48/AreaShop/wiki/Changelog)
|
||||
[►Changelog](https://github.com/NLthijs48/AreaShop/blob/master/changelog.md)
|
||||
[►Compiling](https://github.com/NLthijs48/AreaShop/wiki/Compiling-AreaShop)
|
||||
[►Modules/classes overview](https://github.com/NLthijs48/AreaShop/wiki/Modules,-packages-and-classes-overview)
|
||||
[►Javadocs](https://wiefferink.me/AreaShop/javadocs/)
|
||||
@@ -64,11 +64,11 @@ For a preview join 'mc.go-craft.com' and go to the Survival server, the shops ar
|
||||
Old video for AreaShop v1.0: [Tutorial by VariationVault](https://www.youtube.com/watch?v=k2HMCxCCOYo)
|
||||
|
||||
### Required dependencies
|
||||
* Java 7 or higher (latest recommended)
|
||||
* Bukkit/Spigot 1.7.9 or higher (modded servers often include Bukkit/Spigot support, so it should also work on that, but it is not specifically tested for it)
|
||||
* [WorldGuard](http://dev.bukkit.org/bukkit-plugins/worldguard/): 5.9 or higher (6.0+ recommended)
|
||||
* [WorldEdit](http://dev.bukkit.org/bukkit-plugins/worldedit/): 5.6.3 or higher (6.0+ recommended)
|
||||
* [Vault](http://dev.bukkit.org/bukkit-plugins/vault/): 1.4.1 or higher
|
||||
* Java 8 or higher (latest recommended)
|
||||
* Bukkit/Spigot 1.13.2 or higher (modded servers often include Bukkit/Spigot support, so it should also work on that, but it is not specifically tested for it)
|
||||
* [WorldGuard](http://dev.bukkit.org/bukkit-plugins/worldguard/): 7.0.3 or higher
|
||||
* [WorldEdit](http://dev.bukkit.org/bukkit-plugins/worldedit/): 7.0.1 or higher
|
||||
* [Vault](http://dev.bukkit.org/bukkit-plugins/vault/): 1.7 or higher
|
||||
* An economy plugin supported by Vault (check the [Vault page](http://dev.bukkit.org/bukkit-plugins/vault/) for a list of these)
|
||||
|
||||
### Metrics
|
||||
@@ -83,6 +83,6 @@ Help translating the plugin into different languages and to keep the translation
|
||||
|
||||

|
||||
|
||||
[](https://discord.gg/84kGMCQ)
|
||||
[](https://discord.gg/84kGMCQ)
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VEECV88NG3L5C)
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,44 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldedit-5</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldEdit 5</name>
|
||||
<version>WorldEdit-5</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldedit</artifactId>
|
||||
<version>5.7-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,108 +0,0 @@
|
||||
package me.wiefferink.areashop.handlers;
|
||||
|
||||
import com.sk89q.worldedit.CuboidClipboard;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.selections.Selection;
|
||||
import com.sk89q.worldedit.data.DataException;
|
||||
import com.sk89q.worldedit.schematic.SchematicFormat;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
import me.wiefferink.areashop.interfaces.GeneralRegionInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class WorldEditHandler5 extends WorldEditInterface {
|
||||
|
||||
public WorldEditHandler5(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldEditSelection getPlayerSelection(Player player) {
|
||||
Selection selection = pluginInterface.getWorldEdit().getSelection(player);
|
||||
if (selection == null) {
|
||||
return null;
|
||||
}
|
||||
return new WorldEditSelection(
|
||||
player.getWorld(),
|
||||
selection.getMinimumPoint(),
|
||||
selection.getMaximumPoint()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRegionBlocks(File file, GeneralRegionInterface regionInterface) {
|
||||
file = new File(file.getAbsolutePath() + ".schematic");
|
||||
if(!file.exists() || !file.isFile()) {
|
||||
pluginInterface.getLogger().info("Did not restore region " + regionInterface.getName() + ", schematic file does not exist: " + file.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
boolean result = true;
|
||||
EditSession editSession = pluginInterface.getWorldEdit().getWorldEdit().getEditSessionFactory().getEditSession(new BukkitWorld(regionInterface.getWorld()), pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
// Get the origin and size of the region
|
||||
Vector origin = new Vector(regionInterface.getRegion().getMinimumPoint().getBlockX(), regionInterface.getRegion().getMinimumPoint().getBlockY(), regionInterface.getRegion().getMinimumPoint().getBlockZ());
|
||||
|
||||
editSession.enableQueue();
|
||||
Exception otherException = null;
|
||||
try {
|
||||
CuboidClipboard clipBoard = SchematicFormat.MCEDIT.load(file);
|
||||
if(clipBoard.getHeight() != regionInterface.getHeight()
|
||||
|| clipBoard.getWidth() != regionInterface.getWidth()
|
||||
|| clipBoard.getLength() != regionInterface.getDepth()) {
|
||||
pluginInterface.getLogger().warning("Size of the region " + regionInterface.getName() + " is not the same as the schematic to restore!");
|
||||
pluginInterface.debugI("schematic|region, x:" + clipBoard.getWidth() + "|" + regionInterface.getWidth() + ", y:" + clipBoard.getHeight() + "|" + regionInterface.getHeight() + ", z:" + clipBoard.getLength() + "|" + regionInterface.getDepth());
|
||||
}
|
||||
clipBoard.place(editSession, origin, false);
|
||||
} catch(MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning("exceeded the block limit while restoring schematic of " + regionInterface.getName() + ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: " + pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
result = false;
|
||||
} catch(DataException | IOException e) {
|
||||
otherException = e;
|
||||
}
|
||||
if(otherException != null) {
|
||||
pluginInterface.getLogger().warning("Failed to restore schematic for region " + regionInterface.getName());
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(otherException));
|
||||
result = false;
|
||||
}
|
||||
editSession.flushQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveRegionBlocks(File file, GeneralRegionInterface regionInterface) {
|
||||
file = new File(file.getAbsolutePath() + ".schematic");
|
||||
boolean result = true;
|
||||
ProtectedRegion region = regionInterface.getRegion();
|
||||
// Get the origin and size of the region
|
||||
Vector origin = new Vector(region.getMinimumPoint().getBlockX(), region.getMinimumPoint().getBlockY(), region.getMinimumPoint().getBlockZ());
|
||||
Vector size = (new Vector(region.getMaximumPoint().getBlockX(), region.getMaximumPoint().getBlockY(), region.getMaximumPoint().getBlockZ()).subtract(origin)).add(new Vector(1, 1, 1));
|
||||
EditSession editSession = new EditSession(new BukkitWorld(regionInterface.getWorld()), pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
// Save the schematic
|
||||
editSession.enableQueue();
|
||||
CuboidClipboard clipboard = new CuboidClipboard(size, origin);
|
||||
clipboard.copy(editSession);
|
||||
Exception otherException = null;
|
||||
try {
|
||||
SchematicFormat.MCEDIT.save(clipboard, file);
|
||||
} catch(DataException | IOException e) {
|
||||
otherException = e;
|
||||
}
|
||||
if(otherException != null) {
|
||||
pluginInterface.getLogger().warning("Failed to save schematic for region " + regionInterface.getName());
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(otherException));
|
||||
result = false;
|
||||
}
|
||||
editSession.flushQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,44 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldedit-6</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldEdit 6</name>
|
||||
<version>WorldEdit-6</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldedit</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,191 +0,0 @@
|
||||
package me.wiefferink.areashop.handlers;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.selections.Selection;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.internal.LocalWorldAdapter;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionType;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
import me.wiefferink.areashop.interfaces.GeneralRegionInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class WorldEditHandler6 extends WorldEditInterface {
|
||||
|
||||
public WorldEditHandler6(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldEditSelection getPlayerSelection(Player player) {
|
||||
Selection selection = pluginInterface.getWorldEdit().getSelection(player);
|
||||
if (selection == null) {
|
||||
return null;
|
||||
}
|
||||
return new WorldEditSelection(
|
||||
player.getWorld(),
|
||||
selection.getMinimumPoint(),
|
||||
selection.getMaximumPoint()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRegionBlocks(File file, GeneralRegionInterface regionInterface) {
|
||||
file = new File(file.getAbsolutePath() + ".schematic");
|
||||
if(!file.exists() || !file.isFile()) {
|
||||
pluginInterface.getLogger().info("Did not restore region " + regionInterface.getName() + ", schematic file does not exist: " + file.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
com.sk89q.worldedit.world.World world = null;
|
||||
if(regionInterface.getName() != null) {
|
||||
world = LocalWorldAdapter.adapt(new BukkitWorld(regionInterface.getWorld()));
|
||||
}
|
||||
if(world == null) {
|
||||
pluginInterface.getLogger().info("Did not restore region " + regionInterface.getName() + ", world not found: " + regionInterface.getWorldName());
|
||||
return false;
|
||||
}
|
||||
EditSession editSession = pluginInterface.getWorldEdit().getWorldEdit().getEditSessionFactory().getEditSession(world, pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
editSession.enableQueue();
|
||||
ProtectedRegion region = regionInterface.getRegion();
|
||||
// Get the origin and size of the region
|
||||
Vector origin = new Vector(region.getMinimumPoint().getBlockX(), region.getMinimumPoint().getBlockY(), region.getMinimumPoint().getBlockZ());
|
||||
|
||||
// Read the schematic and paste it into the world
|
||||
try(Closer closer = Closer.create()) {
|
||||
FileInputStream fis = closer.register(new FileInputStream(file));
|
||||
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
ClipboardReader reader = ClipboardFormat.SCHEMATIC.getReader(bis);
|
||||
|
||||
WorldData worldData = world.getWorldData();
|
||||
LocalSession session = new LocalSession(pluginInterface.getWorldEdit().getLocalConfiguration());
|
||||
Clipboard clipboard = reader.read(worldData);
|
||||
if(clipboard.getDimensions().getY() != regionInterface.getHeight()
|
||||
|| clipboard.getDimensions().getX() != regionInterface.getWidth()
|
||||
|| clipboard.getDimensions().getZ() != regionInterface.getDepth()) {
|
||||
pluginInterface.getLogger().warning("Size of the region " + regionInterface.getName() + " is not the same as the schematic to restore!");
|
||||
pluginInterface.debugI("schematic|region, x:" + clipboard.getDimensions().getX() + "|" + regionInterface.getWidth() + ", y:" + clipboard.getDimensions().getY() + "|" + regionInterface.getHeight() + ", z:" + clipboard.getDimensions().getZ() + "|" + regionInterface.getDepth());
|
||||
}
|
||||
clipboard.setOrigin(clipboard.getMinimumPoint());
|
||||
ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard, worldData);
|
||||
session.setBlockChangeLimit(pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
session.setClipboard(clipboardHolder);
|
||||
|
||||
// Build operation
|
||||
BlockTransformExtent extent = new BlockTransformExtent(clipboardHolder.getClipboard(), clipboardHolder.getTransform(), editSession.getWorld().getWorldData().getBlockRegistry());
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), editSession, origin);
|
||||
copy.setRemovingEntities(true);
|
||||
copy.setTransform(clipboardHolder.getTransform());
|
||||
// Mask to region (for polygon and other weird shaped regions)
|
||||
// TODO make this more efficient (especially for polygon regions)
|
||||
if(region.getType() != RegionType.CUBOID) {
|
||||
copy.setSourceMask(new Mask() {
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return region.contains(vector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
} catch(MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning("exceeded the block limit while restoring schematic of " + regionInterface.getName() + ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: " + pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
return false;
|
||||
} catch(IOException e) {
|
||||
pluginInterface.getLogger().warning("An error occured while restoring schematic of " + regionInterface.getName() + ", enable debug to see the complete stacktrace");
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
return false;
|
||||
}
|
||||
editSession.flushQueue();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveRegionBlocks(File file, GeneralRegionInterface regionInterface) {
|
||||
file = new File(file.getAbsolutePath() + ".schematic");
|
||||
com.sk89q.worldedit.world.World world = null;
|
||||
if(regionInterface.getWorld() != null) {
|
||||
world = LocalWorldAdapter.adapt(new BukkitWorld(regionInterface.getWorld()));
|
||||
}
|
||||
if(world == null) {
|
||||
pluginInterface.getLogger().warning("Did not save region " + regionInterface.getName() + ", world not found: " + regionInterface.getWorldName());
|
||||
return false;
|
||||
}
|
||||
EditSession editSession = pluginInterface.getWorldEdit().getWorldEdit().getEditSessionFactory().getEditSession(world, pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
// Create a clipboard
|
||||
CuboidRegion selection = new CuboidRegion(world, regionInterface.getRegion().getMinimumPoint(), regionInterface.getRegion().getMaximumPoint());
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(selection);
|
||||
clipboard.setOrigin(regionInterface.getRegion().getMinimumPoint());
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, new CuboidRegion(world, regionInterface.getRegion().getMinimumPoint(), regionInterface.getRegion().getMaximumPoint()), clipboard, regionInterface.getRegion().getMinimumPoint());
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
} catch(MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning("exceeded the block limit while saving schematic of " + regionInterface.getName() + ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: " + pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
return false;
|
||||
}
|
||||
|
||||
try(Closer closer = Closer.create()) {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(file));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
ClipboardWriter writer = closer.register(ClipboardFormat.SCHEMATIC.getWriter(bos));
|
||||
writer.write(clipboard, world.getWorldData());
|
||||
} catch(IOException e) {
|
||||
pluginInterface.getLogger().warning("An error occured while saving schematic of " + regionInterface.getName() + ", enable debug to see the complete stacktrace");
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,44 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldedit-7</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldEdit 7</name>
|
||||
<version>WorldEdit-7</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldedit</artifactId>
|
||||
<scope>system</scope>
|
||||
<version>any</version>
|
||||
<systemPath>${project.basedir}/../dependencies/worldedit-bukkit-7.0.0-beta-01.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<scope>system</scope>
|
||||
<version>any</version>
|
||||
<systemPath>${project.basedir}/../dependencies/worldguard-legacy-7.0.0-beta01.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,37 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldguard-5</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldGuard 5</name>
|
||||
<version>WorldGuard-5</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<version>5.9.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,141 +0,0 @@
|
||||
package me.wiefferink.areashop.handlers;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.domains.DefaultDomain;
|
||||
import com.sk89q.worldguard.protection.flags.DefaultFlag;
|
||||
import com.sk89q.worldguard.protection.flags.Flag;
|
||||
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroup;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
import me.wiefferink.areashop.interfaces.RegionAccessSet;
|
||||
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WorldGuardHandler5 extends WorldGuardInterface {
|
||||
|
||||
public WorldGuardHandler5(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionManager getRegionManager(World world) {
|
||||
return WorldGuardPlugin.inst().getRegionManager(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtectedRegion> getApplicableRegionsSet(Location location) {
|
||||
Set<ProtectedRegion> result = new HashSet<>();
|
||||
Vector vector = new Vector(location.getX(), location.getY(), location.getZ());
|
||||
for(ProtectedRegion region : pluginInterface.getWorldGuard().getRegionManager(location.getWorld()).getRegions().values()) {
|
||||
if(region.contains(vector)) {
|
||||
result.add(region);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwners(ProtectedRegion region, RegionAccessSet regionAccessSet) {
|
||||
DefaultDomain defaultDomain = buildDomain(regionAccessSet);
|
||||
if(!region.getOwners().toUserFriendlyString().equals(defaultDomain.toUserFriendlyString())) {
|
||||
region.setOwners(defaultDomain);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMembers(ProtectedRegion region, RegionAccessSet regionAccessSet) {
|
||||
DefaultDomain defaultDomain = buildDomain(regionAccessSet);
|
||||
if(!region.getMembers().toUserFriendlyString().equals(defaultDomain.toUserFriendlyString())) {
|
||||
region.setMembers(defaultDomain);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionAccessSet getMembers(ProtectedRegion region) {
|
||||
RegionAccessSet result = new RegionAccessSet();
|
||||
result.getGroupNames().addAll(region.getMembers().getGroups());
|
||||
result.getPlayerNames().addAll(region.getMembers().getPlayers());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionAccessSet getOwners(ProtectedRegion region) {
|
||||
RegionAccessSet result = new RegionAccessSet();
|
||||
result.getGroupNames().addAll(region.getOwners().getGroups());
|
||||
result.getPlayerNames().addAll(region.getOwners().getPlayers());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a DefaultDomain from a RegionAccessSet.
|
||||
* @param regionAccessSet RegionAccessSet to read
|
||||
* @return DefaultDomain containing the entities from the RegionAccessSet
|
||||
*/
|
||||
private DefaultDomain buildDomain(RegionAccessSet regionAccessSet) {
|
||||
DefaultDomain owners = new DefaultDomain();
|
||||
|
||||
for(String playerName : regionAccessSet.getPlayerNames()) {
|
||||
owners.addPlayer(playerName);
|
||||
}
|
||||
|
||||
// Add by name since UUIDs were not yet supported
|
||||
for(UUID uuid : regionAccessSet.getPlayerUniqueIds()) {
|
||||
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
|
||||
if(offlinePlayer != null && offlinePlayer.getName() != null) {
|
||||
owners.addPlayer(offlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
for(String group : regionAccessSet.getGroupNames()) {
|
||||
owners.addGroup(group);
|
||||
}
|
||||
|
||||
return owners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsMember(ProtectedRegion region, UUID player) {
|
||||
if(player == null) {
|
||||
return false;
|
||||
} else {
|
||||
String name = Bukkit.getOfflinePlayer(player).getName();
|
||||
return name != null && region.getMembers().contains(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsOwner(ProtectedRegion region, UUID player) {
|
||||
if(player == null) {
|
||||
return false;
|
||||
} else {
|
||||
String name = Bukkit.getOfflinePlayer(player).getName();
|
||||
return name != null && region.getOwners().contains(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flag<?> fuzzyMatchFlag(String flagName) {
|
||||
return DefaultFlag.fuzzyMatchFlag(flagName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> V parseFlagInput(Flag<V> flag, String input) throws InvalidFlagFormat {
|
||||
return flag.parseInput(WorldGuardPlugin.inst(), null, input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionGroup parseFlagGroupInput(RegionGroupFlag flag, String input) throws InvalidFlagFormat {
|
||||
return flag.parseInput(WorldGuardPlugin.inst(), null, input);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,37 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldguard-6</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldGuard 6</name>
|
||||
<version>WorldGuard-6</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,44 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldguard-6_1_3</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldGuard 6_1_3</name>
|
||||
<version>WorldGuard-6_1_3</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkit.version}</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-6</artifactId>
|
||||
<version>WorldGuard-6</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q.worldguard</groupId>
|
||||
<artifactId>worldguard-legacy</artifactId>
|
||||
<version>6.1.3-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package me.wiefferink.areashop.handlers;
|
||||
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.protection.flags.DefaultFlag;
|
||||
import com.sk89q.worldguard.protection.flags.Flag;
|
||||
import com.sk89q.worldguard.protection.flags.FlagContext;
|
||||
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroup;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
|
||||
public class WorldGuardHandler6_1_3 extends WorldGuardHandler6 {
|
||||
|
||||
public WorldGuardHandler6_1_3(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flag<?> fuzzyMatchFlag(String flagName) {
|
||||
return DefaultFlag.fuzzyMatchFlag(WorldGuardPlugin.inst().getFlagRegistry(), flagName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> V parseFlagInput(Flag<V> flag, String input) throws InvalidFlagFormat {
|
||||
return flag.parseInput(FlagContext.create().setInput(input).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionGroup parseFlagGroupInput(RegionGroupFlag flag, String input) throws InvalidFlagFormat {
|
||||
return flag.parseInput(FlagContext.create().setInput(input).build());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,58 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>areashop-worldguard-7</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>AreaShop WorldGuard 7</name>
|
||||
<version>WorldGuard-7</version>
|
||||
|
||||
<parent>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-parent</artifactId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-interface</artifactId>
|
||||
<version>AreaShopInterface</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldedit</artifactId>
|
||||
<scope>system</scope>
|
||||
<version>any</version>
|
||||
<systemPath>${project.basedir}/../dependencies/worldedit-bukkit-7.0.0-beta-01.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-6</artifactId>
|
||||
<version>WorldGuard-6</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.wiefferink</groupId>
|
||||
<artifactId>areashop-worldguard-6_1_3</artifactId>
|
||||
<version>WorldGuard-6_1_3</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q</groupId>
|
||||
<artifactId>worldguard</artifactId>
|
||||
<scope>system</scope>
|
||||
<version>any</version>
|
||||
<systemPath>${project.basedir}/../dependencies/worldguard-legacy-7.0.0-beta01.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,40 +0,0 @@
|
||||
package me.wiefferink.areashop.handlers;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.protection.flags.Flag;
|
||||
import com.sk89q.worldguard.protection.flags.FlagContext;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroup;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class WorldGuardHandler7 extends WorldGuardHandler6_1_3 {
|
||||
|
||||
public WorldGuardHandler7(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionManager getRegionManager(World world) {
|
||||
return WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flag<?> fuzzyMatchFlag(String flagName) {
|
||||
return Flags.fuzzyMatchFlag(WorldGuard.getInstance().getFlagRegistry(), flagName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> V parseFlagInput(Flag<V> flag, String input) throws InvalidFlagFormat {
|
||||
return flag.parseInput(FlagContext.create().setInput(input).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionGroup parseFlagGroupInput(RegionGroupFlag flag, String input) throws InvalidFlagFormat {
|
||||
return flag.parseInput(FlagContext.create().setInput(input).build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = "me.wiefferink.areashop"
|
||||
version = '2.6.3'
|
||||
|
||||
subprojects {
|
||||
|
||||
plugins.apply('java')
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = 'paper-repo'
|
||||
url = uri('https://papermc.io/repo/repository/maven-public/')
|
||||
}
|
||||
maven {
|
||||
name = 'spigot-repo'
|
||||
url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/')
|
||||
}
|
||||
maven {
|
||||
name = 'jitpack'
|
||||
url = uri('https://jitpack.io')
|
||||
content {
|
||||
includeGroupByRegex("com\\.github.*")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = 'aikar-repo'
|
||||
url = uri('https://repo.aikar.co/content/groups/aikar/')
|
||||
}
|
||||
maven {
|
||||
name = 'enginehub-repo'
|
||||
url = uri('https://maven.enginehub.org/repo/')
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
tasks.withType(JavaCompile) {
|
||||
javaToolchains.compilerFor {
|
||||
JavaLanguageVersion.of(16)
|
||||
}
|
||||
options.release.set(16)
|
||||
options.encoding = 'UTF-8'
|
||||
options.fork = true
|
||||
options.deprecation = true
|
||||
}
|
||||
}
|
||||
}
|
||||
+426
@@ -0,0 +1,426 @@
|
||||
## AreaShop NEXT
|
||||
[**Planned features**](https://github.com/NLthijs48/AreaShop/milestone/5)
|
||||
|
||||
## AreaShop 2.6.0
|
||||
**Features:**
|
||||
* Add 1.13 FastAsyncWorldEdit support (note: FastAsyncWorldEdit does seem to work correctly for 1.13.0, but not yet on 1.13.2)
|
||||
* Add support for the latest WorldEdit/WorldGuard 7 versions (which have refactored the vector classes)
|
||||
* Improve adding back signs after they have been removed by players or schematic restore
|
||||
* Improve performance of the BlockPhysicsEvent (allow signs to get removed to prevent loops, while not dropping an item)
|
||||
* Updated all translations, pulled from Transifex
|
||||
|
||||
**Fixed:**
|
||||
* Fixed `/as setduration` tab completion
|
||||
* Fixed 1.13 Material handling, especially dealing with signs and the checks by the safe teleport function
|
||||
* `/as add`: properly set the landlord when the player is an owner of the region (it was only working for members)
|
||||
|
||||
**Technical:**
|
||||
* Change Maven dependencies to use `.jar` files in the `dependencies/` folder to ensure the build keeps working even though maven repositories have disappeared
|
||||
|
||||
## AreaShop 2.5.0
|
||||
**Features:**
|
||||
* Minecraft 1.13 and 1.13.1 support.
|
||||
* WorldGuard 7 support.
|
||||
* WorldEdit 7 support.
|
||||
* Update all translations (pulled from Transifex).
|
||||
* Add import for RegionForSale regions:
|
||||
* `/as import RegionForSale`
|
||||
* Imports all regions from RegionForSale
|
||||
* Converts almost all settings to their AreaShop equivalent
|
||||
* Handles parent regions
|
||||
* Add setting to automatically extends a rent when the time is up: `rent.autoExtend` in `default.yml`.
|
||||
* Added options to disable players selling/reselling regions: `buy.sellDisabled`, `buy.resellDisabled`.
|
||||
* Add setting to disable cross-world teleports for the `/as tp` command: `teleportCrossWorld` in the `general` section of `default.yml`.
|
||||
* Add setting to disable cross-world teleports for the `/as find` command: `findCrossWorld` in the `general` section of `default.yml`.
|
||||
* Allow `price` and `moneyBack` values to be calculated dynamically:
|
||||
* All region variables can be used: `price: "5*%volume%"` would be `$5` per cubic meter (block in the region).
|
||||
* Full JavaScript expressions and code can be used, the last statement will be the resulting price.
|
||||
* Add `%volume%` variable for the number of blocks in a region, which supports polygon regions correctly.
|
||||
* `/as stack` now allows the usage of `#` to choose the position of the number in the region name.
|
||||
* Add customizable metric suffixes, now you can decide when to shorten a number and how, see `metricSymbols` in `config.yml`.
|
||||
* Add support for automatically adding all AreaShop regions of a certain world to a RegionGroup
|
||||
|
||||
**Technical:**
|
||||
* BREAKING: `BuyingRegionEvent`, `RentingRegionEvent` and `ResellingRegionEvent` now use `OfflinePlayer` instead of `Player`, because renting/buying/reselling is now also possible while the player is offline.
|
||||
* Improved file loading mechanics
|
||||
* Improve sign update performance, AreaShop will never load chunks anymore, and will simply update signs when players load chunks.
|
||||
* Moved the messaging library to its own project: [InteractiveMessenger](https://github.com/NLthijs48/InteractiveMessenger)
|
||||
* Added a lot of automated tests to ensure all functionality keeps working
|
||||
* Fixed bugs with formatting codes, line endings and hover messages
|
||||
* All user input that is inserted into messages is now escaped properly (using variables does not break the message anyore)
|
||||
* Add [bStats.org](https://bstats.org/plugin/bukkit/AreaShop) analytics. Since mcstats.org is really unstable and offline half of the time I added bStats (which tracks the same information, plus the number of regions and their state), MCStats tracking will be removed in a future version.
|
||||
* Groups are never removed from `groups.yml` anymore, previously they were removed when they had zero regions, which wipe settings.
|
||||
* Github update checker has been added as replacement for the BukkitDev updater (it will never download anything, it just notifies about updates).
|
||||
* Only update WorldGuard region settings if they are different, this should prevent unnecessary saving by WorldGuard.
|
||||
* When new code is pushed to Github the translations on Transifex get updated automatically, so that translations can begin immediately.
|
||||
|
||||
**Fixed:**
|
||||
* Security issues caused by saving/restoring entities in schematics
|
||||
* Prevent missing `schematicProfile` causing an exception.
|
||||
* Setting `schematicProfile` in a region file.
|
||||
* Players could resell their region with a negative price.
|
||||
* Using `landlordName` without `landlord` (UUID) setting works correctly now.
|
||||
* Using `/as addfriend` with a player that is online for the first time.
|
||||
* Removing the English time modifiers from the config.yml file would cause all tasks to be broken, because their schedule time is defined with strings like `1 minute`. The English modifiers from the config.yml inside the .jar file are always added now.
|
||||
* `/as setowner` for regions that are not yet rented has been fixed.
|
||||
* Restoring polygon regions will now only touch blocks that are actually inside the region.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.4.0
|
||||
* Change the `config.yml` and `default.yml` files to be easier to understand:
|
||||
* The profiles previously listed in the `config.yml` are now directly assigned to the profile settings in `default.yml`
|
||||
* When you give a profile setting in `default.yml` a string it will still look up the profile in `config.yml`, which ensures your old config still works.
|
||||
* Add permissions `areashop.teleportavailable` and `areashop.teleportavailablesign`, with which you can give players permission to teleport to all forsale/forrent regions (thanks jewome62 for the [pull request](https://github.com/NLthijs48/AreaShop/pull/241)!).
|
||||
* Support for stacking up and down with `/as stack`.
|
||||
* Fix clicking signs while confirmations are enabled trying to execute commands as players by default (causing that the player does not get a confirmation message).
|
||||
* Fix a line break problem in the message parser and fix line breaks on 1.7 servers.
|
||||
* Fix some color parsing issues in the message parser (it would not detect a color if you directly used the section sign).
|
||||
* Add tab completion for `/as me`.
|
||||
* Fix a bug that caused `/as setowner` extending the rent, even though the owner is different as the previous one.
|
||||
* Rename the events AreaShop emits for integration with other plugins (**this breaks existing plugins that use these events!**).
|
||||
* Fix WorldGuard version detection.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.3.2
|
||||
* Added Russian translation (86% complete, so if you know Russian please [help translating](https://github.com/NLthijs48/AreaShop/wiki/Language-support))
|
||||
* Fixed server crash bug caused by the new messages system (#205)
|
||||
* Improve stability of the messages system (all reflection removed, using /tellraw in the background now)
|
||||
* Fix Vault API repo link, thanks Androkai (#206)
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.3.1
|
||||
* Added German, French and Norwegian translations, thanks to all the translators!
|
||||
* Added automatic conversion for language files downloaded from Transifex (this means you can download the latest version from Transifex and AreaShop will correctly read it).
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.3.0
|
||||
**Additions:**
|
||||
- Add hover/click support for all messages of AreaShop:
|
||||
- If a region name is in a message then you can click the region name to see all information about the region.
|
||||
- Player names can be clicked to see which regions they own.
|
||||
- For long lists like `/as info all` AreaShop will use pages, with buttons you can click to go to the next/previous page.
|
||||
- A lot of buttons on the region info page, to rent/unrent, remove friends or teleport to the region
|
||||
- All these messages are defined in the messages file (EN.yml), so you can also edit and [use these yourself](https://github.com/NLthijs48/AreaShop/wiki/Language-support#message-format-specifications).
|
||||
- Got any suggestions for adding more buttons like these? Please let me know.
|
||||
- Can be turned off by `useFancyMessages` in `config.yml` (no idea why you would want to do that though).
|
||||
- Improvements to inserting messages into other messages, for example passing along variables: `%lang:action|My action text|%`.
|
||||
- `/as help` now respects the `areashop.help` permission.
|
||||
- Add an `ALL` state for flagProfiles to set flags for all states (like `priority`).
|
||||
- By default players need to confirm selling/unrenting when using signs, to prevent accidentely losing your region and possibly the contents of it (you can also easily turn it on for renting/buying in the `signProfiles` section in `config.yml`).
|
||||
- Add compatibility for the upcoming WorldGuard version (setting flags of regions changed).
|
||||
|
||||
**Technical:**
|
||||
- Add redunded money to the `UnrentedRegionEvent` and `SoldRegionEvent`.
|
||||
- Add events for adding/removing friends: `AddFriendEvent` and `DeleteFriendEvent`, both can be cancelled.
|
||||
- Move all code to the `me.wiefferink` package, since I intent on keeping this domain, and will not have `nl.evolutioncoding` for long anymore.
|
||||
- Add an issue template to the repository so that creating Github issues has placeholder text and directions on what information to provide.
|
||||
- Cleanup the config file by making all timing settings hidden.
|
||||
- Improve the Maven setup by adding options to move plugin output to a directory, produce a jar with sources and produce Javadoc
|
||||
- Add a [build server](http://wiefferink.me:8080/job/AreaShop/) where you can find the latest **in development** AreaShop version.
|
||||
- Setup a Javadoc site: [https://wiefferink.me/AreaShop/javadocs/](https://wiefferink.me/AreaShop/javadocs/), automatically updated by the Jenkins build server.
|
||||
|
||||
**Fixes:**
|
||||
- Fix problems with detecting most important region when placing a sign (problem showed up when using child/parent system of WorldGuard)
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.2.2
|
||||
**Additions:**
|
||||
* Add full 1.9 compatibility (only stats reporting and some tab completions were broken, all other functionality was functional already).
|
||||
* Add feature that lets players rent a region at least to the maximum rental time (before they could not extend before the region had `max-duration` time left). Can be turned off in the `default.yml` file with `extendToFullWhenAboveMaxRentTime`.
|
||||
* Add event system:
|
||||
- 'ask' type events that can be cancelled, broadcasted before the action happens.
|
||||
- 'notify' type events that cannot be cancelled, but only let you know that it has happened.
|
||||
- Events for renting (with extending flag), unrenting, buying, selling, reselling, adding and removing.
|
||||
- General 'RegionUpdateEvent' to listen to as display service (update signs, update regions flags, etc).
|
||||
- Can be used to write addons for AreaShop.
|
||||
- Is currently only used for updating signs and regions, but other parts of AreaShop will also be using it soon.
|
||||
* Add `areashop.linksigns` permissions to the `areashop.*` permissions group.
|
||||
* Add priority, interact and build flag to the default `config.yml` file, helps to reduce support for issues with this.
|
||||
* Add `middle` and number options to the `teleportLocationY` setting in `default.yml`.
|
||||
* Add variable support for all language messages that can support it, which means where a region is known.
|
||||
* Add Czech language, translated by Fractival.
|
||||
|
||||
**Fixes:**
|
||||
* Fix last active time of players sometimes not updating correctly, influences inactive unrent/sell feature.
|
||||
* Fix message variables for `/as info player <player>`.
|
||||
* Fix the `n:<name>` option for member/owner region flags (the `n:` was not stripped away before adding them).
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.2.1
|
||||
* Added a setting to deny extending rental regions when the player is above his limits (if the player cannot rent the region back when he unrents it then it he is considered to be above his limits). Setting `allowRegionExtendsWhenAboveLimits` can be found in `config.yml` and is by default set at `false`, this modifies the behaviour of AreaShop compared to the previous version, but this is probably something that users already expect to happen.
|
||||
* Fixed a bug with `/as tp` sometimes teleporting to the region instead of a the sign when a player has certain permissions.
|
||||
* Moved all documentation to GitHub, as you probably have already seen.
|
||||
* Added permission `areashop.buyresell` and `areashop.buynormal` to be able to prevent players from buying regions that are in reselling mode, or regions that are not in reselling mode.
|
||||
* Fixed `/as find` without balance argument using a maximum of zero instead of the balance of the player + formatting of the price will now use the proper currency formatting instead of a plain number.
|
||||
* Fixed `/as info` trying to filter by group for a couple of sub commands when it should not.
|
||||
* Fixed `/as info region <region>` always showing a line specifying the landlord, even when there is not one (it would show `<UNKNOWN>`).
|
||||
* Added Vault jar file to the repository to make compiling easier, only cloning + running with Maven is enough now.
|
||||
* Improved handling of failed file loading for all config and region files, better messages in console for when it happens.
|
||||
* Remove `lastActive` line from region files when unrented/sold, nothing serious, just cleanup.
|
||||
* Fixed sign click actions still executing even when the Bukkit event is cancelled.
|
||||
* Breaking signs that are connected to regions will not longer disconnect it, but instead make it float.
|
||||
* Made removing regions from AreaShop less destructible for region flags, only greeting and farewell are removed to avoid confusion (this helps when you accidentally add wrong regions).
|
||||
* Fixed support for the seconds modifiers when using `/as setduration`.
|
||||
* Added support for weeks modifiers for specifying time durations.
|
||||
* Cleaned old Dutch time modifiers from `config.yml`, **Warning: This will break existing signs with these modifiers if not re-added in the config**. Regions using incorrect time specifiers will be listed in the console/log at startup.
|
||||
* Unrenting/selling a region that has a landlord will now get the money from the landlord instead of introducing new money. If the landlord does not have enough money then the user will get nothing back.
|
||||
* Change the default sign tags to `[asrent]` and `[asbuy]`, this prevents clashes with for example Essentials. This will not impact already linked signs, only creating new signs and the tags can still be easily changed in the config.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.2.0
|
||||
* Change to a module based Maven project to support dependencies with multiple versions:
|
||||
* 1 .jar file for AreaShop, no different files for certain dependencies anymore.
|
||||
* Support for WorldGuard 5 and WorldGuard 6.
|
||||
* Support for WorldEdit 5 and WorldEdit 6.
|
||||
* Setup to easily add support for more version if breaking changes in dependencies happen.
|
||||
* Add support for the new schematic save/restore classes of WorldEdit (supports entities).
|
||||
* Added the `/as stack` command to easily create and register a lot of regions, syntax:
|
||||
* /as stack <amount> <gap> <name> <rent|buy> [group]
|
||||
* `<amount>` Number of regions that will be created
|
||||
* `<gap>` Blocks distance between the regions
|
||||
* `<name>` Name of the regions (number will be behind it)
|
||||
* `<rent|buy>` The type of the region
|
||||
* `[group]` A group to add the created regions to
|
||||
* The regions will be created in the direction you are facing
|
||||
* Don't be afraid to create 100+ regions with this command, it will do a certain number per tick, and therefore not lag/crash the server.
|
||||
* Setting `stackRegionNumberLength` to config.yml to indicate how long the numbers appended to the base region name should at least be (generate names like this: `region-001`, `region-014`, `region-4567`).
|
||||
* Make region loading non-descructive:
|
||||
Regions will never be removed again by AreaShop itself. If the world or WorldGuard region is missing that is required for the functions of the region then it will simply say so in the console. This will make sure that regions are not removed when you have trouble loading your world or your WorldGuard regions.
|
||||
* Make the update checker async, also when it cannot reach BukkitDev to check for updates it does not slow down the start of the server.
|
||||
* Fix `/as setowner` not saving the region file, and therefore losing changes when restarting the server.
|
||||
* Change Vault integration to support custom (not build into Vault) economies. This also enables support to change economies while the server is running.
|
||||
* Fix a bug with teleporting to regions, and add a message when the teleport changes from sign to region or the other way around (this happens when the user does not have permission for one of them, but has for the other).
|
||||
* Remove the `enableSchematics` setting from the config file, this setting is already in default.yml and only caused confusion.
|
||||
* Added landlord functionality:
|
||||
* Set the landlord of a region with `/as setlandlord <player>`.
|
||||
* Set the landlord in default.yml or groups by UUID or name.
|
||||
* All revenue of a region (buy/rental) will go to the landlord.
|
||||
* Permissions `areashop.createrent.owner`, `areashop.createrent.member`, `areashop.createbuy.owner` and `areashop.createbuy.member` to enable users to add existing WorldGuard regions to AreaShop if they are already owner/member (they are automatically assigned as landlord when they add regions).
|
||||
* Permissions `areashop.destroybuy.landlord` and `areashop.destroyrent.landlord` to give landlords the permission to remove their region from AreaShop.
|
||||
* Permission `areashop.setprice.landlord` to let landlords change the price of their region.
|
||||
* Permission `areashop.setduration.landlord` to let landlords change the duration of their region.
|
||||
* Permission `areashop.landlord.*` to give all landlord permissions to a player (all permissions above).
|
||||
* Added arguments `default` and `reset` to `/as setprice` and `/as setduration` to remove the setting from the region file (then it inherits it again from the groups or default.yml).
|
||||
* Support Metric prefixes (https://en.wikipedia.org/wiki/Metric_prefix) to display large numbers nicely. This means you can display numbers like `1000000` as `1.00G` instead. Has options to indicate from which number prefixes should be used.
|
||||
* Added a decimalMark setting to config.yml to change the character used to indicate the fractional part of numbers (change from dot to comma for example).
|
||||
* Changed all time period settings in config files to a readable format like the rental times. Old values will still be read correctly, and should work exactly like in the old version.
|
||||
* Make sure regions are not unnecessary saved directly after loading them at server startup.
|
||||
* Fixed an issue with `/as addfriend` denying you to add players that just joined for the first time.
|
||||
* Fix a problem with depositing money to players that never joined the server (or for which there is no player.dat file anymore).
|
||||
* Add date and time variables for all config settings (can be used to save schematics as backup, creating a new one each time instead of overwriting).
|
||||
* Add fallback system for owners and landlords, if the UUID has no correct name within the Bukkit API it will use the cached name. This makes sure that these people can still be paid through Vault.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.1.5
|
||||
* Changed all translations to have a period at the end of sentences.
|
||||
* Added a Chinese (Taiwan) language file
|
||||
* Added a blacklist option in the config to block certain regions from being added to AreaShop (you can provide a list of region names with regular expressions) by default only `_global_` is on the list. Regular expressions make it possible to for example block all regions with a certain pattern.
|
||||
* Added a setting `findTeleportToSign` to change if `/as find` should teleport you to the first sign of the region or to the `/as settp` spot (with fallback to the middle of the region).
|
||||
* Fixed a small bug that would cause you to get teleported to the fallback spot instead of the `/as settp` one when you try to teleport to a sign but don't have permission for it (AreaShop changes your request to a non-sign teleport if you do have permission for that in that case)
|
||||
* Added an extra option to `/as info` to list all regions that do not have a group, use `/as info nogroup`.
|
||||
* Added name change detection on login of the player (checks if the players name matches the saved name for the regions that are owned by the players, works because getting regions happens with the UUID) and if it changed it will update the region flags and signs.
|
||||
* Changed that now all region flags and signs will be updated when starting the server, that way users don't think that something does not work simply because the region is not updated. This can be turned off by setting `updateRegionsOnStartup` to false in the config (updating the region happens slowly so it should not cause any noticeable lag).
|
||||
* Removed the `/as updaterents` and `/as updatebuys` commands, became redundant because `/as reload` also updates all regions now so that can be used instead.
|
||||
* Fixed translation of color codes for greeting/farewell messages for WorldGuard 6.0+ users (this problem was caused by an unintended breaking change by WorldGuard, check [this ticket](http://dev.bukkit.org/bukkit-plugins/regionbuyandrent/tickets/26-color-issue/) for details).
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.1.4
|
||||
* Fixed a bug with regions that are in reselling mode, they will now correctly check if you have enough money to pay the resell price instead of checking if you have enough money for the normal price.
|
||||
* Added a line to the `/as info region` output for regions that are in resell mode which displays the resell price.
|
||||
* Changed `/as find` to first search all matching regions (rent/buy, maxprice and group) and after that select a random region from that list.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.1.3
|
||||
* Splitted into 2 versions now, 1 for WorldGuard 5.9 and 1 for WorldGuard 6.x+ Use the correct version that matches the WorldGuard version you have installed.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.1.2
|
||||
* Fixed a bug with the `/as settp` command not accepting arguments, it would always try to find regions at your location instead of first checking if you give it a region name.
|
||||
* Fixed a bug with inactive player unrent/sell settings. If the `inactiveTimeUntilUnrent` or `inactiveTimeUntilSell` settings would be set to a value above 35000 it would cause an integer overflow, resulting in a 50% chance that all regions will be unrentend/sold (and if that does not happen it will still sell/unrent them too early).
|
||||
* Fixed a bug with periodic sign updating crashing when a region has 0 signs.
|
||||
* Add an update checker, will check BukkitDev for the latest file and print a message in console if an update has been found. Also notifies OPs + players with the `areashop.notifyupdate` permission. It will never download the latest version, because those might require a backup or manual changes to run properly.
|
||||
* Fixed some possible bugs with getting the list of players that are added as friend to a region.
|
||||
* --Restored compatibility with WorldGuard 5.9 (WorldGuard 6.0+ is still recommended because that one properly supports UUID's, so 5.9 would cause problems with name changing) and WorldEdit 5.6.3 (could probably already be used with previous AreaShop versions)-- Broken in this version, fixed in V2.1.3 by releasing 2 jar files.
|
||||
* The French language file has been corrected at some points.
|
||||
* The German language file has been completed and corrected at some points
|
||||
* The Polish language file has been improved slightly, but is not 100% complete yet (can you help translating? Check [this page](http://dev.bukkit.org/bukkit-plugins/regionbuyandrent/pages/schematics-languages/#w-option-2))
|
||||
|
||||
***
|
||||
|
||||
|
||||
## AreaShop V2.1.1
|
||||
* Fixed a bug with setting the `owners` flag through the flagProfiles section. (previously it would split the list behind owners into different entries using ` ` as separator, but that should be `, ` this has been fixed now)
|
||||
* Fixed a bug that cause the "conversion to a new version of the file format starts, could take some time" message to always appear after reload/restart of the server. It would not actually do anything to the files, but would print the message.
|
||||
* Fixed the unnecessary saving of the groups.yml file, if loaded from disk it would automatically mark the file as changed, causing it to save at the next iteration of the save task.
|
||||
* Fixed a bug that caused the region flags and signs to update for each member that is added (this is unnecessary when loading the groups from disk, commands still update signs etc properly). Now it will update after all the members of a group are added, and this update is spread over multiple ticks like the `/as updaterents` command
|
||||
* Updated the French language file to the latest version that is made at [Transifex](https://www.transifex.com/projects/p/areashop/), it has been fully updated by Yaelknown.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.1.0
|
||||
#### Features added/changed
|
||||
* Changed the `/as info region` command to show more relevant information:
|
||||

|
||||
|
||||
These are almost all things that could show there, some lines will not show up when based on config options (extending, in advance renting, restoring), some don't show up if empty (friends, signs) and some don't show up based on permissions (groups, teleport location, restoring).
|
||||
* Adding friends to your region is now possible with `/as addfriend <player> [region]` (delete with `/as delfriend <player> [region]`), by default these players will also be added as member of the region, this can however be changed in the `flagProfiles` section of config.yml. By default friends can also teleport to the regions they are added to, deny permission `areashop.teleportfriend` to stop this.
|
||||
* Automatic unrenting for players that are inactive for a certain period of time (`inactiveTimeUntilUnrent` and `inactiveTimeUntilSell` in default.yml, so this can also be changed for groups of regions or individual ones) OPs are excluded by default, those regions will not be unrented/sold.
|
||||
* Added a argument to `/as find` to specify a group, it will only search for regions in that group if specified. Could be useful to create command signs and let players automatically get a region that is at a certain place.
|
||||
* Added a command `/as me`, which lists all your rent and buy regions, plus regions you are added as friend.
|
||||
* Added a `/as setowner <player> [region]` command to change the owner of a region without triggering events for commands, schematics or money transactions (using this command on a rent region with the player that already rents it will extend the region by 1 time period).
|
||||
* Added a `/as resell <price> [region]` command to let players put their bought region into resell mode. If they do that the sign will indicate you can buy the region (shows [Resale] at the top), but the owner can still do anything like normal. When another player buys the region then the money will get transferred to the original owner and the new player will be owner (then the sign shows [Sold] again). If a player changed his mind and does not want to resell his region anymore he can use `/as resell`.
|
||||
* Added a tag `%timeleft%` for signs to show the time that a rent has left instead of the end date, AreaShop will update signs that have this every minute by default (check the values in the `signs` section at the bottom of the config to change this)
|
||||
* All files (config.yml, default.yml, groups.yml, <region>.yml and <lang>.yml) are now loaded in UTF-8 mode, so now they support all fancy characters like € or ê.
|
||||
* Limitgroups for limiting how much regions a player can buy/rent have changed to be more flexible. Now a `worlds` and `groups` section can be added to a group to let the limits only count for regions in these worlds and groups. This allows for different limits for regions in different world (let players have max 2 plots in creative, while limiting the number of shops in survival to 1) the groups allow you to limit certain type of regions that are in the same world.
|
||||
* The limitgroup `unlimited` that was normally in the config by default has been removed and now the permission `areashop.limitbypass` allows you to ignore the limits (default to OPs)
|
||||
* The `areashop.setteleportoutsideregion` permission now works correctly
|
||||
* Added a setting to specify the maximum time a rent region can be rented in advance: `maxRentTime` in default.yml. This prevents players from renting a region a year in advance, instead they have to extend their rent every now and then.
|
||||
* Added `areashop.teleportsignall` permission to teleport to signs of region you do not own (default for OPs)
|
||||
* If a language string contains tags other then `%0%`, `%1%`, `%2%` etc, then all tags for regions can be used (check the config.yml file on the [Config System](http://dev.bukkit.org/bukkit-plugins/regionbuyandrent/pages/the-config-system/) page to see all available tags)
|
||||
* All places where tags can be used, now also language strings can be inserted. Use `%lang:<key>%`, where <key> is the part before the colon in the language file. All tags that are available in the original string will be available in the inserted language string.
|
||||
* The default commands that are executed by clicking on signs now use the full `/areashop` instead of `/as` to prevent collisions with commands of other plugins.
|
||||
* The number of digits behind the decimal point of prices can be changed with the `fractionalNumbers` setting in config.yml, the setting `hideEmptyFractionalPart` determines if the `.0` part of a number should be hidden or not. Default settings produce numbers like this: `$10`, `$5,50`, `$3.45`.
|
||||
* Fixed a bug with with money withdrawal: If a player is in world A and buys a region in world B the plugin now correctly withdraws money from world B.
|
||||
* Added a setting to force a user to be in the correct world before he can buy/rent a region: `restrictedToWorld` in default.yml
|
||||
* Added a setting to force a user to be inside the region before he can buy/rent it: `restrictedToRegion` in default.yml
|
||||
* Added a warning system for players to indicate their rent is running out, `expirationWarningProfiles` section in the config. Different times can be specifed when a message should be sent and a custom list of commands can be executed (all region tags can be used)
|
||||
* Added a settting `warningOnLoginTime` to default.yml, when a rent region has less then this time left when the owner of it logs in it will send a warning message to the owner.
|
||||
* The command `/as rentduration` is renamed to `/as setduration` to be consistent with the other commands
|
||||
* The flagprofiles changed, owners and members now take a list of UUID's, when setting to a region only these will be set (others are cleared). It is now possible to add groups to owners/members by using `g:<group>` in the list, this does the same as `/region addmember <region> g:<group>`. It is now possible to specify the group a flag is about, use `g:<members|non_members|owners|non_owners|all>`, can for example be used to only let members of a region walk into it.
|
||||
* If a schematic is wrongly sized compared to the region size AreaShop will print a warning in the console (but it will still restore it)
|
||||
|
||||
#### Performance improvements
|
||||
* Operations that change/check multiple regions have been changed to do this spread over multiple ticks (now it does a certain number of regions per second instead of all at once, prevents lag spikes for if you have a lot of regions). At the bottom of the config is a section `Limits and Timings` where the speed of these tasks can be changed. The following actions have been changed to this new system (NEW indicates that this is added for a new feature of this update):
|
||||
* Checking expiration of rent regions
|
||||
* Updating of regions when using `/as updaterents` or `/as updatebuys`
|
||||
* Checking of regions for players that are inactive for too long (NEW)
|
||||
* Periodic sign updates of regions for when it has tags like `%timeleft%` (NEW)
|
||||
* Saving region files, now regions only get saved every 10 minutes now by default. Only regions that actually changed will be saved, when shutting down the server it will also safe the regions to prevent data loss. This task also handles saving the groups.yml file (also only saved when necessary) and saving of WorldGuard regions (uses the saveChanged() method of WorldGuard to only save regions that require it).
|
||||
* Checking for when to send warning about rent expiration to players (NEW)
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.0.2
|
||||
* Adds compatibility with WorldGuard 6, but does not work with WorldGuard 5 anymore
|
||||
* Fixes a bug with upgrading from a lower version. With V2.0.0 and V2.0.1 it could happen that the plugin does not update correctly from a lower version, the config.yml would not be moved to the `#old` folder preventing AreaShop to generate a new config. Then the plugin would load the old config and deny users to rent/buy regions because the limits are set incorrectly.
|
||||
* Fixes the incompatibility of UTF-8 characters with the language files, now characters like é, ê, etc. will show up correctly in-game.
|
||||
* Adds a fully updated French language file to the plugin, thanks BlaZingHope for translating, check [the ticket](http://dev.bukkit.org/bukkit-plugins/regionbuyandrent/tickets/5-language-add-a-language/).
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.0.1
|
||||
* Moves setting to determine y location of teleport position to default.yml/groups/region files
|
||||
* Adds setting to specify if teleporting should be inside the region or not (default.yml/groups/region files)
|
||||
* Adds a setting to the config.yml to specify the maximum number of tries the safe teleport function can do (default 50000)
|
||||
* The teleport function now functions properly with locations close to build limit or below 0 (no more falling from the sky).
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V2.0.0
|
||||
#### WARNING
|
||||
Before updating to this version of the plugin make a backup of all worlds that contain regions registered in this plugin!
|
||||
After updating from a previous version the old config.yml will be placed in the folder `#old` because the config changed
|
||||
a lot, you can copy the old settings to the new config, just put them in the right position. In the `#old` folder are also
|
||||
the necessary files to revert back to version 1.X of AreaShop.
|
||||
|
||||
#### Feature changes
|
||||
Note: sections in the config ending with `Profile` can be assigned to region with the inheritance system. You can create new profiles by copying an existing one and changing the values.
|
||||
Parts you don't need can usually be left out.
|
||||
* Adds a permission to set the teleport location outside the WorldGuard region: areashop.setteleportoutsideregion (given to OPs by default)
|
||||
* If you remove a rent or buy region all the flags of the WorldGuard region will be reset
|
||||
* Adds extra checks for teleportation, now also check blocks around you so now a 3x3x4 shape will be checked for danger
|
||||
* Adds a setting in the config to specify what the default y coordinate should be for teleporting, setting `teleportLocationY`, values: bottom, middle, top
|
||||
* You can specify in the config if AreaShop messages in the console should be in color or not
|
||||
* Adds support for different limits for players by using permissions, declare limit groups in the section `limitGroups` and then give players the permission
|
||||
`areashop.limits.<group>`, replacing <group> with the name of the group (if a player has multiple groups then highest limit will be used, by default they have group `default` and OPs have `unlimited`)
|
||||
* Adds full customization of signs, in the section `signProfiles` all lines of a sign can be changed and also the commands to execute when a players right/left clicks a sign (multiple commands can be used, it is a list). Tags are provided to insert region all region data (check config)
|
||||
* Adds support for multiple signs for one region, for every sign you can set the profile (profiles specified in the config), if not set the profile will be inherited from the region/groups/default.yml
|
||||
signs can be added by `as addsign` or placing a sign with the first line `[as]`, second line the region (optional if sign is inside region) and third line the profile (optional)
|
||||
* Adds support to execute commands at certain events (created, deleted, rented, extended, unrented, bought, sold) check config section `eventCommandProfiles`
|
||||
* Flag settings are now by profile (check `flagProfiles`), so regions can have different flags set (for example a different greeting)
|
||||
* Adds a setting to limit the maximum number of times a rent can be extended (check default.yml/groups/region files)
|
||||
|
||||
#### Command changes
|
||||
* Adds tab completion for all commands if you are OP or have the permission areashop.tabcomplete
|
||||
* Adds color and format support to greeting and farewell messages (use the normal bukkit formatting codes)
|
||||
* Adds a command to find an available rent/buy with an optional maximumprice (with no maxprice your balance will be used as max), /as find <buy|rent> [maxprice]
|
||||
* Adds extra optional parameter `sign` to `as tp`, with that parameter you will teleport to the (first) sign instead of the region
|
||||
* With a lot of player command you don't have to specify a region anymore, just stand in the region and the plugin will detect it
|
||||
* Merges commands `as rentrestore` and `as buyrestore` into `as setrestore`
|
||||
* Merges commands `as buyprice` and `as rentprice` into `as setprice`
|
||||
* Adds `as groupadd` command to add regions to groups. Rents and buys can be mixed, region can be specified or taken from your WorldEdit selection (adds them all), group will be created if it has no members yet
|
||||
* Adds `as groupdel` command to delete regions from groups, region can be specified or taken from your WorldEdit selection (removes them all), if a groups is empty it will be removed
|
||||
* Adds `as grouplist` command that lists all groups registered
|
||||
* Adds `as groupinfo` command that displays members of the specified group
|
||||
* Adds `as add` command to add a region or all regions inside your WorldEdit selection (no signs will be added)
|
||||
* Adds `as del` command to delete a region from AreaShop or all inside your WorldEdit selection (signs will be removed)
|
||||
* Adds `as addsign` command to add the sign you are looking at (max 100 blocks away) to the specified region (with optionally a profile)
|
||||
* Adds `as delsign` command to delete the sign you are looking at from the region it belongs to
|
||||
* Adds `as schemevent` command to manually trigger a schematic event
|
||||
|
||||
#### The new config system
|
||||
The config system has drastically changed and an inheritance system has been added to support global, group and individual settings.
|
||||
Now the config only contains global settings and profiles, these profiles can be assigned with the inheritance system.
|
||||
A file called `default.yml` will appear, this file contains all settings that can be changed globally, in a group or in a individual region.
|
||||
When you create a group with the build-in commands a file `groups.yml` will appear, this contains the groups and members of the groups.
|
||||
Each region has its own file inside the folder `/regions` located inside the AreaShop folder, this file contains the individual settings.
|
||||
When checking a setting, for example `price`, the plugin first checks if it has been set in the region file, then it checks
|
||||
all groups assigned to the region for the setting (the one with highest priority will apply, or otherwise the first one with the setting).
|
||||
If it still did not find the setting it gets it from `default.yml`. All settings in `default.yml` can be used in group files and region files,
|
||||
just add them to the file, to for example set the price for a group with buy regions you add the setting `price` inside the section `buy`.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V1.3.0
|
||||
* Adds support for name changing, all files will be converted to UUID's on startup. It will create files `rents.old` and `buys.old` as backup for if the conversion goes wrong, you can delete these after you are sure everything works
|
||||
* Adds version system for all files, this is for converting to next version and is just a `behind the scenes` thing, a `versions` file will appear in the datafolder of the plugin
|
||||
* Adds a command to teleport to regions, normal players can only teleport to their bought/rented regions (can be changed with permissions) ops can teleport to all rent/buy regions. Teleportation is safe, the plugin tries to find a safe spot within the region.
|
||||
* Adds a command to set the teleport location, normal players can only set it for their bought/rented regions (can be changed with permissions) ops can change it for all regions. If no location is set the teleport command will try to teleport to the bottom middle of the region (and then checking a cube of increasing size around that while it is not safe).
|
||||
* Fixes problem with Multiverse-Core, if Multiverse would load after AreaShop then all rents/buys in other worlds then `world`, `world_nether` and `world_the_end` will deregister. Now AreaShop softdepends on Multiverse-Core so if Multiverse is on the server it should load before AreaShop.
|
||||
* Fixes problem with the flags sections in the config, it was not possible to reset flag with the previous way of handling the flags. If you put no value behind a flag or `none` it will now reset.
|
||||
* Fixes bug with percentage of money back after buying/renting not working, only 100% and 0% were possible before, now it works normally.
|
||||
* Refactored the commands system, adding commands and maintenance should be easier now. Also tab completion would be possible now, leave a comment if you would like to have that.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V1.2.1
|
||||
* Fixes bugs with deleting regions and worlds (plugin would not start correctly)
|
||||
* Adds support for automatically using the region you place the sign in when you leave the second line empty (looks at priority and parent/child relations)
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V1.2.0
|
||||
* Fixed a bug with accessing the Vault api to early (plugin does not load in rare cases)
|
||||
* Added option to set `moneyCharacterAfter`, instead of $10 you can create something like `10 gold` now.
|
||||
* Added statistics, using Metrics, can be disabled in the config (check http://mcstats.org/|http://mcstats.org/)
|
||||
* Added commands to change the price of buy and rent regions. `/as rentprice` and `/as buyprice`
|
||||
* Added command to change the duration of a rent region. `/as rentduration`
|
||||
* Added config option to change the timeformat that is used on the signs and in the chat
|
||||
* Added config options to change the identifiers used for rent regions (minutes, hours, days, months, years) This also fixes that `M` did not work as month, but as minute.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V1.1.2
|
||||
* Small bugfix for restoring, the `rented` restore event was also firing when you extended your rent, possibly removing all your items within the region.
|
||||
* The included language file for Dutch (NL.yml) should work now.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V1.1
|
||||
* This release adds a very configurable saving and restoring of regions. You can let the plugin save and restore the region from/to a .schematic file on certain events. Commands are added to change the restoring profile for a rent/buy and the state (true, false, general) which are respectively enabled, disabled and `as general config option`. Check the [[http://dev.bukkit.org/bukkit-plugins/regionbuyandrent/pages/default-config/|Config page]] for which options you are missing or let the plugin generate a new one for you. Also some commands are merged to make it simpler.
|
||||
|
||||
***
|
||||
|
||||
## AreaShop V1.0
|
||||
* First public release of the plugin, contains language support, commands, sign interaction and a config.
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
Based on the Google Java Style Guide: https://google.github.io/styleguide/javaguide.html
|
||||
@@ -42,9 +42,7 @@
|
||||
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||
</module>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="LeftCurly">
|
||||
<property name="maxLineLength" value="100"/>
|
||||
</module>
|
||||
<module name="LeftCurly" />
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_DO"/>
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
# How to release a version of AreaShop
|
||||
Below the steps to follow for releasing a version of AreaShop are listed.
|
||||
|
||||
## Pull the latest translations from Transifex
|
||||
**Setup:**
|
||||
1. Clone the [InteractiveMessengerTransifex](https://github.com/NLthijs48/InteractiveMessengerTransifex) repository
|
||||
2. Run `mvn package`
|
||||
- The `target\InteractiveMessengerTransifex.jar` file should now be present
|
||||
|
||||
**Pull translations:**
|
||||
1. Run `target/InteractiveMessengerTransifex.jar` using Java with the following arguments:
|
||||
- **`download`**
|
||||
- **<transifex api key>**, get from Transifex
|
||||
- **`areashop`**, project name
|
||||
- **`enyml`**, name of the file to download, this is the name AreaShop uses on Transifex
|
||||
- **`./AreaShop/src/main/resources/lang`**, path to the `lang` directory in your clone of the AreaShop repository
|
||||
- **`70`**, meaning only languages translated for at least 70% will get downloaded
|
||||
- **`true`**, reformat the files to be suitable for using in the plugin
|
||||
- **`./langHeader.yml`**, header to add to language file, this file is in the AreaShop repository
|
||||
- **`<version>`**, release version to put in the header
|
||||
2. Commit the changed files in the AreaShop repository
|
||||
3. Push the commit to Github
|
||||
|
||||
## Update the version number
|
||||
1. In `./AreaShop/pom.xml` update the `<version>` tag with the new version (following semantic versioning)
|
||||
2. In `./changelog.md` add notes about the features/fixes of this new version
|
||||
3. Commit the updated files
|
||||
4. Push the commit to Github
|
||||
5. Jenkins will build a new version and make it available on Maven
|
||||
|
||||
## Uploading to distribution platforms
|
||||
The order is important, uploading to Github will trigger the update notification, but points people to Spigot
|
||||
1. Post a [resource update on Spigot](https://www.spigotmc.org/resources/areashop.2991/add-version)
|
||||
- Use the changelog in the update message
|
||||
- Indicate major features in the update title
|
||||
- Update the supported Spigot versions if necessary
|
||||
2. Upload a [new file on Bukkit](https://dev.bukkit.org/projects/regionbuyandrent/files/upload)
|
||||
- Use the changelog in the update message
|
||||
- The file needs to be approved before it will be available for everyone
|
||||
3. Add a [new release on Github](https://github.com/NLthijs48/AreaShop/releases/new)
|
||||
- Enter a tag like `v2.6.0`
|
||||
- Enter a title like `AreaShop 2.6.0`
|
||||
- Add the changelog
|
||||
- Add the .jar file as `AreaShop.jar`
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
org.gradle.parallel=true
|
||||
org.gradle.java.installations.auto-download=false
|
||||
Vendored
BIN
Binary file not shown.
+5
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,16 @@
|
||||
repositories {
|
||||
maven {
|
||||
name = 'IS-Repo'
|
||||
url = uri('https://mvn.intellectualsites.com/content/repositories/releases/')
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly project(':areashop-interface')
|
||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||
compileOnly ('com.intellectualsites.fawe:FAWE-Core:1.16-725')
|
||||
compileOnly ('com.intellectualsites.fawe:FAWE-Bukkit:1.16-725')
|
||||
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.5'
|
||||
}
|
||||
|
||||
description = 'AreaShop FastAsyncWorldEdit 1.16'
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
package me.wiefferink.areashop.handlers.fawe.v1_16;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.*;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionType;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
import me.wiefferink.areashop.interfaces.GeneralRegionInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
// Future: this class could use the schematic save/paste api of FAWE: https://github.com/boy0001/FastAsyncWorldedit/wiki/Pasting-a-schematic
|
||||
// This would not allow for shaping the schematic to a polygon region though
|
||||
public class FastAsyncWorldEditHandler extends WorldEditInterface {
|
||||
|
||||
public FastAsyncWorldEditHandler(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
private static class RegionBoundMask implements Mask {
|
||||
|
||||
private final BoundingBox boundingBox;
|
||||
|
||||
public RegionBoundMask(final ProtectedRegion region) {
|
||||
final BlockVector3 min = region.getMinimumPoint(), max = region.getMaximumPoint();
|
||||
this.boundingBox = new BoundingBox(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ());
|
||||
}
|
||||
|
||||
public RegionBoundMask(final BoundingBox boundingBox) {
|
||||
this.boundingBox = boundingBox.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockVector3 vector) {
|
||||
return boundingBox.contains(vector.getX(), vector.getY(), vector.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask copy() {
|
||||
return new RegionBoundMask(boundingBox);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Beta
|
||||
public CompletableFuture<Boolean> restoreRegionBlocksAsync(File rawFile, GeneralRegionInterface regionInterface) {
|
||||
File file = null;
|
||||
ClipboardFormat format = null;
|
||||
for (ClipboardFormat formatOption : BuiltInClipboardFormat.values()) {
|
||||
if (new File(rawFile.getAbsolutePath() + "." + formatOption.getPrimaryFileExtension())
|
||||
.exists()) {
|
||||
file = new File(
|
||||
rawFile.getAbsolutePath() + "." + formatOption.getPrimaryFileExtension());
|
||||
format = formatOption;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (file == null) {
|
||||
pluginInterface.getLogger().info("Did not restore region " + regionInterface.getName()
|
||||
+ ", schematic file does not exist: " + rawFile.getAbsolutePath());
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
pluginInterface.debugI("Trying to restore region", regionInterface.getName(), " from file",
|
||||
file.getAbsolutePath(), "with format", format.getName());
|
||||
|
||||
com.sk89q.worldedit.world.World world = null;
|
||||
if (regionInterface.getName() != null) {
|
||||
world = BukkitAdapter.adapt(regionInterface.getWorld());
|
||||
}
|
||||
if (world == null) {
|
||||
pluginInterface.getLogger().info(
|
||||
"Did not restore region " + regionInterface.getName() + ", world not found: "
|
||||
+ regionInterface.getWorldName());
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
final CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||
final FaweLimit limit = new FaweLimit();
|
||||
limit.MAX_CHANGES = pluginInterface.getConfig().getInt("maximumBlocks");
|
||||
EditSession editSession = new EditSessionBuilder(world).limit(limit).relightMode(RelightMode.OPTIMAL).build();
|
||||
editSession.setReorderMode(EditSession.ReorderMode.MULTI_STAGE);
|
||||
ProtectedRegion region = regionInterface.getRegion();
|
||||
final RegionType regionType = region.getType();
|
||||
// Get the origin and size of the region
|
||||
final BlockVector3 origin = BlockVector3
|
||||
.at(region.getMinimumPoint().getBlockX(), region.getMinimumPoint().getBlockY(),
|
||||
region.getMinimumPoint().getBlockZ());
|
||||
final RegionBoundMask mask = new RegionBoundMask(region);
|
||||
final File finalFile = file;
|
||||
final String regionName = regionInterface.getName();
|
||||
final double regionWidth = regionInterface.getWidth(), regionHeight = regionInterface.getHeight(), regionDepth = regionInterface.getDepth();
|
||||
final LocalSession session =
|
||||
new LocalSession(pluginInterface.getWorldEdit().getLocalConfiguration());
|
||||
FaweAPI.getTaskManager().async(() -> {
|
||||
// Read the schematic and paste it into the world
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileInputStream fis = closer.register(new FileInputStream(finalFile));
|
||||
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(bis));
|
||||
ClipboardReader reader = new FastSchematicReader(nbtStream);
|
||||
|
||||
Clipboard clipboard = reader.read();
|
||||
if (clipboard.getDimensions().getY() != regionHeight
|
||||
|| clipboard.getDimensions().getX() != regionWidth
|
||||
|| clipboard.getDimensions().getZ() != regionDepth) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"Size of the region " + regionName
|
||||
+ " is not the same as the schematic to restore!");
|
||||
pluginInterface.debugI(
|
||||
"schematic|region, x:" + clipboard.getDimensions().getX() + "|"
|
||||
+ regionWidth + ", y:" + clipboard.getDimensions().getY()
|
||||
+ "|" + regionHeight + ", z:" + clipboard.getDimensions()
|
||||
.getZ() + "|" + regionDepth);
|
||||
}
|
||||
clipboard.setOrigin(clipboard.getMinimumPoint());
|
||||
ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard);
|
||||
session.setBlockChangeLimit(limit.MAX_CHANGES);
|
||||
session.setClipboard(clipboardHolder);
|
||||
|
||||
// Build operation
|
||||
|
||||
BlockTransformExtent extent = new BlockTransformExtent(clipboard);
|
||||
ForwardExtentCopy copy =
|
||||
new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(),
|
||||
editSession, origin);
|
||||
copy.setTransform(clipboardHolder.getTransform());
|
||||
// Mask to region (for polygon and other weird shaped regions)
|
||||
// TODO make this more efficient (especially for polygon regions)
|
||||
if (regionType != RegionType.CUBOID) {
|
||||
copy.setSourceMask(mask);
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"exceeded the block limit while restoring schematic of " + regionInterface.getName()
|
||||
+ ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: "
|
||||
+ pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
CompletableFuture.completedFuture(false);
|
||||
} catch (IOException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"An error occured while restoring schematic of " + regionInterface.getName()
|
||||
+ ", enable debug to see the complete stacktrace");
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
CompletableFuture.completedFuture(false);
|
||||
} catch (Exception e) {
|
||||
pluginInterface.getLogger()
|
||||
.warning("crashed during restore of " + regionInterface.getName());
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
CompletableFuture.completedFuture(false);
|
||||
}
|
||||
editSession.flushQueue();
|
||||
CompletableFuture.completedFuture(true);
|
||||
});
|
||||
return completableFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRegionBlocks(File rawFile, GeneralRegionInterface regionInterface) {
|
||||
return restoreRegionBlocksAsync(rawFile, regionInterface).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Beta
|
||||
public CompletableFuture<Boolean> saveRegionBlocksAsync(File file, GeneralRegionInterface regionInterface) {
|
||||
// TODO implement using the FastAsyncWorldEdit api to save async
|
||||
ClipboardFormat format = BuiltInClipboardFormat.MINECRAFT_STRUCTURE;
|
||||
// TODO allow selecting FAWE format in the config? (when enabled you cannot go back to vanilla WorldEdit easily)
|
||||
|
||||
file = new File(file.getAbsolutePath() + "." + format.getPrimaryFileExtension());
|
||||
pluginInterface.debugI("Trying to save region", regionInterface.getName(), " to file",
|
||||
file.getAbsolutePath(), "with format", format.getName());
|
||||
com.sk89q.worldedit.world.World world = null;
|
||||
if (regionInterface.getWorld() != null) {
|
||||
world = BukkitAdapter.adapt(regionInterface.getWorld());
|
||||
}
|
||||
if (world == null) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"Did not save region " + regionInterface.getName() + ", world not found: "
|
||||
+ regionInterface.getWorldName());
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
final FaweLimit limit = new FaweLimit();
|
||||
limit.MAX_CHANGES = pluginInterface.getConfig().getInt("maximumBlocks");
|
||||
EditSession editSession = new EditSessionBuilder(world).relightMode(RelightMode.OPTIMAL).limit(limit).build();
|
||||
|
||||
final ProtectedRegion region = regionInterface.getRegion();
|
||||
final BlockVector3 min = region.getMinimumPoint(), max = region.getMaximumPoint();
|
||||
final String regionName = regionInterface.getName();
|
||||
final World finalWorld = world;
|
||||
final CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||
final File finalFile = file;
|
||||
FaweAPI.getTaskManager().async(() -> {
|
||||
// Create a clipboard
|
||||
CuboidRegion selection =
|
||||
new CuboidRegion(finalWorld, min, max);
|
||||
Clipboard clipboard = new MemoryOptimizedClipboard(selection);
|
||||
clipboard.setOrigin(min);
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(editSession,
|
||||
selection.clone(), clipboard,
|
||||
min);
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"Exceeded the block limit while saving schematic of " + regionName
|
||||
+ ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: "
|
||||
+ pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
completableFuture.complete(false);
|
||||
}
|
||||
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(finalFile));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
ClipboardWriter writer = closer.register(format.getWriter(bos));
|
||||
writer.write(clipboard);
|
||||
} catch (IOException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"An error occured while saving schematic of " + regionName
|
||||
+ ", enable debug to see the complete stacktrace");
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
completableFuture.complete(false);
|
||||
} catch (Exception e) {
|
||||
pluginInterface.getLogger()
|
||||
.warning("Crashed during save of " + regionName);
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
completableFuture.complete(false);
|
||||
}
|
||||
completableFuture.complete(true);
|
||||
});
|
||||
return completableFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveRegionBlocks(File file, GeneralRegionInterface regionInterface) {
|
||||
return saveRegionBlocksAsync(file, regionInterface).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldEditSelection getPlayerSelection(Player player) {
|
||||
try {
|
||||
Region region = pluginInterface.getWorldEdit().getSession(player)
|
||||
.getSelection(BukkitAdapter.adapt(player.getWorld()));
|
||||
return new WorldEditSelection(player.getWorld(),
|
||||
BukkitAdapter.adapt(player.getWorld(), region.getMinimumPoint()),
|
||||
BukkitAdapter.adapt(player.getWorld(), region.getMaximumPoint()));
|
||||
} catch (IncompleteRegionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
repositories {
|
||||
maven {
|
||||
name = 'IS-Repo'
|
||||
url = uri('https://mvn.intellectualsites.com/content/repositories/releases/')
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly project(':areashop-interface')
|
||||
compileOnly('org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT')
|
||||
compileOnly("com.fastasyncworldedit:FAWE-Core:1.17-5")
|
||||
compileOnly("com.fastasyncworldedit:FAWE-Bukkit:1.17-5")
|
||||
compileOnly('com.sk89q.worldguard:worldguard-bukkit:7.0.5')
|
||||
}
|
||||
|
||||
description = 'AreaShop FastAsyncWorldEdit 1.17'
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
package me.wiefferink.areashop.handlers.fawe.v1_17;
|
||||
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.FaweLimit;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.fastasyncworldedit.core.object.clipboard.MemoryOptimizedClipboard;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.*;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionType;
|
||||
import me.wiefferink.areashop.interfaces.AreaShopInterface;
|
||||
import me.wiefferink.areashop.interfaces.GeneralRegionInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditInterface;
|
||||
import me.wiefferink.areashop.interfaces.WorldEditSelection;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
// Future: this class could use the schematic save/paste api of FAWE: https://github.com/boy0001/FastAsyncWorldedit/wiki/Pasting-a-schematic
|
||||
// This would not allow for shaping the schematic to a polygon region though
|
||||
public class FastAsyncWorldEditHandler extends WorldEditInterface {
|
||||
|
||||
public FastAsyncWorldEditHandler(AreaShopInterface pluginInterface) {
|
||||
super(pluginInterface);
|
||||
}
|
||||
|
||||
private static class RegionBoundMask implements Mask {
|
||||
|
||||
private final BoundingBox boundingBox;
|
||||
|
||||
public RegionBoundMask(final ProtectedRegion region) {
|
||||
final BlockVector3 min = region.getMinimumPoint(), max = region.getMaximumPoint();
|
||||
this.boundingBox = new BoundingBox(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ());
|
||||
}
|
||||
|
||||
public RegionBoundMask(final BoundingBox boundingBox) {
|
||||
this.boundingBox = boundingBox.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockVector3 vector) {
|
||||
return boundingBox.contains(vector.getX(), vector.getY(), vector.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask copy() {
|
||||
return new RegionBoundMask(boundingBox);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Beta
|
||||
public CompletableFuture<Boolean> restoreRegionBlocksAsync(File rawFile, GeneralRegionInterface regionInterface) {
|
||||
File file = null;
|
||||
ClipboardFormat format = null;
|
||||
for (ClipboardFormat formatOption : BuiltInClipboardFormat.values()) {
|
||||
if (new File(rawFile.getAbsolutePath() + "." + formatOption.getPrimaryFileExtension())
|
||||
.exists()) {
|
||||
file = new File(
|
||||
rawFile.getAbsolutePath() + "." + formatOption.getPrimaryFileExtension());
|
||||
format = formatOption;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (file == null) {
|
||||
pluginInterface.getLogger().info("Did not restore region " + regionInterface.getName()
|
||||
+ ", schematic file does not exist: " + rawFile.getAbsolutePath());
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
pluginInterface.debugI("Trying to restore region", regionInterface.getName(), " from file",
|
||||
file.getAbsolutePath(), "with format", format.getName());
|
||||
|
||||
com.sk89q.worldedit.world.World world = null;
|
||||
if (regionInterface.getName() != null) {
|
||||
world = BukkitAdapter.adapt(regionInterface.getWorld());
|
||||
}
|
||||
if (world == null) {
|
||||
pluginInterface.getLogger().info(
|
||||
"Did not restore region " + regionInterface.getName() + ", world not found: "
|
||||
+ regionInterface.getWorldName());
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
final CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||
final FaweLimit limit = new FaweLimit();
|
||||
limit.MAX_CHANGES = pluginInterface.getConfig().getInt("maximumBlocks");
|
||||
EditSession editSession = new EditSessionBuilder(world).limit(limit).relightMode(RelightMode.OPTIMAL).build();
|
||||
editSession.setReorderMode(EditSession.ReorderMode.MULTI_STAGE);
|
||||
ProtectedRegion region = regionInterface.getRegion();
|
||||
final RegionType regionType = region.getType();
|
||||
// Get the origin and size of the region
|
||||
final BlockVector3 origin = BlockVector3
|
||||
.at(region.getMinimumPoint().getBlockX(), region.getMinimumPoint().getBlockY(),
|
||||
region.getMinimumPoint().getBlockZ());
|
||||
final RegionBoundMask mask = new RegionBoundMask(region);
|
||||
final File finalFile = file;
|
||||
final String regionName = regionInterface.getName();
|
||||
final double regionWidth = regionInterface.getWidth(), regionHeight = regionInterface.getHeight(), regionDepth = regionInterface.getDepth();
|
||||
final LocalSession session =
|
||||
new LocalSession(pluginInterface.getWorldEdit().getLocalConfiguration());
|
||||
FaweAPI.getTaskManager().async(() -> {
|
||||
// Read the schematic and paste it into the world
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileInputStream fis = closer.register(new FileInputStream(finalFile));
|
||||
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(bis));
|
||||
ClipboardReader reader = new FastSchematicReader(nbtStream);
|
||||
|
||||
Clipboard clipboard = reader.read();
|
||||
if (clipboard.getDimensions().getY() != regionHeight
|
||||
|| clipboard.getDimensions().getX() != regionWidth
|
||||
|| clipboard.getDimensions().getZ() != regionDepth) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"Size of the region " + regionName
|
||||
+ " is not the same as the schematic to restore!");
|
||||
pluginInterface.debugI(
|
||||
"schematic|region, x:" + clipboard.getDimensions().getX() + "|"
|
||||
+ regionWidth + ", y:" + clipboard.getDimensions().getY()
|
||||
+ "|" + regionHeight + ", z:" + clipboard.getDimensions()
|
||||
.getZ() + "|" + regionDepth);
|
||||
}
|
||||
clipboard.setOrigin(clipboard.getMinimumPoint());
|
||||
ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard);
|
||||
session.setBlockChangeLimit(limit.MAX_CHANGES);
|
||||
session.setClipboard(clipboardHolder);
|
||||
|
||||
// Build operation
|
||||
|
||||
BlockTransformExtent extent = new BlockTransformExtent(clipboard);
|
||||
ForwardExtentCopy copy =
|
||||
new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(),
|
||||
editSession, origin);
|
||||
copy.setTransform(clipboardHolder.getTransform());
|
||||
// Mask to region (for polygon and other weird shaped regions)
|
||||
// TODO make this more efficient (especially for polygon regions)
|
||||
if (regionType != RegionType.CUBOID) {
|
||||
copy.setSourceMask(mask);
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"exceeded the block limit while restoring schematic of " + regionInterface.getName()
|
||||
+ ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: "
|
||||
+ pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
CompletableFuture.completedFuture(false);
|
||||
} catch (IOException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"An error occured while restoring schematic of " + regionInterface.getName()
|
||||
+ ", enable debug to see the complete stacktrace");
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
CompletableFuture.completedFuture(false);
|
||||
} catch (Exception e) {
|
||||
pluginInterface.getLogger()
|
||||
.warning("crashed during restore of " + regionInterface.getName());
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
CompletableFuture.completedFuture(false);
|
||||
}
|
||||
editSession.flushQueue();
|
||||
CompletableFuture.completedFuture(true);
|
||||
});
|
||||
return completableFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRegionBlocks(File rawFile, GeneralRegionInterface regionInterface) {
|
||||
return restoreRegionBlocksAsync(rawFile, regionInterface).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Beta
|
||||
public CompletableFuture<Boolean> saveRegionBlocksAsync(File file, GeneralRegionInterface regionInterface) {
|
||||
// TODO implement using the FastAsyncWorldEdit api to save async
|
||||
ClipboardFormat format = BuiltInClipboardFormat.MINECRAFT_STRUCTURE;
|
||||
// TODO allow selecting FAWE format in the config? (when enabled you cannot go back to vanilla WorldEdit easily)
|
||||
|
||||
file = new File(file.getAbsolutePath() + "." + format.getPrimaryFileExtension());
|
||||
pluginInterface.debugI("Trying to save region", regionInterface.getName(), " to file",
|
||||
file.getAbsolutePath(), "with format", format.getName());
|
||||
com.sk89q.worldedit.world.World world = null;
|
||||
if (regionInterface.getWorld() != null) {
|
||||
world = BukkitAdapter.adapt(regionInterface.getWorld());
|
||||
}
|
||||
if (world == null) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"Did not save region " + regionInterface.getName() + ", world not found: "
|
||||
+ regionInterface.getWorldName());
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
final FaweLimit limit = new FaweLimit();
|
||||
limit.MAX_CHANGES = pluginInterface.getConfig().getInt("maximumBlocks");
|
||||
EditSession editSession = new EditSessionBuilder(world).relightMode(RelightMode.OPTIMAL).limit(limit).build();
|
||||
|
||||
final ProtectedRegion region = regionInterface.getRegion();
|
||||
final BlockVector3 min = region.getMinimumPoint(), max = region.getMaximumPoint();
|
||||
final String regionName = regionInterface.getName();
|
||||
final World finalWorld = world;
|
||||
final CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
|
||||
final File finalFile = file;
|
||||
FaweAPI.getTaskManager().async(() -> {
|
||||
// Create a clipboard
|
||||
CuboidRegion selection =
|
||||
new CuboidRegion(finalWorld, min, max);
|
||||
Clipboard clipboard = new MemoryOptimizedClipboard(selection);
|
||||
clipboard.setOrigin(min);
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(editSession,
|
||||
selection.clone(), clipboard,
|
||||
min);
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"Exceeded the block limit while saving schematic of " + regionName
|
||||
+ ", limit in exception: " + e.getBlockLimit() + ", limit passed by AreaShop: "
|
||||
+ pluginInterface.getConfig().getInt("maximumBlocks"));
|
||||
completableFuture.complete(false);
|
||||
}
|
||||
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(finalFile));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
ClipboardWriter writer = closer.register(format.getWriter(bos));
|
||||
writer.write(clipboard);
|
||||
} catch (IOException e) {
|
||||
pluginInterface.getLogger().warning(
|
||||
"An error occured while saving schematic of " + regionName
|
||||
+ ", enable debug to see the complete stacktrace");
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
completableFuture.complete(false);
|
||||
} catch (Exception e) {
|
||||
pluginInterface.getLogger()
|
||||
.warning("Crashed during save of " + regionName);
|
||||
pluginInterface.debugI(ExceptionUtils.getStackTrace(e));
|
||||
completableFuture.complete(false);
|
||||
}
|
||||
completableFuture.complete(true);
|
||||
});
|
||||
return completableFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveRegionBlocks(File file, GeneralRegionInterface regionInterface) {
|
||||
return saveRegionBlocksAsync(file, regionInterface).join();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldEditSelection getPlayerSelection(Player player) {
|
||||
try {
|
||||
Region region = pluginInterface.getWorldEdit().getSession(player)
|
||||
.getSelection(BukkitAdapter.adapt(player.getWorld()));
|
||||
return new WorldEditSelection(player.getWorld(),
|
||||
BukkitAdapter.adapt(player.getWorld(), region.getMinimumPoint()),
|
||||
BukkitAdapter.adapt(player.getWorld(), region.getMaximumPoint()));
|
||||
} catch (IncompleteRegionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencies {
|
||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||
compileOnly 'com.sk89q.worldedit:worldedit-bukkit:7.2.5-SNAPSHOT'
|
||||
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.5'
|
||||
}
|
||||
|
||||
description = 'AreaShop Interface'
|
||||
+2
-1
@@ -3,10 +3,11 @@ package me.wiefferink.areashop.interfaces;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface AreaShopInterface {
|
||||
public interface AreaShopInterface extends Plugin {
|
||||
void debugI(Object... message);
|
||||
|
||||
YamlConfiguration getConfig();
|
||||
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user