mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-07-03 06:04:43 +02:00
Compare commits
91 Commits
fix/big-bo
...
feature/co
Author | SHA1 | Date | |
---|---|---|---|
a5c1f1a74b | |||
16a4ee835c | |||
c013b92e62 | |||
b00a46b286 | |||
44b1127181 | |||
c7bfd48a21 | |||
dc13783db8 | |||
0a390ab342 | |||
d111740f64 | |||
28e97e8441 | |||
a30cdb37d6 | |||
f848162066 | |||
40c70aa98d | |||
0d2b36bac8 | |||
d7e5bcdaa5 | |||
fc783574a3 | |||
5f7bb784f0 | |||
26c55a318f | |||
ee68bc3d9e | |||
a3bc3968a5 | |||
79454da1a6 | |||
12a4c92ad9 | |||
167692d464 | |||
ae26e8155c | |||
286ea62a21 | |||
d95c74d8c9 | |||
c1555ddbc7 | |||
4fe0c586d9 | |||
aae6ea4fee | |||
385d018504 | |||
f4def082c1 | |||
69c9f1df83 | |||
e138dc0267 | |||
ca50b53f94 | |||
f705487055 | |||
b7c9453a1a | |||
1aa370d562 | |||
d3dab0d736 | |||
764156b267 | |||
665f5251bf | |||
7c328095d7 | |||
7884c91d52 | |||
e9a19e0821 | |||
022847fc4b | |||
1ee673be58 | |||
3c2aa99e86 | |||
11fac3f060 | |||
3e57e524b9 | |||
f582ec03c5 | |||
893be136f0 | |||
b74ba30281 | |||
ba9dab1f73 | |||
8e60fdb477 | |||
443fe8dd47 | |||
e56e52ba4f | |||
cd008bed9b | |||
d4c90283d6 | |||
dc04ec955a | |||
72f511ce99 | |||
0d63c2bdb6 | |||
49e13384cf | |||
1ddc19ff69 | |||
a6d436e841 | |||
9b0b39ac2e | |||
638f0bd078 | |||
c27b838dad | |||
e0cb2949df | |||
59be582c28 | |||
f6cbb3792f | |||
a68918f830 | |||
1a7ded864e | |||
cbc8bc8879 | |||
21f79d1c13 | |||
293d7acf2d | |||
d876d3722a | |||
dffb7672ff | |||
f867867a42 | |||
59eefd6865 | |||
587a286d05 | |||
e10caf6aa0 | |||
08b325e37d | |||
c394108ba6 | |||
31e89019f1 | |||
3a7075e28d | |||
8373b7874e | |||
fe13882b97 | |||
f45064c4c4 | |||
af32399dd2 | |||
f3c03348d9 | |||
a53330e39b | |||
e2ba93dab9 |
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -7,7 +7,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report for PlotSquared! Fill out the following form to your best ability to help us fix the problem.
|
||||
Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.github.io/plotsquared-documentation/).
|
||||
Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.gitbook.io/plotsquared/).
|
||||
Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://github.com/IntellectualSites/PlotSquared/security/policy) GitHub form!
|
||||
|
||||
- type: dropdown
|
||||
@ -27,7 +27,7 @@ body:
|
||||
description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first.
|
||||
multiple: false
|
||||
options:
|
||||
- '1.20.1'
|
||||
- '1.20.2'
|
||||
- '1.20'
|
||||
- '1.19.4'
|
||||
- '1.19.3'
|
||||
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -4,5 +4,5 @@ contact_links:
|
||||
url: https://discord.gg/intellectualsites
|
||||
about: Our support Discord, please ask questions and seek support here.
|
||||
- name: PlotSquared Wiki
|
||||
url: https://intellectualsites.github.io/plotsquared-documentation/
|
||||
url: https://intellectualsites.gitbook.io/plotsquared/
|
||||
about: Take a look at the wiki page for instructions how to setup PlotSquared and use its commands.
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -7,7 +7,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this feature request for PlotSquared! Fill out the following form to your best ability to help us understand your feature request and greately improve the change of it getting added.
|
||||
For anything else than a feature request, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.github.io/plotsquared-documentation/).
|
||||
For anything else than a feature request, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.gitbook.io/plotsquared/).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
9
.github/renovate.json
vendored
9
.github/renovate.json
vendored
@ -4,9 +4,16 @@
|
||||
"config:base",
|
||||
":semanticCommitsDisabled"
|
||||
],
|
||||
"automerge": true,
|
||||
"labels": [
|
||||
"dependencies"
|
||||
],
|
||||
"rebaseWhen": "conflicted",
|
||||
"schedule": ["on the first day of the month"]
|
||||
"schedule": ["on the first day of the month"],
|
||||
"ignoreDeps": [
|
||||
"com.google.code.gson:gson",
|
||||
"com.google.guava:guava",
|
||||
"org.yaml:snakeyaml",
|
||||
"org.apache.logging.log4j:log4j-api",
|
||||
]
|
||||
}
|
||||
|
2
.github/workflows/build-pr.yml
vendored
2
.github/workflows/build-pr.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: Setup Java
|
||||
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: Setup Java
|
||||
@ -42,7 +42,7 @@ jobs:
|
||||
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
|
||||
- name: Publish core javadoc
|
||||
# if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
uses: cpina/github-action-push-to-another-repository@main
|
||||
env:
|
||||
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
|
||||
@ -54,7 +54,7 @@ jobs:
|
||||
target-branch: main
|
||||
target-directory: v7/core
|
||||
- name: Publish bukkit javadoc
|
||||
# if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
uses: cpina/github-action-push-to-another-repository@main
|
||||
env:
|
||||
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
|
||||
|
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
language: [ 'java' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -138,6 +138,5 @@ build/
|
||||
|
||||
.DS_Store
|
||||
# Ignore run folders
|
||||
run-[0-0].[0-9]/
|
||||
run-[0-0].[0-9].[0-9]/
|
||||
|
||||
run-[0-9].[0-9][0-9]/
|
||||
run-[0-9].[0-9][0-9].[0-9]/
|
||||
|
@ -21,20 +21,20 @@ dependencies {
|
||||
api(projects.plotsquaredCore)
|
||||
|
||||
// Metrics
|
||||
implementation("org.bstats:bstats-bukkit")
|
||||
implementation(libs.bstatsBukkit)
|
||||
|
||||
// Paper
|
||||
compileOnly("io.papermc.paper:paper-api")
|
||||
implementation("io.papermc:paperlib")
|
||||
compileOnly(libs.paper)
|
||||
implementation(libs.paperlib)
|
||||
|
||||
// Plugins
|
||||
compileOnly(libs.worldeditBukkit) {
|
||||
exclude(group = "org.bukkit")
|
||||
exclude(group = "org.spigotmc")
|
||||
}
|
||||
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit") { isTransitive = false }
|
||||
testImplementation("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit") { isTransitive = false }
|
||||
compileOnly("com.github.MilkBowl:VaultAPI") {
|
||||
compileOnly(libs.faweBukkit) { isTransitive = false }
|
||||
testImplementation(libs.faweBukkit) { isTransitive = false }
|
||||
compileOnly(libs.vault) {
|
||||
exclude(group = "org.bukkit")
|
||||
}
|
||||
compileOnly(libs.placeholderapi)
|
||||
@ -44,15 +44,15 @@ dependencies {
|
||||
|
||||
// Other libraries
|
||||
implementation(libs.squirrelid) { isTransitive = false }
|
||||
implementation("dev.notmyfault.serverlib:ServerLib")
|
||||
implementation(libs.serverlib)
|
||||
|
||||
// Our libraries
|
||||
implementation(libs.arkitektonika)
|
||||
implementation("com.intellectualsites.paster:Paster")
|
||||
implementation("com.intellectualsites.informative-annotations:informative-annotations")
|
||||
implementation(libs.paster)
|
||||
implementation(libs.informativeAnnotations)
|
||||
|
||||
// Adventure
|
||||
implementation("net.kyori:adventure-platform-bukkit")
|
||||
implementation(libs.adventureBukkit)
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
@ -89,6 +89,8 @@ tasks.named<ShadowJar>("shadowJar") {
|
||||
relocate("net.jcip", "com.plotsquared.core.annotations.jcip")
|
||||
relocate("edu.umd.cs.findbugs", "com.plotsquared.core.annotations.findbugs")
|
||||
relocate("com.intellectualsites.annotations", "com.plotsquared.core.annotations.informative")
|
||||
relocate("org.jdbi.v3", "com.plotsquared.core.jdbi")
|
||||
relocate("com.zaxxer.hikari", "com.plotsquared.core.hikari")
|
||||
|
||||
// Get rid of all the libs which are 100% unused.
|
||||
minimize()
|
||||
@ -100,7 +102,7 @@ tasks {
|
||||
withType<Javadoc> {
|
||||
val isRelease = if (rootProject.version.toString().endsWith("-SNAPSHOT")) "TODO" else rootProject.version.toString()
|
||||
val opt = options as StandardJavadocDocletOptions
|
||||
opt.links("https://jd.papermc.io/paper/1.19/")
|
||||
opt.links("https://jd.papermc.io/paper/1.20/")
|
||||
opt.links("https://docs.enginehub.org/javadoc/com.sk89q.worldedit/worldedit-bukkit/" + libs.worldeditBukkit.get().versionConstraint.toString())
|
||||
opt.links("https://intellectualsites.github.io/plotsquared-javadocs/core/")
|
||||
opt.links("https://jd.advntr.dev/api/4.14.0/")
|
||||
|
@ -82,6 +82,8 @@ import com.plotsquared.core.inject.annotations.DefaultGenerator;
|
||||
import com.plotsquared.core.inject.annotations.ImpromptuPipeline;
|
||||
import com.plotsquared.core.inject.annotations.WorldConfig;
|
||||
import com.plotsquared.core.inject.annotations.WorldFile;
|
||||
import com.plotsquared.core.inject.modules.DatabaseModule;
|
||||
import com.plotsquared.core.inject.modules.JdbiModule;
|
||||
import com.plotsquared.core.inject.modules.PlotSquaredModule;
|
||||
import com.plotsquared.core.listener.PlotListener;
|
||||
import com.plotsquared.core.listener.WESubscriber;
|
||||
@ -140,6 +142,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.incendo.serverlib.ServerLib;
|
||||
|
||||
import javax.xml.crypto.Data;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
@ -252,6 +255,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
public void onEnable() {
|
||||
this.pluginName = getDescription().getName();
|
||||
|
||||
@ -291,7 +295,9 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
new WorldManagerModule(),
|
||||
new PlotSquaredModule(),
|
||||
new BukkitModule(this),
|
||||
new BackupModule()
|
||||
new BackupModule(),
|
||||
new JdbiModule(),
|
||||
new DatabaseModule()
|
||||
);
|
||||
this.injector.injectMembers(this);
|
||||
|
||||
@ -550,7 +556,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
this.startMetrics();
|
||||
|
||||
if (Settings.Enabled_Components.WORLDS) {
|
||||
TaskManager.getPlatformImplementation().taskRepeat(this::unload, TaskTime.seconds(1L));
|
||||
TaskManager.getPlatformImplementation().taskRepeat(this::unload, TaskTime.seconds(10L));
|
||||
try {
|
||||
singleWorldListener = injector().getInstance(SingleWorldListener.class);
|
||||
Bukkit.getPluginManager().registerEvents(singleWorldListener, this);
|
||||
@ -1160,6 +1166,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
return new BukkitPlotGenerator(world, generator, this.plotAreaManager);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
@Override
|
||||
public @NonNull String pluginsFormatted() {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
@ -1181,7 +1188,7 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@SuppressWarnings({"ConstantConditions", "deprecation"}) // Paper deprecation
|
||||
public @NonNull String worldEditImplementations() {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
if (Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null) {
|
||||
|
@ -33,6 +33,7 @@ import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Bat;
|
||||
import org.bukkit.entity.Boat;
|
||||
import org.bukkit.entity.Breedable;
|
||||
import org.bukkit.entity.ChestedHorse;
|
||||
import org.bukkit.entity.EnderDragon;
|
||||
import org.bukkit.entity.Entity;
|
||||
@ -74,6 +75,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
private HorseStats horse;
|
||||
private boolean noGravity;
|
||||
|
||||
@SuppressWarnings("deprecation") // Deprecation exists since 1.20, while we support 1.16 onwards
|
||||
public ReplicatingEntityWrapper(Entity entity, short depth) {
|
||||
super(entity);
|
||||
|
||||
@ -164,7 +166,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
//this.horse.style = horse.getStyle();
|
||||
//this.horse.color = horse.getColor();
|
||||
storeTameable(horse);
|
||||
storeAgeable(horse);
|
||||
storeBreedable(horse);
|
||||
storeLiving(horse);
|
||||
storeInventory(horse);
|
||||
return;
|
||||
@ -172,7 +174,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
// END INVENTORY HOLDER //
|
||||
case "WOLF", "OCELOT" -> {
|
||||
storeTameable((Tameable) entity);
|
||||
storeAgeable((Ageable) entity);
|
||||
storeBreedable((Breedable) entity);
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
@ -186,18 +188,18 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
this.dataByte = (byte) 0;
|
||||
}
|
||||
this.dataByte2 = sheep.getColor().getDyeData();
|
||||
storeAgeable(sheep);
|
||||
storeBreedable(sheep);
|
||||
storeLiving(sheep);
|
||||
return;
|
||||
}
|
||||
case "VILLAGER", "CHICKEN", "COW", "MUSHROOM_COW", "PIG", "TURTLE", "POLAR_BEAR" -> {
|
||||
storeAgeable((Ageable) entity);
|
||||
storeBreedable((Breedable) entity);
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
case "RABBIT" -> {
|
||||
this.dataByte = getOrdinal(Rabbit.Type.values(), ((Rabbit) entity).getRabbitType());
|
||||
storeAgeable((Ageable) entity);
|
||||
storeBreedable((Breedable) entity);
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
@ -381,6 +383,11 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #restoreBreedable(Breedable)} instead
|
||||
* @since 7.1.0
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.1.0")
|
||||
private void restoreAgeable(Ageable entity) {
|
||||
if (!this.aged.adult) {
|
||||
entity.setBaby();
|
||||
@ -391,6 +398,11 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #storeBreedable(Breedable)} instead
|
||||
* @since 7.1.0
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.1.0")
|
||||
public void storeAgeable(Ageable aged) {
|
||||
this.aged = new AgeableStats();
|
||||
this.aged.age = aged.getAge();
|
||||
@ -398,6 +410,29 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
this.aged.adult = aged.isAdult();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 7.1.0
|
||||
*/
|
||||
private void restoreBreedable(Breedable entity) {
|
||||
if (!this.aged.adult) {
|
||||
entity.setBaby();
|
||||
}
|
||||
entity.setAgeLock(this.aged.locked);
|
||||
if (this.aged.age > 0) {
|
||||
entity.setAge(this.aged.age);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 7.1.0
|
||||
*/
|
||||
private void storeBreedable(Breedable breedable) {
|
||||
this.aged = new AgeableStats();
|
||||
this.aged.age = breedable.getAge();
|
||||
this.aged.locked = breedable.getAgeLock();
|
||||
this.aged.adult = breedable.isAdult();
|
||||
}
|
||||
|
||||
public void storeTameable(Tameable tamed) {
|
||||
this.tamed = new TameableStats();
|
||||
this.tamed.owner = tamed.getOwner();
|
||||
@ -501,7 +536,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
//horse.setStyle(this.horse.style);
|
||||
//horse.setColor(this.horse.color);
|
||||
restoreTameable(horse);
|
||||
restoreAgeable(horse);
|
||||
restoreBreedable(horse);
|
||||
restoreLiving(horse);
|
||||
restoreInventory(horse);
|
||||
return entity;
|
||||
@ -509,7 +544,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
// END INVENTORY HOLDER //
|
||||
case "WOLF", "OCELOT" -> {
|
||||
restoreTameable((Tameable) entity);
|
||||
restoreAgeable((Ageable) entity);
|
||||
restoreBreedable((Breedable) entity);
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
@ -522,12 +557,12 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
if (this.dataByte2 != 0) {
|
||||
sheep.setColor(DyeColor.getByDyeData(this.dataByte2));
|
||||
}
|
||||
restoreAgeable(sheep);
|
||||
restoreBreedable(sheep);
|
||||
restoreLiving(sheep);
|
||||
return sheep;
|
||||
}
|
||||
case "VILLAGER", "CHICKEN", "COW", "TURTLE", "POLAR_BEAR", "MUSHROOM_COW", "PIG" -> {
|
||||
restoreAgeable((Ageable) entity);
|
||||
restoreBreedable((Breedable) entity);
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
@ -536,7 +571,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
if (this.dataByte != 0) {
|
||||
((Rabbit) entity).setRabbitType(Rabbit.Type.values()[this.dataByte]);
|
||||
}
|
||||
restoreAgeable((Ageable) entity);
|
||||
restoreBreedable((Breedable) entity);
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import com.plotsquared.core.queue.ZeroedDelegateScopedQueueCoordinator;
|
||||
import com.plotsquared.core.util.ChunkManager;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.HeightMap;
|
||||
@ -420,7 +421,11 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
|
||||
if (lastPlotArea != null && name.equals(this.levelName) && chunkX == lastChunkX && chunkZ == lastChunkZ) {
|
||||
return lastPlotArea;
|
||||
}
|
||||
PlotArea area = UncheckedWorldLocation.at(name, chunkX << 4, 0, chunkZ << 4).getPlotArea();
|
||||
BlockVector3 loc = BlockVector3.at(chunkX << 4, 0, chunkZ << 4);
|
||||
if (lastPlotArea != null && lastPlotArea.getRegion().contains(loc) && lastPlotArea.getRegion().contains(loc)) {
|
||||
return lastPlotArea;
|
||||
}
|
||||
PlotArea area = UncheckedWorldLocation.at(name, loc).getPlotArea();
|
||||
if (area == null) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Cannot generate chunk that does not belong to a plot area. World: %s",
|
||||
|
@ -33,6 +33,7 @@ import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.flag.implementations.BlockBurnFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.BlockIgnitionFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.BreakFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.ConcreteHardenFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.CoralDryFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.CropGrowFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.DisablePhysicsFlag;
|
||||
@ -586,6 +587,12 @@ public class BlockEventListener implements Listener {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
if (event.getNewState().getType().toString().endsWith("CONCRETE")) {
|
||||
if (!plot.getFlag(ConcreteHardenFlag.class)) {
|
||||
plot.debug("Concrete powder could not harden because concrete-harden = false");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
|
@ -26,6 +26,7 @@ import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.flag.implementations.CopperOxideFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.MiscInteractFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.SculkSensorInteractFlag;
|
||||
import com.plotsquared.core.util.PlotFlagUtil;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
@ -96,12 +97,12 @@ public class BlockEventListener117 implements Listener {
|
||||
area,
|
||||
MiscInteractFlag.class,
|
||||
true
|
||||
) || plot != null && !plot.getFlag(
|
||||
MiscInteractFlag.class)) {
|
||||
) || plot != null && (!plot.getFlag(MiscInteractFlag.class) || !plot.getFlag(SculkSensorInteractFlag.class))) {
|
||||
if (plotPlayer != null) {
|
||||
if (plot != null) {
|
||||
if (!plot.isAdded(plotPlayer.getUUID())) {
|
||||
plot.debug(plotPlayer.getName() + " couldn't trigger sculk sensors because misc-interact = false");
|
||||
plot.debug(plotPlayer.getName() + " couldn't trigger sculk sensors because both " +
|
||||
"sculk-sensor-interact and misc-interact = false");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@ -112,13 +113,15 @@ public class BlockEventListener117 implements Listener {
|
||||
if (plot != null) {
|
||||
if (itemThrower == null && (itemThrower = item.getOwner()) == null) {
|
||||
plot.debug(
|
||||
"A thrown item couldn't trigger sculk sensors because misc-interact = false and the item's owner could not be resolved.");
|
||||
"A thrown item couldn't trigger sculk sensors because both sculk-sensor-interact and " +
|
||||
"misc-interact = false and the item's owner could not be resolved.");
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (!plot.isAdded(itemThrower)) {
|
||||
if (!plot.isAdded(itemThrower)) {
|
||||
plot.debug("A thrown item couldn't trigger sculk sensors because misc-interact = false");
|
||||
plot.debug("A thrown item couldn't trigger sculk sensors because both sculk-sensor-interact and " +
|
||||
"misc-interact = false");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@ -137,7 +140,6 @@ public class BlockEventListener117 implements Listener {
|
||||
if (area == null) {
|
||||
for (int i = blocks.size() - 1; i >= 0; i--) {
|
||||
Location blockLocation = BukkitUtil.adapt(blocks.get(i).getLocation());
|
||||
blockLocation = BukkitUtil.adapt(blocks.get(i).getLocation());
|
||||
if (blockLocation.isPlotArea()) {
|
||||
blocks.remove(i);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.world.PlotAreaManager;
|
||||
import com.plotsquared.core.plot.world.SinglePlotArea;
|
||||
import com.plotsquared.core.util.ReflectionUtils;
|
||||
import com.plotsquared.core.util.ReflectionUtils.RefClass;
|
||||
import com.plotsquared.core.util.ReflectionUtils.RefField;
|
||||
import com.plotsquared.core.util.ReflectionUtils.RefMethod;
|
||||
@ -64,9 +65,11 @@ public class ChunkListener implements Listener {
|
||||
private final PlotAreaManager plotAreaManager;
|
||||
private final int version;
|
||||
|
||||
private RefMethod methodSetUnsaved;
|
||||
private RefMethod methodGetHandleChunk;
|
||||
private RefMethod methodGetHandleWorld;
|
||||
private RefField mustSave;
|
||||
private RefField mustNotSave;
|
||||
private Object objChunkStatusFull = null;
|
||||
/*
|
||||
private RefMethod methodGetFullChunk;
|
||||
private RefMethod methodGetBukkitChunk;
|
||||
@ -79,7 +82,6 @@ public class ChunkListener implements Listener {
|
||||
*/
|
||||
private Chunk lastChunk;
|
||||
private boolean ignoreUnload = false;
|
||||
private boolean isTrueForNotSave = true;
|
||||
|
||||
@Inject
|
||||
public ChunkListener(final @NonNull PlotAreaManager plotAreaManager) {
|
||||
@ -90,22 +92,27 @@ public class ChunkListener implements Listener {
|
||||
}
|
||||
try {
|
||||
RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
|
||||
this.methodGetHandleWorld = classCraftWorld.getMethod("getHandle");
|
||||
RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
|
||||
ReflectionUtils.RefClass classChunkAccess = getRefClass("net.minecraft.world.level.chunk.IChunkAccess");
|
||||
this.methodSetUnsaved = classChunkAccess.getMethod("a", boolean.class);
|
||||
try {
|
||||
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
try {
|
||||
RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus");
|
||||
this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null);
|
||||
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass());
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (version < 17) {
|
||||
RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
if (version == 13) {
|
||||
this.mustSave = classChunk.getField("mustSave");
|
||||
this.isTrueForNotSave = false;
|
||||
} else {
|
||||
this.mustSave = classChunk.getField("mustNotSave");
|
||||
}
|
||||
this.mustNotSave = classChunk.getField("mustNotSave");
|
||||
} else {
|
||||
RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk");
|
||||
this.mustSave = classChunk.getField("mustNotSave");
|
||||
|
||||
this.mustNotSave = classChunk.getField("mustNotSave");
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
@ -167,10 +174,13 @@ public class ChunkListener implements Listener {
|
||||
if (safe && shouldSave(world, chunk.getX(), chunk.getZ())) {
|
||||
return false;
|
||||
}
|
||||
Object c = this.methodGetHandleChunk.of(chunk).call();
|
||||
RefField.RefExecutor field = this.mustSave.of(c);
|
||||
if ((Boolean) field.get() != isTrueForNotSave) {
|
||||
field.set(isTrueForNotSave);
|
||||
Object c = objChunkStatusFull != null
|
||||
? this.methodGetHandleChunk.of(chunk).call(objChunkStatusFull)
|
||||
: this.methodGetHandleChunk.of(chunk).call();
|
||||
RefField.RefExecutor field = this.mustNotSave.of(c);
|
||||
methodSetUnsaved.of(c).call(false);
|
||||
if (!((Boolean) field.get())) {
|
||||
field.set(true);
|
||||
if (chunk.isLoaded()) {
|
||||
ignoreUnload = true;
|
||||
chunk.unload(false);
|
||||
|
@ -152,7 +152,8 @@ public class EntityEventListener implements Listener {
|
||||
}
|
||||
}
|
||||
case "REINFORCEMENTS", "NATURAL", "MOUNT", "PATROL", "RAID", "SHEARED", "SILVERFISH_BLOCK", "ENDER_PEARL",
|
||||
"TRAP", "VILLAGE_DEFENSE", "VILLAGE_INVASION", "BEEHIVE", "CHUNK_GEN" -> {
|
||||
"TRAP", "VILLAGE_DEFENSE", "VILLAGE_INVASION", "BEEHIVE", "CHUNK_GEN", "NETHER_PORTAL",
|
||||
"DUPLICATION", "FROZEN", "SPELL" -> {
|
||||
if (!area.isMobSpawning()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
|
@ -369,6 +369,7 @@ public class PlayerEventListener implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
public void onConnect(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
PlotSquared.platform().playerManager().removePlayer(player.getUniqueId());
|
||||
@ -733,6 +734,7 @@ public class PlayerEventListener implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
@ -1063,6 +1065,7 @@ public class PlayerEventListener implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
public void onCancelledInteract(PlayerInteractEvent event) {
|
||||
if (event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_AIR) {
|
||||
Player player = event.getPlayer();
|
||||
@ -1167,7 +1170,7 @@ public class PlayerEventListener implements Listener {
|
||||
}
|
||||
}
|
||||
if (type.isEdible()) {
|
||||
//Allow all players to eat while also allowing the block place event ot be fired
|
||||
//Allow all players to eat while also allowing the block place event to be fired
|
||||
return;
|
||||
}
|
||||
if (type == Material.ARMOR_STAND) {
|
||||
|
@ -31,45 +31,39 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static com.plotsquared.core.util.ReflectionUtils.getRefClass;
|
||||
|
||||
public class SingleWorldListener implements Listener {
|
||||
|
||||
private final Method methodGetHandleChunk;
|
||||
private Field shouldSave = null;
|
||||
private final Method methodSetUnsaved;
|
||||
private Method methodGetHandleChunk;
|
||||
private Object objChunkStatusFull = null;
|
||||
|
||||
public SingleWorldListener() throws Exception {
|
||||
ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
|
||||
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod();
|
||||
ReflectionUtils.RefClass classChunkAccess = getRefClass("net.minecraft.world.level.chunk.IChunkAccess");
|
||||
this.methodSetUnsaved = classChunkAccess.getMethod("a", boolean.class).getRealMethod();
|
||||
try {
|
||||
if (PlotSquared.platform().serverVersion()[1] < 17) {
|
||||
ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
if (PlotSquared.platform().serverVersion()[1] == 13) {
|
||||
this.shouldSave = classChunk.getField("mustSave").getRealField();
|
||||
} else {
|
||||
this.shouldSave = classChunk.getField("s").getRealField();
|
||||
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod();
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
try {
|
||||
ReflectionUtils.RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus");
|
||||
this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null);
|
||||
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()).getRealMethod();
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} else if (PlotSquared.platform().serverVersion()[1] == 17) {
|
||||
ReflectionUtils.RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk");
|
||||
this.shouldSave = classChunk.getField("r").getRealField();
|
||||
} else if (PlotSquared.platform().serverVersion()[1] == 18) {
|
||||
ReflectionUtils.RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.IChunkAccess");
|
||||
this.shouldSave = classChunk.getField("b").getRealField();
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void markChunkAsClean(Chunk chunk) {
|
||||
try {
|
||||
Object nmsChunk = methodGetHandleChunk.invoke(chunk);
|
||||
if (shouldSave != null) {
|
||||
this.shouldSave.set(nmsChunk, false);
|
||||
}
|
||||
Object nmsChunk = objChunkStatusFull != null
|
||||
? this.methodGetHandleChunk.invoke(chunk, objChunkStatusFull)
|
||||
: this.methodGetHandleChunk.invoke(chunk);
|
||||
methodSetUnsaved.invoke(nmsChunk, false);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -85,7 +79,12 @@ public class SingleWorldListener implements Listener {
|
||||
if (!SinglePlotArea.isSinglePlotWorld(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = event.getChunk().getX();
|
||||
int z = event.getChunk().getZ();
|
||||
if (x < 16 && x > -16 && z < 16 && z > -16) {
|
||||
// Allow spawn to generate
|
||||
return;
|
||||
}
|
||||
markChunkAsClean(event.getChunk());
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ import java.util.stream.IntStream;
|
||||
@Singleton
|
||||
public class BukkitInventoryUtil extends InventoryUtil {
|
||||
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
private static @Nullable ItemStack getItem(PlotItemStack item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
|
@ -67,6 +67,7 @@ public class BukkitSetupUtils extends SetupUtils {
|
||||
this.worldFile = worldFile;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Paper deprecation
|
||||
@Override
|
||||
public void updateGenerators(final boolean force) {
|
||||
if (loaded && !SetupUtils.generators.isEmpty() && !force) {
|
||||
|
@ -28,7 +28,7 @@ import java.nio.file.Paths;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* This is a helper class which replaces occurrences of 'suggest_command' with 'run_command' in messages_%.json.
|
||||
* This is a helper class which replaces older syntax no longer supported by MiniMessage with replacements in messages_%.json.
|
||||
* MiniMessage changed the syntax between major releases. To warrant a smooth upgrade, we attempt to replace any occurrences
|
||||
* while loading PlotSquared.
|
||||
*
|
||||
@ -38,14 +38,28 @@ import java.util.stream.Stream;
|
||||
public class TranslationUpdateManager {
|
||||
|
||||
public static void upgradeTranslationFile() throws IOException {
|
||||
String searchText = "suggest_command";
|
||||
String replacementText = "run_command";
|
||||
String suggestCommand = "suggest_command";
|
||||
String suggestCommandReplacement = "run_command";
|
||||
String minHeight = "minHeight";
|
||||
String minheightReplacement = "minheight";
|
||||
String maxHeight = "maxHeight";
|
||||
String maxheightReplacement = "maxheight";
|
||||
String usedGrants = "usedGrants";
|
||||
String usedGrantsReplacement = "used_grants";
|
||||
String remainingGrants = "remainingGrants";
|
||||
String rremainingGrantsReplacement = "remaining_grants";
|
||||
|
||||
try (Stream<Path> paths = Files.walk(Paths.get(PlotSquared.platform().getDirectory().toPath().resolve("lang").toUri()))) {
|
||||
paths
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(p -> p.getFileName().toString().matches("messages_[a-z]{2}\\.json"))
|
||||
.forEach(p -> replaceInFile(p, searchText, replacementText));
|
||||
.forEach(p -> {
|
||||
replaceInFile(p, suggestCommand, suggestCommandReplacement);
|
||||
replaceInFile(p, minHeight, minheightReplacement);
|
||||
replaceInFile(p, maxHeight, maxheightReplacement);
|
||||
replaceInFile(p, usedGrants, usedGrantsReplacement);
|
||||
replaceInFile(p, remainingGrants, rremainingGrantsReplacement);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ import org.bukkit.scheduler.BukkitTask;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URI;
|
||||
|
||||
public class UpdateUtility implements Listener {
|
||||
|
||||
@ -59,8 +59,9 @@ public class UpdateUtility implements Listener {
|
||||
public void updateChecker() {
|
||||
task = Bukkit.getScheduler().runTaskTimerAsynchronously(this.javaPlugin, () -> {
|
||||
try {
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(
|
||||
"https://api.spigotmc.org/simple/0.1/index.php?action=getResource&id=77506")
|
||||
HttpsURLConnection connection = (HttpsURLConnection) URI.create(
|
||||
"https://api.spigotmc.org/simple/0.2/index.php?action=getResource&id=77506")
|
||||
.toURL()
|
||||
.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
JsonObject result = new JsonParser()
|
||||
|
@ -1,76 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at contact<at>intellectualsites.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
@ -2,18 +2,18 @@ import java.time.format.DateTimeFormatter
|
||||
|
||||
dependencies {
|
||||
// Expected everywhere.
|
||||
compileOnlyApi("org.checkerframework:checker-qual")
|
||||
compileOnlyApi(libs.checkerqual)
|
||||
|
||||
// Minecraft expectations
|
||||
compileOnlyApi("com.google.code.gson:gson")
|
||||
compileOnly("com.google.guava:guava")
|
||||
compileOnlyApi(libs.gson)
|
||||
compileOnly(libs.guava)
|
||||
|
||||
// Platform expectations
|
||||
compileOnlyApi("org.yaml:snakeyaml")
|
||||
compileOnlyApi(libs.snakeyaml)
|
||||
|
||||
// Adventure
|
||||
api("net.kyori:adventure-api")
|
||||
api("net.kyori:adventure-text-minimessage")
|
||||
api(libs.adventureApi)
|
||||
api(libs.adventureMiniMessage)
|
||||
|
||||
// Guice
|
||||
api(libs.guice) {
|
||||
@ -31,19 +31,24 @@ dependencies {
|
||||
exclude(group = "dummypermscompat")
|
||||
}
|
||||
testImplementation(libs.worldeditCore)
|
||||
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core") { isTransitive = false }
|
||||
testImplementation("com.fastasyncworldedit:FastAsyncWorldEdit-Core") { isTransitive = false }
|
||||
compileOnly(libs.faweBukkit) { isTransitive = false }
|
||||
testImplementation(libs.faweCore) { isTransitive = false }
|
||||
|
||||
// Logging
|
||||
compileOnlyApi("org.apache.logging.log4j:log4j-api")
|
||||
compileOnlyApi(libs.log4j)
|
||||
|
||||
// Database
|
||||
api(libs.hikaricp)
|
||||
api(libs.jdbiCore)
|
||||
api(libs.jdbiGuice)
|
||||
|
||||
// Other libraries
|
||||
api(libs.prtree)
|
||||
api(libs.aopalliance)
|
||||
api(libs.cloudServices)
|
||||
api(libs.arkitektonika)
|
||||
api("com.intellectualsites.paster:Paster")
|
||||
api("com.intellectualsites.informative-annotations:informative-annotations")
|
||||
api(libs.paster)
|
||||
api(libs.informativeAnnotations)
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
@ -57,8 +62,8 @@ tasks.processResources {
|
||||
|
||||
doLast {
|
||||
copy {
|
||||
from(File("$rootDir/LICENSE"))
|
||||
into("$buildDir/resources/main/")
|
||||
from(layout.buildDirectory.file("$rootDir/LICENSE"))
|
||||
into(layout.buildDirectory.dir("resources/main"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,7 +77,6 @@ tasks {
|
||||
opt.links("https://jd.advntr.dev/text-minimessage/4.14.0/")
|
||||
opt.links("https://google.github.io/guice/api-docs/" + libs.guice.get().versionConstraint.toString() + "/javadoc/")
|
||||
opt.links("https://checkerframework.org/api/")
|
||||
opt.links("https://javadoc.io/doc/com.intellectualsites.informative-annotations/informative-annotations/latest/")
|
||||
opt.isLinkSource = true
|
||||
opt.bottom(File("$rootDir/javadocfooter.html").readText())
|
||||
opt.isUse = true
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.plotsquared.core;
|
||||
|
||||
import com.google.inject.Key;
|
||||
import com.plotsquared.core.configuration.ConfigurationSection;
|
||||
import com.plotsquared.core.configuration.ConfigurationUtil;
|
||||
import com.plotsquared.core.configuration.MemorySection;
|
||||
@ -31,14 +32,12 @@ import com.plotsquared.core.configuration.caption.load.DefaultCaptionProvider;
|
||||
import com.plotsquared.core.configuration.file.YamlConfiguration;
|
||||
import com.plotsquared.core.configuration.serialization.ConfigurationSerialization;
|
||||
import com.plotsquared.core.database.DBFunc;
|
||||
import com.plotsquared.core.database.Database;
|
||||
import com.plotsquared.core.database.MySQL;
|
||||
import com.plotsquared.core.database.SQLManager;
|
||||
import com.plotsquared.core.database.SQLite;
|
||||
import com.plotsquared.core.generator.GeneratorWrapper;
|
||||
import com.plotsquared.core.generator.HybridPlotWorld;
|
||||
import com.plotsquared.core.generator.HybridUtils;
|
||||
import com.plotsquared.core.generator.IndependentPlotGenerator;
|
||||
import com.plotsquared.core.inject.annotations.PlotDatabase;
|
||||
import com.plotsquared.core.inject.factory.HybridPlotWorldFactory;
|
||||
import com.plotsquared.core.listener.PlotListener;
|
||||
import com.plotsquared.core.location.Location;
|
||||
@ -75,7 +74,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -84,7 +85,7 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
@ -210,9 +211,10 @@ public class PlotSquared {
|
||||
try {
|
||||
URL logurl = PlotSquared.class.getProtectionDomain().getCodeSource().getLocation();
|
||||
this.jarFile = new File(
|
||||
new URL(logurl.toURI().toString().split("\\!")[0].replaceAll("jar:file", "file"))
|
||||
.toURI().getPath());
|
||||
} catch (MalformedURLException | URISyntaxException | SecurityException e) {
|
||||
URI.create(
|
||||
logurl.toURI().toString().split("\\!")[0].replaceAll("jar:file", "file"))
|
||||
.getPath());
|
||||
} catch (URISyntaxException | SecurityException e) {
|
||||
e.printStackTrace();
|
||||
this.jarFile = new File(this.platform.getDirectory().getParentFile(), "PlotSquared.jar");
|
||||
if (!this.jarFile.exists()) {
|
||||
@ -1235,8 +1237,11 @@ public class PlotSquared {
|
||||
DBFunc.validatePlots(plots);
|
||||
|
||||
// Close the connection
|
||||
DBFunc.close();
|
||||
} catch (NullPointerException throwable) {
|
||||
final DataSource dataSource = platform().injector().getInstance(Key.get(DataSource.class, PlotDatabase.class));
|
||||
if (dataSource instanceof Closeable closeable) {
|
||||
closeable.close();
|
||||
}
|
||||
} catch (IOException | NullPointerException throwable) {
|
||||
LOGGER.error("Could not close database connection", throwable);
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
@ -1288,26 +1293,7 @@ public class PlotSquared {
|
||||
if (DBFunc.dbManager != null) {
|
||||
DBFunc.dbManager.close();
|
||||
}
|
||||
Database database;
|
||||
if (Storage.MySQL.USE) {
|
||||
database = new MySQL(Storage.MySQL.HOST, Storage.MySQL.PORT, Storage.MySQL.DATABASE,
|
||||
Storage.MySQL.USER, Storage.MySQL.PASSWORD
|
||||
);
|
||||
} else if (Storage.SQLite.USE) {
|
||||
File file = FileUtils.getFile(platform.getDirectory(), Storage.SQLite.DB + ".db");
|
||||
database = new SQLite(file);
|
||||
} else {
|
||||
LOGGER.error("No storage type is set. Disabling PlotSquared");
|
||||
this.platform.shutdown(); //shutdown used instead of disable because no database is set
|
||||
return;
|
||||
}
|
||||
DBFunc.dbManager = new SQLManager(
|
||||
database,
|
||||
Storage.PREFIX,
|
||||
this.eventDispatcher,
|
||||
this.plotListener,
|
||||
this.worldConfiguration
|
||||
);
|
||||
DBFunc.dbManager = platform().injector().getInstance(SQLManager.class);
|
||||
this.plots_tmp = DBFunc.getPlots();
|
||||
if (getPlotAreaManager() instanceof SinglePlotAreaManager) {
|
||||
SinglePlotArea area = ((SinglePlotAreaManager) getPlotAreaManager()).getArea();
|
||||
@ -1321,13 +1307,13 @@ public class PlotSquared {
|
||||
}
|
||||
this.clustersTmp = DBFunc.getClusters();
|
||||
LOGGER.info("Connection to database established. Type: {}", Storage.MySQL.USE ? "MySQL" : "SQLite");
|
||||
} catch (ClassNotFoundException | SQLException e) {
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(
|
||||
"Failed to open database connection ({}). Disabling PlotSquared",
|
||||
Storage.MySQL.USE ? "MySQL" : "SQLite"
|
||||
);
|
||||
LOGGER.error("==== Here is an ugly stacktrace, if you are interested in those things ===");
|
||||
e.printStackTrace();
|
||||
LOGGER.error("", e);
|
||||
LOGGER.error("==== End of stacktrace ====");
|
||||
LOGGER.error(
|
||||
"Please go to the {} 'storage.yml' and configure the database correctly",
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.plotsquared.core.command;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.database.DBFunc;
|
||||
@ -101,8 +102,13 @@ public class Add extends Command {
|
||||
Permission.PERMISSION_ADMIN_COMMAND_TRUST))) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("errors.invalid_player"),
|
||||
TagResolver.resolver("value", Tag.inserting(
|
||||
PlayerManager.resolveName(uuid).toComponent(player)
|
||||
PlotSquared
|
||||
.platform()
|
||||
.playerManager()
|
||||
.getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"value",
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
iterator.remove();
|
||||
@ -111,8 +117,10 @@ public class Add extends Command {
|
||||
if (plot.isOwner(uuid)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("member.already_added"),
|
||||
TagResolver.resolver("player", Tag.inserting(
|
||||
PlayerManager.resolveName(uuid).toComponent(player)
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
iterator.remove();
|
||||
@ -121,8 +129,10 @@ public class Add extends Command {
|
||||
if (plot.getMembers().contains(uuid)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("member.already_added"),
|
||||
TagResolver.resolver("player", Tag.inserting(
|
||||
PlayerManager.resolveName(uuid).toComponent(player)
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
iterator.remove();
|
||||
|
@ -131,8 +131,8 @@ public class Auto extends SubCommand {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.removed_granted_plot"),
|
||||
TagResolver.builder()
|
||||
.tag("usedGrants", Tag.inserting(Component.text(grantedPlots - left)))
|
||||
.tag("remainingGrants", Tag.inserting(Component.text(left)))
|
||||
.tag("used_grants", Tag.inserting(Component.text(grantedPlots - left)))
|
||||
.tag("remaining_grants", Tag.inserting(Component.text(left)))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
@ -294,11 +294,11 @@ public class Auto extends SubCommand {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.econHandler != null && plotarea.useEconomy()) {
|
||||
if (this.econHandler != null && plotarea.useEconomy() && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) {
|
||||
PlotExpression costExp = plotarea.getPrices().get("claim");
|
||||
PlotExpression mergeCostExp = plotarea.getPrices().get("merge");
|
||||
int size = sizeX * sizeZ;
|
||||
double mergeCost = size > 1 && mergeCostExp == null ? 0d : mergeCostExp.evaluate(size);
|
||||
double mergeCost = size <= 1 || mergeCostExp == null ? 0d : mergeCostExp.evaluate(size);
|
||||
double cost = costExp.evaluate(Settings.Limit.GLOBAL ?
|
||||
player.getPlotCount() :
|
||||
player.getPlotCount(plotarea.getWorldName()));
|
||||
|
@ -141,7 +141,7 @@ public class Claim extends SubCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.econHandler.isEnabled(area) && !force) {
|
||||
if (this.econHandler.isEnabled(area) && !force && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) {
|
||||
PlotExpression costExr = area.getPrices().get("claim");
|
||||
double cost = costExr.evaluate(currentPlots);
|
||||
if (cost > 0d) {
|
||||
@ -186,8 +186,8 @@ public class Claim extends SubCommand {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.removed_granted_plot"),
|
||||
TagResolver.builder()
|
||||
.tag("usedGrants", Tag.inserting(Component.text(grants - 1)))
|
||||
.tag("remainingGrants", Tag.inserting(Component.text(grants)))
|
||||
.tag("used_grants", Tag.inserting(Component.text(grants - 1)))
|
||||
.tag("remaining_grants", Tag.inserting(Component.text(grants)))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import com.plotsquared.core.player.PlotPlayer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* CommandCategory.
|
||||
@ -82,7 +83,7 @@ public enum CommandCategory implements Caption {
|
||||
// TODO this method shouldn't be invoked
|
||||
@Deprecated
|
||||
@Override
|
||||
public String toString() {
|
||||
public @NotNull String toString() {
|
||||
return this.caption.getComponent(LocaleHolder.console());
|
||||
}
|
||||
|
||||
@ -108,4 +109,5 @@ public enum CommandCategory implements Caption {
|
||||
return !MainCommand.getInstance().getCommands(this, player).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import com.plotsquared.core.util.WorldUtil;
|
||||
import com.plotsquared.core.util.entity.EntityCategories;
|
||||
import com.plotsquared.core.util.entity.EntityCategory;
|
||||
import com.plotsquared.core.util.query.PlotQuery;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.plotsquared.core.uuid.UUIDMapping;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -71,7 +70,7 @@ public class Debug extends SubCommand {
|
||||
TranslatableCaption.of("commandconfig.command_syntax"),
|
||||
TagResolver.resolver(
|
||||
"value",
|
||||
Tag.inserting(Component.text("/plot debug <loadedchunks | player | debug-players | entitytypes | msg>"))
|
||||
Tag.inserting(Component.text("/plot debug <player | debug-players | entitytypes | msg>"))
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -85,16 +84,6 @@ public class Debug extends SubCommand {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (args.length > 0 && "loadedchunks".equalsIgnoreCase(args[0])) {
|
||||
final long start = System.currentTimeMillis();
|
||||
player.sendMessage(TranslatableCaption.of("debug.fetching_loaded_chunks"));
|
||||
TaskManager.runTaskAsync(() -> player.sendMessage(StaticCaption
|
||||
.of("Loaded chunks: " + this.worldUtil
|
||||
.getChunkChunks(player.getLocation().getWorldName())
|
||||
.size() + " (" + (System.currentTimeMillis()
|
||||
- start) + "ms) using thread: " + Thread.currentThread().getName())));
|
||||
return true;
|
||||
}
|
||||
if (args.length > 0 && "uuids".equalsIgnoreCase(args[0])) {
|
||||
final Collection<UUIDMapping> mappings = PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately();
|
||||
player.sendMessage(
|
||||
@ -196,7 +185,7 @@ public class Debug extends SubCommand {
|
||||
|
||||
@Override
|
||||
public Collection<Command> tab(final PlotPlayer<?> player, String[] args, boolean space) {
|
||||
return Stream.of("loadedchunks", "debug-players", "entitytypes")
|
||||
return Stream.of("debug-players", "entitytypes")
|
||||
.filter(value -> value.startsWith(args[0].toLowerCase(Locale.ENGLISH)))
|
||||
.map(value -> new Command(null, false, value, "plots.admin", RequiredType.NONE, null) {
|
||||
}).collect(Collectors.toList());
|
||||
|
@ -96,6 +96,7 @@ public class DebugRoadRegen extends SubCommand {
|
||||
PlotArea area = location.getPlotArea();
|
||||
if (area == null) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world"));
|
||||
return false;
|
||||
}
|
||||
Plot plot = player.getCurrentPlot();
|
||||
if (plot == null) {
|
||||
|
@ -117,10 +117,11 @@ public class Deny extends SubCommand {
|
||||
} else if (plot.getDenied().contains(uuid)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("member.already_added"),
|
||||
TagResolver.resolver(
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(PlayerManager.resolveName(uuid).toComponent(player))
|
||||
)
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
|
@ -112,15 +112,15 @@ public class Kick extends SubCommand {
|
||||
for (PlotPlayer<?> player2 : players) {
|
||||
if (!plot.equals(player2.getCurrentPlot())) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("errors.invalid_player"),
|
||||
TagResolver.resolver("value", Tag.inserting(Component.text(args[0])))
|
||||
TranslatableCaption.of("kick.player_not_in_plot"),
|
||||
TagResolver.resolver("player", Tag.inserting(Component.text(player2.getName())))
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (player2.hasPermission(Permission.PERMISSION_ADMIN_ENTRY_DENIED)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("cluster.cannot_kick_player"),
|
||||
TagResolver.resolver("name", Tag.inserting(Component.text(player2.getName())))
|
||||
TranslatableCaption.of("kick.cannot_kick_player"),
|
||||
TagResolver.resolver("player", Tag.inserting(Component.text(player2.getName())))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -517,6 +517,7 @@ public class ListCmd extends SubCommand {
|
||||
}
|
||||
}
|
||||
finalResolver.tag("players", Tag.inserting(builder.asComponent()));
|
||||
finalResolver.tag("size", Tag.inserting(Component.text(plot.getConnectedPlots().size())));
|
||||
caption.set(TranslatableCaption.of("info.plot_list_item"));
|
||||
caption.setTagResolvers(finalResolver.build());
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -116,7 +117,7 @@ public class Load extends SubCommand {
|
||||
}
|
||||
final URL url;
|
||||
try {
|
||||
url = new URL(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schematic);
|
||||
url = URI.create(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schematic).toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
player.sendMessage(TranslatableCaption.of("web.load_failed"));
|
||||
|
@ -183,7 +183,7 @@ public class MainCommand extends Command {
|
||||
if (cmd.hasConfirmation(player)) {
|
||||
CmdConfirm.addPending(player, cmd.getUsage(), () -> {
|
||||
PlotArea area = player.getApplicablePlotArea();
|
||||
if (area != null && econHandler.isEnabled(area)) {
|
||||
if (area != null && econHandler.isEnabled(area) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) {
|
||||
PlotExpression priceEval =
|
||||
area.getPrices().get(cmd.getFullId());
|
||||
double price = priceEval != null ? priceEval.evaluate(0d) : 0d;
|
||||
@ -201,7 +201,7 @@ public class MainCommand extends Command {
|
||||
return;
|
||||
}
|
||||
PlotArea area = player.getApplicablePlotArea();
|
||||
if (area != null && econHandler.isEnabled(area)) {
|
||||
if (area != null && econHandler.isEnabled(area) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) {
|
||||
PlotExpression priceEval = area.getPrices().get(cmd.getFullId());
|
||||
double price = priceEval != null ? priceEval.evaluate(0d) : 0d;
|
||||
if (price != 0d && econHandler.getMoney(player) < price) {
|
||||
|
@ -109,7 +109,7 @@ public class Merge extends SubCommand {
|
||||
}
|
||||
}
|
||||
if (direction == null && (args[0].equalsIgnoreCase("all") || args[0]
|
||||
.equalsIgnoreCase("auto"))) {
|
||||
.equalsIgnoreCase("auto")) && player.hasPermission(Permission.PERMISSION_MERGE_ALL)) {
|
||||
direction = Direction.ALL;
|
||||
}
|
||||
}
|
||||
@ -178,7 +178,7 @@ public class Merge extends SubCommand {
|
||||
return true;
|
||||
}
|
||||
if (plot.getPlotModificationManager().autoMerge(Direction.ALL, maxSize, uuid, player, terrain)) {
|
||||
if (this.econHandler.isEnabled(plotArea) && price > 0d) {
|
||||
if (this.econHandler.isEnabled(plotArea) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON) && price > 0d) {
|
||||
this.econHandler.withdrawMoney(player, price);
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.removed_balance"),
|
||||
@ -196,8 +196,8 @@ public class Merge extends SubCommand {
|
||||
player.sendMessage(TranslatableCaption.of("merge.no_available_automerge"));
|
||||
return false;
|
||||
}
|
||||
if (!force && this.econHandler.isEnabled(plotArea) && price > 0d
|
||||
&& this.econHandler.getMoney(player) < price) {
|
||||
if (!force && this.econHandler.isEnabled(plotArea) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON) && price > 0d && this.econHandler.getMoney(
|
||||
player) < price) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.cannot_afford_merge"),
|
||||
TagResolver.resolver("money", Tag.inserting(Component.text(this.econHandler.format(price))))
|
||||
@ -218,7 +218,7 @@ public class Merge extends SubCommand {
|
||||
return true;
|
||||
}
|
||||
if (plot.getPlotModificationManager().autoMerge(direction, maxSize - size, uuid, player, terrain)) {
|
||||
if (this.econHandler.isEnabled(plotArea) && price > 0d) {
|
||||
if (this.econHandler.isEnabled(plotArea) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON) && price > 0d) {
|
||||
this.econHandler.withdrawMoney(player, price);
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.removed_balance"),
|
||||
@ -259,7 +259,7 @@ public class Merge extends SubCommand {
|
||||
accepter.sendMessage(TranslatableCaption.of("merge.merge_not_valid"));
|
||||
return;
|
||||
}
|
||||
if (this.econHandler.isEnabled(plotArea) && price > 0d) {
|
||||
if (this.econHandler.isEnabled(plotArea) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON) && price > 0d) {
|
||||
if (!force && this.econHandler.getMoney(player) < price) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.cannot_afford_merge"),
|
||||
@ -303,7 +303,7 @@ public class Merge extends SubCommand {
|
||||
player,
|
||||
terrain
|
||||
)) {
|
||||
if (this.econHandler.isEnabled(plotArea) && price > 0d) {
|
||||
if (this.econHandler.isEnabled(plotArea) && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON) && price > 0d) {
|
||||
if (!force && this.econHandler.getMoney(player) < price) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("economy.cannot_afford_merge"),
|
||||
|
@ -31,7 +31,6 @@ import com.plotsquared.core.player.PlayerMetaDataKeys;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.util.EventDispatcher;
|
||||
import com.plotsquared.core.util.PlayerManager;
|
||||
import com.plotsquared.core.util.TabCompletions;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -136,10 +135,11 @@ public class Owner extends SetCommand {
|
||||
if (plot.isOwner(uuid)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("member.already_owner"),
|
||||
TagResolver.resolver(
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(PlayerManager.resolveName(uuid, false).toComponent(player))
|
||||
)
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -147,10 +147,11 @@ public class Owner extends SetCommand {
|
||||
if (other == null) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("errors.invalid_player_offline"),
|
||||
TagResolver.resolver(
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(PlayerManager.resolveName(uuid).toComponent(player))
|
||||
)
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public class PluginCmd extends SubCommand {
|
||||
player.sendMessage(StaticCaption.of(
|
||||
"<gray>>> </gray><gold><bold>Authors<reset><gray>: </gray><gold>Citymonstret </gold><gray>& </gray><gold>Empire92 </gold><gray>& </gray><gold>MattBDev </gold><gray>& </gray><gold>dordsor21 </gold><gray>& </gray><gold>NotMyFault </gold><gray>& </gray><gold>SirYwell</gold>"));
|
||||
player.sendMessage(StaticCaption.of(
|
||||
"<gray>>> </gray><gold><bold>Wiki<reset><gray>: </gray><gold><click:open_url:https://intellectualsites.github.io/plotsquared-documentation/>https://intellectualsites.github.io/plotsquared-documentation/</gold>"));
|
||||
"<gray>>> </gray><gold><bold>Wiki<reset><gray>: </gray><gold><click:open_url:https://intellectualsites.gitbook.io/plotsquared/>https://intellectualsites.gitbook.io/plotsquared/</gold>"));
|
||||
player.sendMessage(StaticCaption.of(
|
||||
"<gray>>> </gray><gold><bold>Discord<reset><gray>: </gray><gold><click:open_url:https://discord.gg/intellectualsites>https://discord.gg/intellectualsites</gold>"));
|
||||
player.sendMessage(
|
||||
|
@ -40,6 +40,7 @@ import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -130,8 +131,7 @@ public class SchematicCmd extends SubCommand {
|
||||
if (location.startsWith("url:")) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(location.substring(4));
|
||||
URL base = new URL(Settings.Web.URL);
|
||||
URL url = new URL(base, "uploads/" + uuid + ".schematic");
|
||||
URL url = URI.create(Settings.Web.URL + "uploads/" + uuid + ".schematic").toURL();
|
||||
schematic = this.schematicHandler.getSchematic(url);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.plotsquared.core.command;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.database.DBFunc;
|
||||
@ -103,10 +104,11 @@ public class Trust extends Command {
|
||||
player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_TRUST))) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("errors.invalid_player"),
|
||||
TagResolver.resolver(
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"value",
|
||||
Tag.inserting(PlayerManager.resolveName(uuid).toComponent(player))
|
||||
)
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
iterator.remove();
|
||||
continue;
|
||||
@ -114,10 +116,11 @@ public class Trust extends Command {
|
||||
if (currentPlot.isOwner(uuid)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("member.already_added"),
|
||||
TagResolver.resolver(
|
||||
"value",
|
||||
Tag.inserting(PlayerManager.resolveName(uuid).toComponent(player))
|
||||
)
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
iterator.remove();
|
||||
continue;
|
||||
@ -125,10 +128,11 @@ public class Trust extends Command {
|
||||
if (currentPlot.getTrusted().contains(uuid)) {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("member.already_added"),
|
||||
TagResolver.resolver(
|
||||
"value",
|
||||
Tag.inserting(PlayerManager.resolveName(uuid).toComponent(player))
|
||||
)
|
||||
PlotSquared.platform().playerManager().getUsernameCaption(uuid)
|
||||
.thenApply(caption -> TagResolver.resolver(
|
||||
"player",
|
||||
Tag.inserting(caption.toComponent(player))
|
||||
))
|
||||
);
|
||||
iterator.remove();
|
||||
continue;
|
||||
|
@ -206,7 +206,7 @@ public class ComponentPresetManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (componentPreset.cost() > 0.0D) {
|
||||
if (componentPreset.cost() > 0.0D && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) {
|
||||
if (!econHandler.isEnabled(plot.getArea())) {
|
||||
getPlayer().sendMessage(
|
||||
TranslatableCaption.of("preset.economy_disabled"),
|
||||
|
@ -194,7 +194,7 @@ public class Settings extends Config {
|
||||
public List<String> WORLDS = new ArrayList<>(Collections.singletonList("*"));
|
||||
|
||||
|
||||
@Comment("See: https://intellectualsites.github.io/plotsquared-documentation/optimization/plot-analysis for a description of each value.")
|
||||
@Comment("See: https://intellectualsites.gitbook.io/plotsquared/optimization/plot-analysis for a description of each value.")
|
||||
public static final class CALIBRATION {
|
||||
|
||||
public int VARIETY = 0;
|
||||
@ -214,7 +214,7 @@ public class Settings extends Config {
|
||||
|
||||
|
||||
@Comment({"Chunk processor related settings",
|
||||
"See https://intellectualsites.github.io/plotsquared-documentation/optimization/chunk-processor for more information."})
|
||||
"See https://intellectualsites.gitbook.io/plotsquared/optimization/chunk-processor for more information."})
|
||||
public static class Chunk_Processor {
|
||||
|
||||
@Comment("Auto trim will not save chunks which aren't claimed")
|
||||
@ -280,7 +280,7 @@ public class Settings extends Config {
|
||||
@Comment("Always show explosion Particles, even if explosion flag is set to false")
|
||||
public static boolean ALWAYS_SHOW_EXPLOSIONS = false;
|
||||
@Comment({"Blocks that may not be used in plot components",
|
||||
"Checkout the wiki article regarding plot components before modifying: https://intellectualsites.github.io/plotsquared-documentation/customization/plot-components"})
|
||||
"Checkout the wiki article regarding plot components before modifying: https://intellectualsites.gitbook.io/plotsquared/customization/plot-components"})
|
||||
public static List<String>
|
||||
INVALID_BLOCKS = Arrays.asList(
|
||||
// Acacia Stuff
|
||||
@ -402,7 +402,7 @@ public class Settings extends Config {
|
||||
|
||||
|
||||
@Comment({"Schematic Settings",
|
||||
"See https://intellectualsites.github.io/plotsquared-documentation/schematics/schematic-on-claim for more information."})
|
||||
"See https://intellectualsites.gitbook.io/plotsquared/schematics/schematic-on-claim for more information."})
|
||||
public static final class Schematics {
|
||||
|
||||
@Comment(
|
||||
@ -531,7 +531,7 @@ public class Settings extends Config {
|
||||
|
||||
|
||||
@Comment({"Backup related settings",
|
||||
"See https://intellectualsites.github.io/plotsquared-documentation/plot-backups for more information."})
|
||||
"See https://intellectualsites.gitbook.io/plotsquared/plot-backups for more information."})
|
||||
public static final class Backup {
|
||||
|
||||
@Comment("Automatically backup plots when destructive commands are performed, e.g. /plot clear")
|
||||
@ -783,7 +783,7 @@ public class Settings extends Config {
|
||||
public static boolean
|
||||
PERSISTENT_ROAD_REGEN = true;
|
||||
@Comment({"Enable the `/plot component` preset GUI",
|
||||
"Read more about components here: https://intellectualsites.github.io/plotsquared-documentation/customization/plot-components"})
|
||||
"Read more about components here: https://intellectualsites.gitbook.io/plotsquared/customization/plot-components"})
|
||||
public static boolean COMPONENT_PRESETS = true;
|
||||
@Comment("Enable per user locale")
|
||||
public static boolean PER_USER_LOCALE = false;
|
||||
|
@ -44,4 +44,6 @@ public interface Caption {
|
||||
*/
|
||||
@NonNull Component toComponent(@NonNull LocaleHolder localeHolder);
|
||||
|
||||
@NonNull String toString();
|
||||
|
||||
}
|
||||
|
@ -51,4 +51,9 @@ public final class StaticCaption implements Caption {
|
||||
return MiniMessage.miniMessage().deserialize(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return "StaticCaption(" + value + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
@ -132,4 +133,9 @@ public final class TranslatableCaption implements NamespacedCaption {
|
||||
return Objects.hashCode(this.getNamespace(), this.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String toString() {
|
||||
return "TranslatableCaption(" + getNamespace() + ":" + getKey() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import java.sql.Statement;
|
||||
* @author -_Husky_-
|
||||
* @author tips48
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public abstract class Database {
|
||||
|
||||
public abstract Connection forceConnection() throws SQLException, ClassNotFoundException;
|
||||
|
@ -33,6 +33,7 @@ import java.sql.Statement;
|
||||
* @author -_Husky_-
|
||||
* @author tips48
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class MySQL extends Database {
|
||||
|
||||
private final String user;
|
||||
|
@ -25,6 +25,7 @@ import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.configuration.Storage;
|
||||
import com.plotsquared.core.configuration.caption.CaptionUtility;
|
||||
import com.plotsquared.core.configuration.file.YamlConfiguration;
|
||||
import com.plotsquared.core.inject.annotations.PlotDatabase;
|
||||
import com.plotsquared.core.inject.annotations.WorldConfig;
|
||||
import com.plotsquared.core.listener.PlotListener;
|
||||
import com.plotsquared.core.location.BlockLoc;
|
||||
@ -44,10 +45,14 @@ import com.plotsquared.core.util.HashUtil;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.plotsquared.core.util.task.RunnableVal;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.Closeable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
@ -92,12 +97,12 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
// Private Final
|
||||
private final String prefix;
|
||||
private final Database database;
|
||||
private final boolean mySQL;
|
||||
@SuppressWarnings({"unused", "FieldCanBeLocal"})
|
||||
private final EventDispatcher eventDispatcher;
|
||||
@SuppressWarnings({"unused", "FieldCanBeLocal"})
|
||||
private final PlotListener plotListener;
|
||||
private final DataSource dataSource;
|
||||
private final YamlConfiguration worldConfiguration;
|
||||
/**
|
||||
* important tasks
|
||||
@ -129,20 +134,12 @@ public class SQLManager implements AbstractDB {
|
||||
*/
|
||||
public volatile ConcurrentHashMap<PlotCluster, Queue<UniqueStatement>> clusterTasks;
|
||||
// Private
|
||||
private Connection connection;
|
||||
private boolean supportsGetGeneratedKeys;
|
||||
private boolean closed = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param database
|
||||
* @param prefix prefix
|
||||
* @throws SQLException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@Inject
|
||||
public SQLManager(
|
||||
final @NonNull Database database,
|
||||
final @NonNull String prefix,
|
||||
final @NonNull @PlotDatabase DataSource dataSource,
|
||||
final @NonNull EventDispatcher eventDispatcher,
|
||||
final @NonNull PlotListener plotListener,
|
||||
@WorldConfig final @NonNull YamlConfiguration worldConfiguration
|
||||
@ -152,15 +149,27 @@ public class SQLManager implements AbstractDB {
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.plotListener = plotListener;
|
||||
this.worldConfiguration = worldConfiguration;
|
||||
this.database = database;
|
||||
this.connection = database.openConnection();
|
||||
this.mySQL = database instanceof MySQL;
|
||||
this.dataSource = dataSource;
|
||||
this.mySQL = Storage.MySQL.USE;
|
||||
this.globalTasks = new ConcurrentLinkedQueue<>();
|
||||
this.notifyTasks = new ConcurrentLinkedQueue<>();
|
||||
this.plotTasks = new ConcurrentHashMap<>();
|
||||
this.playerTasks = new ConcurrentHashMap<>();
|
||||
this.clusterTasks = new ConcurrentHashMap<>();
|
||||
this.prefix = prefix;
|
||||
this.prefix = Storage.PREFIX;
|
||||
|
||||
try (final Connection connection = dataSource.getConnection()) {
|
||||
final DatabaseMetaData metaData = connection.getMetaData();
|
||||
this.supportsGetGeneratedKeys = metaData.supportsGetGeneratedKeys();
|
||||
|
||||
if (this.mySQL && !this.supportsGetGeneratedKeys) {
|
||||
final String driver = metaData.getDriverName();
|
||||
final String driverVersion = metaData.getDriverVersion();
|
||||
throw new SQLException("Database Driver for MySQL does not support Statement#getGeneratedKeys - which breaks " +
|
||||
"PlotSquared functionality (Using " + driver + ":" + driverVersion + ")");
|
||||
}
|
||||
}
|
||||
|
||||
this.SET_OWNER = "UPDATE `" + this.prefix
|
||||
+ "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?";
|
||||
this.GET_ALL_PLOTS =
|
||||
@ -171,20 +180,32 @@ public class SQLManager implements AbstractDB {
|
||||
"INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values ";
|
||||
this.CREATE_TIERS =
|
||||
"INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values ";
|
||||
this.CREATE_PLOT = "INSERT INTO `" + this.prefix
|
||||
String tempCreatePlot = "INSERT INTO `" + this.prefix
|
||||
+ "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)";
|
||||
|
||||
if (!supportsGetGeneratedKeys) {
|
||||
tempCreatePlot += " RETURNING `id`";
|
||||
}
|
||||
this.CREATE_PLOT = tempCreatePlot;
|
||||
if (mySQL) {
|
||||
this.CREATE_PLOT_SAFE = "INSERT IGNORE INTO `" + this.prefix
|
||||
+ "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `"
|
||||
+ this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)";
|
||||
} else {
|
||||
this.CREATE_PLOT_SAFE = "INSERT INTO `" + this.prefix
|
||||
String tempCreatePlotSafe = "INSERT INTO `" + this.prefix
|
||||
+ "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `"
|
||||
+ this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)";
|
||||
if (!supportsGetGeneratedKeys) {
|
||||
tempCreatePlotSafe += " RETURNING `id`";
|
||||
}
|
||||
this.CREATE_CLUSTER = "INSERT INTO `" + this.prefix
|
||||
this.CREATE_PLOT_SAFE = tempCreatePlotSafe;
|
||||
}
|
||||
String tempCreateCluster = "INSERT INTO `" + this.prefix
|
||||
+ "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)";
|
||||
if (!supportsGetGeneratedKeys) {
|
||||
tempCreateCluster += " RETURNING `id`";
|
||||
}
|
||||
this.CREATE_CLUSTER = tempCreateCluster;
|
||||
|
||||
try {
|
||||
createTables();
|
||||
} catch (SQLException e) {
|
||||
@ -197,11 +218,6 @@ public class SQLManager implements AbstractDB {
|
||||
!globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty()
|
||||
|| !clusterTasks.isEmpty();
|
||||
if (hasTask) {
|
||||
if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000
|
||||
|| !isValid()) {
|
||||
last = System.currentTimeMillis();
|
||||
reconnect();
|
||||
}
|
||||
if (!sendBatch()) {
|
||||
try {
|
||||
if (!getNotifyTasks().isEmpty()) {
|
||||
@ -226,32 +242,6 @@ public class SQLManager implements AbstractDB {
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
try {
|
||||
if (connection.isClosed()) {
|
||||
return false;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) {
|
||||
stmt.execute();
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void reconnect() {
|
||||
try {
|
||||
close();
|
||||
SQLManager.this.closed = false;
|
||||
SQLManager.this.connection = database.forceConnection();
|
||||
} catch (SQLException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Queue<Runnable> getGlobalTasks() {
|
||||
return this.globalTasks;
|
||||
}
|
||||
@ -270,7 +260,7 @@ public class SQLManager implements AbstractDB {
|
||||
task = new UniqueStatement(String.valueOf(plot.hashCode())) {
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() {
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -304,7 +294,7 @@ public class SQLManager implements AbstractDB {
|
||||
task = new UniqueStatement(String.valueOf(uuid.hashCode())) {
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() {
|
||||
public PreparedStatement get(final @NonNull Connection connection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -335,7 +325,7 @@ public class SQLManager implements AbstractDB {
|
||||
task = new UniqueStatement(String.valueOf(cluster.hashCode())) {
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() {
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -367,10 +357,10 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
public boolean sendBatch() {
|
||||
try {
|
||||
try (Connection connection = this.dataSource().getConnection()) {
|
||||
if (!getGlobalTasks().isEmpty()) {
|
||||
if (this.connection.getAutoCommit()) {
|
||||
this.connection.setAutoCommit(false);
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
Runnable task = getGlobalTasks().remove();
|
||||
if (task != null) {
|
||||
@ -381,18 +371,19 @@ public class SQLManager implements AbstractDB {
|
||||
LOGGER.error("============ DATABASE ERROR ============");
|
||||
LOGGER.error("There was an error updating the database.");
|
||||
LOGGER.error(" - It will be corrected on shutdown");
|
||||
e.printStackTrace();
|
||||
LOGGER.error("", e);
|
||||
LOGGER.error("========================================");
|
||||
}
|
||||
}
|
||||
commit();
|
||||
commit(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
int count = -1;
|
||||
if (!this.plotTasks.isEmpty()) {
|
||||
count = Math.max(count, 0);
|
||||
if (this.connection.getAutoCommit()) {
|
||||
this.connection.setAutoCommit(false);
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
String method = null;
|
||||
PreparedStatement statement = null;
|
||||
@ -446,8 +437,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
if (!this.playerTasks.isEmpty()) {
|
||||
count = Math.max(count, 0);
|
||||
if (this.connection.getAutoCommit()) {
|
||||
this.connection.setAutoCommit(false);
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
String method = null;
|
||||
PreparedStatement statement = null;
|
||||
@ -491,8 +482,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
if (!this.clusterTasks.isEmpty()) {
|
||||
count = Math.max(count, 0);
|
||||
if (this.connection.getAutoCommit()) {
|
||||
this.connection.setAutoCommit(false);
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
String method = null;
|
||||
PreparedStatement statement = null;
|
||||
@ -536,12 +527,12 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
commit();
|
||||
commit(connection);
|
||||
return true;
|
||||
}
|
||||
if (count != -1) {
|
||||
if (!this.connection.getAutoCommit()) {
|
||||
this.connection.setAutoCommit(true);
|
||||
if (!connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
}
|
||||
if (!this.clusterTasks.isEmpty()) {
|
||||
@ -561,10 +552,6 @@ public class SQLManager implements AbstractDB {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return this.connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Plot owner
|
||||
*
|
||||
@ -583,8 +570,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER);
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(SQLManager.this.SET_OWNER);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -592,7 +579,7 @@ public class SQLManager implements AbstractDB {
|
||||
@Override
|
||||
public void createPlotsAndData(final List<Plot> myList, final Runnable whenDone) {
|
||||
addGlobalTask(() -> {
|
||||
try {
|
||||
try (Connection connection = this.dataSource().getConnection()) {
|
||||
// Create the plots
|
||||
createPlots(myList, () -> {
|
||||
final Map<PlotId, Integer> idMap = new HashMap<>();
|
||||
@ -609,7 +596,7 @@ public class SQLManager implements AbstractDB {
|
||||
final ArrayList<UUIDPair> denied = new ArrayList<>();
|
||||
|
||||
// Populating structures
|
||||
try (PreparedStatement stmt = SQLManager.this.connection
|
||||
try (PreparedStatement stmt = connection
|
||||
.prepareStatement(SQLManager.this.GET_ALL_PLOTS);
|
||||
ResultSet result = stmt.executeQuery()) {
|
||||
while (result.next()) {
|
||||
@ -634,13 +621,14 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
}
|
||||
|
||||
createFlags(idMap, myList, () -> createSettings(
|
||||
createFlags(connection, idMap, myList, () -> createSettings(
|
||||
connection,
|
||||
settings,
|
||||
() -> createTiers(helpers, "helpers",
|
||||
() -> createTiers(trusted, "trusted",
|
||||
() -> createTiers(denied, "denied", () -> {
|
||||
try {
|
||||
SQLManager.this.connection.commit();
|
||||
connection.commit();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -654,7 +642,7 @@ public class SQLManager implements AbstractDB {
|
||||
} catch (SQLException e) {
|
||||
LOGGER.warn("Failed to set all flags and member tiers for plots", e);
|
||||
try {
|
||||
SQLManager.this.connection.commit();
|
||||
connection.commit();
|
||||
} catch (SQLException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
@ -662,11 +650,6 @@ public class SQLManager implements AbstractDB {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Warning! Failed to set all helper for plots", e);
|
||||
try {
|
||||
SQLManager.this.connection.commit();
|
||||
} catch (SQLException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -723,8 +706,13 @@ public class SQLManager implements AbstractDB {
|
||||
setBulk(myList, mod, whenDone);
|
||||
}
|
||||
|
||||
public void createFlags(Map<PlotId, Integer> ids, List<Plot> plots, Runnable whenDone) {
|
||||
try (final PreparedStatement preparedStatement = this.connection.prepareStatement(
|
||||
private void createFlags(
|
||||
final @NonNull Connection connection,
|
||||
final @NonNull Map<@NonNull PlotId, @NonNull Integer> ids,
|
||||
final @NonNull List<@NonNull Plot> plots,
|
||||
final @NonNull Runnable whenDone
|
||||
) {
|
||||
try (final PreparedStatement preparedStatement = connection.prepareStatement(
|
||||
"INSERT INTO `" + SQLManager.this.prefix
|
||||
+ "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) {
|
||||
for (final Plot plot : plots) {
|
||||
@ -822,6 +810,7 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
public <T> void setBulk(List<T> objList, StmtMod<T> mod, Runnable whenDone) {
|
||||
try (Connection connection = this.dataSource().getConnection()) {
|
||||
int size = objList.size();
|
||||
if (size == 0) {
|
||||
if (whenDone != null) {
|
||||
@ -849,13 +838,13 @@ public class SQLManager implements AbstractDB {
|
||||
if (last == -1) {
|
||||
last = subList.size();
|
||||
statement = mod.getCreateMySQL(subList.size());
|
||||
preparedStmt = this.connection.prepareStatement(statement);
|
||||
preparedStmt = connection.prepareStatement(statement);
|
||||
}
|
||||
if (subList.size() != last || count % 5000 == 0 && count > 0) {
|
||||
preparedStmt.executeBatch();
|
||||
preparedStmt.close();
|
||||
statement = mod.getCreateMySQL(subList.size());
|
||||
preparedStmt = this.connection.prepareStatement(statement);
|
||||
preparedStmt = connection.prepareStatement(statement);
|
||||
}
|
||||
for (int i = 0; i < subList.size(); i++) {
|
||||
count++;
|
||||
@ -891,13 +880,13 @@ public class SQLManager implements AbstractDB {
|
||||
if (last == -1) {
|
||||
last = subList.size();
|
||||
statement = mod.getCreateSQLite(subList.size());
|
||||
preparedStmt = this.connection.prepareStatement(statement);
|
||||
preparedStmt = connection.prepareStatement(statement);
|
||||
}
|
||||
if (subList.size() != last || count % 5000 == 0 && count > 0) {
|
||||
preparedStmt.executeBatch();
|
||||
preparedStmt.clearParameters();
|
||||
statement = mod.getCreateSQLite(subList.size());
|
||||
preparedStmt = this.connection.prepareStatement(statement);
|
||||
preparedStmt = connection.prepareStatement(statement);
|
||||
}
|
||||
for (int i = 0; i < subList.size(); i++) {
|
||||
count++;
|
||||
@ -914,7 +903,7 @@ public class SQLManager implements AbstractDB {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("2: | {}", objList.get(0).getClass().getCanonicalName());
|
||||
LOGGER.error("Could not bulk save!");
|
||||
try (PreparedStatement preparedStmt = this.connection
|
||||
try (PreparedStatement preparedStmt = connection
|
||||
.prepareStatement(mod.getCreateSQL())) {
|
||||
for (T obj : objList) {
|
||||
mod.setSQL(preparedStmt, obj);
|
||||
@ -929,10 +918,16 @@ public class SQLManager implements AbstractDB {
|
||||
if (whenDone != null) {
|
||||
whenDone.run();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to create SQL connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void createSettings(final ArrayList<LegacySettings> myList, final Runnable whenDone) {
|
||||
try (final PreparedStatement preparedStatement = this.connection.prepareStatement(
|
||||
private void createSettings(
|
||||
final @NonNull Connection connection,
|
||||
final @NonNull List<@NonNull LegacySettings> myList,
|
||||
final @NonNull Runnable whenDone) {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
||||
"INSERT INTO `" + SQLManager.this.prefix + "plot_settings`"
|
||||
+ "(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`merged`,`position`) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
|
||||
|
||||
@ -1059,8 +1054,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
SQLManager.this.CREATE_PLOT_SAFE,
|
||||
Statement.RETURN_GENERATED_KEYS
|
||||
);
|
||||
@ -1073,9 +1068,8 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
@Override
|
||||
public void addBatch(PreparedStatement statement) throws SQLException {
|
||||
int inserted = statement.executeUpdate();
|
||||
if (inserted > 0) {
|
||||
try (ResultSet keys = statement.getGeneratedKeys()) {
|
||||
if (statement.execute() || statement.getUpdateCount() > 0) {
|
||||
try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) {
|
||||
if (keys.next()) {
|
||||
plot.temp = keys.getInt(1);
|
||||
addPlotTask(plot, new UniqueStatement(
|
||||
@ -1087,8 +1081,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"INSERT INTO `" + SQLManager.this.prefix
|
||||
+ "plot_settings`(`plot_plot_id`) VALUES(?)");
|
||||
}
|
||||
@ -1107,17 +1101,14 @@ public class SQLManager implements AbstractDB {
|
||||
});
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
private void commit(final @NonNull Connection connection) {
|
||||
try {
|
||||
if (!this.connection.getAutoCommit()) {
|
||||
this.connection.commit();
|
||||
this.connection.setAutoCommit(true);
|
||||
if (!connection.getAutoCommit()) {
|
||||
connection.commit();
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failed to commit database transaction", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1134,8 +1125,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection
|
||||
.prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS);
|
||||
}
|
||||
|
||||
@ -1145,8 +1136,8 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
@Override
|
||||
public void addBatch(PreparedStatement statement) throws SQLException {
|
||||
statement.executeUpdate();
|
||||
try (ResultSet keys = statement.getGeneratedKeys()) {
|
||||
statement.execute();
|
||||
try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) {
|
||||
if (keys.next()) {
|
||||
plot.temp = keys.getInt(1);
|
||||
}
|
||||
@ -1160,8 +1151,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"INSERT INTO `" + SQLManager.this.prefix
|
||||
+ "plot_settings`(`plot_plot_id`) VALUES(?)");
|
||||
}
|
||||
@ -1176,6 +1167,7 @@ public class SQLManager implements AbstractDB {
|
||||
*/
|
||||
@Override
|
||||
public void createTables() throws SQLException {
|
||||
try (Connection connection = this.dataSource().getConnection()) {
|
||||
String[] tables =
|
||||
new String[]{"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted",
|
||||
"plot_rating", "plot_settings", "cluster", "player_meta", "plot_flags"};
|
||||
@ -1193,7 +1185,7 @@ public class SQLManager implements AbstractDB {
|
||||
return;
|
||||
}
|
||||
boolean addConstraint = create == tables.length;
|
||||
try (Statement stmt = this.connection.createStatement()) {
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
if (this.mySQL) {
|
||||
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` ("
|
||||
+ "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`plot_id_x` INT(11) NOT NULL,"
|
||||
@ -1328,6 +1320,7 @@ public class SQLManager implements AbstractDB {
|
||||
stmt.clearBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSettings(final Plot plot) {
|
||||
@ -1338,8 +1331,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "plot_settings` WHERE `plot_plot_id` = ?");
|
||||
}
|
||||
@ -1358,8 +1351,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "plot_helpers` WHERE `plot_plot_id` = ?");
|
||||
}
|
||||
@ -1378,8 +1371,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "plot_trusted` WHERE `plot_plot_id` = ?");
|
||||
}
|
||||
@ -1398,8 +1391,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "plot_denied` WHERE `plot_plot_id` = ?");
|
||||
}
|
||||
@ -1416,8 +1409,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "plot_comments` WHERE `world` = ? AND `hashcode` = ?");
|
||||
}
|
||||
@ -1436,8 +1429,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "plot_rating` WHERE `plot_plot_id` = ?");
|
||||
}
|
||||
@ -1464,8 +1457,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?");
|
||||
}
|
||||
});
|
||||
@ -1486,8 +1479,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"INSERT INTO `" + SQLManager.this.prefix
|
||||
+ "plot_settings`(`plot_plot_id`) VALUES(?)");
|
||||
}
|
||||
@ -1496,16 +1489,12 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
@Override
|
||||
public int getClusterId(PlotCluster cluster) {
|
||||
if (cluster.temp > 0) {
|
||||
return cluster.temp;
|
||||
}
|
||||
try {
|
||||
commit();
|
||||
try (Connection connection = this.dataSource.getConnection()) {
|
||||
if (cluster.temp > 0) {
|
||||
return cluster.temp;
|
||||
}
|
||||
int c_id;
|
||||
try (PreparedStatement stmt = this.connection.prepareStatement(
|
||||
try (PreparedStatement stmt = connection.prepareStatement(
|
||||
"SELECT `id` FROM `" + this.prefix
|
||||
+ "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) {
|
||||
stmt.setInt(1, cluster.getP1().getX());
|
||||
@ -1539,13 +1528,12 @@ public class SQLManager implements AbstractDB {
|
||||
if (plot.temp > 0) {
|
||||
return plot.temp;
|
||||
}
|
||||
try {
|
||||
commit();
|
||||
try (Connection connection = this.dataSource().getConnection()) {
|
||||
if (plot.temp > 0) {
|
||||
return plot.temp;
|
||||
}
|
||||
int id;
|
||||
try (PreparedStatement statement = this.connection.prepareStatement(
|
||||
try (PreparedStatement statement = connection.prepareStatement(
|
||||
"SELECT `id` FROM `" + this.prefix
|
||||
+ "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) {
|
||||
statement.setInt(1, plot.getId().getX());
|
||||
@ -1574,15 +1562,15 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
@Override
|
||||
public void updateTables(int[] oldVersion) {
|
||||
try {
|
||||
try (Connection connection = this.dataSource().getConnection()) {
|
||||
if (this.mySQL && !PlotSquared.get().checkVersion(oldVersion, 3, 3, 2)) {
|
||||
try (Statement stmt = this.connection.createStatement()) {
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.executeUpdate(
|
||||
"ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`");
|
||||
} catch (SQLException ignored) {
|
||||
}
|
||||
}
|
||||
DatabaseMetaData data = this.connection.getMetaData();
|
||||
DatabaseMetaData data = connection.getMetaData();
|
||||
ResultSet rs =
|
||||
data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id");
|
||||
if (rs.next()) {
|
||||
@ -1590,7 +1578,7 @@ public class SQLManager implements AbstractDB {
|
||||
rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode");
|
||||
if (!rs.next()) {
|
||||
rs.close();
|
||||
try (Statement statement = this.connection.createStatement()) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`");
|
||||
if (Storage.MySQL.USE) {
|
||||
statement.addBatch(
|
||||
@ -1625,7 +1613,7 @@ public class SQLManager implements AbstractDB {
|
||||
rs.close();
|
||||
rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id");
|
||||
if (rs.next()) {
|
||||
try (Statement statement = this.connection.createStatement()) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.executeUpdate("DELETE FROM `" + this.prefix
|
||||
+ "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `"
|
||||
+ this.prefix + "plot`)");
|
||||
@ -1634,7 +1622,7 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
rs.close();
|
||||
try (Statement statement = this.connection.createStatement()) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
for (String table : new String[]{"plot_denied", "plot_helpers",
|
||||
"plot_trusted"}) {
|
||||
ResultSet result = statement.executeQuery(
|
||||
@ -1706,9 +1694,12 @@ public class SQLManager implements AbstractDB {
|
||||
@Override
|
||||
public boolean convertFlags() {
|
||||
final Map<Integer, Map<String, String>> flagMap = new HashMap<>();
|
||||
try (Statement statement = this.connection.createStatement()) {
|
||||
try (ResultSet resultSet = statement
|
||||
.executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) {
|
||||
try (
|
||||
Connection connection = this.dataSource().getConnection();
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement
|
||||
.executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")
|
||||
) {
|
||||
while (resultSet.next()) {
|
||||
final int id = resultSet.getInt("plot_plot_id");
|
||||
final String plotFlags = resultSet.getString("flags");
|
||||
@ -1729,14 +1720,14 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
LOGGER.error("Failed to load old flag values", e);
|
||||
return false;
|
||||
}
|
||||
LOGGER.info("Loaded {} plot flag collections...", flagMap.size());
|
||||
LOGGER.info("Attempting to store these flags in the new table...");
|
||||
try (final PreparedStatement preparedStatement = this.connection.prepareStatement(
|
||||
try (Connection connection = this.dataSource().getConnection(); PreparedStatement preparedStatement =
|
||||
connection.prepareStatement(
|
||||
"INSERT INTO `" + SQLManager.this.prefix
|
||||
+ "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) {
|
||||
|
||||
@ -1821,7 +1812,7 @@ public class SQLManager implements AbstractDB {
|
||||
/*
|
||||
* Getting plots
|
||||
*/
|
||||
try (Statement statement = this.connection.createStatement()) {
|
||||
try (Connection connection = this.dataSource().getConnection(); Statement statement = connection.createStatement()) {
|
||||
int id;
|
||||
String o;
|
||||
UUID user;
|
||||
@ -2154,8 +2145,8 @@ public class SQLManager implements AbstractDB {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
public @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(
|
||||
"UPDATE `" + SQLManager.this.prefix
|
||||
+ "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?");
|
||||
}
|
||||
@ -3058,8 +3049,8 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
@Override
|
||||
public void addBatch(PreparedStatement statement) throws SQLException {
|
||||
statement.executeUpdate();
|
||||
try (ResultSet keys = statement.getGeneratedKeys()) {
|
||||
statement.execute();
|
||||
try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) {
|
||||
if (keys.next()) {
|
||||
cluster.temp = keys.getInt(1);
|
||||
}
|
||||
@ -3140,6 +3131,8 @@ public class SQLManager implements AbstractDB {
|
||||
|
||||
@Override
|
||||
public PreparedStatement get() throws SQLException {
|
||||
try (final Connection connection = )
|
||||
|
||||
return SQLManager.this.connection.prepareStatement(
|
||||
"DELETE FROM `" + SQLManager.this.prefix
|
||||
+ "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?");
|
||||
@ -3407,13 +3400,16 @@ public class SQLManager implements AbstractDB {
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
this.closed = true;
|
||||
this.connection.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
((Closeable) this.dataSource()).close();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to close data source", e);
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull DataSource dataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
private record LegacySettings(
|
||||
int id,
|
||||
PlotSettings settings
|
||||
@ -3437,7 +3433,7 @@ public class SQLManager implements AbstractDB {
|
||||
statement.executeBatch();
|
||||
}
|
||||
|
||||
public abstract PreparedStatement get() throws SQLException;
|
||||
public abstract @Nullable PreparedStatement get(final @NonNull Connection connection) throws SQLException;
|
||||
|
||||
public abstract void set(PreparedStatement statement) throws SQLException;
|
||||
|
||||
|
@ -33,6 +33,7 @@ import java.sql.Statement;
|
||||
/**
|
||||
* Connects to and uses a SQLite database.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class SQLite extends Database {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SQLite.class.getSimpleName());
|
||||
|
@ -69,8 +69,8 @@ public class HybridGen extends IndependentPlotGenerator {
|
||||
EnumSet<SchematicFeature> features
|
||||
) {
|
||||
int minY; // Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT);
|
||||
if ((features.contains(SchematicFeature.ROAD) && Settings.Schematics.PASTE_ROAD_ON_TOP)
|
||||
|| (!features.contains(SchematicFeature.ROAD) && Settings.Schematics.PASTE_ON_TOP)) {
|
||||
boolean isRoad = features.contains(SchematicFeature.ROAD);
|
||||
if ((isRoad && Settings.Schematics.PASTE_ROAD_ON_TOP) || (!isRoad && Settings.Schematics.PASTE_ON_TOP)) {
|
||||
minY = world.SCHEM_Y;
|
||||
} else {
|
||||
minY = world.getMinBuildHeight();
|
||||
|
@ -162,6 +162,7 @@ public class HybridPlotManager extends ClassicPlotManager {
|
||||
} else {
|
||||
minY = hybridPlotWorld.getMinBuildHeight();
|
||||
}
|
||||
int schemYDiff = (isRoad ? hybridPlotWorld.getRoadYStart() : hybridPlotWorld.getPlotYStart()) - minY;
|
||||
BaseBlock airBlock = BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
for (int x = pos1.getX(); x <= pos2.getX(); x++) {
|
||||
short absX = (short) ((x - hybridPlotWorld.ROAD_OFFSET_X) % size);
|
||||
@ -178,10 +179,14 @@ public class HybridPlotManager extends ClassicPlotManager {
|
||||
for (int y = 0; y < blocks.length; y++) {
|
||||
if (blocks[y] != null) {
|
||||
queue.setBlock(x, minY + y, z, blocks[y]);
|
||||
} else if (!isRoad) {
|
||||
// This is necessary, otherwise any blocks not specified in the schematic will remain after a clear
|
||||
// Do not set air for road as this may cause cavernous roads when debugroadregen is used
|
||||
} else if (y > schemYDiff) {
|
||||
// This is necessary, otherwise any blocks not specified in the schematic will remain after a clear.
|
||||
// This should only be done where the schematic has actually "started"
|
||||
queue.setBlock(x, minY + y, z, airBlock);
|
||||
} else if (isRoad) {
|
||||
queue.setBlock(x, minY + y, z, hybridPlotWorld.ROAD_BLOCK.toPattern());
|
||||
} else {
|
||||
queue.setBlock(x, minY + y, z, hybridPlotWorld.MAIN_BLOCK.toPattern());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ public class HybridPlotWorld extends ClassicPlotWorld {
|
||||
* The Y level at which schematic generation will start, lowest of either road or plot schematic generation.
|
||||
*/
|
||||
public int SCHEM_Y;
|
||||
|
||||
private int plotY;
|
||||
private int roadY;
|
||||
private Location SIGN_LOCATION;
|
||||
private File root = null;
|
||||
private int lastOverlayHeightError = Integer.MIN_VALUE;
|
||||
@ -186,7 +189,7 @@ public class HybridPlotWorld extends ClassicPlotWorld {
|
||||
}
|
||||
Object value;
|
||||
try {
|
||||
final boolean accessible = field.isAccessible();
|
||||
final boolean accessible = field.canAccess(this);
|
||||
field.setAccessible(true);
|
||||
value = field.get(this);
|
||||
field.setAccessible(accessible);
|
||||
@ -252,68 +255,60 @@ public class HybridPlotWorld extends ClassicPlotWorld {
|
||||
|
||||
SCHEM_Y = schematicStartHeight();
|
||||
|
||||
// plotY and roadY are important to allow plot and/or road schematic "overflow" into each other without causing AIOOB
|
||||
// exceptions when attempting either to set blocks to, or get block from G_SCH
|
||||
// plotY and roadY are important to allow plot and/or road schematic "overflow" into each other
|
||||
// without causing AIOOB exceptions when attempting either to set blocks to, or get block from G_SCH
|
||||
// Default plot schematic start height, normalized to the minimum height schematics are pasted from.
|
||||
int plotY = PLOT_HEIGHT - SCHEM_Y;
|
||||
plotY = PLOT_HEIGHT - SCHEM_Y;
|
||||
int minRoadWall = Settings.Schematics.USE_WALL_IN_ROAD_SCHEM_HEIGHT ? Math.min(ROAD_HEIGHT, WALL_HEIGHT) : ROAD_HEIGHT;
|
||||
// Default road schematic start height, normalized to the minimum height schematics are pasted from.
|
||||
int roadY = minRoadWall - SCHEM_Y;
|
||||
roadY = minRoadWall - SCHEM_Y;
|
||||
|
||||
int worldGenHeight = getMaxGenHeight() - getMinGenHeight() + 1;
|
||||
|
||||
int maxSchematicHeight = 0;
|
||||
int plotSchemHeight = 0;
|
||||
|
||||
// SCHEM_Y should be normalised to the plot "start" height
|
||||
if (schematic3 != null) {
|
||||
plotSchemHeight = maxSchematicHeight = schematic3.getClipboard().getDimensions().getY();
|
||||
if (maxSchematicHeight == worldGenHeight) {
|
||||
plotSchemHeight = schematic3.getClipboard().getDimensions().getY();
|
||||
if (plotSchemHeight == worldGenHeight) {
|
||||
SCHEM_Y = getMinGenHeight();
|
||||
plotY = 0;
|
||||
} else if (!Settings.Schematics.PASTE_ON_TOP) {
|
||||
SCHEM_Y = getMinBuildHeight();
|
||||
SCHEM_Y = getMinGenHeight();
|
||||
plotY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int roadSchemHeight;
|
||||
int roadSchemHeight = 0;
|
||||
|
||||
if (schematic1 != null) {
|
||||
roadSchemHeight = Math.max(
|
||||
schematic1.getClipboard().getDimensions().getY(),
|
||||
schematic2.getClipboard().getDimensions().getY()
|
||||
);
|
||||
maxSchematicHeight = Math.max(roadSchemHeight, maxSchematicHeight);
|
||||
if (maxSchematicHeight == worldGenHeight) {
|
||||
if (roadSchemHeight == worldGenHeight) {
|
||||
SCHEM_Y = getMinGenHeight();
|
||||
roadY = 0; // Road is the lowest schematic
|
||||
if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != worldGenHeight) {
|
||||
// Road is the lowest schematic. Normalize plotY to it.
|
||||
if (Settings.Schematics.PASTE_ON_TOP) {
|
||||
plotY = PLOT_HEIGHT - getMinGenHeight();
|
||||
} else {
|
||||
plotY = getMinBuildHeight() - getMinGenHeight();
|
||||
}
|
||||
}
|
||||
} else if (!Settings.Schematics.PASTE_ROAD_ON_TOP) {
|
||||
if (SCHEM_Y == getMinGenHeight()) { // Only possible if plot schematic is enabled
|
||||
// Plot is still the lowest schematic, normalize roadY to it
|
||||
roadY = getMinBuildHeight() - getMinGenHeight();
|
||||
} else if (schematic3 != null) {
|
||||
SCHEM_Y = getMinBuildHeight();
|
||||
roadY = 0;// Road is the lowest schematic
|
||||
roadY = 0;
|
||||
SCHEM_Y = getMinGenHeight();
|
||||
if (schematic3 != null) {
|
||||
if (Settings.Schematics.PASTE_ON_TOP) {
|
||||
// Road is the lowest schematic. Normalize plotY to it.
|
||||
plotY = PLOT_HEIGHT - getMinBuildHeight();
|
||||
plotY = PLOT_HEIGHT - SCHEM_Y;
|
||||
}
|
||||
maxSchematicHeight = Math.max(maxSchematicHeight, plotY + plotSchemHeight);
|
||||
}
|
||||
} else {
|
||||
roadY = minRoadWall - SCHEM_Y;
|
||||
maxSchematicHeight = Math.max(maxSchematicHeight, roadY + roadSchemHeight);
|
||||
}
|
||||
}
|
||||
int maxSchematicHeight = Math.max(plotY + plotSchemHeight, roadY + roadSchemHeight);
|
||||
|
||||
if (schematic3 != null) {
|
||||
this.PLOT_SCHEMATIC = true;
|
||||
@ -554,4 +549,24 @@ public class HybridPlotWorld extends ClassicPlotWorld {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y value where the plot schematic should be pasted from.
|
||||
*
|
||||
* @return plot schematic y start value
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public int getPlotYStart() {
|
||||
return SCHEM_Y + plotY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y value where the road schematic should be pasted from.
|
||||
*
|
||||
* @return road schematic y start value
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public int getRoadYStart() {
|
||||
return SCHEM_Y + roadY;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -77,6 +77,10 @@ public class HybridUtils {
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + HybridUtils.class.getSimpleName());
|
||||
private static final BlockState AIR = BlockTypes.AIR.getDefaultState();
|
||||
|
||||
/**
|
||||
* Deprecated and likely to be removed in a future release.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.0.0")
|
||||
public static HybridUtils manager;
|
||||
public static Set<BlockVector2> regions;
|
||||
public static int height;
|
||||
@ -529,7 +533,7 @@ public class HybridUtils {
|
||||
Math.min(plotworld.PLOT_HEIGHT, Math.min(plotworld.WALL_HEIGHT, plotworld.ROAD_HEIGHT)) : plotworld.ROAD_HEIGHT;
|
||||
int sx = bot.getX() - plotworld.ROAD_WIDTH + 1;
|
||||
int sz = bot.getZ() + 1;
|
||||
int sy = Settings.Schematics.PASTE_ROAD_ON_TOP ? schemY : plot.getArea().getMinBuildHeight();
|
||||
int sy = Settings.Schematics.PASTE_ROAD_ON_TOP ? schemY : plot.getArea().getMinGenHeight();
|
||||
int ex = bot.getX();
|
||||
int ez = top.getZ();
|
||||
int ey = get_ey(plotworld, queue, sx, ex, sz, ez, sy);
|
||||
@ -668,7 +672,7 @@ public class HybridUtils {
|
||||
}
|
||||
if (condition) {
|
||||
BaseBlock[] blocks = plotWorld.G_SCH.get(MathMan.pair(absX, absZ));
|
||||
int minY = Settings.Schematics.PASTE_ROAD_ON_TOP ? plotWorld.SCHEM_Y : area.getMinGenHeight() + 1;
|
||||
int minY = plotWorld.getRoadYStart();
|
||||
int maxDy = Math.max(extend, blocks.length);
|
||||
for (int dy = 0; dy < maxDy; dy++) {
|
||||
if (dy > blocks.length - 1) {
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.plotsquared.core.inject.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PlotDatabase {
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.plotsquared.core.inject.modules;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.configuration.Storage;
|
||||
import com.plotsquared.core.inject.annotations.PlotDatabase;
|
||||
import com.plotsquared.core.util.FileUtils;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
|
||||
public class DatabaseModule extends AbstractModule {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PlotSquared.class.getSimpleName());
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
try {
|
||||
if (Storage.MySQL.USE) {
|
||||
this.configureMySQL();
|
||||
} else if (Storage.SQLite.USE) {
|
||||
this.configureSQLite();
|
||||
} else {
|
||||
LOGGER.error("No storage type is set. Disabling PlotSquared");
|
||||
PlotSquared.platform().shutdown();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
LOGGER.error("Unable to initialize database", e);
|
||||
PlotSquared.platform().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSQLite() throws Exception {
|
||||
final File file = FileUtils.getFile(PlotSquared.platform().getDirectory(), Storage.SQLite.DB + ".db");
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
|
||||
final HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:sqlite:" + file);
|
||||
config.setDriverClassName("org.sqlite.JDBC");
|
||||
final DataSource dataSource = new HikariDataSource();
|
||||
|
||||
binder().bind(DataSource.class).annotatedWith(PlotDatabase.class).toInstance(dataSource);
|
||||
}
|
||||
|
||||
private void configureMySQL() {
|
||||
final HikariConfig hikariConfig = new HikariConfig();
|
||||
hikariConfig.setJdbcUrl(
|
||||
String.format(
|
||||
"jdbc:mysql://%s:%s/%s?%s",
|
||||
Storage.MySQL.HOST,
|
||||
Storage.MySQL.PORT,
|
||||
Storage.MySQL.DATABASE,
|
||||
StringMan.join(Storage.MySQL.PROPERTIES, "&")
|
||||
));
|
||||
hikariConfig.setUsername(Storage.MySQL.USER);
|
||||
hikariConfig.setPassword(Storage.MySQL.PASSWORD);
|
||||
hikariConfig.addDataSourceProperty("cachePrepStmts", "true");
|
||||
hikariConfig.addDataSourceProperty("prepStmtCacheSize", "512");
|
||||
hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
||||
final DataSource dataSource = new HikariDataSource(hikariConfig);
|
||||
|
||||
binder().bind(DataSource.class).annotatedWith(PlotDatabase.class).toInstance(dataSource);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.plotsquared.core.inject.modules;
|
||||
|
||||
import com.plotsquared.core.inject.annotations.PlotDatabase;
|
||||
import org.jdbi.v3.guice.AbstractJdbiDefinitionModule;
|
||||
|
||||
public class JdbiModule extends AbstractJdbiDefinitionModule {
|
||||
|
||||
public JdbiModule() {
|
||||
super(PlotDatabase.class);
|
||||
}
|
||||
@Override
|
||||
public void configureJdbi() {
|
||||
|
||||
}
|
||||
}
|
@ -55,7 +55,6 @@ import com.plotsquared.core.plot.flag.implementations.TitlesFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.WeatherFlag;
|
||||
import com.plotsquared.core.plot.flag.types.TimedFlag;
|
||||
import com.plotsquared.core.util.EventDispatcher;
|
||||
import com.plotsquared.core.util.PlayerManager;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.plotsquared.core.util.task.TaskTime;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
@ -63,7 +62,6 @@ import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
@ -77,6 +75,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class PlotListener {
|
||||
|
||||
@ -321,22 +320,27 @@ public class PlotListener {
|
||||
}
|
||||
if ((lastPlot != null) && plot.getId().equals(lastPlot.getId()) && plot.hasOwner()) {
|
||||
final UUID plotOwner = plot.getOwnerAbs();
|
||||
ComponentLike owner = PlayerManager.resolveName(plotOwner, true).toComponent(player);
|
||||
Caption header = fromFlag ? StaticCaption.of(title) : TranslatableCaption.of("titles" +
|
||||
".title_entered_plot");
|
||||
Caption subHeader = fromFlag ? StaticCaption.of(subtitle) : TranslatableCaption.of("titles" +
|
||||
".title_entered_plot_sub");
|
||||
TagResolver resolver = TagResolver.builder()
|
||||
|
||||
CompletableFuture<TagResolver> future = PlotSquared.platform().playerManager()
|
||||
.getUsernameCaption(plotOwner).thenApply(caption -> TagResolver.builder()
|
||||
.tag("owner", Tag.inserting(caption.toComponent(player)))
|
||||
.tag("plot", Tag.inserting(Component.text(lastPlot.getId().toString())))
|
||||
.tag("world", Tag.inserting(Component.text(player.getLocation().getWorldName())))
|
||||
.tag("owner", Tag.inserting(owner))
|
||||
.tag("alias", Tag.inserting(Component.text(plot.getAlias())))
|
||||
.build();
|
||||
.build()
|
||||
);
|
||||
|
||||
future.whenComplete((tagResolver, throwable) -> {
|
||||
if (Settings.Titles.TITLES_AS_ACTIONBAR) {
|
||||
player.sendActionBar(header, resolver);
|
||||
player.sendActionBar(header, tagResolver);
|
||||
} else {
|
||||
player.sendTitle(header, subHeader, resolver);
|
||||
player.sendTitle(header, subHeader, tagResolver);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, TaskTime.seconds(1L));
|
||||
}
|
||||
|
@ -60,6 +60,19 @@ public final class UncheckedWorldLocation extends Location {
|
||||
return new UncheckedWorldLocation(world, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new location with yaw and pitch equal to 0
|
||||
*
|
||||
* @param world World
|
||||
* @param loc Coordinates
|
||||
* @return New location
|
||||
* @since 7.0.0
|
||||
*/
|
||||
@DoNotUse
|
||||
public static @NonNull UncheckedWorldLocation at(final @NonNull String world, BlockVector3 loc) {
|
||||
return new UncheckedWorldLocation(world, loc.getX(), loc.getY(), loc.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
@DoNotUse
|
||||
public @NonNull String getWorldName() {
|
||||
|
@ -45,6 +45,7 @@ public enum Permission implements ComponentLike {
|
||||
PERMISSION_ADMIN_ENTRY_FORCEFIELD("plots.admin.entry.forcefield"),
|
||||
PERMISSION_ADMIN_COMMANDS_CHATSPY("plots.admin.command.chatspy"),
|
||||
PERMISSION_MERGE("plots.merge"),
|
||||
PERMISSION_MERGE_ALL("plots.merge.all"),
|
||||
PERMISSION_MERGE_OTHER("plots.merge.other"),
|
||||
PERMISSION_MERGE_KEEP_ROAD("plots.merge.keeproad"),
|
||||
PERMISSION_ADMIN_CAPS_OTHER("plots.admin.caps.other"),
|
||||
@ -200,7 +201,8 @@ public enum Permission implements ComponentLike {
|
||||
PERMISSION_RATE("plots.rate"),
|
||||
PERMISSION_ADMIN_FLIGHT("plots.admin.flight"),
|
||||
PERMISSION_ADMIN_COMPONENTS_OTHER("plots.admin.component.other"),
|
||||
PERMISSION_ADMIN_BYPASS_BORDER("plots.admin.border.bypass");
|
||||
PERMISSION_ADMIN_BYPASS_BORDER("plots.admin.border.bypass"),
|
||||
PERMISSION_ADMIN_BYPASS_ECON("plots.admin.econ.bypass");
|
||||
//</editor-fold>
|
||||
|
||||
private final String text;
|
||||
|
@ -25,9 +25,9 @@ import java.util.UUID;
|
||||
public interface OfflinePlotPlayer extends PermissionHolder {
|
||||
|
||||
/**
|
||||
* Gets the {@code UUID} of this player
|
||||
* Returns the UUID of the player.
|
||||
*
|
||||
* @return the player {@link UUID}
|
||||
* @return the UUID of the player
|
||||
*/
|
||||
UUID getUUID();
|
||||
|
||||
@ -39,9 +39,9 @@ public interface OfflinePlotPlayer extends PermissionHolder {
|
||||
long getLastPlayed();
|
||||
|
||||
/**
|
||||
* Gets the name of this player.
|
||||
* Returns the name of the player.
|
||||
*
|
||||
* @return the player name
|
||||
* @return the name of the player
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
@ -80,6 +80,7 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -273,8 +274,9 @@ public abstract class PlotPlayer<P> implements CommandCaller, OfflinePlotPlayer,
|
||||
return this.meta == null ? null : this.meta.remove(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This player's name.
|
||||
* Returns the name of the player.
|
||||
*
|
||||
* @return the name of the player
|
||||
*/
|
||||
@ -880,7 +882,7 @@ public abstract class PlotPlayer<P> implements CommandCaller, OfflinePlotPlayer,
|
||||
final Component titleComponent = MiniMessage.miniMessage().deserialize(title.getComponent(this), replacements);
|
||||
final Component subtitleComponent =
|
||||
MiniMessage.miniMessage().deserialize(subtitle.getComponent(this), replacements);
|
||||
final Title.Times times = Title.Times.of(
|
||||
final Title.Times times = Title.Times.times(
|
||||
Duration.of(Settings.Titles.TITLES_FADE_IN * 50L, ChronoUnit.MILLIS),
|
||||
Duration.of(Settings.Titles.TITLES_STAY * 50L, ChronoUnit.MILLIS),
|
||||
Duration.of(Settings.Titles.TITLES_FADE_OUT * 50L, ChronoUnit.MILLIS)
|
||||
@ -952,6 +954,54 @@ public abstract class PlotPlayer<P> implements CommandCaller, OfflinePlotPlayer,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the command caller, when the future is resolved
|
||||
*
|
||||
* @param caption Caption to send
|
||||
* @param asyncReplacement Async variable replacement
|
||||
* @return A Future to be resolved, after the message was sent
|
||||
* @since 7.1.0
|
||||
*/
|
||||
public final CompletableFuture<Void> sendMessage(
|
||||
@NonNull Caption caption,
|
||||
CompletableFuture<@NonNull TagResolver> asyncReplacement
|
||||
) {
|
||||
return sendMessage(caption, new CompletableFuture[]{asyncReplacement});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the command caller, when all futures are resolved
|
||||
*
|
||||
* @param caption Caption to send
|
||||
* @param asyncReplacements Async variable replacements
|
||||
* @param replacements Sync variable replacements
|
||||
* @return A Future to be resolved, after the message was sent
|
||||
* @since 7.1.0
|
||||
*/
|
||||
public final CompletableFuture<Void> sendMessage(
|
||||
@NonNull Caption caption,
|
||||
CompletableFuture<@NonNull TagResolver>[] asyncReplacements,
|
||||
@NonNull TagResolver... replacements
|
||||
) {
|
||||
return CompletableFuture.allOf(asyncReplacements).whenComplete((unused, throwable) -> {
|
||||
Set<TagResolver> resolvers = new HashSet<>(Arrays.asList(replacements));
|
||||
if (throwable != null) {
|
||||
sendMessage(
|
||||
TranslatableCaption.of("errors.error"),
|
||||
TagResolver.resolver("value", Tag.inserting(
|
||||
Component.text("Failed to resolve asynchronous caption replacements")
|
||||
))
|
||||
);
|
||||
LOGGER.error("Failed to resolve asynchronous tagresolver(s) for " + caption, throwable);
|
||||
} else {
|
||||
for (final CompletableFuture<TagResolver> asyncReplacement : asyncReplacements) {
|
||||
resolvers.add(asyncReplacement.join());
|
||||
}
|
||||
}
|
||||
sendMessage(caption, resolvers.toArray(TagResolver[]::new));
|
||||
});
|
||||
}
|
||||
|
||||
// Redefine from PermissionHolder as it's required from CommandCaller
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String permission) {
|
||||
|
@ -51,6 +51,8 @@ import com.plotsquared.core.util.MathMan;
|
||||
import com.plotsquared.core.util.PlotExpression;
|
||||
import com.plotsquared.core.util.RegionUtil;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.plotsquared.core.util.task.TaskTime;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
@ -180,8 +182,7 @@ public abstract class PlotArea implements ComponentLike {
|
||||
this.worldConfiguration = worldConfiguration;
|
||||
}
|
||||
|
||||
private static Collection<PlotFlag<?, ?>> parseFlags(List<String> flagStrings) {
|
||||
final Collection<PlotFlag<?, ?>> flags = new ArrayList<>();
|
||||
private static void parseFlags(FlagContainer flagContainer, List<String> flagStrings) {
|
||||
for (final String key : flagStrings) {
|
||||
final String[] split;
|
||||
if (key.contains(";")) {
|
||||
@ -193,7 +194,7 @@ public abstract class PlotArea implements ComponentLike {
|
||||
GlobalFlagContainer.getInstance().getFlagFromString(split[0]);
|
||||
if (flagInstance != null) {
|
||||
try {
|
||||
flags.add(flagInstance.parse(split[1]));
|
||||
flagContainer.addFlag(flagInstance.parse(split[1]));
|
||||
} catch (final FlagParseException e) {
|
||||
LOGGER.warn(
|
||||
"Failed to parse default flag with key '{}' and value '{}'. "
|
||||
@ -204,9 +205,10 @@ public abstract class PlotArea implements ComponentLike {
|
||||
);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
flagContainer.addUnknownFlag(split[0], split[1]);
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -391,6 +393,28 @@ public abstract class PlotArea implements ComponentLike {
|
||||
}
|
||||
}
|
||||
|
||||
this.spawnEggs = config.getBoolean("event.spawn.egg");
|
||||
this.spawnCustom = config.getBoolean("event.spawn.custom");
|
||||
this.spawnBreeding = config.getBoolean("event.spawn.breeding");
|
||||
|
||||
if (PlotSquared.get().isWeInitialised()) {
|
||||
loadFlags(config);
|
||||
} else {
|
||||
ConsolePlayer.getConsole().sendMessage(
|
||||
TranslatableCaption.of("flags.delaying_loading_area_flags"),
|
||||
TagResolver.resolver("area", Tag.inserting(Component.text(this.id == null ? this.worldName : this.id)))
|
||||
);
|
||||
TaskManager.runTaskLater(() -> loadFlags(config), TaskTime.ticks(1));
|
||||
}
|
||||
|
||||
loadConfiguration(config);
|
||||
}
|
||||
|
||||
private void loadFlags(ConfigurationSection config) {
|
||||
ConsolePlayer.getConsole().sendMessage(
|
||||
TranslatableCaption.of("flags.loading_area_flags"),
|
||||
TagResolver.resolver("area", Tag.inserting(Component.text(this.id == null ? this.worldName : this.id)))
|
||||
);
|
||||
List<String> flags = config.getStringList("flags.default");
|
||||
if (flags.isEmpty()) {
|
||||
flags = config.getStringList("flags");
|
||||
@ -405,16 +429,12 @@ public abstract class PlotArea implements ComponentLike {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.getFlagContainer().addAll(parseFlags(flags));
|
||||
parseFlags(this.getFlagContainer(), flags);
|
||||
ConsolePlayer.getConsole().sendMessage(
|
||||
TranslatableCaption.of("flags.area_flags"),
|
||||
TagResolver.resolver("flags", Tag.inserting(Component.text(flags.toString())))
|
||||
);
|
||||
|
||||
this.spawnEggs = config.getBoolean("event.spawn.egg");
|
||||
this.spawnCustom = config.getBoolean("event.spawn.custom");
|
||||
this.spawnBreeding = config.getBoolean("event.spawn.breeding");
|
||||
|
||||
List<String> roadflags = config.getStringList("road.flags");
|
||||
if (roadflags.isEmpty()) {
|
||||
roadflags = new ArrayList<>();
|
||||
@ -426,14 +446,12 @@ public abstract class PlotArea implements ComponentLike {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.roadFlags = roadflags.size() > 0;
|
||||
this.getRoadFlagContainer().addAll(parseFlags(roadflags));
|
||||
this.roadFlags = !roadflags.isEmpty();
|
||||
parseFlags(this.getRoadFlagContainer(), roadflags);
|
||||
ConsolePlayer.getConsole().sendMessage(
|
||||
TranslatableCaption.of("flags.road_flags"),
|
||||
TagResolver.resolver("flags", Tag.inserting(Component.text(roadflags.toString())))
|
||||
);
|
||||
|
||||
loadConfiguration(config);
|
||||
}
|
||||
|
||||
public abstract void loadConfiguration(ConfigurationSection config);
|
||||
@ -657,9 +675,9 @@ public abstract class PlotArea implements ComponentLike {
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("height.height_limit"),
|
||||
TagResolver.builder()
|
||||
.tag("minHeight", Tag.inserting(Component.text(minBuildHeight)))
|
||||
.tag("minheight", Tag.inserting(Component.text(minBuildHeight)))
|
||||
.tag(
|
||||
"maxHeight",
|
||||
"maxheight",
|
||||
Tag.inserting(Component.text(maxBuildHeight))
|
||||
).build()
|
||||
);
|
||||
|
@ -26,8 +26,8 @@ import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Plot (X,Y) tuples for plot locations
|
||||
* within a plot area
|
||||
* The PlotId class represents a Plot's x and y coordinates within a {@link PlotArea}. PlotId x,y values do not correspond to Block locations.
|
||||
* A PlotId instance can be created using the {@link #of(int, int)} method or parsed from a string using the {@link #fromString(String)} method.
|
||||
*/
|
||||
public final class PlotId {
|
||||
|
||||
@ -36,10 +36,10 @@ public final class PlotId {
|
||||
private final int hash;
|
||||
|
||||
/**
|
||||
* PlotId class (PlotId x,y values do not correspond to Block locations)
|
||||
* Constructs a new PlotId with the given x and y coordinates.
|
||||
*
|
||||
* @param x The plot x coordinate
|
||||
* @param y The plot y coordinate
|
||||
* @param x the x-coordinate of the plot
|
||||
* @param y the y-coordinate of the plot
|
||||
*/
|
||||
private PlotId(final int x, final int y) {
|
||||
this.x = x;
|
||||
@ -48,11 +48,11 @@ public final class PlotId {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new plot ID instance
|
||||
* Returns a new PlotId instance with the specified x and y coordinates.
|
||||
*
|
||||
* @param x The plot x coordinate
|
||||
* @param y The plot y coordinate
|
||||
* @return a new PlotId at x,y
|
||||
* @param x the x-coordinate of the plot
|
||||
* @param y the y-coordinate of the plot
|
||||
* @return a new PlotId instance with the specified x and y coordinates
|
||||
*/
|
||||
public static @NonNull PlotId of(final int x, final int y) {
|
||||
return new PlotId(x, y);
|
||||
@ -74,10 +74,13 @@ public final class PlotId {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to parse a plot ID from a string
|
||||
* Returns a PlotId object from the given string, or null if the string is invalid.
|
||||
* The string should be in the format "x;y" where x and y are integers.
|
||||
* The string can also contain any combination of the characters ";_,."
|
||||
* as delimiters.
|
||||
*
|
||||
* @param string ID string
|
||||
* @return Plot ID, or {@code null} if none could be parsed
|
||||
* @param string the string to parse
|
||||
* @return a PlotId object parsed from the given string, or null if the string is invalid
|
||||
*/
|
||||
public static @Nullable PlotId fromStringOrNull(final @NonNull String string) {
|
||||
final String[] parts = string.split("[;_,.]");
|
||||
@ -95,39 +98,39 @@ public final class PlotId {
|
||||
return of(x, y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the PlotId from the HashCode<br>
|
||||
* Note: Only accurate for small x,z values (short)
|
||||
* Returns a new PlotId instance from the given hash.
|
||||
*
|
||||
* @param hash ID hash
|
||||
* @return Plot ID
|
||||
* @param hash the hash to unpair
|
||||
* @return a new PlotId instance
|
||||
*/
|
||||
public static @NonNull PlotId unpair(final int hash) {
|
||||
return PlotId.of(hash >> 16, hash & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID X component
|
||||
* Returns the x-coordinate of this Plot ID.
|
||||
*
|
||||
* @return X component
|
||||
* @return the x-coordinate of this Plot ID
|
||||
*/
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID Y component
|
||||
* Returns the y-coordinate of this Plot ID.
|
||||
*
|
||||
* @return Y component
|
||||
* @return the y-coordinate of this Plot ID
|
||||
*/
|
||||
public int getY() {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next plot ID for claiming purposes
|
||||
* Returns the next Plot ID for claiming purposes based on the current Plot ID.
|
||||
*
|
||||
* @return Next plot ID
|
||||
* @return the next Plot ID
|
||||
*/
|
||||
public @NonNull PlotId getNextId() {
|
||||
final int absX = Math.abs(x);
|
||||
@ -159,10 +162,11 @@ public final class PlotId {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PlotId in a relative direction
|
||||
* Returns a new Plot ID in the specified relative direction based on the
|
||||
* current Plot ID.
|
||||
*
|
||||
* @param direction Direction
|
||||
* @return Relative plot ID
|
||||
* @param direction the direction in which to get the relative Plot ID
|
||||
* @return the relative Plot ID
|
||||
*/
|
||||
public @NonNull PlotId getRelative(final @NonNull Direction direction) {
|
||||
return switch (direction) {
|
||||
@ -193,10 +197,11 @@ public final class PlotId {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of the plot ID where the
|
||||
* components are separated by ";"
|
||||
* Returns a string representation of this Plot ID in the format "x;y".
|
||||
*
|
||||
* @return {@code x + ";" + y}
|
||||
* <p> The format is {@code x + ";" + y}
|
||||
*
|
||||
* @return a string representation of this Plot ID
|
||||
*/
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
@ -204,41 +209,40 @@ public final class PlotId {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of the plot ID where the
|
||||
* components are separated by a specified string
|
||||
* Returns a string representation of this Plot ID with the specified separator.
|
||||
* <p>
|
||||
* The format is {@code x + separator + y}
|
||||
*
|
||||
* @param separator Separator
|
||||
* @return {@code x + separator + y}
|
||||
* @param separator the separator to use between the X and Y coordinates
|
||||
* @return a string representation of this Plot ID with the specified separator
|
||||
*/
|
||||
public @NonNull String toSeparatedString(String separator) {
|
||||
return this.getX() + separator + this.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of the plot ID where the
|
||||
* components are separated by ","
|
||||
* Returns a string representation of this Plot ID in the format "x,y".
|
||||
*
|
||||
* @return {@code x + "," + y}
|
||||
* @return a string representation of this Plot ID
|
||||
*/
|
||||
public @NonNull String toCommaSeparatedString() {
|
||||
return this.getX() + "," + this.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of the plot ID where the
|
||||
* components are separated by "_"
|
||||
* Returns a string representation of this Plot ID in the format "x_y".
|
||||
*
|
||||
* @return {@code x + "_" + y}
|
||||
* @return a string representation of this Plot ID
|
||||
*/
|
||||
|
||||
public @NonNull String toUnderscoreSeparatedString() {
|
||||
return this.getX() + "_" + this.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of the plot ID where the
|
||||
* components are separated by "-"
|
||||
* Returns a string representation of this Plot ID in the format "x-y".
|
||||
*
|
||||
* @return {@code x + "-" + y}
|
||||
* @return a string representation of this Plot ID
|
||||
*/
|
||||
public @NonNull String toDashSeparatedString() {
|
||||
return this.getX() + "-" + this.getY();
|
||||
@ -250,6 +254,10 @@ public final class PlotId {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An iterator that iterates over a range of {@link PlotId}s.
|
||||
* The range is defined by a start and end {@link PlotId}.
|
||||
*/
|
||||
public static final class PlotRangeIterator implements Iterator<PlotId>, Iterable<PlotId> {
|
||||
|
||||
private final PlotId start;
|
||||
@ -265,6 +273,13 @@ public final class PlotId {
|
||||
this.y = this.start.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link PlotRangeIterator} that iterates over the range of Plots between the specified start and end Plots (inclusive).
|
||||
*
|
||||
* @param start the starting Plot of the range
|
||||
* @param end the ending Plot of the range
|
||||
* @return a new {@link PlotRangeIterator} that iterates over the range of Plots between the specified start and end Plots (inclusive)
|
||||
*/
|
||||
public static PlotRangeIterator range(final @NonNull PlotId start, final @NonNull PlotId end) {
|
||||
return new PlotRangeIterator(start, end);
|
||||
}
|
||||
|
@ -67,14 +67,25 @@ public class PlotItemStack {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in this stack.
|
||||
* Valid values range from 1-255.
|
||||
*
|
||||
* @return the amount of items in this stack
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given name of this stack of items. The name is displayed when
|
||||
* hovering over the item.
|
||||
*
|
||||
* @return the given name of this stack of items
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String[] getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.flag.PlotFlag;
|
||||
import com.plotsquared.core.queue.QueueCoordinator;
|
||||
import com.plotsquared.core.util.PlayerManager;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.plotsquared.core.util.task.TaskTime;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
@ -59,6 +58,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@ -383,13 +383,17 @@ public final class PlotModificationManager {
|
||||
}
|
||||
if (createSign) {
|
||||
queue.setCompleteTask(() -> TaskManager.runTaskAsync(() -> {
|
||||
for (Plot current : plots) {
|
||||
current.getPlotModificationManager().setSign(PlayerManager.resolveName(current.getOwnerAbs()).getComponent(
|
||||
LocaleHolder.console()));
|
||||
}
|
||||
List<CompletableFuture<Void>> tasks = plots.stream().map(current -> PlotSquared.platform().playerManager()
|
||||
.getUsernameCaption(current.getOwnerAbs())
|
||||
.thenAccept(caption -> current
|
||||
.getPlotModificationManager()
|
||||
.setSign(caption.getComponent(LocaleHolder.console()))))
|
||||
.toList();
|
||||
CompletableFuture.allOf(tasks.toArray(CompletableFuture[]::new)).whenComplete((unused, throwable) -> {
|
||||
if (whenDone != null) {
|
||||
TaskManager.runTask(whenDone);
|
||||
}
|
||||
});
|
||||
}));
|
||||
} else if (whenDone != null) {
|
||||
queue.setCompleteTask(whenDone);
|
||||
@ -891,7 +895,6 @@ public final class PlotModificationManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* /**
|
||||
* Sets components such as border, wall, floor.
|
||||
* (components are generator specific)
|
||||
*
|
||||
|
@ -18,9 +18,25 @@
|
||||
*/
|
||||
package com.plotsquared.core.plot;
|
||||
|
||||
/**
|
||||
* The different types of weather that can be set for a Plot.
|
||||
*/
|
||||
public enum PlotWeather {
|
||||
|
||||
/**
|
||||
* Rainy weather conditions
|
||||
*/
|
||||
RAIN,
|
||||
/**
|
||||
* Clear weather conditions
|
||||
*/
|
||||
CLEAR,
|
||||
/**
|
||||
* Use the weather of the world the plot is in
|
||||
*/
|
||||
WORLD,
|
||||
/**
|
||||
* Turn off weather for the plot
|
||||
*/
|
||||
OFF
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import com.plotsquared.core.plot.flag.implementations.BlockIgnitionFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.BlockedCmdsFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.BreakFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.ChatFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.ConcreteHardenFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.CopperOxideFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.CoralDryFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.CropGrowFlag;
|
||||
@ -91,6 +92,7 @@ import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.PveFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.PvpFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.RedstoneFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.SculkSensorInteractFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.ServerPlotFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.SnowFormFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.SnowMeltFlag;
|
||||
@ -141,6 +143,7 @@ public final class GlobalFlagContainer extends FlagContainer {
|
||||
this.addFlag(BeaconEffectsFlag.BEACON_EFFECT_TRUE);
|
||||
this.addFlag(BlockIgnitionFlag.BLOCK_IGNITION_TRUE);
|
||||
this.addFlag(ChatFlag.CHAT_FLAG_TRUE);
|
||||
this.addFlag(ConcreteHardenFlag.CONCRETE_HARDEN_TRUE);
|
||||
this.addFlag(CopperOxideFlag.COPPER_OXIDE_FALSE);
|
||||
this.addFlag(CoralDryFlag.CORAL_DRY_FALSE);
|
||||
this.addFlag(CropGrowFlag.CROP_GROW_TRUE);
|
||||
@ -172,6 +175,7 @@ public final class GlobalFlagContainer extends FlagContainer {
|
||||
this.addFlag(MobBreakFlag.MOB_BREAK_FALSE);
|
||||
this.addFlag(MobPlaceFlag.MOB_PLACE_FALSE);
|
||||
this.addFlag(MiscInteractFlag.MISC_INTERACT_FALSE);
|
||||
this.addFlag(SculkSensorInteractFlag.SCULK_SENSOR_INTERACT_FALSE);
|
||||
this.addFlag(MiscPlaceFlag.MISC_PLACE_FALSE);
|
||||
this.addFlag(MycelGrowFlag.MYCEL_GROW_TRUE);
|
||||
this.addFlag(NotifyEnterFlag.NOTIFY_ENTER_FALSE);
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.core.plot.flag.implementations;
|
||||
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.plot.flag.types.BooleanFlag;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class ConcreteHardenFlag extends BooleanFlag<ConcreteHardenFlag> {
|
||||
|
||||
public static final ConcreteHardenFlag CONCRETE_HARDEN_TRUE = new ConcreteHardenFlag(true);
|
||||
public static final ConcreteHardenFlag CONCRETE_HARDEN_FALSE = new ConcreteHardenFlag(false);
|
||||
|
||||
private ConcreteHardenFlag(boolean value) {
|
||||
super(value, TranslatableCaption.of("flags.flag_description_concrete_harden"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConcreteHardenFlag flagOf(@NonNull Boolean value) {
|
||||
return value ? CONCRETE_HARDEN_TRUE : CONCRETE_HARDEN_FALSE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.core.plot.flag.implementations;
|
||||
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.plot.flag.types.BooleanFlag;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class SculkSensorInteractFlag extends BooleanFlag<SculkSensorInteractFlag> {
|
||||
|
||||
public static final SculkSensorInteractFlag SCULK_SENSOR_INTERACT_TRUE = new SculkSensorInteractFlag(true);
|
||||
public static final SculkSensorInteractFlag SCULK_SENSOR_INTERACT_FALSE = new SculkSensorInteractFlag(false);
|
||||
|
||||
private SculkSensorInteractFlag(boolean value) {
|
||||
super(value, TranslatableCaption.of("flags.flag_description_sculk_sensor_interact"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SculkSensorInteractFlag flagOf(@NonNull Boolean value) {
|
||||
return value ? SCULK_SENSOR_INTERACT_TRUE : SCULK_SENSOR_INTERACT_FALSE;
|
||||
}
|
||||
|
||||
}
|
@ -29,17 +29,17 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Singleton
|
||||
public class DefaultPlotAreaManager implements PlotAreaManager {
|
||||
|
||||
final PlotArea[] noPlotAreas = new PlotArea[0];
|
||||
private final Map<String, PlotWorld> plotWorlds = new HashMap<>();
|
||||
private final Map<String, PlotWorld> plotWorlds = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public @NonNull PlotArea[] getAllPlotAreas() {
|
||||
|
@ -183,7 +183,7 @@ public class ChunkCoordinatorBuilder {
|
||||
* Set whether the chunks should be allow to unload after being accessed. This should only be used where the chunks are read from
|
||||
* and then written to from a separate queue where they're consequently unloaded.
|
||||
*
|
||||
* @param unloadAfter if to unload chuns afterwards
|
||||
* @param unloadAfter if to unload chunks afterwards
|
||||
* @return this ChunkCoordinatorBuilder instance
|
||||
*/
|
||||
public @NonNull ChunkCoordinatorBuilder unloadAfter(final boolean unloadAfter) {
|
||||
|
@ -42,28 +42,14 @@ public class EntityUtil {
|
||||
}
|
||||
|
||||
private static int capNumeral(final @NonNull String flagName) {
|
||||
int i;
|
||||
switch (flagName) {
|
||||
case "mob-cap":
|
||||
i = CAP_MOB;
|
||||
break;
|
||||
case "hostile-cap":
|
||||
i = CAP_MONSTER;
|
||||
break;
|
||||
case "animal-cap":
|
||||
i = CAP_ANIMAL;
|
||||
break;
|
||||
case "vehicle-cap":
|
||||
i = CAP_VEHICLE;
|
||||
break;
|
||||
case "misc-cap":
|
||||
i = CAP_MISC;
|
||||
break;
|
||||
case "entity-cap":
|
||||
default:
|
||||
i = CAP_ENTITY;
|
||||
}
|
||||
return i;
|
||||
return switch (flagName) {
|
||||
case "mob-cap" -> CAP_MOB;
|
||||
case "hostile-cap" -> CAP_MONSTER;
|
||||
case "animal-cap" -> CAP_ANIMAL;
|
||||
case "vehicle-cap" -> CAP_VEHICLE;
|
||||
case "misc-cap" -> CAP_MISC;
|
||||
default -> CAP_ENTITY;
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -28,6 +28,7 @@ import com.plotsquared.core.database.DBFunc;
|
||||
import com.plotsquared.core.player.ConsolePlayer;
|
||||
import com.plotsquared.core.player.OfflinePlotPlayer;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.uuid.UUIDMapping;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
@ -37,6 +38,7 @@ import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -48,6 +50,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@ -169,7 +172,9 @@ public abstract class PlayerManager<P extends PlotPlayer<? extends T>, T> {
|
||||
* @return A caption containing either the name, {@code None}, {@code Everyone} or {@code Unknown}
|
||||
* @see #resolveName(UUID, boolean)
|
||||
* @since 6.4.0
|
||||
* @deprecated Don't unnecessarily block threads and utilize playerMap - see {@link #getUsernameCaption(UUID)}
|
||||
*/
|
||||
@Deprecated(since = "7.1.0")
|
||||
public static @NonNull Caption resolveName(final @Nullable UUID owner) {
|
||||
return resolveName(owner, true);
|
||||
}
|
||||
@ -181,7 +186,9 @@ public abstract class PlayerManager<P extends PlotPlayer<? extends T>, T> {
|
||||
* @param blocking If the operation should block the current thread for {@link Settings.UUID#BLOCKING_TIMEOUT} milliseconds
|
||||
* @return A caption containing either the name, {@code None}, {@code Everyone} or {@code Unknown}
|
||||
* @since 6.4.0
|
||||
* @deprecated Don't unnecessarily block threads and utilize playerMap - see {@link #getUsernameCaption(UUID)}
|
||||
*/
|
||||
@Deprecated(since = "7.1.0")
|
||||
public static @NonNull Caption resolveName(final @Nullable UUID owner, final boolean blocking) {
|
||||
if (owner == null) {
|
||||
return TranslatableCaption.of("info.none");
|
||||
@ -211,6 +218,50 @@ public abstract class PlayerManager<P extends PlotPlayer<? extends T>, T> {
|
||||
return StaticCaption.of(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a UUID to a formatted {@link Caption} representing the player behind the UUID.
|
||||
* Returns a {@link CompletableFuture} instead of a plain {@link UUID} as this method may query the
|
||||
* {@link com.plotsquared.core.uuid.UUIDPipeline ImpromptuUUIDPipeline}.
|
||||
* <br>
|
||||
* Special Cases:
|
||||
* <ul>
|
||||
* <li>{@code null}: Resolves to a {@link TranslatableCaption} with the key {@code info.none}</li>
|
||||
* <li>{@link DBFunc#EVERYONE}: Resolves to a {@link TranslatableCaption} with the key {@code info.everyone}</li>
|
||||
* <li>{@link DBFunc#SERVER}: Resolves to a {@link TranslatableCaption} with the key {@code info.server}</li>
|
||||
* </ul>
|
||||
* <br>
|
||||
* Otherwise, if the UUID is a valid UUID and not reserved by PlotSquared itself, this method first attempts to query the
|
||||
* online players ({@link #getPlayerIfExists(UUID)}) for the specific UUID.
|
||||
* If no online player was found for that UUID, the {@link com.plotsquared.core.uuid.UUIDPipeline ImpromptuUUIDPipeline} is
|
||||
* queried to retrieve the known username
|
||||
*
|
||||
* @param uuid The UUID of the player (for example provided by {@link Plot#getOwner()}
|
||||
* @return A CompletableFuture resolving to a Caption representing the players name of the uuid
|
||||
* @since 7.1.0
|
||||
*/
|
||||
@Contract("_->!null")
|
||||
public @NonNull CompletableFuture<Caption> getUsernameCaption(@Nullable UUID uuid) {
|
||||
if (uuid == null) {
|
||||
return CompletableFuture.completedFuture(TranslatableCaption.of("info.none"));
|
||||
}
|
||||
if (uuid.equals(DBFunc.EVERYONE)) {
|
||||
return CompletableFuture.completedFuture(TranslatableCaption.of("info.everyone"));
|
||||
}
|
||||
if (uuid.equals(DBFunc.SERVER)) {
|
||||
return CompletableFuture.completedFuture(TranslatableCaption.of("info.server"));
|
||||
}
|
||||
P player = getPlayerIfExists(uuid);
|
||||
if (player != null) {
|
||||
return CompletableFuture.completedFuture(StaticCaption.of(player.getName()));
|
||||
}
|
||||
return PlotSquared.get().getImpromptuUUIDPipeline().getNames(Collections.singleton(uuid)).thenApply(mapping -> {
|
||||
if (mapping.isEmpty()) {
|
||||
return TranslatableCaption.of("info.unknown");
|
||||
}
|
||||
return StaticCaption.of(mapping.get(0).username());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a player from the player map
|
||||
*
|
||||
|
@ -83,6 +83,7 @@ import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.Channels;
|
||||
@ -144,7 +145,7 @@ public abstract class SchematicHandler {
|
||||
}
|
||||
final URL url;
|
||||
try {
|
||||
url = new URL(Settings.Web.URL + "?key=" + uuid + "&type=" + extension);
|
||||
url = URI.create(Settings.Web.URL + "?key=" + uuid + "&type=" + extension).toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
whenDone.run();
|
||||
@ -153,7 +154,7 @@ public abstract class SchematicHandler {
|
||||
TaskManager.runTaskAsync(() -> {
|
||||
try {
|
||||
String boundary = Long.toHexString(System.currentTimeMillis());
|
||||
URLConnection con = new URL(website).openConnection();
|
||||
URLConnection con = URI.create(website).toURL().openConnection();
|
||||
con.setDoOutput(true);
|
||||
con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
||||
try (OutputStream output = con.getOutputStream();
|
||||
@ -498,9 +499,10 @@ public abstract class SchematicHandler {
|
||||
public List<String> getSaves(UUID uuid) {
|
||||
String rawJSON;
|
||||
try {
|
||||
String website = Settings.Web.URL + "list.php?" + uuid.toString();
|
||||
URL url = new URL(website);
|
||||
URLConnection connection = new URL(url.toString()).openConnection();
|
||||
URLConnection connection = URI.create(
|
||||
Settings.Web.URL + "list.php?" + uuid.toString())
|
||||
.toURL()
|
||||
.openConnection();
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
rawJSON = reader.lines().collect(Collectors.joining());
|
||||
|
@ -47,6 +47,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
@ -109,9 +110,9 @@ public final class PlaceholderRegistry {
|
||||
if (plotOwner == null) {
|
||||
return legacyComponent(TranslatableCaption.of("generic.generic_unowned"), player);
|
||||
}
|
||||
|
||||
try {
|
||||
return PlayerManager.resolveName(plotOwner, false).getComponent(player);
|
||||
return PlotSquared.platform().playerManager().getUsernameCaption(plotOwner)
|
||||
.get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS).getComponent(player);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
return legacyComponent(TranslatableCaption.of("info.unknown"), player);
|
||||
@ -187,6 +188,7 @@ public final class PlaceholderRegistry {
|
||||
}
|
||||
});
|
||||
this.createPlaceholder("currentplot_biome", (player, plot) -> plot.getBiomeSynchronous().toString());
|
||||
this.createPlaceholder("currentplot_size", (player, plot) -> String.valueOf(plot.getConnectedPlots().size()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,7 @@
|
||||
"cluster.cluster_deleted": "<prefix><dark_aqua>Successfully deleted the cluster </dark_aqua><gold><cluster></gold><dark_aqua>.</dark_aqua>",
|
||||
"cluster.cluster_resized": "<prefix><dark_aqua>Successfully resized the cluster.</dark_aqua>",
|
||||
"cluster.cluster_added_user": "<prefix><dark_aqua>Successfully added user to the cluster.</dark_aqua>",
|
||||
"cluster.cannot_kick_player": "<prefix><red>You cannot kick that player: </red><gray><name></gray>",
|
||||
"cluster.cannot_kick_player": "<prefix><red>You cannot kick the player <gray><name></gray>.</red>",
|
||||
"cluster.cluster_invited": "<prefix><gold>You have been invited to the following cluster: </gold><gray><cluster>.</gray>",
|
||||
"cluster.cluster_removed": "<prefix><gold>You have been removed from cluster: </gold><gray><cluster>.</gray>",
|
||||
"cluster.cluster_kicked_user": "<prefix><dark_aqua>Successfully kicked the user from the cluster.</dark_aqua>",
|
||||
@ -124,7 +124,7 @@
|
||||
"economy.cannot_afford_merge": "<prefix><red>You cannot afford to merge the plots. It costs <gold><money></gold>.</red>",
|
||||
"economy.added_balance": "<prefix><gold><money> </gold><gray>has been added to your balance.</gray>",
|
||||
"economy.removed_balance": "<prefix><gold><money> </gold><gray>has been taken from your balance.</gray>",
|
||||
"economy.removed_granted_plot": "<prefix><gray>You used <usedGrants> plot grant(s), you've got </gray><gold><remainingGrants></gold> <gray>left.</gray>",
|
||||
"economy.removed_granted_plot": "<prefix><gray>You used <used_grants> plot grant(s), you've got </gray><gold><remaining_grants></gold> <gray>left.</gray>",
|
||||
"setup.choose_generator": "<gold>What generator do you want?</gold>",
|
||||
"setup.setup_not_started": "<prefix><gold>No setup started.</gold>",
|
||||
"setup.setup_init": "<prefix><gold>Usage: </gold><gray>/plot setup <value></gray>",
|
||||
@ -411,6 +411,8 @@
|
||||
"deny.no_enter": "<prefix><red>You are denied from the plot <red><gold><plot></gold><red> and therefore not allowed to enter.</red>",
|
||||
"deny.you_got_denied": "<prefix><red>You are denied from the plot you were previously on, and got teleported to spawn.</red>",
|
||||
"deny.cant_remove_owner": "<prefix><red>You can't remove the plot owner.</red>",
|
||||
"kick.player_not_in_plot": "<prefix><red>The player <gray><player></gray> is not on this plot.</red>",
|
||||
"kick.cannot_kick_player": "<prefix><red>You cannot kick the player <gray><player></gray>.</red>",
|
||||
"kick.you_got_kicked": "<prefix><dark_aqua>You got kicked from the plot!</dark_aqua>",
|
||||
"trusted.trusted_added": "<prefix><dark_aqua>You successfully trusted a user to the plot.</dark_aqua>",
|
||||
"trusted.plot_removed_user": "<prefix><red>Plot <plot> of which you were added to has been deleted due to owner inactivity.</red>",
|
||||
@ -486,7 +488,7 @@
|
||||
"single.get_position": "<prefix><gold>Go to the first corner and use: <gray><command> to create position 1.</gold>",
|
||||
"single.delete_world_region": "<prefix><red>Stop the server and delete: <world>/region.</red>",
|
||||
"single.regeneration_complete": "<prefix><gold>Regeneration complete.</gold>",
|
||||
"single.worldcreation_location": "<prefix><gold>World creation settings may be stored in multiple locations:</gold>\n<dark_gray> - </dark_gray><gray>bukkit.yml in your server's root folder.</gray>\n<dark_gray> - </dark_gray><gray>PlotSquared's settings.yml</gray>\n<dark_gray> - </dark_gray><gray>Hyperverse's worlds.yml (or any world management plugin)</gray>\n<dark_gray> - </dark_gray><red>Stop the server and delete it from these locations.</red>",
|
||||
"single.worldcreation_location": "<prefix><gold>World creation settings may be stored in multiple locations:</gold>\n<dark_gray> - </dark_gray><gray>bukkit.yml in your server's root folder.</gray>\n<dark_gray> - </dark_gray><gray>PlotSquared's worlds.yml</gray>\n<dark_gray> - </dark_gray><gray>Hyperverse's worlds.yml (or any world management plugin)</gray>\n<dark_gray> - </dark_gray><red>Stop the server and delete it from these locations.</red>",
|
||||
"legacyconfig.legacy_config_found": "<prefix><green>A legacy configuration file was detected. Conversion will be attempted.</green>",
|
||||
"legacyconfig.legacy_config_backup": "<prefix><gold>A copy of worlds.yml has been saved in the file worlds.yml.old</gold>.",
|
||||
"legacyconfig.legacy_config_replaced": "<prefix><gray><value1> has been replaced with <value2></gray>",
|
||||
@ -549,6 +551,7 @@
|
||||
"flags.flag_description_block_burn": "<gray>Set to `true` to allow blocks to burn within the plot.</gray>",
|
||||
"flags.flag_description_block_ignition": "<gray>Set to `false` to prevent blocks from igniting within the plot.</gray>",
|
||||
"flags.flag_description_break": "<gray>Define a list of materials players should be able to break even when they aren't added to the plot.</gray>",
|
||||
"flags.flag_description_concrete_harden": "<gray>Set to `false` to disable concrete powder forming to concrete with water.</gray>",
|
||||
"flags.flag_description_device_interact": "<gray>Set to `true` to allow devices to be interacted with in the plot.</gray>",
|
||||
"flags.flag_description_disable_physics": "<gray>Set to `true` to disable block physics in the plot.</gray>",
|
||||
"flags.flag_description_drop_protection": "<gray>Set to `true` to prevent dropped items from being picked up by non-members of the plot.</gray>",
|
||||
@ -572,6 +575,7 @@
|
||||
"flags.flag_description_misc_break": "<gray>Set to `true` to allow guests to break miscellaneous items.</gray>",
|
||||
"flags.flag_description_misc_cap": "<gray>Set to an integer value to limit the amount of miscellaneous entities on the plot.</gray>",
|
||||
"flags.flag_description_misc_interact": "<gray>Set to `true` to allow guests to interact with miscellaneous items.</gray>",
|
||||
"flags.flag_description_sculk_sensor_interact": "<gray>Set to `true` to allow guests to interact with sculk sensors.</gray>",
|
||||
"flags.flag_description_misc_place": "<gray>Set to `true` to allow guests to place miscellaneous items.</gray>",
|
||||
"flags.flag_description_mob_break": "<gray>Set to `true` to allow mobs to break blocks within the plot.</gray>",
|
||||
"flags.flag_description_mob_cap": "<gray>Set to an integer value to limit the amount of mobs on the plot.</gray>",
|
||||
@ -628,6 +632,8 @@
|
||||
"flags.flag_error_double": "Flag value must be a decimal number.",
|
||||
"flags.flag_error_music": "Flag value must be a valid music disc ID.",
|
||||
"flags.flag_error_title": "Flag value must be in the format </red><grey>\"A title\" \"The subtitle\"</grey><red>.",
|
||||
"flags.delaying_loading_area_flags": "<prefix><gray>Delaying loading flags for area `</gray><dark_aqua><area></dark_aqua><gray>` as WorldEdit is not initialised yet.</gray>",
|
||||
"flags.loading_area_flags": "<prefix><gray>Loading flags for area: </gray><dark_aqua><area></dark_aqua>",
|
||||
"flags.area_flags": "<prefix><gray>Area flags: </gray><dark_aqua><flags></dark_aqua>",
|
||||
"flags.road_flags": "<prefix><gray>Road flags: </gray><dark_aqua><flags></dark_aqua>",
|
||||
"commands.description.add": "<gray>Allow a user to build in a plot while the plot owner is online.</gray>",
|
||||
|
@ -27,16 +27,16 @@ is to provide a lag-free and smooth experience.
|
||||
|
||||
* [Download](https://www.spigotmc.org/resources/77506/)
|
||||
* [Discord](https://discord.gg/intellectualsites)
|
||||
* [Wiki](https://intellectualsites.github.io/plotsquared-documentation/)
|
||||
* [Wiki](https://intellectualsites.gitbook.io/plotsquared/)
|
||||
* [Issues](https://github.com/IntellectualSites/PlotSquared/issues)
|
||||
* [Translations](https://intellectualsites.crowdin.com/plotsquared/)
|
||||
* [Contributing](https://github.com/IntellectualSites/.github/blob/main/CONTRIBUTING.md)
|
||||
|
||||
### Developer Resources
|
||||
|
||||
* [API Documentation](https://intellectualsites.github.io/plotsquared-documentation/api/api-documentation)
|
||||
* [Event API](https://intellectualsites.github.io/plotsquared-documentation/api/event-api)
|
||||
* [Flag API](https://intellectualsites.github.io/plotsquared-documentation/api/flag-api)
|
||||
* [API Documentation](https://intellectualsites.gitbook.io/plotsquared/api/api-documentation)
|
||||
* [Event API](https://intellectualsites.gitbook.io/plotsquared/api/event-api)
|
||||
* [Flag API](https://intellectualsites.gitbook.io/plotsquared/api/flag-api)
|
||||
|
||||
# Official Addons
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import com.diffplug.gradle.spotless.SpotlessPlugin
|
||||
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||
import groovy.json.JsonSlurper
|
||||
import java.net.URI
|
||||
import xyz.jpenilla.runpaper.task.RunServer
|
||||
|
||||
@ -17,11 +18,11 @@ plugins {
|
||||
eclipse
|
||||
idea
|
||||
|
||||
id("xyz.jpenilla.run-paper") version "2.1.0"
|
||||
alias(libs.plugins.runPaper)
|
||||
}
|
||||
|
||||
group = "com.intellectualsites.plotsquared"
|
||||
version = "7.0.0-SNAPSHOT"
|
||||
version = "7.1.1-SNAPSHOT"
|
||||
|
||||
if (!File("$rootDir/.git").exists()) {
|
||||
logger.lifecycle("""
|
||||
@ -76,13 +77,9 @@ subprojects {
|
||||
plugin<IdeaPlugin>()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform("com.intellectualsites.bom:bom-newest:1.29"))
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Tests
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
|
||||
}
|
||||
|
||||
plugins.withId("java") {
|
||||
@ -153,29 +150,34 @@ subprojects {
|
||||
id.set("Sauilitired")
|
||||
name.set("Alexander Söderberg")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
developer {
|
||||
id.set("NotMyFault")
|
||||
name.set("Alexander Brandes")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
email.set("contact(at)notmyfault.dev")
|
||||
}
|
||||
developer {
|
||||
id.set("SirYwell")
|
||||
name.set("Hannes Greule")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
developer {
|
||||
id.set("dordsor21")
|
||||
name.set("dordsor21")
|
||||
organization.set("IntellectualSites")
|
||||
organizationUrl.set("https://github.com/IntellectualSites")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
url.set("https://github.com/IntellectualSites/PlotSquared")
|
||||
connection.set("scm:https://IntellectualSites@github.com/IntellectualSites/PlotSquared.git")
|
||||
developerConnection.set("scm:git://github.com/IntellectualSites/PlotSquared.git")
|
||||
connection.set("scm:git:https://github.com/IntellectualSites/PlotSquared.git")
|
||||
developerConnection.set("scm:git:git@github.com:IntellectualSites/PlotSquared.git")
|
||||
tag.set("${project.version}")
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
@ -222,14 +224,28 @@ tasks.getByName<Jar>("jar") {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
val supportedVersions = listOf("1.16.5", "1.17", "1.17.1", "1.18.2", "1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4", "1.20")
|
||||
val supportedVersions = listOf("1.16.5", "1.17.1", "1.18.2", "1.19.4", "1.20.1", "1.20.2")
|
||||
tasks {
|
||||
register("cacheLatestFaweArtifact") {
|
||||
val lastSuccessfulBuildUrl = uri("https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/api/json").toURL()
|
||||
val artifact = ((JsonSlurper().parse(lastSuccessfulBuildUrl) as Map<*, *>)["artifacts"] as List<*>)
|
||||
.map { it as Map<*, *> }
|
||||
.map { it["fileName"] as String }
|
||||
.first { it -> it.contains("Bukkit") }
|
||||
project.ext["faweArtifact"] = artifact
|
||||
}
|
||||
|
||||
supportedVersions.forEach {
|
||||
register<RunServer>("runServer-$it") {
|
||||
dependsOn(getByName("cacheLatestFaweArtifact"))
|
||||
minecraftVersion(it)
|
||||
pluginJars(*project(":plotsquared-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
||||
pluginJars(*project(":plotsquared-bukkit").getTasksByName("shadowJar", false)
|
||||
.map { task -> (task as Jar).archiveFile }
|
||||
.toTypedArray())
|
||||
jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true")
|
||||
downloadPlugins {
|
||||
url("https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/artifacts/${project.ext["faweArtifact"]}")
|
||||
}
|
||||
group = "run paper"
|
||||
runDirectory.set(file("run-$it"))
|
||||
}
|
||||
|
@ -1,33 +1,62 @@
|
||||
[versions]
|
||||
# Platform expectations
|
||||
paper = "1.20.2-R0.1-SNAPSHOT"
|
||||
guice = "7.0.0"
|
||||
spotbugs = "4.7.3"
|
||||
checkerqual = "3.39.0"
|
||||
gson = "2.10"
|
||||
guava = "31.1-jre"
|
||||
snakeyaml = "2.0"
|
||||
adventure = "4.14.0"
|
||||
adventure-bukkit = "4.3.1"
|
||||
log4j = "2.19.0"
|
||||
|
||||
# Plugins
|
||||
worldedit = "7.2.14"
|
||||
placeholderapi = "2.11.3"
|
||||
worldedit = "7.2.16"
|
||||
fawe = "2.8.0"
|
||||
placeholderapi = "2.11.4"
|
||||
luckperms = "5.4"
|
||||
essentialsx = "2.20.0"
|
||||
essentialsx = "2.20.1"
|
||||
mvdwapi = "3.1.1"
|
||||
|
||||
# Datebase
|
||||
hikaricp = "5.0.1"
|
||||
jdbi = "3.41.3"
|
||||
|
||||
# Third party
|
||||
prtree = "2.0.1"
|
||||
aopalliance = "1.0"
|
||||
cloud-services = "1.8.3"
|
||||
cloud-services = "1.8.4"
|
||||
arkitektonika = "2.1.2"
|
||||
squirrelid = "0.3.2"
|
||||
paster = "1.1.5"
|
||||
bstats = "3.0.2"
|
||||
paperlib = "1.0.8"
|
||||
informative-annotations = "1.4"
|
||||
vault = "1.7.1"
|
||||
serverlib = "2.3.4"
|
||||
|
||||
# Gradle plugins
|
||||
shadow = "8.1.1"
|
||||
grgit = "4.1.1"
|
||||
spotless = "6.19.0"
|
||||
spotless = "6.22.0"
|
||||
nexus = "1.3.0"
|
||||
runPaper = "2.2.0"
|
||||
|
||||
[libraries]
|
||||
# Platform expectations
|
||||
paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" }
|
||||
guice = { group = "com.google.inject", name = "guice", version.ref = "guice" }
|
||||
guiceassistedinject = { group = "com.google.inject.extensions", name = "guice-assistedinject", version.ref = "guice" }
|
||||
spotbugs = { group = "com.github.spotbugs", name = "spotbugs-annotations", version.ref = "spotbugs" }
|
||||
checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerqual" }
|
||||
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
|
||||
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
|
||||
snakeyaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeyaml" }
|
||||
adventureApi = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
|
||||
adventureMiniMessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "adventure" }
|
||||
adventureBukkit = { group = "net.kyori", name = "adventure-platform-bukkit", version.ref = "adventure-bukkit" }
|
||||
log4j = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" }
|
||||
|
||||
# Plugins
|
||||
worldeditCore = { group = "com.sk89q.worldedit", name = "worldedit-core", version.ref = "worldedit" }
|
||||
@ -35,6 +64,13 @@ worldeditBukkit = { group = "com.sk89q.worldedit", name = "worldedit-bukkit", ve
|
||||
placeholderapi = { group = "me.clip", name = "placeholderapi", version.ref = "placeholderapi" }
|
||||
luckperms = { group = "net.luckperms", name = "api", version.ref = "luckperms" }
|
||||
essentialsx = { group = "net.essentialsx", name = "EssentialsX", version.ref = "essentialsx" }
|
||||
faweCore = { group = "com.fastasyncworldedit", name = "FastAsyncWorldEdit-Core", version.ref = "fawe" }
|
||||
faweBukkit = { group = "com.fastasyncworldedit", name = "FastAsyncWorldEdit-Bukkit", version.ref = "fawe" }
|
||||
|
||||
# Database
|
||||
hikaricp = { group = "com.zaxxer", name = "HikariCP", version.ref = "hikaricp" }
|
||||
jdbiCore = { group = "org.jdbi", name = "jdbi3-core", version.ref = "jdbi" }
|
||||
jdbiGuice = { group = "org.jdbi", name = "jdbi3-guice", version.ref = "jdbi" }
|
||||
|
||||
# Third party
|
||||
prtree = { group = "com.intellectualsites.prtree", name = "PRTree", version.ref = "prtree" }
|
||||
@ -43,9 +79,17 @@ cloudServices = { group = "cloud.commandframework", name = "cloud-services", ver
|
||||
mvdwapi = { group = "com.intellectualsites.mvdwplaceholderapi", name = "MVdWPlaceholderAPI", version.ref = "mvdwapi" }
|
||||
squirrelid = { group = "org.enginehub", name = "squirrelid", version.ref = "squirrelid" }
|
||||
arkitektonika = { group = "com.intellectualsites.arkitektonika", name = "Arkitektonika-Client", version.ref = "arkitektonika" }
|
||||
paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref = "paster" }
|
||||
bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" }
|
||||
bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
|
||||
informativeAnnotations = { group = "com.intellectualsites.informative-annotations", name = "informative-annotations", version.ref = "informative-annotations" }
|
||||
paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" }
|
||||
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
|
||||
serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" }
|
||||
|
||||
[plugins]
|
||||
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
|
||||
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }
|
||||
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
|
||||
nexus = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus" }
|
||||
runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" }
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
22
gradlew
vendored
22
gradlew
vendored
@ -83,7 +83,8 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@ -130,18 +131,21 @@ 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.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@ -198,11 +202,11 @@ fi
|
||||
# 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"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
@ -1,4 +1,4 @@
|
||||
Javadocs generated for
|
||||
<a href="https://github.com/IntellectualSites/PlotSquared/" rel="noopener nofollow noreferrer" target="_blank"> PlotSquared</a> |
|
||||
<a href="https://intellectualsites.github.io/plotsquared-documentation/" rel="noopener nofollow noreferrer"> Documentation </a> |
|
||||
<a href="https://intellectualsites.gitbook.io/plotsquared/" rel="noopener nofollow noreferrer"> Documentation </a> |
|
||||
Visit us on our <a href="https://discord.gg/intellectualsites" rel="noopener nofollow noreferrer"> Discord server</a> :)
|
||||
|
Reference in New Issue
Block a user