Initial commit
This commit is contained in:
commit
42789e012b
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Project exclude paths
|
||||
/.gradle/
|
||||
/build/
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
19
.idea/compiler.xml
generated
Normal file
19
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Gradle Imported" enabled="true">
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<option name="bungeeAnnotationResultPath" value="C:\Users\Lenovo\IdeaProjects\SpigotChunkProtector\build\spigradle\bungee_main" />
|
||||
<option name="nukkitAnnotationResultPath" value="C:\Users\Lenovo\IdeaProjects\SpigotChunkProtector\build\spigradle\nukkit_main" />
|
||||
<option name="pluginAnnotationResultPath" value="C:\Users\Lenovo\IdeaProjects\SpigotChunkProtector\build\spigradle\plugin_main" />
|
||||
<option name="spigotAnnotationResultPath" value="C:\Users\Lenovo\IdeaProjects\SpigotChunkProtector\build\spigradle\spigot_main" />
|
||||
<processorPath useClasspath="false">
|
||||
<entry name="$USER_HOME$/gradle-7.1/caches/modules-2/files-2.1/kr.entree/spigradle-annotations/2.1.1/140e14d5fb373843420f0719f6f83cacc07d8cd1/spigradle-annotations-2.1.1.jar" />
|
||||
</processorPath>
|
||||
<module name="SpigotChunkProtector.main" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel target="16" />
|
||||
</component>
|
||||
</project>
|
20
.idea/gradle.xml
generated
Normal file
20
.idea/gradle.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="delegatedBuild" value="false" />
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="16" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
75
.idea/jarRepositories.xml
generated
Normal file
75
.idea/jarRepositories.xml
generated
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven3" />
|
||||
<option name="name" value="maven3" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven4" />
|
||||
<option name="name" value="maven4" />
|
||||
<option name="url" value="https://hub.spigotmc.org/nexus/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven9" />
|
||||
<option name="name" value="maven9" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven6" />
|
||||
<option name="name" value="maven6" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/repositories/central" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven8" />
|
||||
<option name="name" value="maven8" />
|
||||
<option name="url" value="https://repo.dmulloy2.net/nexus/repository/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven5" />
|
||||
<option name="name" value="maven5" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/repositories/snapshots" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven5" />
|
||||
<option name="name" value="maven5" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-public" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:/$MAVEN_REPOSITORY$/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Gradle Central Plugin Repository" />
|
||||
<option name="name" value="Gradle Central Plugin Repository" />
|
||||
<option name="url" value="https://plugins.gradle.org/m2" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
6
.idea/kotlinc.xml
generated
Normal file
6
.idea/kotlinc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="16" />
|
||||
</component>
|
||||
</project>
|
65
.idea/libraries-with-intellij-classes.xml
generated
Normal file
65
.idea/libraries-with-intellij-classes.xml
generated
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="libraries-with-intellij-classes">
|
||||
<option name="intellijApiContainingLibraries">
|
||||
<list>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIU" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.idea" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIU" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIC" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.idea" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIC" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPY" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPY" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPC" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPC" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="clion" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.clion" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="clion" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="riderRD" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.rider" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="riderRD" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="goland" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.goland" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="goland" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
15
.idea/libraries/KotlinJavaRuntime.xml
generated
Normal file
15
.idea/libraries/KotlinJavaRuntime.xml
generated
Normal file
@ -0,0 +1,15 @@
|
||||
<component name="libraryTable">
|
||||
<library name="KotlinJavaRuntime">
|
||||
<CLASSES>
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-sources.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect-sources.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
9
.idea/libraries/SpigotWizCompat.xml
generated
Normal file
9
.idea/libraries/SpigotWizCompat.xml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="SpigotWizCompat">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/SpigotWizCompat.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="16" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
124
.idea/uiDesigner.xml
generated
Normal file
124
.idea/uiDesigner.xml
generated
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
139
README.md
Normal file
139
README.md
Normal file
@ -0,0 +1,139 @@
|
||||
# Spigot Chunk Protector
|
||||
by Gabriel Tofvesson (IKEA_Jesus)
|
||||
|
||||
## Index
|
||||
|
||||
* [Permissions](#Permissions)
|
||||
|
||||
* [Commands](#Commands)
|
||||
|
||||
* [claim](#claim)
|
||||
|
||||
* [unclaim](#unclaim)
|
||||
|
||||
* [claims](#claims)
|
||||
|
||||
* [invite](#invite)
|
||||
|
||||
* [uninvite](#uninvite)
|
||||
|
||||
* [showclaim](#showclaim)
|
||||
|
||||
* [claimowner](#claimowner)
|
||||
|
||||
* [claimoption](#claimoption)
|
||||
|
||||
* [Options](#Options)
|
||||
|
||||
## Permissions
|
||||
|
||||
|Permission Node|Description|Applies to (by default)|
|
||||
|:---|:---|:---:|
|
||||
|`chunkprotector.claim`|Allows access to [`/claim`](#claim)|All players|
|
||||
|`chunkprotector.unclaim`|Allows access to [`/unclaim`](#unclaim)|All players|
|
||||
|`chunkprotector.invite`|Allows access to [`/invite`](#invite)|All players|
|
||||
|`chunkprotector.uninvite`|Allows access to [`/uninvite`](#uninvite)|All players|
|
||||
|`chunkprotector.listclaims`|Allows access to [`/claims`](#claims)|All players|
|
||||
|`chunkprotector.claimowner`|Allows access to [`/claimowner`](#claimowner)|All players|
|
||||
|`chunkprotector.showclaim`|Allows access to [`/showclaim`](#showclaim)|All players|
|
||||
|`chunkprotector.claimoption`|Allows access to [`/claimoption`](#claimoption)|All players|
|
||||
|`chunkprotector.bypass`|Allows for modification of otherp player's claims|Operators|
|
||||
|`chunkprotector.ignore`|Allows bypassing of all physical restrictions|Operators|
|
||||
|
||||
## Commands
|
||||
|
||||
### claim
|
||||
|
||||
*Claim an area and give it a specified name*
|
||||
|
||||
| Action |Command|
|
||||
|:--- | :---: |
|
||||
|Select area|`/claim [name]`|
|
||||
|Cancel selection|`/claim`|
|
||||
|
||||
|
||||
### unclaim
|
||||
|
||||
*Remove a claim with a given name for a specific player*
|
||||
|
||||
|Who|Command|
|
||||
|:--- | :---:|
|
||||
|All players|`/unclaim [claim]`|
|
||||
|Bypass permission + Console|`/unclaim [claim] [player]`|
|
||||
|
||||
|
||||
### claims
|
||||
|
||||
*List all claimed areas for a player*
|
||||
|
||||
|Who|Command|
|
||||
|:--- | :---:|
|
||||
|All players|`/claims`|
|
||||
|Bypass permission + Console|`/claims [player]`|
|
||||
|
||||
|
||||
### invite
|
||||
|
||||
*Invite a player to a claim*
|
||||
|
||||
|Who|Command|Context|
|
||||
|:--- | :---:|:---|
|
||||
|All players|`/invite [player]`|Invite player to claim that owner is standing in|
|
||||
|All players|`/invite [player] [claim]`|Invite player to given claim|
|
||||
|Bypass permission + Console|`/invite [player] [claim] [claimOwner]`|Invite player to another players claim|
|
||||
|
||||
|
||||
### uninvite
|
||||
|
||||
*Un-invite a player to a claim*
|
||||
|
||||
|Who|Command|Context|
|
||||
|:--- | :---:|:---|
|
||||
|All players|`/uninvite [player]`|Un-invite player to claim that owner is standing in|
|
||||
|All players|`/uninvite [player] [claim]`|Un-invite player to given claim|
|
||||
|Bypass permission + Console|`/uninvite [player] [claim] [claimOwner]`|Un-invite player to another players claim|
|
||||
|
||||
|
||||
### showclaim
|
||||
|
||||
*Show the boundaries of a claimed area*
|
||||
|
||||
|Action|Command|
|
||||
|:--- | :---:|
|
||||
|Current claim|`/claims`|
|
||||
|Specific claim|`/claims [claim]`|
|
||||
|Specific claim|`/claims [claim] [player]`|
|
||||
|
||||
|
||||
### claimowner
|
||||
|
||||
*Get the name and owner of the claim the command sender is standing in*
|
||||
|
||||
|Where|Command|
|
||||
|:--- | :---:|
|
||||
|Current claim|`/claimowner`|
|
||||
|
||||
|
||||
### claimoption
|
||||
|
||||
*Set a configuration option for a given claim. Values will always be either `true` or `false`*
|
||||
|
||||
|Who|Command|Context|
|
||||
|:--- | :---:|:---|
|
||||
|All players|`/claimoption [option] [value]`|Set option for the claim the command sender is standing in|
|
||||
|All players|`/claimoption [claim] [option] [value]`|Set option for the given claim|
|
||||
|Bypass permission + Console|`/claimoption [player] [claim] [option] [value]`|Set option for the claim of the given player|
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
|Option name|Description|
|
||||
|:---|:---|
|
||||
|`allowAllLiquids`|Allow all liquids to enter a claimed area|
|
||||
|`allowEntityInteract`|Allow entities to interact with the environment (e.g. creepers break blocks, mobs can hurt each other). When this is false, mobs will act as if players that are not invited to a claim do not exist|
|
||||
|`allowGuestLiquids`|Allow liquids to enter claimed area if they originate from a claim owned by an invited player|
|
||||
|`allowPlayerEntityInteract`|Allow all players (invited or not) to interact with non-hostile mobs in a claim|
|
||||
|`allowTNT`|Allow TNT explosions to break blocks|
|
||||
|`disablePVP`|Disable player-versus-player interactions|
|
||||
|
||||
**NOTE:** Regarding `allowPlayerEntityInteract`, players can always interact with hostile mobs, so long as said mobs do not have a custom name.
|
195
build.gradle
Normal file
195
build.gradle
Normal file
@ -0,0 +1,195 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'kr.entree.spigradle' version '2.2.4'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.5.20'
|
||||
}
|
||||
|
||||
group 'dev.w1zzrd.spigot.chunkprotector'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/'
|
||||
|
||||
// As of Gradle 5.1, you can limit this to only those
|
||||
// dependencies you expect from it
|
||||
content {
|
||||
includeGroup 'org.bukkit'
|
||||
includeGroup 'org.spigotmc'
|
||||
}
|
||||
}
|
||||
/*
|
||||
As Spigot-API depends on the Bungeecord ChatComponent-API,
|
||||
we need to add the Sonatype OSS repository, as Gradle,
|
||||
in comparison to maven, doesn't want to understand the ~/.m2
|
||||
directory unless added using mavenLocal(). Maven usually just gets
|
||||
it from there, as most people have run the BuildTools at least once.
|
||||
This is therefore not needed if you're using the full Spigot/CraftBukkit,
|
||||
or if you're using the Bukkit API.
|
||||
*/
|
||||
maven {
|
||||
url = "https://papermc.io/repo/repository/maven-public"
|
||||
|
||||
content {
|
||||
includeGroup 'io.papermc.paper'
|
||||
}
|
||||
}
|
||||
maven { url = 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
maven { url = 'https://oss.sonatype.org/content/repositories/central' }
|
||||
mavenLocal() // This is needed for CraftBukkit and Spigot.
|
||||
|
||||
mavenCentral()
|
||||
protocolLib()
|
||||
jitpack() // For vault
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Pick only one of these and read the comment in the repositories block.
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" // The Spigot API with no shadowing. Requires the OSS repo.
|
||||
implementation files('lib/SpigotWizCompat.jar')
|
||||
|
||||
compileOnly spigot('1.17') // Or spigot()
|
||||
//compileOnly protocolLib()
|
||||
//compileOnly vault()
|
||||
}
|
||||
|
||||
spigot {
|
||||
authors = ['IKEAJesus']
|
||||
depends = ['WizCompat', 'Kotlin']
|
||||
apiVersion = '1.16'
|
||||
load = STARTUP
|
||||
|
||||
commands {
|
||||
claim {
|
||||
description = 'Start claiming land'
|
||||
permission = 'chunkprotector.claim'
|
||||
permissionMessage = 'You are not allowed to claim land!'
|
||||
usage = '/<command> [claim]'
|
||||
}
|
||||
|
||||
unclaim {
|
||||
description = 'Un-claim a claimed region'
|
||||
permission = 'chunkprotector.unclaim'
|
||||
permissionMessage = 'You are not allowed to unclaim land!'
|
||||
usage = '/<command> [claim]'
|
||||
}
|
||||
|
||||
invite {
|
||||
description = 'Invite a player to a claimed area'
|
||||
permission = 'chunkprotector.invite'
|
||||
permissionMessage = 'You are not allowed to invite players!'
|
||||
usage = '/<command> [player] [claim]'
|
||||
}
|
||||
|
||||
uninvite {
|
||||
description = 'Un-invite a player from a claimed area'
|
||||
permission = 'chunkprotector.uninvite'
|
||||
permissionMessage = 'You are not allowed to un-invite players!'
|
||||
usage = '/<command> [player] [claim]'
|
||||
}
|
||||
|
||||
claims {
|
||||
description = 'Get a list of all owned claims'
|
||||
permission = 'chunkprotector.listclaims'
|
||||
permissionMessage = 'You are not allowed get a list of your claims!'
|
||||
usage = '/<command>'
|
||||
}
|
||||
|
||||
claimowner {
|
||||
description = 'Get the owner of the current chunk'
|
||||
permission = 'chunkprotector.claimowner'
|
||||
permissionMessage = 'You are not allowed to check who owns this chunk!'
|
||||
usage = '/<command>'
|
||||
}
|
||||
|
||||
showclaim {
|
||||
description = 'Show the outline of a claimed region'
|
||||
permission = 'chunkprotector.showclaim'
|
||||
permissionMessage = 'You are not allowed to see the claimed region!'
|
||||
usage = '/<command> {claim}'
|
||||
}
|
||||
|
||||
claimoption {
|
||||
description = 'Change properties of a claimed area'
|
||||
permission = 'chunkprotector.claimoption'
|
||||
permissionMessage = 'You are not allowed to change the properties of a claimed area!'
|
||||
usage = '/<command> {claim} [claimOption] [true/false]'
|
||||
}
|
||||
}
|
||||
|
||||
permissions {
|
||||
'chunkprotector.claim' {
|
||||
description = 'Allows access to /claim'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.unclaim' {
|
||||
description = 'Allows access to /unclaim'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.invite' {
|
||||
description = 'Allows access to /invite'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.uninvite' {
|
||||
description = 'Allows access to /uninvite'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.listclaims' {
|
||||
description = 'Allows access to /claims'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.bypass' {
|
||||
description = 'Allows bypassing of all command-related claim restrictions'
|
||||
defaults = 'op'
|
||||
}
|
||||
'chunkprotector.ignore' {
|
||||
description = 'Allows bypassing of all physical claim restrictions'
|
||||
defaults = 'op'
|
||||
}
|
||||
'chunkprotector.claimowner' {
|
||||
description = 'Allows access to /claimowner'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.showclaim' {
|
||||
description = 'Allows access to /showclaim'
|
||||
defaults = 'true'
|
||||
}
|
||||
'chunkprotector.claimoption' {
|
||||
description = 'Allows access to /claimoption'
|
||||
defaults = 'true'
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
commands {
|
||||
give {
|
||||
aliases = ['i']
|
||||
description = 'Give command.'
|
||||
permission = 'test.foo'
|
||||
permissionMessage = 'You do not have permission!'
|
||||
usage = '/<command> [test|stop]'
|
||||
}
|
||||
}
|
||||
permissions {
|
||||
'test.foo' {
|
||||
description = 'Allows foo command'
|
||||
defaults = 'true'
|
||||
}
|
||||
'test.*' {
|
||||
description = 'Wildcard permission'
|
||||
defaults = 'op'
|
||||
children = ['test.foo': true]
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "16"
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "16"
|
||||
}
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
185
gradlew
vendored
Normal file
185
gradlew
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@ -0,0 +1,86 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.Claim
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimChunk
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.chunkprotector.collection.SerializableBinaryList
|
||||
import dev.w1zzrd.spigot.chunkprotector.command.*
|
||||
import dev.w1zzrd.spigot.chunkprotector.freecam.FreeCamManager
|
||||
import dev.w1zzrd.spigot.chunkprotector.listener.PlayerActionListener
|
||||
import dev.w1zzrd.spigot.chunkprotector.listener.TabCompleteListener
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.PersistentData
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.UUIDList
|
||||
import kr.entree.spigradle.annotations.SpigotPlugin
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
|
||||
@SpigotPlugin
|
||||
class ChunkProtectorPlugin: JavaPlugin() {
|
||||
private val freeCamManager = FreeCamManager()
|
||||
|
||||
private val tabCompleteListener = TabCompleteListener()
|
||||
|
||||
// Properties that should be initialized only after serializers are enabled
|
||||
private val persistentData: PersistentData by lazy { PersistentData("data", this) }
|
||||
private val claimManager: ClaimManager by lazy { ClaimManager(freeCamManager, persistentData) }
|
||||
private val actionListener: PlayerActionListener by lazy {
|
||||
PlayerActionListener(claimManager)
|
||||
}
|
||||
|
||||
override fun onEnable() {
|
||||
super.onEnable()
|
||||
enableSerializers()
|
||||
freeCamManager.onEnable(this)
|
||||
claimManager.onEnable(this)
|
||||
enableListeners()
|
||||
enableCommands()
|
||||
}
|
||||
|
||||
private fun enableSerializers() {
|
||||
ConfigurationSerialization.registerClass(UUIDList::class.java)
|
||||
ConfigurationSerialization.registerClass(SerializableBinaryList::class.java)
|
||||
ConfigurationSerialization.registerClass(ClaimChunk::class.java)
|
||||
ConfigurationSerialization.registerClass(Claim::class.java)
|
||||
}
|
||||
|
||||
private fun enableListeners() {
|
||||
server.pluginManager.registerEvents(tabCompleteListener, this)
|
||||
server.pluginManager.registerEvents(actionListener, this)
|
||||
}
|
||||
|
||||
private fun enableCommands() {
|
||||
getCommand("claim")!!.setExecutor(ClaimCommand(claimManager))
|
||||
getCommand("unclaim")!!.setExecutor(UnClaimCommand(claimManager))
|
||||
getCommand("invite")!!.setExecutor(InviteCommand(claimManager))
|
||||
getCommand("uninvite")!!.setExecutor(UnInviteCommand(claimManager))
|
||||
getCommand("claims")!!.setExecutor(ListClaimsCommand(claimManager))
|
||||
getCommand("claimowner")!!.setExecutor(ClaimOwnerCommand(claimManager))
|
||||
getCommand("showclaim")!!.setExecutor(ShowClaimCommand(claimManager, this))
|
||||
getCommand("claimoption")!!.setExecutor(
|
||||
ClaimOptionCommand(claimManager).also { tabCompleteListener.registerTabCompleter("claimoption", it.completionProcessor) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
disableListeners()
|
||||
claimManager.onDisable()
|
||||
freeCamManager.onDisable()
|
||||
persistentData.saveData()
|
||||
disableSerializers()
|
||||
super.onDisable()
|
||||
}
|
||||
|
||||
private fun disableSerializers() {
|
||||
ConfigurationSerialization.unregisterClass(Claim::class.java)
|
||||
ConfigurationSerialization.unregisterClass(ClaimChunk::class.java)
|
||||
ConfigurationSerialization.unregisterClass(SerializableBinaryList::class.java)
|
||||
ConfigurationSerialization.unregisterClass(UUIDList::class.java)
|
||||
}
|
||||
|
||||
private fun disableListeners() {
|
||||
HandlerList.unregisterAll(actionListener)
|
||||
tabCompleteListener.unRegisterAll()
|
||||
HandlerList.unregisterAll(tabCompleteListener)
|
||||
}
|
||||
}
|
217
src/main/java/dev/w1zzrd/spigot/chunkprotector/claim/Claim.kt
Normal file
217
src/main/java/dev/w1zzrd/spigot/chunkprotector/claim/Claim.kt
Normal file
@ -0,0 +1,217 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.claim
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.collection.BinaryList
|
||||
import dev.w1zzrd.spigot.wizcompat.packet.EntityCreator.*
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.SimpleReflectiveConfigItem
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.UUIDList
|
||||
import org.bukkit.Chunk
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.World
|
||||
import org.bukkit.entity.Player
|
||||
import java.lang.Integer.max
|
||||
import java.lang.Integer.min
|
||||
import java.util.*
|
||||
|
||||
class ClaimBuilder(val who: Player, val world: World, val name: String): Comparable<ClaimBuilder> {
|
||||
private val first = CornerSelection()
|
||||
private val second = CornerSelection()
|
||||
|
||||
val isValidRegion: Boolean
|
||||
get() = second.corner != null
|
||||
|
||||
val built: Claim
|
||||
get() = Claim(who.uniqueId, world.uid, name, ClaimChunk(first.corner!!.x, first.corner!!.z), ClaimChunk(second.corner!!.x, second.corner!!.z))
|
||||
|
||||
fun toggleCorner(corner: Chunk) {
|
||||
when (corner) {
|
||||
first.corner -> first.corner = null
|
||||
second.corner -> second.corner = null
|
||||
else -> {
|
||||
if ((second.corner != null && first.corner != null) || first.corner == null) {
|
||||
second.corner = null
|
||||
first.corner = corner
|
||||
} else {
|
||||
second.corner = corner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
first.render()
|
||||
second.render()
|
||||
}
|
||||
|
||||
fun clearRenders() {
|
||||
first.clearRender()
|
||||
second.clearRender()
|
||||
}
|
||||
|
||||
override fun compareTo(other: ClaimBuilder) = who.uniqueId.compareTo(other.who.uniqueId)
|
||||
override fun equals(other: Any?) = other is ClaimBuilder && hashCode() == other.hashCode()
|
||||
override fun hashCode() = who.hashCode()
|
||||
|
||||
private inner class CornerSelection {
|
||||
private var render = -1
|
||||
private var location: Location? = null
|
||||
|
||||
var isDirty: Boolean = true
|
||||
private set
|
||||
var corner: Chunk? = null
|
||||
set(value) {
|
||||
isDirty = isDirty || (field != value)
|
||||
field = value
|
||||
|
||||
adjustHeight()
|
||||
}
|
||||
|
||||
fun adjustHeight() {
|
||||
val currentCorner = corner
|
||||
|
||||
if (currentCorner != null) {
|
||||
location = Location(
|
||||
who.world,
|
||||
(currentCorner.x shl 4) + 8.5,
|
||||
kotlin.math.max(who.location.y - 3.0, 0.0),
|
||||
(currentCorner.z shl 4) + 8.5,
|
||||
0f,
|
||||
0f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun render() {
|
||||
if (isDirty) {
|
||||
clearRender()
|
||||
|
||||
if (corner != null) {
|
||||
val renderShulker = createFakeShulker(who)
|
||||
setEntityInvisible(renderShulker, true)
|
||||
setEntityInvulnerable(renderShulker, true)
|
||||
setEntityLocation(
|
||||
renderShulker,
|
||||
location!!.x,
|
||||
location!!.y,
|
||||
location!!.z,
|
||||
location!!.yaw,
|
||||
location!!.pitch
|
||||
)
|
||||
setEntityCollision(renderShulker, false)
|
||||
setEntityGlowing(renderShulker, true)
|
||||
|
||||
sendEntitySpawnPacket(who, renderShulker)
|
||||
sendEntityMetadataPacket(who, renderShulker)
|
||||
|
||||
render = getEntityID(renderShulker)
|
||||
}
|
||||
|
||||
isDirty = false
|
||||
}
|
||||
}
|
||||
|
||||
fun clearRender() {
|
||||
if (render != -1) {
|
||||
sendEntityDespawnPacket(who, render)
|
||||
render = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Claim: SimpleReflectiveConfigItem, Comparable<Claim> {
|
||||
@Transient
|
||||
var owner: UUID
|
||||
private set
|
||||
private lateinit var ownerString: String
|
||||
|
||||
@Transient
|
||||
var world: UUID
|
||||
private set
|
||||
private lateinit var worldString: String
|
||||
|
||||
lateinit var name: String
|
||||
private set
|
||||
|
||||
lateinit var topLeft: ClaimChunk
|
||||
private set
|
||||
|
||||
lateinit var bottomRight: ClaimChunk
|
||||
private set
|
||||
|
||||
private lateinit var guests: UUIDList
|
||||
|
||||
|
||||
// Per-claim settings
|
||||
var allowPlayerEntityInteract = false
|
||||
var allowTNT = false
|
||||
var allowEntityInteract = false
|
||||
var allowAllLiquids = false
|
||||
var allowGuestLiquids = true
|
||||
var disablePVP = false
|
||||
|
||||
constructor(map: Map<String, Any?>): super(map) {
|
||||
owner = UUID.fromString(ownerString)
|
||||
world = UUID.fromString(worldString)
|
||||
}
|
||||
constructor(owner: UUID, world: UUID, name: String, corner1: ClaimChunk, corner2: ClaimChunk): super(Collections.emptyMap()) {
|
||||
this.owner = owner
|
||||
ownerString = owner.toString()
|
||||
this.world = world
|
||||
worldString = world.toString()
|
||||
this.name = name
|
||||
this.topLeft = ClaimChunk(min(corner1.chunkX, corner2.chunkX), max(corner1.chunkZ, corner2.chunkZ))
|
||||
this.bottomRight = ClaimChunk(max(corner1.chunkX, corner2.chunkX), min(corner1.chunkZ, corner2.chunkZ))
|
||||
guests = UUIDList(BinaryList.newBinaryList())
|
||||
}
|
||||
|
||||
fun addGuest(player: OfflinePlayer) = guests.uuids.add(player.uniqueId)
|
||||
fun removeGuest(player: OfflinePlayer) = guests.uuids.remove(player.uniqueId)
|
||||
|
||||
fun hasGuest(player: OfflinePlayer) = guests.uuids.contains(player.uniqueId)
|
||||
|
||||
fun isAccessible(player: OfflinePlayer) = owner == player.uniqueId || guests.uuids.contains(player.uniqueId)
|
||||
|
||||
fun overlaps(other: Claim) =
|
||||
!(topLeft.chunkX > other.bottomRight.chunkX || other.topLeft.chunkX > bottomRight.chunkZ) &&
|
||||
!(bottomRight.chunkZ > other.topLeft.chunkZ || other.bottomRight.chunkZ > topLeft.chunkZ)
|
||||
|
||||
fun contains(chunk: Chunk) = contains(chunk.x, chunk.z)
|
||||
fun contains(chunkX: Int, chunkZ: Int) =
|
||||
!(topLeft.chunkX > chunkX || chunkX > bottomRight.chunkX) &&
|
||||
!(bottomRight.chunkZ > chunkZ || chunkZ > topLeft.chunkZ)
|
||||
|
||||
override fun compareTo(other: Claim) = compareRaw(other.owner, other.name)
|
||||
|
||||
fun compareRaw(owner: UUID, name: String): Int {
|
||||
val comp1 = this.owner.compareTo(owner)
|
||||
return if (comp1 == 0) this.name.compareTo(name) else comp1
|
||||
}
|
||||
|
||||
fun compareFindFirst(owner: UUID): Int {
|
||||
val comp1 = this.owner.compareTo(owner)
|
||||
return if (comp1 == 0) 1 else comp1
|
||||
}
|
||||
|
||||
fun compareFindLast(owner: UUID): Int {
|
||||
val comp1 = this.owner.compareTo(owner)
|
||||
return if (comp1 == 0) -1 else comp1
|
||||
}
|
||||
}
|
||||
|
||||
fun BinaryList<Claim>.getByName(owner: UUID, name: String): Claim? {
|
||||
val index = binarySearch { it.compareRaw(owner, name) }
|
||||
|
||||
if (index >= 0)
|
||||
return this[index]
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun BinaryList<Claim>.getAllForOwner(owner: UUID): List<Claim> {
|
||||
val startIndex = -(binarySearch { it.compareFindFirst(owner) } + 1)
|
||||
val endIndex = -(binarySearch { it.compareFindLast(owner) } + 1)
|
||||
|
||||
if (startIndex >= endIndex)
|
||||
return emptyList()
|
||||
|
||||
return subList(startIndex, endIndex)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.claim
|
||||
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.SimpleReflectiveConfigItem
|
||||
import java.util.*
|
||||
|
||||
class ClaimChunk: SimpleReflectiveConfigItem, Comparable<ClaimChunk> {
|
||||
var chunkX: Int = 0
|
||||
private set
|
||||
|
||||
var chunkZ: Int = 0
|
||||
private set
|
||||
|
||||
constructor(map: Map<String, Any?>): super(map)
|
||||
|
||||
constructor(chunkX: Int, chunkZ: Int): super(Collections.emptyMap()) {
|
||||
this.chunkX = chunkX
|
||||
this.chunkZ = chunkZ
|
||||
}
|
||||
|
||||
private val longCoordinate: Long
|
||||
get() = chunkX.toLong().shl(32) or chunkZ.toLong().and(0xFFFFFFFFL)
|
||||
|
||||
override fun compareTo(other: ClaimChunk) =
|
||||
longCoordinate.compareTo(other.longCoordinate)
|
||||
|
||||
override fun equals(other: Any?) = other is ClaimChunk && compareTo(other) == 0
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.claim
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.collection.BinaryCache
|
||||
import dev.w1zzrd.spigot.chunkprotector.collection.BinaryList.Companion.newBinaryList
|
||||
import dev.w1zzrd.spigot.chunkprotector.collection.SerializableBinaryList
|
||||
import dev.w1zzrd.spigot.chunkprotector.freecam.FreeCamManager
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.errorMessage
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.PersistentData
|
||||
import org.bukkit.Chunk
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.World
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.plugin.Plugin
|
||||
|
||||
private val Chunk.longChunkCoordinate: Long
|
||||
get() = (x.toLong() shl 32) or (z.toLong() and 0xFFFFFFFFL)
|
||||
|
||||
private fun Chunk.compareTo(other: Chunk): Int {
|
||||
val comp1 = world.uid.compareTo(other.world.uid)
|
||||
return if (comp1 == 0) longChunkCoordinate.compareTo(other.longChunkCoordinate) else comp1
|
||||
}
|
||||
|
||||
private data class ClaimNameCacheEntry(val player: OfflinePlayer, val name: String): Comparable<ClaimNameCacheEntry> {
|
||||
override fun compareTo(other: ClaimNameCacheEntry): Int {
|
||||
val comp1 = player.uniqueId.compareTo(player.uniqueId)
|
||||
return if (comp1 == 0) name.compareTo(other.name) else comp1
|
||||
}
|
||||
}
|
||||
|
||||
class ClaimManager(private val freeCamManager: FreeCamManager, persistentData: PersistentData) {
|
||||
private val claimSelectListener = ClaimSelectListener()
|
||||
private val claimBuilders = newBinaryList<ClaimBuilder>()
|
||||
private val claims: SerializableBinaryList<Claim> = persistentData.loadData("claims") { SerializableBinaryList(newBinaryList()) }
|
||||
private val chunkPermCache = BinaryCache.makeCache(512, Chunk::compareTo) { chunk ->
|
||||
claims.list.find { it.world == chunk.world.uid && it.contains(chunk) }
|
||||
}
|
||||
private val namePermCache = BinaryCache.makeCache<ClaimNameCacheEntry, Claim>(64, ClaimNameCacheEntry::compareTo) {
|
||||
claims.list.getByName(it.player.uniqueId, it.name)
|
||||
}
|
||||
|
||||
init {
|
||||
freeCamManager.addOnPlayerExitFreeCam { player ->
|
||||
val builderIndex = claimBuilders.binarySearch { it.who.uniqueId.compareTo(player.uniqueId) }
|
||||
if (builderIndex >= 0) {
|
||||
val builder = claimBuilders.removeAt(builderIndex)
|
||||
builder.clearRenders()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onEnable(plugin: Plugin) = plugin.server.pluginManager.registerEvents(claimSelectListener, plugin)
|
||||
fun onDisable() = HandlerList.unregisterAll(claimSelectListener)
|
||||
|
||||
fun toggleClaim(player: Player, name: String) =
|
||||
if (isClaiming(player)) {
|
||||
freeCamManager.disableFreeCam(player)
|
||||
false
|
||||
} else {
|
||||
freeCamManager.enableFreeCam(player)
|
||||
claimBuilders.add(ClaimBuilder(player, player.world, name))
|
||||
true
|
||||
}
|
||||
|
||||
fun isClaiming(player: Player) = claimBuilders.contains(player.uniqueId) { who.uniqueId }
|
||||
|
||||
fun addClaim(claim: Claim): Boolean {
|
||||
if (claims.list.any { it.overlaps(claim) })
|
||||
return false
|
||||
|
||||
claims.list.add(claim)
|
||||
return true
|
||||
}
|
||||
|
||||
fun removeClaim(claim: Claim): Boolean {
|
||||
chunkPermCache.clearValues(claim)
|
||||
namePermCache.clearValues(claim)
|
||||
return claims.list.remove(claim)
|
||||
}
|
||||
|
||||
fun invitePlayer(owner: Player, name: String, invitedPlayer: Player) =
|
||||
claims.list.getByName(owner.uniqueId, name)?.addGuest(invitedPlayer) ?: false
|
||||
|
||||
fun unInvitePlayer(owner: Player, name: String, unInvitedPlayer: Player) =
|
||||
claims.list.getByName(owner.uniqueId, name)?.removeGuest(unInvitedPlayer) ?: false
|
||||
|
||||
// This is slow, because a sequential search must be done
|
||||
fun getClaimAt(chunk: Chunk) = chunkPermCache[chunk]
|
||||
fun getClaimByName(owner: OfflinePlayer, name: String) = namePermCache[ClaimNameCacheEntry(owner, name)]
|
||||
fun getClaimsForOwner(owner: OfflinePlayer) = claims.list.getAllForOwner(owner.uniqueId)
|
||||
|
||||
private inner class ClaimSelectListener: Listener {
|
||||
@EventHandler
|
||||
fun onFreeCamHit(event: PlayerInteractEvent) {
|
||||
if ((event.action == Action.LEFT_CLICK_AIR || event.action == Action.LEFT_CLICK_BLOCK) && isClaiming(event.player)) {
|
||||
val claimBuilder = claimBuilders.find { it.who == event.player }!!
|
||||
|
||||
claimBuilder.toggleCorner(event.player.location.chunk)
|
||||
|
||||
if (claimBuilder.isValidRegion) {
|
||||
event.player.spigot()
|
||||
.sendMessage(CommandUtils.successMessage("Region selected! Right-click a block to confirm selections"))
|
||||
}
|
||||
} else if (event.action == Action.RIGHT_CLICK_BLOCK && isClaiming(event.player)) {
|
||||
val claimBuilder = claimBuilders.find { it.who == event.player }!!
|
||||
|
||||
if (assertTrue(claimBuilder.isValidRegion, "You have not selected a region", event.player) ||
|
||||
assertTrue(addClaim(claimBuilder.built), "This claim overlaps with another claim", event.player))
|
||||
return
|
||||
|
||||
freeCamManager.disableFreeCam(event.player)
|
||||
|
||||
event.player.spigot().sendMessage(CommandUtils.successMessage("Region claimed!"))
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerWorldChange(event: PlayerChangedWorldEvent) {
|
||||
if (isClaiming(event.player)) {
|
||||
freeCamManager.disableFreeCam(event.player)
|
||||
event.player.spigot().sendMessage(errorMessage("Cancelled claiming!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.collection
|
||||
|
||||
import java.util.*
|
||||
import kotlin.Comparator
|
||||
|
||||
class BinaryCache<K, V> (cacheSize: Int, private val comparator: Comparator<K>, private val cacheMiss: (K) -> V?, private val keyType: Class<K>) {
|
||||
|
||||
companion object {
|
||||
inline fun <reified K, V> makeCache(cacheSize: Int, comparator: Comparator<K>, noinline cacheMiss: (K) -> V?) =
|
||||
BinaryCache(cacheSize, comparator, cacheMiss, K::class.java)
|
||||
|
||||
inline fun <reified K: Comparable<K>, V> makeCache(cacheSize: Int, noinline cacheMiss: (K) -> V?) =
|
||||
BinaryCache(cacheSize, Comparable<K>::compareTo, cacheMiss, K::class.java)
|
||||
}
|
||||
|
||||
private val keys = java.lang.reflect.Array.newInstance(keyType, cacheSize) as Array<K>
|
||||
private val values = Array<Any?>(cacheSize) { null }
|
||||
private val ages = java.lang.reflect.Array.newInstance(keyType, cacheSize) as Array<K> // Essentially a fifo queue
|
||||
|
||||
private var entryCount = 0
|
||||
private var oldest = 0
|
||||
|
||||
fun clearValues(value: V) {
|
||||
val scratch1 = java.lang.reflect.Array.newInstance(keyType, ages.size) as Array<K>
|
||||
|
||||
// Since ages softly depend on key/value entries, it's easiest to process them first
|
||||
var copyIndex = 0
|
||||
for (index in oldest until entryCount)
|
||||
if (values[indexOf(ages[index])] != value)
|
||||
scratch1[copyIndex++] = ages[index]
|
||||
|
||||
if (entryCount == ages.size) {
|
||||
for (index in 0 until oldest)
|
||||
if (values[indexOf(ages[index])] != value)
|
||||
scratch1[copyIndex++] = ages[index]
|
||||
}
|
||||
|
||||
// No change
|
||||
if (copyIndex == entryCount)
|
||||
return
|
||||
|
||||
// Just re-index the queue so that the oldest entry lies at index 0
|
||||
System.arraycopy(scratch1, 0, ages, 0, copyIndex)
|
||||
oldest = 0
|
||||
|
||||
copyIndex = 0
|
||||
|
||||
val scratch2 = Array<Any?>(values.size){ null }
|
||||
|
||||
for (index in 0 until entryCount)
|
||||
if (values[index] != value) {
|
||||
scratch1[copyIndex] = keys[index]
|
||||
scratch2[copyIndex++] = values[index]
|
||||
}
|
||||
|
||||
System.arraycopy(scratch1, 0, keys, 0, copyIndex)
|
||||
System.arraycopy(scratch2, 0, values, 0, copyIndex)
|
||||
|
||||
entryCount -= copyIndex
|
||||
}
|
||||
|
||||
operator fun get(key: K): V? {
|
||||
var index = indexOf(key)
|
||||
|
||||
// Cache hit
|
||||
if (index >= 0)
|
||||
return values[index] as V
|
||||
|
||||
// Cache miss
|
||||
index = -(index + 1)
|
||||
|
||||
val value = cacheMiss(key) ?: return null
|
||||
|
||||
if (entryCount < keys.size) {
|
||||
System.arraycopy(keys, index, keys, index + 1, entryCount - index)
|
||||
System.arraycopy(values, index, values, index + 1, entryCount - index)
|
||||
|
||||
ages[(oldest + entryCount).rem(ages.size)] = key
|
||||
|
||||
++entryCount
|
||||
} else {
|
||||
// We're out of spaces. This works
|
||||
if (index > 0)
|
||||
--index
|
||||
|
||||
// Find oldest entry
|
||||
val oldestIndex = indexOf(ages[oldest])
|
||||
|
||||
if (oldestIndex > index) {
|
||||
System.arraycopy(keys, index, keys, index + 1, oldestIndex - index)
|
||||
System.arraycopy(values, index, values, index + 1, oldestIndex - index)
|
||||
} else if (oldestIndex < index) {
|
||||
System.arraycopy(keys, oldestIndex + 1, keys, oldestIndex, index - oldestIndex)
|
||||
System.arraycopy(values, oldestIndex + 1, values, oldestIndex, index - oldestIndex)
|
||||
}
|
||||
|
||||
// Overwrite oldest entry with new entry
|
||||
ages[oldest] = key
|
||||
|
||||
// Re-index age list so that current oldest entry becomes youngest
|
||||
oldest = (oldest + 1).rem(ages.size)
|
||||
}
|
||||
|
||||
keys[index] = key
|
||||
values[index] = value
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
private fun indexOf(key: K) =
|
||||
keys.binarySearch(key, comparator, 0, entryCount)
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.collection
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.collection.BinaryList.Companion.wrapSortedList
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable
|
||||
|
||||
class SerializableBinaryList<T>: ConfigurationSerializable {
|
||||
lateinit var list: BinaryList<T>
|
||||
private set
|
||||
|
||||
constructor(map: Map<String, Any?>) {
|
||||
if (map.containsKey("list"))
|
||||
list = wrapSortedList({ a, b -> (a as Comparable<T>).compareTo(b) }, map["list"] as MutableList<T>)
|
||||
}
|
||||
|
||||
constructor(list: BinaryList<T>) {
|
||||
this.list = list
|
||||
}
|
||||
|
||||
override fun serialize() = mutableMapOf("list" to list.toMutableList())
|
||||
}
|
||||
|
||||
class BinaryList<T> private constructor(private val backing: MutableList<T>, private val comparator: Comparator<in T>): MutableList<T> by backing {
|
||||
|
||||
companion object {
|
||||
fun <K> newBinaryList(comparator: Comparator<in K>, backingFactory: () -> MutableList<K> = ::ArrayList) =
|
||||
BinaryList(backingFactory(), comparator)
|
||||
|
||||
fun <K: Comparable<K>> newBinaryList(backingFactory: () -> MutableList<K> = ::ArrayList) =
|
||||
newBinaryList({ a, b -> a.compareTo(b) }, backingFactory)
|
||||
|
||||
fun <K> wrapSortedList(comparator: Comparator<in K>, backingList: MutableList<K>) =
|
||||
BinaryList(backingList, comparator)
|
||||
|
||||
fun <K: Comparable<K>> wrapSortedList(backingList: MutableList<K>) =
|
||||
wrapSortedList({ a, b -> a.compareTo(b) }, backingList)
|
||||
}
|
||||
|
||||
override fun add(element: T): Boolean {
|
||||
val index = binarySearch(element, comparator)
|
||||
if (index >= 0)
|
||||
return false
|
||||
|
||||
backing.add(-(index + 1), element)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<T>) = elements.map(this::add).reduce(Boolean::or)
|
||||
override fun addAll(index: Int, elements: Collection<T>): Boolean {
|
||||
throw UnsupportedOperationException("Sorted list does not support inserting elements at a specific index")
|
||||
}
|
||||
|
||||
override fun remove(element: T): Boolean {
|
||||
val index = binarySearch(element, comparator)
|
||||
if (index < 0)
|
||||
return false
|
||||
|
||||
backing.removeAt(index)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<T>) = elements.map(this::remove).reduce(Boolean::or)
|
||||
|
||||
override fun contains(element: T) = binarySearch(element, comparator) >= 0
|
||||
fun <K : Comparable<K>> contains(element: K, convert: T.() -> K) = binarySearch { it.convert().compareTo(element) } >= 0
|
||||
override fun indexOf(element: T): Int {
|
||||
val index = binarySearch(element, comparator)
|
||||
if (index < 0)
|
||||
return -1
|
||||
|
||||
return index
|
||||
}
|
||||
|
||||
fun getOrAdd(element: T): T {
|
||||
val index = binarySearch(element, comparator)
|
||||
return if (index >= 0)
|
||||
backing[index]
|
||||
else {
|
||||
backing.add(-(index + 1), element)
|
||||
element
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.chunkprotector.listener.TabCompleteListener
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class ClaimCommand(private val claimManager: ClaimManager): CommandExecutor {
|
||||
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
if (assertTrue(sender is Player, "Only players can claim land", sender))
|
||||
return true
|
||||
|
||||
val isClaiming = claimManager.isClaiming(sender as Player)
|
||||
|
||||
if (assertTrue(isClaiming || args.size == 1, "Expected exactly one argument", sender) ||
|
||||
assertTrue(!isClaiming || args.isEmpty(), "You are already claiming a region!", sender) ||
|
||||
assertTrue(isClaiming || claimManager.getClaimByName(sender, args[0]) == null, "You already have a claim with that name", sender))
|
||||
return true
|
||||
|
||||
if (claimManager.toggleClaim(sender, if(isClaiming) "" else args[0]))
|
||||
sender.spigot().sendMessage(CommandUtils.successMessage("Enabled claim mode"))
|
||||
else
|
||||
sender.spigot().sendMessage(CommandUtils.successMessage("Cancelled claim!"))
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.Claim
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.chunkprotector.kotlin.assertNotNull
|
||||
import dev.w1zzrd.spigot.chunkprotector.listener.CompletionProcessor
|
||||
import dev.w1zzrd.spigot.wizcompat.OfflinePlayers
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.successMessage
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
private val OPTIONS = arrayOf(
|
||||
Claim::allowAllLiquids,
|
||||
Claim::allowEntityInteract,
|
||||
Claim::allowGuestLiquids,
|
||||
Claim::allowPlayerEntityInteract,
|
||||
Claim::allowTNT,
|
||||
Claim::disablePVP
|
||||
)
|
||||
|
||||
class ClaimOptionCommand(private val claimManager: ClaimManager): TabCompletionCommandExecutor() {
|
||||
override val completionProcessor: CompletionProcessor
|
||||
get() = { sender, args ->
|
||||
if (args.isEmpty() || (args.size == 1 && args[0].isBlank()))
|
||||
if(sender is Player && !sender.hasPermission("chunkprotector.bypass")) claimManager.getClaimsForOwner(sender).map(Claim::name)
|
||||
else OfflinePlayers.getAllKnownPlayers(
|
||||
Bukkit.getServer(),
|
||||
true
|
||||
).mapNotNull { Bukkit.getOfflinePlayer(it).name }
|
||||
else emptyList()
|
||||
}
|
||||
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player || args.size == 4, "Command can only be run by players", sender) && return true
|
||||
assertTrue(
|
||||
(sender is Player && (args.size in 2..3 || (sender.hasPermission("chunkprotector.bypass") && args.size in 2..4))) || (sender !is Player && args.size == 4),
|
||||
"Wrong number of arguments",
|
||||
sender
|
||||
) && return true
|
||||
|
||||
// It has been written. Let it nevermore be read
|
||||
(assertNotNull(OPTIONS.firstOrNull { it.name.equals(args[args.size - 2], ignoreCase = true) }, "Unknown option", sender) ?: return true).set(
|
||||
if(args.size == 2)
|
||||
assertNotNull(claimManager.getClaimAt((sender as Player).location.chunk), "This location is unclaimed", sender) ?: return true
|
||||
else
|
||||
assertNotNull(claimManager.getClaimByName(assertNotNull(
|
||||
if(args.size == 3) sender as Player
|
||||
else OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[0]), "Could not find a player with the given name", sender
|
||||
) ?: return true, args[1]), "No claim with the given name could be found", sender) ?: return true,
|
||||
args[args.size - 1].lowercase().toBoolean()
|
||||
)
|
||||
|
||||
sender.spigot().sendMessage(successMessage("Option has been updated!"))
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.*
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class ClaimOwnerCommand(private val claimManager: ClaimManager): CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player, "Only players can check the owner of a chunk", sender) && return true
|
||||
assertTrue(args.isEmpty(), "No arguments expected for this command", sender) && return true
|
||||
sender as Player
|
||||
|
||||
val claim = claimManager.getClaimAt(sender.location.chunk)
|
||||
assertTrue(claim != null, "No one owns this chunk", sender) && return true
|
||||
claim!!
|
||||
|
||||
sender.spigot().sendMessage(successMessage("Chunk is owned by ${if(claim.owner == sender.uniqueId) "you" else Bukkit.getOfflinePlayer(claim.owner).name} (name: ${claim.name})"))
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.wizcompat.OfflinePlayers
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.successMessage
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class InviteCommand(private val claimManager: ClaimManager): CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player || args.size == 3, "Command can only be issued by players", sender) && true
|
||||
assertTrue(
|
||||
(sender is Player && args.size in 1..2) || ((sender !is Player || sender.hasPermission("chunkprotector.bypass")) && args.size == 3),
|
||||
"Wrong number of arguments supplied!",
|
||||
sender
|
||||
) && return true
|
||||
|
||||
val targetPlayer = if(args.size == 3) OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[2]) else sender as Player
|
||||
assertTrue(targetPlayer != null, "Could not find given player", sender) && return true
|
||||
assertTrue(args[0] != targetPlayer!!.name, "The owner of a claim cannot be invited to said claim", sender) && return true
|
||||
|
||||
val claim = if(args.size == 1) claimManager.getClaimAt((targetPlayer as Player).location.chunk) else claimManager.getClaimByName(targetPlayer, args[1])
|
||||
assertTrue(claim != null && claim.owner == targetPlayer.uniqueId, "Could not find a claim with that name", sender) && return true
|
||||
|
||||
val guest = OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[0])
|
||||
assertTrue(guest != null, "Cannot find a player with that name", sender) && return true
|
||||
|
||||
if (claim!!.addGuest(guest!!) && guest.isOnline)
|
||||
(guest as Player).spigot().sendMessage(successMessage("You have been invited to \"${claim.name}\" (owned by ${targetPlayer.name})"))
|
||||
sender.spigot().sendMessage(successMessage("${guest.name} has been invited to ${claim.name}"))
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.Claim
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.wizcompat.OfflinePlayers
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.successMessage
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class ListClaimsCommand(private val claimManager: ClaimManager): CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player || args.size == 1, "Command can only be issued by players", sender) && return true
|
||||
assertTrue(
|
||||
((sender !is Player || sender.hasPermission("chunkprotector.bypass")) && args.size == 1) || (sender is Player && args.isEmpty()),
|
||||
"This command expects no arguments",
|
||||
sender
|
||||
) && return true
|
||||
|
||||
val targetPlayer = if(args.isNotEmpty()) OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[0]) else sender as Player
|
||||
assertTrue(targetPlayer != null, "Could not find given player", sender) && return true
|
||||
|
||||
val owned = claimManager.getClaimsForOwner(targetPlayer!!)
|
||||
if (owned.isEmpty())
|
||||
sender.spigot().sendMessage(successMessage("${if(targetPlayer != sender) "${targetPlayer.name} has" else "You have" } no claims"))
|
||||
else
|
||||
sender.spigot().sendMessage(successMessage("Claims: ${owned.map(Claim::name).joinToString(", ")}"))
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimChunk
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.wizcompat.OfflinePlayers
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Color
|
||||
import org.bukkit.Particle
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
private val inaccessible = Particle.DustOptions(Color.fromRGB(255, 0, 0), 10.0F)
|
||||
private val accessible = Particle.DustOptions(Color.fromRGB(0, 255, 0), 10.0F)
|
||||
|
||||
class ShowClaimCommand(private val claimManager: ClaimManager, private val plugin: Plugin): CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player, "Claims can only be visualised by players", sender) && return true
|
||||
assertTrue(args.size <= 2, "Too many arguments supplied", sender) && return true
|
||||
sender as Player
|
||||
|
||||
val targetPlayer = if(args.size == 2) OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[1]) else sender
|
||||
assertTrue(targetPlayer != null, "Specified player could not be found", sender) && return true
|
||||
targetPlayer!!
|
||||
|
||||
val targetRegion = if(args.isEmpty()) claimManager.getClaimAt(sender.location.chunk) else claimManager.getClaimByName(targetPlayer, args[0])
|
||||
assertTrue(targetRegion != null, "Region is either not claimed, or a claim with the given name does not exist", sender) && return true
|
||||
targetRegion!!
|
||||
|
||||
fun ClaimChunk.asCoords() = (chunkX shl 4).toDouble() to (chunkZ shl 4).toDouble()
|
||||
fun Pair<Double, Double>.lerp(other: Pair<Double, Double>) = (first + other.first).div(2.0) to (second + other.second).div(2.0)
|
||||
|
||||
val baseVerts = arrayOf(
|
||||
ClaimChunk(targetRegion.topLeft.chunkX, targetRegion.topLeft.chunkZ + 1).asCoords(),
|
||||
ClaimChunk(targetRegion.topLeft.chunkX, targetRegion.bottomRight.chunkZ).asCoords(),
|
||||
ClaimChunk(targetRegion.bottomRight.chunkX + 1, targetRegion.bottomRight.chunkZ).asCoords(),
|
||||
ClaimChunk(targetRegion.bottomRight.chunkX + 1, targetRegion.topLeft.chunkZ + 1).asCoords()
|
||||
)
|
||||
|
||||
val allVerts = arrayOf(
|
||||
*baseVerts,
|
||||
baseVerts[0].lerp(baseVerts[1]),
|
||||
baseVerts[1].lerp(baseVerts[2]),
|
||||
baseVerts[2].lerp(baseVerts[3]),
|
||||
baseVerts[3].lerp(baseVerts[0])
|
||||
)
|
||||
var count = 0
|
||||
var task: BukkitTask? = null
|
||||
|
||||
val particleData = if (targetRegion.isAccessible(sender)) accessible else inaccessible
|
||||
|
||||
task = Bukkit.getScheduler().runTaskTimer(
|
||||
plugin,
|
||||
Runnable {
|
||||
if (count == 40)
|
||||
task!!.cancel()
|
||||
|
||||
count += 1
|
||||
for (vert in allVerts)
|
||||
sender.spawnParticle(
|
||||
Particle.REDSTONE,
|
||||
vert.first,
|
||||
sender.location.y + 1.0,
|
||||
vert.second,
|
||||
10,
|
||||
particleData
|
||||
)
|
||||
},
|
||||
0,
|
||||
10
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.listener.CompletionProcessor
|
||||
import org.bukkit.command.CommandExecutor
|
||||
|
||||
abstract class TabCompletionCommandExecutor: CommandExecutor {
|
||||
abstract val completionProcessor: CompletionProcessor
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.wizcompat.OfflinePlayers
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.successMessage
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class UnClaimCommand(private val claimManager: ClaimManager): CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player || args.size == 2, "Command can only be run by players", sender) && return true
|
||||
assertTrue((sender is Player && args.size in 0..1) || ((sender !is Player || sender.hasPermission("chunkprotector.bypass")) && args.size == 2), "Wrong number of arguments", sender) && return true
|
||||
|
||||
val targetPlayer = if (args.size == 2) OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[1]) else sender as Player
|
||||
assertTrue(targetPlayer != null, "Could not find target player", sender) && return true
|
||||
|
||||
val claim = if(args.isEmpty()) claimManager.getClaimAt((targetPlayer!! as Player).location.chunk) else claimManager.getClaimByName(targetPlayer!!, args[0])
|
||||
assertTrue(claim != null, "Could not find a claim with that name", sender) && return true
|
||||
|
||||
claimManager.removeClaim(claim!!)
|
||||
sender.spigot().sendMessage(successMessage("Unclaimed ${args[0]}"))
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.command
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import dev.w1zzrd.spigot.wizcompat.OfflinePlayers
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.*
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
|
||||
class UnInviteCommand(private val claimManager: ClaimManager): CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
assertTrue(sender is Player || args.size == 3, "Command can only be issued by players", sender) && return true
|
||||
assertTrue(
|
||||
args.size in 1..2 || ((sender !is Player || sender.hasPermission("chunkprotector.bypass")) && args.size == 3),
|
||||
"Wrong number of arguments supplied!",
|
||||
sender
|
||||
) && return true
|
||||
|
||||
val targetPlayer = if(args.size == 3) OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[2]) else sender as Player
|
||||
assertTrue(targetPlayer != null, "Could not find given player", sender) && return true
|
||||
assertTrue(args[0] != targetPlayer!!.name, "The owner of a claim cannot be uninvited from said claim", sender) && return true
|
||||
|
||||
val claim = if(args.size == 1) claimManager.getClaimAt((targetPlayer as Player).location.chunk) else claimManager.getClaimByName(targetPlayer, args[1])
|
||||
assertTrue(claim != null && claim.owner == targetPlayer.uniqueId, "Could not find a claim with that name", sender) && return true
|
||||
|
||||
val guest = OfflinePlayers.getKnownPlayer(Bukkit.getServer(), args[0])
|
||||
assertTrue(guest != null, "Cannot find a player with that name", sender) && return true
|
||||
|
||||
if (claim!!.removeGuest(guest!!) && guest.isOnline)
|
||||
(guest as Player).spigot().sendMessage(errorMessage("You have been uninvited from \"${claim.name}\" (owned by ${targetPlayer.name})"))
|
||||
sender.spigot().sendMessage(successMessage("${guest.name} is no longer invited to ${claim.name}"))
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.freecam
|
||||
|
||||
import dev.w1zzrd.spigot.wizcompat.packet.Players
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import org.bukkit.event.player.PlayerTeleportEvent
|
||||
import org.bukkit.plugin.Plugin
|
||||
|
||||
class FreeCamManager {
|
||||
private val freeCammers = ArrayList<FreeCammer>()
|
||||
private val freeCamEventListener = FreeCamEventListener()
|
||||
private val freeCamEnableListeners = ArrayList<(Player) -> Unit>()
|
||||
private val freeCamDisableListeners = ArrayList<(Player) -> Unit>()
|
||||
|
||||
fun disableFreeCam(player: Player): Boolean {
|
||||
val index = freeCammers.binarySearch(FreeCammer(player))
|
||||
|
||||
if (index < 0)
|
||||
return false
|
||||
|
||||
// Disable before removal to prevent TOCTOU (in case I decide to multi-thread this)
|
||||
freeCammers[index].disable()
|
||||
freeCammers.removeAt(index)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun enableFreeCam(player: Player): Boolean {
|
||||
val freeCammer = FreeCammer(player, player.location.clone(), player.gameMode)
|
||||
|
||||
val index = freeCammers.binarySearch(freeCammer)
|
||||
|
||||
if (index >= 0)
|
||||
return false
|
||||
|
||||
// Enable after insertion to prevent TOCTOU (in case I decide to multi-thread this)
|
||||
freeCammers.add(-(index + 1), freeCammer)
|
||||
freeCammer.enable()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun toggleFreeCam(player: Player): Boolean {
|
||||
val freeCammer = FreeCammer(player, player.location.clone(), player.gameMode)
|
||||
|
||||
val index = freeCammers.binarySearch(freeCammer)
|
||||
|
||||
return if (index >= 0) {
|
||||
freeCammers[index].disable()
|
||||
freeCammers.removeAt(index)
|
||||
false
|
||||
} else {
|
||||
freeCammers.add(-(index + 1), freeCammer)
|
||||
freeCammer.enable()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun isFreeCamming(player: Player) = freeCammers.binarySearch(FreeCammer(player)) >= 0
|
||||
|
||||
fun addOnPlayerEnterFreeCam(callback: (Player) -> Unit) = freeCamEnableListeners.add(callback)
|
||||
fun addOnPlayerExitFreeCam(callback: (Player) -> Unit) = freeCamDisableListeners.add(callback)
|
||||
|
||||
fun onEnable(plugin: Plugin) = plugin.server.pluginManager.registerEvents(freeCamEventListener, plugin)
|
||||
fun onDisable() {
|
||||
HandlerList.unregisterAll(freeCamEventListener)
|
||||
|
||||
freeCammers.forEach(FreeCammer::disable)
|
||||
freeCammers.clear()
|
||||
}
|
||||
|
||||
private inner class FreeCamEventListener: Listener {
|
||||
@EventHandler
|
||||
fun onPlayerQuit(event: PlayerQuitEvent) = disableFreeCam(event.player)
|
||||
}
|
||||
|
||||
inner class FreeCammer(val player: Player, val startLocation: Location? = null, val originalMode: GameMode? = null): Comparable<FreeCammer> {
|
||||
|
||||
fun enable() {
|
||||
player.gameMode = GameMode.SPECTATOR
|
||||
Players.sendPlayerGameModePacket(player, GameMode.CREATIVE)
|
||||
|
||||
freeCamEnableListeners.forEach { it(player) }
|
||||
}
|
||||
|
||||
fun disable() {
|
||||
player.teleport(startLocation!!, PlayerTeleportEvent.TeleportCause.PLUGIN)
|
||||
player.gameMode = originalMode!!
|
||||
Players.sendPlayerGameModePacket(player, originalMode)
|
||||
|
||||
freeCamDisableListeners.forEach { it(player) }
|
||||
}
|
||||
|
||||
override fun compareTo(other: FreeCammer) = player.uniqueId.compareTo(other.player.uniqueId)
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.freecam
|
||||
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.player.PlayerTeleportEvent
|
||||
|
||||
data class FreeCammer(val player: Player, val startLocation: Location? = null, val originalMode: GameMode? = null): Comparable<FreeCammer> {
|
||||
|
||||
fun enable() {
|
||||
player.gameMode = GameMode.SPECTATOR
|
||||
}
|
||||
|
||||
fun disable() {
|
||||
player.teleport(startLocation!!, PlayerTeleportEvent.TeleportCause.PLUGIN)
|
||||
player.gameMode = originalMode!!
|
||||
}
|
||||
|
||||
override fun compareTo(other: FreeCammer) = player.uniqueId.compareTo(other.player.uniqueId)
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.kotlin
|
||||
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue
|
||||
import org.bukkit.command.CommandSender
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun <T> assertNotNull(value: T?, errorMessage: String, sender: CommandSender): T? {
|
||||
contract { returnsNotNull() implies (value != null) }
|
||||
|
||||
assertTrue(value != null, errorMessage, sender)
|
||||
|
||||
return value
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.listener
|
||||
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.Claim
|
||||
import dev.w1zzrd.spigot.chunkprotector.claim.ClaimManager
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Chunk
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.entity.Entity
|
||||
import org.bukkit.entity.Monster
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.Cancellable
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.BlockBreakEvent
|
||||
import org.bukkit.event.block.BlockExplodeEvent
|
||||
import org.bukkit.event.block.BlockFromToEvent
|
||||
import org.bukkit.event.block.BlockPlaceEvent
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.entity.EntityExplodeEvent
|
||||
import org.bukkit.event.entity.EntityTargetEvent
|
||||
import org.bukkit.event.entity.PlayerLeashEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerShearEntityEvent
|
||||
|
||||
@Suppress("unused")
|
||||
class PlayerActionListener(private val claimManager: ClaimManager): Listener {
|
||||
@EventHandler
|
||||
fun onPlayerInteract(event: PlayerInteractEvent) =
|
||||
doConditionalCancellation(event.player, event)
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerBreakBlock(event: BlockBreakEvent) =
|
||||
doConditionalCancellation(event.player, event, event.block.location)
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerPlaceBlock(event: BlockPlaceEvent) =
|
||||
doConditionalCancellation(event.player, event, event.blockPlaced.location)
|
||||
|
||||
@EventHandler
|
||||
fun onEntityExplode(event: EntityExplodeEvent) {
|
||||
if (event.isCancelled)
|
||||
return
|
||||
|
||||
filterProtectedBlocks(event.blockList(), Claim::allowEntityInteract)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onBlockExplode(event: BlockExplodeEvent) {
|
||||
if (event.isCancelled)
|
||||
return
|
||||
|
||||
filterProtectedBlocks(event.blockList(), Claim::allowTNT)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onLiquidMove(event: BlockFromToEvent) {
|
||||
if (event.isCancelled)
|
||||
return
|
||||
|
||||
// Cancel the event if a liquid is moving into a claimed area from an area that is not owned by the claimer
|
||||
val toClaim = claimManager.getClaimAt(event.toBlock.chunk) ?: return
|
||||
val fromClaim = claimManager.getClaimAt(event.toBlock.location.subtract(event.face.direction).chunk)
|
||||
if (fromClaim == null) {
|
||||
event.isCancelled = true
|
||||
return
|
||||
}
|
||||
|
||||
if (toClaim.allowAllLiquids || toClaim.owner == fromClaim.owner || (toClaim.allowGuestLiquids && toClaim.hasGuest(Bukkit.getPlayer(fromClaim.owner)!!)))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerInteractEntity(event: PlayerInteractEntityEvent) {
|
||||
if (!event.isCancelled && checkEntityInteraction(event.player, event.rightClicked, Claim::allowPlayerEntityInteract))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerShearEntity(event: PlayerShearEntityEvent) {
|
||||
if (!event.isCancelled && checkEntityInteraction(event.player, event.entity, Claim::allowPlayerEntityInteract))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerLeashEntity(event: PlayerLeashEntityEvent) {
|
||||
if (!event.isCancelled && checkEntityInteraction(event.player, event.entity, Claim::allowPlayerEntityInteract))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerAttractAnimal(event: EntityTargetEvent) {
|
||||
if (!event.isCancelled && event.target is Player && event.reason == EntityTargetEvent.TargetReason.TEMPT && checkEntityInteraction(event.target as Player, event.entity, Claim::allowPlayerEntityInteract))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerAttackMob(event: EntityDamageByEntityEvent) {
|
||||
if (!event.isCancelled && checkEntityInteraction(
|
||||
event.damager,
|
||||
event.entity,
|
||||
if(event.damager is Player) Claim::allowPlayerEntityInteract
|
||||
else Claim::allowEntityInteract
|
||||
))
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
private fun checkEntityInteraction(source: Entity, entity: Entity, permissionType: Claim.() -> Boolean): Boolean {
|
||||
if (entity is Monster && entity.customName == null)
|
||||
return false
|
||||
|
||||
val claim = claimManager.getClaimAt(entity.location.chunk)
|
||||
|
||||
return (claim != null && claim.disablePVP && source is Player && entity is Player) || !(entity is Player || claim == null || claim.permissionType() || (source is Player && (claim.isAccessible(source) || source.hasPermission("chunkprotector.ignore"))))
|
||||
}
|
||||
|
||||
private fun filterProtectedBlocks(changedBlocks: MutableList<Block>, configCheck: Claim.() -> Boolean) {
|
||||
val chunks = HashMap<Chunk, MutableList<Block>>()
|
||||
|
||||
for (block in changedBlocks) {
|
||||
if (block.chunk !in chunks)
|
||||
chunks[block.chunk] = ArrayList()
|
||||
chunks[block.chunk]!!.add(block)
|
||||
}
|
||||
|
||||
for ((chunk, blocks) in chunks) {
|
||||
val claim = claimManager.getClaimAt(chunk)
|
||||
if (claim != null && !claim.configCheck())
|
||||
changedBlocks.removeAll(blocks)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doConditionalCancellation(player: Player, event: Cancellable, eventLocation: Location = player.location) {
|
||||
if (event.isCancelled || player.hasPermission("chunkprotector.ignore"))
|
||||
return
|
||||
|
||||
if (claimManager.getClaimAt(eventLocation.chunk)?.isAccessible(player) == false)
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package dev.w1zzrd.spigot.chunkprotector.listener
|
||||
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.server.TabCompleteEvent
|
||||
|
||||
typealias CompletionProcessor = (CommandSender, List<String>) -> Collection<String>
|
||||
private val SPLITTER = Regex(" +")
|
||||
|
||||
class TabCompleteListener: Listener {
|
||||
|
||||
private val tabCompleters = HashMap<String, CompletionProcessor>()
|
||||
|
||||
@EventHandler
|
||||
fun onTabComplete(event: TabCompleteEvent) {
|
||||
if (!event.isCancelled) {
|
||||
val split = event.buffer.split(SPLITTER)
|
||||
event.completions.addAll((tabCompleters[split[0]] ?: return).invoke(event.sender, if(split.size > 1) split.subList(1, split.size) else emptyList()))
|
||||
}
|
||||
}
|
||||
|
||||
fun registerTabCompleter(command: String, processor: CompletionProcessor) {
|
||||
tabCompleters[command] = processor
|
||||
}
|
||||
|
||||
fun unRegisterTabCompleter(command: String) {
|
||||
tabCompleters.remove(command)
|
||||
}
|
||||
|
||||
fun unRegisterAll() {
|
||||
tabCompleters.clear()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user