├── .githooks
└── pre-commit
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── res
├── command.rdcml
├── plugin.yml
└── redlib
│ └── messages.txt
├── settings.gradle
└── src
└── redempt
└── redlib
├── RedLib.java
├── RedLibConfig.java
├── blockdata
├── BlockDataListener.java
├── BlockDataManager.java
├── BlockPosition.java
├── ChunkPosition.java
├── DataBlock.java
├── backend
│ ├── BlockDataBackend.java
│ ├── PDCBackend.java
│ └── SQLiteBackend.java
├── custom
│ ├── CustomBlock.java
│ ├── CustomBlockRegistry.java
│ └── CustomBlockType.java
└── events
│ ├── CustomBlockPlaceEvent.java
│ ├── DataBlockDestroyEvent.java
│ └── DataBlockMoveEvent.java
├── config
├── ConfigField.java
├── ConfigManager.java
├── ConfigType.java
├── ConversionManager.java
├── annotations
│ ├── Comment.java
│ ├── Comments.java
│ ├── ConfigConstructor.java
│ ├── ConfigMappable.java
│ ├── ConfigName.java
│ ├── ConfigPath.java
│ ├── ConfigPostInit.java
│ └── ConfigSubclassable.java
├── conversion
│ ├── CollectionConverter.java
│ ├── EnumConverter.java
│ ├── MapConverter.java
│ ├── NativeConverter.java
│ ├── ObjectConverter.java
│ ├── PrimitiveConverter.java
│ ├── StaticRootConverter.java
│ ├── StringConverter.java
│ ├── SubclassConverter.java
│ └── TypeConverter.java
├── data
│ ├── ConfigurationSectionDataHolder.java
│ ├── DataHolder.java
│ ├── ListDataHolder.java
│ └── MapDataHolder.java
└── instantiation
│ ├── ConstructorInstantiator.java
│ ├── EmptyInstantiator.java
│ ├── FieldSummary.java
│ └── Instantiator.java
├── dev
├── ChainCommand.java
├── StructureTool.java
└── profiler
│ ├── BurstProfiler.java
│ ├── PassiveProfiler.java
│ ├── Profiler.java
│ ├── ProfilerCommands.java
│ ├── Sample.java
│ ├── SampleSummary.java
│ └── TickMonitorProfiler.java
├── enchants
├── CustomEnchant.java
├── EnchantInfo.java
├── EnchantListener.java
├── EnchantRegistry.java
├── EventItems.java
├── events
│ ├── PlayerChangedArmorEvent.java
│ └── PlayerChangedHeldItemEvent.java
└── trigger
│ ├── AttackEntityTrigger.java
│ ├── EnchantTrigger.java
│ ├── EquipArmorTrigger.java
│ ├── HoldItemTrigger.java
│ ├── KillEntityTrigger.java
│ ├── MineBlockTrigger.java
│ ├── ShootArrowTrigger.java
│ └── TakeDamageTrigger.java
├── inventorygui
├── InventoryGUI.java
├── ItemButton.java
└── PaginationPanel.java
├── itemutils
├── CustomItem.java
├── ItemBuilder.java
├── ItemSerializer.java
├── ItemTrait.java
├── ItemUtils.java
├── LoreStats.java
└── MockInventory.java
├── json
├── JSONList.java
├── JSONMap.java
└── JSONParser.java
├── misc
├── ChatPrompt.java
├── EntityPersistor.java
├── EventListener.java
├── Hologram.java
├── LocationUtils.java
├── Path.java
├── PlayerWrapper.java
├── Task.java
├── UserCache.java
└── WeightedRandom.java
├── multiblock
├── MultiBlockStructure.java
├── Rotator.java
├── Structure.java
├── StructureData.java
└── StructureFinder.java
├── nms
├── NMSArray.java
├── NMSClass.java
├── NMSHelper.java
└── NMSObject.java
├── protection
├── BypassPolicy.java
├── ProtectedRegion.java
├── ProtectionListener.java
├── ProtectionPolicy.java
└── ProtectionRegistrations.java
├── region
├── CuboidRegion.java
├── MultiRegion.java
├── MultiRegionMeta.java
├── Overlappable.java
├── Region.java
├── RegionEnterExitListener.java
├── RegionMap.java
├── RegionUtils.java
├── SelectionTool.java
├── SpheroidRegion.java
└── events
│ ├── RegionEnterEvent.java
│ └── RegionExitEvent.java
├── sql
├── SQLCache.java
├── SQLCacheEntry.java
└── SQLHelper.java
└── worldgen
├── NoiseGenerator.java
└── NoiseOctave.java
/.githooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | sed -E "s/^version: .+/version: $(date -u '+%Y-%m-%d %H:%M')/" -i res/plugin.yml
3 | git add res/plugin.yml
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Eclipse ###
2 | .metadata
3 | bin/
4 | tmp/
5 | *.tmp
6 | *.bak
7 | *.swp
8 | *~.nib
9 | local.properties
10 | .settings/
11 | .loadpath
12 | .recommenders
13 |
14 | # Idea #
15 | .idea
16 |
17 | # External tool builders
18 | .externalToolBuilders/
19 |
20 | # Locally stored "Eclipse launch configurations"
21 | *.launch
22 |
23 | # PyDev specific (Python IDE for Eclipse)
24 | *.pydevproject
25 |
26 | # CDT-specific (C/C++ Development Tooling)
27 | .cproject
28 |
29 | # CDT- autotools
30 | .autotools
31 |
32 | # Java annotation processor (APT)
33 | .factorypath
34 |
35 | # PDT-specific (PHP Development Tools)
36 | .buildpath
37 |
38 | # sbteclipse plugin
39 | .target
40 |
41 | # Tern plugin
42 | .tern-project
43 |
44 | # TeXlipse plugin
45 | .texlipse
46 |
47 | # STS (Spring Tool Suite)
48 | .springBeans
49 |
50 | # Code Recommenders
51 | .recommenders/
52 |
53 | # Annotation Processing
54 | .apt_generated/
55 |
56 | # Scala IDE specific (Scala & Java development for Eclipse)
57 | .cache-main
58 | .scala_dependencies
59 | .worksheet
60 |
61 | ### Eclipse Patch ###
62 | # Eclipse Core
63 | .project
64 |
65 | # JDT-specific (Eclipse Java Development Tools)
66 | .classpath
67 |
68 | # Annotation Processing
69 | .apt_generated
70 |
71 | .sts4-cache/
72 |
73 | ### Java ###
74 | # Compiled class file
75 | *.class
76 |
77 | # Log file
78 | *.log
79 |
80 | # BlueJ files
81 | *.ctxt
82 |
83 | # Mobile Tools for Java (J2ME)
84 | .mtj.tmp/
85 |
86 | # Package Files #
87 | *.jar
88 | *.war
89 | *.nar
90 | *.ear
91 | *.zip
92 | *.tar.gz
93 | *.rar
94 |
95 | ### Gradle ###
96 | .gradle
97 | build/
98 |
99 | # Ignore Gradle GUI config
100 | gradle-app.setting
101 |
102 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
103 | !gradle-wrapper.jar
104 |
105 | # Cache of project
106 | .gradletasknamecache
107 |
108 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
109 | # gradle/wrapper/gradle-wrapper.properties
110 |
111 | ### Gradle Patch ###
112 | **/build/
113 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Julien Marcuse
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RedLib
2 | RedLib is a Spigot plugin development library, designed to make your life easier and soothe the pain points of plugin development. Below, find instructions for the various components of RedLib.
3 |
4 | Support Discord: https://discord.gg/agu5xGy2YZ
5 |
6 | Docs: https://redempt.dev/javadoc/com/github/Redempt/RedLib/index.html
7 |
8 | # Installation for Development
9 |
10 | RedLib is a standalone plugin, but can also be used as a shaded dependency if you do not want to distribute RedLib directly. To use it as a plugin dependency, you must add it as a dependency in your plugin.yml:
11 |
12 | ```yaml
13 | depend: [RedLib]
14 | ```
15 |
16 | To get the jar, either download it from the releases tab either here on [GitHub](https://github.com/Redempt/RedLib/releases) or on [Spigot](https://www.spigotmc.org/resources/redlib.78713/), or [build it locally](https://github.com/Redempt/RedLib#build-locally).
17 |
18 | ## Gradle
19 |
20 | ```groovy
21 | repositories {
22 | maven { url = 'https://redempt.dev' }
23 | }
24 |
25 | ```
26 |
27 | ```groovy
28 | dependencies {
29 | compileOnly 'com.github.Redempt:RedLib:Tag'
30 | }
31 | ```
32 |
33 | Replace `Tag` with a release tag for RedLib. You can see the latest version [here](https://github.com/Redempt/RedLib/releases/latest).
34 |
35 | To shade RedLib, change the dependency from `compileOnly` to `implementation`, and install the [gradle shadow plugin](https://github.com/johnrengelman/shadow).
36 |
37 | If you are having a problem while building, such as plugin.yml is duplicate, try setting duplicatesStrategy to DuplicatesStrategy.EXCLUDE.
38 | ```groovy
39 | tasks {
40 | processResources {
41 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE
42 | }
43 | }
44 | ```
45 |
46 | ## Maven:
47 |
48 | ```xml
49 |
50 | redempt.dev
51 | https://redempt.dev
52 |
53 | ```
54 |
55 | ```xml
56 |
57 | com.github.Redempt
58 | RedLib
59 | Tag
60 | provided
61 |
62 | ```
63 | Replace `Tag` with a release tag for RedLib. You can see the latest version [here](https://github.com/Redempt/RedLib/releases/latest).
64 |
65 | To shade RedLib, change the scope from `provided` to `compile`.
66 |
67 | ## Build locally:
68 |
69 | For Windows, use Git Bash. For Linux or OSX, just ensure you have Git installed.Navigate to the directory where you want to clone the repository, and run:
70 |
71 | ```
72 | git clone https://github.com/Redempt/RedLib
73 | cd RedLib
74 | ./gradlew jar
75 | ```
76 |
77 | After running these commands, the jar will be at `build/libs/RedLib.jar`.
78 | You may also need to add the jar to your classpath. After that, you should be good to go!
79 |
80 | # Usage
81 |
82 | For info on how to use RedLib, please see the [wiki](https://github.com/Redempt/RedLib/wiki).
83 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'com.github.johnrengelman.shadow' version '7.0.0'
4 | id 'maven-publish'
5 | }
6 | targetCompatibility = 1.8
7 | sourceCompatibility = 1.8
8 | repositories {
9 | mavenCentral()
10 | maven { url = 'https://oss.sonatype.org/content/repositories/snapshots' }
11 | maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
12 | maven { url = 'https://redempt.dev' }
13 | mavenLocal()
14 | }
15 | dependencies {
16 | compileOnly 'org.spigotmc:spigot-api:1.18.1-R0.1-SNAPSHOT'
17 | api 'com.github.Redempt:RedCommands:1.5.7'
18 | }
19 | sourceSets {
20 | main {
21 | java {
22 | srcDir 'src'
23 | }
24 | resources {
25 | srcDir 'res'
26 | }
27 | }
28 | }
29 |
30 | jar.configure {
31 | actions.clear()
32 | dependsOn shadowJar
33 | }
34 |
35 | task javadocJar(type: Jar) {
36 | from javadoc
37 | archiveClassifier.set('javadoc')
38 | }
39 |
40 | task sourcesJar(type: Jar) {
41 | from sourceSets.main.allJava
42 | archiveClassifier.set('sources')
43 | }
44 |
45 | shadowJar.configure {
46 | archiveClassifier.set('')
47 | }
48 |
49 | publishing {
50 | publications {
51 | maven(MavenPublication) {
52 | groupId = 'com.github.Redempt'
53 | artifactId = rootProject.name
54 | version = System.env.BUILD_VERSION ?: "1.0"
55 | artifact javadocJar
56 | artifact sourcesJar
57 | from components.java
58 | }
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxbeam/RedLib/5242c84787bb534885aab79a692a6ec8707f4652/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | before_install:
2 | - sdk install java 16.0.1.j9-adpt
3 | - sdk use java 16.0.1.j9-adpt
4 | install:
5 | - ./gradlew publishToMavenLocal
--------------------------------------------------------------------------------
/res/command.rdcml:
--------------------------------------------------------------------------------
1 | structure,struct {
2 | help The structure base command
3 | permission redlib.dev
4 | tool,wand {
5 | user player
6 | help Get a structure dev tool
7 | hook wand
8 | }
9 | create string:name* {
10 | help Register a structure from the selected points for testing
11 | hook create
12 | user player
13 | }
14 | build int<0,3>:rotation?(0) boolean:mirrored?(false) {
15 | help Build the created structure at your location
16 | hook build
17 | user player
18 | }
19 | export string:filename*?(structure) {
20 | help Exports the structure data for the selected points to a file
21 | hook export
22 | user player
23 | }
24 | import string:filename*? {
25 | help Imports the structure data from a file
26 | hook import
27 | user player
28 | }
29 | skip material:type? {
30 | help Sets a block type to skip when scanning, in case you want to use it for the corners
31 | hook skip
32 | user player
33 | }
34 | }
35 | profiler,rprofiler {
36 | permission redlib.dev
37 | monitor {
38 | start int<0,>:--minimum {
39 | help Starts the tick monitor profiler
40 | hook startmonitor
41 | }
42 | setminimum int<0,>:minimum {
43 | help Sets the minimum milliseconds for a tick to take to be reported
44 | hook setminimum
45 | }
46 | clear {
47 | help Clears the tick monitor profiler reports
48 | hook clear
49 | }
50 | reports {
51 | help Shows reports for the longest ticks since the tick monitor profiler started
52 | hook reports
53 | user player
54 | }
55 | select int:num {
56 | notab
57 | hook selectreport
58 | }
59 | }
60 | start {
61 | help Starts or resets the RedLib passive profiler
62 | hook start
63 | }
64 | stop {
65 | help Stops the RedLib passive profiler
66 | hook stop
67 | }
68 | summary {
69 | help Creates and selects a summary from the manual RedLib profiler
70 | hook summary
71 | user player
72 | }
73 | verbose {
74 | help Toggle verbose mode
75 | hook verbose
76 | user player
77 | }
78 | timeformat {
79 | help Toggle time between percentages and milliseconds
80 | hook timeformat
81 | user player
82 | }
83 | root {
84 | help Shows the root method from the selected summary
85 | hook root
86 | user player
87 | }
88 | select string:selector {
89 | hook select
90 | user player
91 | notab
92 | }
93 | up int<1,>:count?(1) {
94 | help Selects the parent method of the currently selected method
95 | hook up
96 | user player
97 | }
98 | collapse {
99 | help Collapses all methods
100 | hook collapse
101 | user player
102 | }
103 | toggleexpand string:selector {
104 | hook toggleexpand
105 | user player
106 | notab
107 | }
108 | search int<0,>:--depth(0) double<0,>:--over-percent(0) int<0,>:--over-milliseconds(0) string:term {
109 | help Searches the profiler with the given conditions
110 | hook search
111 | user player
112 | }
113 | limit int<1,>:amount {
114 | help Limits the number of children that can be shown under a single method
115 | hook limit
116 | user player
117 | }
118 | }
119 | commandchain,cchain commandchain...:commandchain {
120 | help Runs several commands in a row separated by ;
121 | hook commandchain
122 | permission redlib.commandchain
123 | }
--------------------------------------------------------------------------------
/res/plugin.yml:
--------------------------------------------------------------------------------
1 | name: RedLib
2 | main: redempt.redlib.RedLib
3 | version: 2024-02-29 21:48
4 | author: Redempt
5 | api-version: 1.13
6 | load: STARTUP
7 |
--------------------------------------------------------------------------------
/res/redlib/messages.txt:
--------------------------------------------------------------------------------
1 | firstLocationSet: &aFirst location set!
2 | secondLocationSet: &aSecond location set!
3 | cancelPromptMessage: &cType '%canceltext%' to cancel.
4 | cancelText: cancel
5 | teleportDelay: &aPlease stand still for %seconds% seconds to teleport...
6 | teleportCancelled: &cTeleport cancelled!
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This file was generated by the Gradle 'init' task.
3 | *
4 | * The settings file is used to specify which projects to include in your build.
5 | *
6 | * Detailed information about configuring a multi-project build in Gradle can be found
7 | * in the user manual at https://docs.gradle.org/5.4/userguide/multi_project_builds.html
8 | */
9 |
10 | rootProject.name = 'RedLib'
11 |
--------------------------------------------------------------------------------
/src/redempt/redlib/RedLibConfig.java:
--------------------------------------------------------------------------------
1 | package redempt.redlib;
2 |
3 | public class RedLibConfig {
4 |
5 | public static boolean devMode = false;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/redempt/redlib/blockdata/BlockDataListener.java:
--------------------------------------------------------------------------------
1 | package redempt.redlib.blockdata;
2 |
3 | import org.bukkit.Bukkit;
4 | import org.bukkit.block.Block;
5 | import org.bukkit.event.Cancellable;
6 | import org.bukkit.event.Event;
7 | import org.bukkit.event.EventHandler;
8 | import org.bukkit.event.EventPriority;
9 | import org.bukkit.event.Listener;
10 | import org.bukkit.event.block.BlockBreakEvent;
11 | import org.bukkit.event.block.BlockBurnEvent;
12 | import org.bukkit.event.block.BlockExplodeEvent;
13 | import org.bukkit.event.block.BlockPistonEvent;
14 | import org.bukkit.event.block.BlockPistonExtendEvent;
15 | import org.bukkit.event.block.BlockPistonRetractEvent;
16 | import org.bukkit.event.entity.EntityChangeBlockEvent;
17 | import org.bukkit.event.entity.EntityExplodeEvent;
18 | import org.bukkit.plugin.Plugin;
19 | import redempt.redlib.blockdata.events.DataBlockDestroyEvent;
20 | import redempt.redlib.blockdata.events.DataBlockDestroyEvent.DestroyCause;
21 | import redempt.redlib.blockdata.events.DataBlockMoveEvent;
22 | import redempt.redlib.json.JSONMap;
23 |
24 | import java.util.ArrayList;
25 | import java.util.HashMap;
26 | import java.util.List;
27 | import java.util.Map;
28 |
29 | class BlockDataListener implements Listener {
30 |
31 | private BlockDataManager manager;
32 |
33 | public BlockDataListener(BlockDataManager manager, Plugin plugin) {
34 | this.manager = manager;
35 | Bukkit.getPluginManager().registerEvents(this, plugin);
36 | }
37 |
38 | private void fireDestroy(DataBlock db, Event parent, DestroyCause cause) {
39 | if (db == null) {
40 | return;
41 | }
42 | DataBlockDestroyEvent ev = new DataBlockDestroyEvent(db, parent, cause);
43 | Bukkit.getPluginManager().callEvent(ev);
44 | if (!ev.isCancelled()) {
45 | manager.remove(db);
46 | }
47 | }
48 |
49 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
50 | public void onBreak(BlockBreakEvent e) {
51 | DataBlock db = manager.getDataBlock(e.getBlock(), false);
52 | fireDestroy(db, e, DestroyCause.PLAYER_BREAK);
53 | }
54 |
55 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
56 | public void onExplode(BlockExplodeEvent e) {
57 | handleExplosion(e.blockList(), e);
58 | }
59 |
60 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
61 | public void onExplode(EntityExplodeEvent e) {
62 | handleExplosion(e.blockList(), e);
63 | }
64 |
65 | private void handleExplosion(List blocks, Cancellable e) {
66 | List toRemove = new ArrayList<>();
67 | blocks.forEach(b -> {
68 | DataBlock db = manager.getDataBlock(b);
69 | if (db == null) {
70 | return;
71 | }
72 | DataBlockDestroyEvent ev = new DataBlockDestroyEvent(db, (Event) e, DestroyCause.EXPLOSION);
73 | Bukkit.getPluginManager().callEvent(ev);
74 | if (!ev.isCancelled()) {
75 | toRemove.add(db);
76 | }
77 | });
78 | if (e.isCancelled()) {
79 | return;
80 | }
81 | toRemove.forEach(manager::remove);
82 | }
83 |
84 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
85 | public void onCombust(BlockBurnEvent e) {
86 | DataBlock db = manager.getDataBlock(e.getBlock());
87 | fireDestroy(db, e, DestroyCause.COMBUST);
88 | }
89 |
90 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
91 | public void onPistonExtend(BlockPistonExtendEvent e) {
92 | handlePiston(e.getBlocks(), e);
93 | }
94 |
95 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
96 | public void onPistonRetract(BlockPistonRetractEvent e) {
97 | handlePiston(e.getBlocks(), e);
98 | }
99 |
100 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
101 | public void onEntityChangeBlock(EntityChangeBlockEvent e) {
102 | DataBlock db = manager.getDataBlock(e.getBlock());
103 | fireDestroy(db, e, DestroyCause.ENTITY);
104 | }
105 |
106 | private void handlePiston(List blocks, BlockPistonEvent e) {
107 | List toMove = new ArrayList<>();
108 | blocks.forEach(b -> {
109 | DataBlock db = manager.getDataBlock(b);
110 | if (db == null) {
111 | return;
112 | }
113 | Block destination = db.getBlock().getRelative(e.getDirection());
114 | DataBlockMoveEvent ev = new DataBlockMoveEvent(db, destination, e);
115 | Bukkit.getPluginManager().callEvent(ev);
116 | if (!ev.isCancelled()) {
117 | toMove.add(db);
118 | }
119 | });
120 | if (e.isCancelled()) {
121 | return;
122 | }
123 | Map moved = new HashMap<>();
124 | toMove.forEach(db -> {
125 | Block destination = db.getBlock().getRelative(e.getDirection());
126 | moved.put(destination, db.data);
127 | });
128 | toMove.forEach(manager::remove);
129 | moved.forEach((block, data) -> {
130 | manager.getDataBlock(block).data = data;
131 | });
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/redempt/redlib/blockdata/BlockPosition.java:
--------------------------------------------------------------------------------
1 | package redempt.redlib.blockdata;
2 |
3 | import org.bukkit.Location;
4 | import org.bukkit.World;
5 | import org.bukkit.block.Block;
6 |
7 | import java.util.Objects;
8 |
9 | class BlockPosition {
10 |
11 | private final int x;
12 | private final int y;
13 | private final int z;
14 |
15 | public BlockPosition(int x, int y, int z) {
16 | this.x = x;
17 | this.y = y;
18 | this.z = z;
19 | }
20 |
21 | public BlockPosition(Block block) {
22 | this(block.getX(), block.getY(), block.getZ());
23 | }
24 |
25 | public int getX() {
26 | return x;
27 | }
28 |
29 | public int getY() {
30 | return y;
31 | }
32 |
33 | public int getZ() {
34 | return z;
35 | }
36 |
37 | public Block getBlock(World world) {
38 | return world.getBlockAt(x, y, z);
39 | }
40 |
41 | public Location getLocation(World world) {
42 | return new Location(world, x, y, z);
43 | }
44 |
45 | @Override
46 | public int hashCode() {
47 | return Objects.hash(x, y, z);
48 | }
49 |
50 | @Override
51 | public boolean equals(Object o) {
52 | if (!(o instanceof BlockPosition)) {
53 | return false;
54 | }
55 | BlockPosition pos = (BlockPosition) o;
56 | return pos.x == x && pos.y == y && pos.z == z;
57 | }
58 |
59 | @Override
60 | public String toString() {
61 | return x + " " + y + " " + z;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/redempt/redlib/blockdata/ChunkPosition.java:
--------------------------------------------------------------------------------
1 | package redempt.redlib.blockdata;
2 |
3 | import org.bukkit.Bukkit;
4 | import org.bukkit.Chunk;
5 | import org.bukkit.World;
6 | import org.bukkit.block.Block;
7 |
8 | import java.util.Objects;
9 |
10 | /**
11 | * Represents a world and chunk X and Z
12 | *
13 | * @author Redempt
14 | */
15 | public class ChunkPosition {
16 |
17 | private final int x;
18 | private final int z;
19 | private final String world;
20 |
21 | /**
22 | * Creates a ChunkPosition from a chunk
23 | *
24 | * @param chunk The chunk to create a position for
25 | */
26 | public ChunkPosition(Chunk chunk) {
27 | this(chunk.getX(), chunk.getZ(), chunk.getWorld().getName());
28 | }
29 |
30 | /**
31 | * Creates a ChunkPosition from a Block
32 | *
33 | * @param block The Block to create a position for
34 | */
35 | public ChunkPosition(Block block) {
36 | this(new BlockPosition(block), block.getWorld().getName());
37 | }
38 |
39 | /**
40 | * Creates a ChunkPosition from chunk coordinates and a world name
41 | *
42 | * @param x The chunk X
43 | * @param z The chunk Z
44 | * @param world The world name
45 | */
46 | public ChunkPosition(int x, int z, String world) {
47 | this.x = x;
48 | this.z = z;
49 | this.world = world;
50 | }
51 |
52 | public ChunkPosition(BlockPosition bPos, String world) {
53 | this(bPos.getX() >> 4, bPos.getZ() >> 4, world);
54 | }
55 |
56 | /**
57 | * @return The chunk X
58 | */
59 | public int getX() {
60 | return x;
61 | }
62 |
63 | /**
64 | * @return The chunk Z
65 | */
66 | public int getZ() {
67 | return z;
68 | }
69 |
70 | /**
71 | * @return The world this ChunkPosition is in
72 | */
73 | public World getWorld() {
74 | return Bukkit.getWorld(world);
75 | }
76 |
77 | /**
78 | * @return The name of the world this ChunkPosition is in
79 | */
80 | public String getWorldName() {
81 | return world;
82 | }
83 |
84 | /**
85 | * Gets the chunk
86 | *
87 | * @return The chunk at this position
88 | * @throws IllegalStateException if the world is not loaded
89 | */
90 | public Chunk getChunk() {
91 | World world = this.getWorld();
92 | if (world == null) {
93 | throw new IllegalStateException("World " + this.world + " is not loaded");
94 | }
95 | return world.getChunkAt(x, z);
96 | }
97 |
98 | @Override
99 | public int hashCode() {
100 | return Objects.hash(x, z, world);
101 | }
102 |
103 | @Override
104 | public String toString() {
105 | return world + " " + x + " " + z;
106 | }
107 |
108 | @Override
109 | public boolean equals(Object o) {
110 | if (!(o instanceof ChunkPosition)) {
111 | return false;
112 | }
113 | ChunkPosition pos = (ChunkPosition) o;
114 | return pos.x == x && pos.z == z && world.equals(pos.world);
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/redempt/redlib/blockdata/DataBlock.java:
--------------------------------------------------------------------------------
1 | package redempt.redlib.blockdata;
2 |
3 | import org.bukkit.Bukkit;
4 | import org.bukkit.block.Block;
5 | import redempt.redlib.json.JSONList;
6 | import redempt.redlib.json.JSONMap;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 | import java.util.Set;
11 |
12 | /**
13 | * Represents a Block with data attached to it
14 | *
15 | * @author Redempt
16 | */
17 | public class DataBlock {
18 |
19 | protected JSONMap data;
20 | private BlockDataManager manager;
21 | private BlockPosition block;
22 | private String world;
23 | private Map transientProperties;
24 |
25 | DataBlock(JSONMap data, BlockPosition block, String world, BlockDataManager manager) {
26 | this.data = data;
27 | this.block = block;
28 | this.manager = manager;
29 | this.world = world;
30 | }
31 |
32 | /**
33 | * @return The BlockDataManager this DataBlock belongs to
34 | */
35 | public BlockDataManager getManager() {
36 | return manager;
37 | }
38 |
39 | /**
40 | * @return A map which can be used to store properties that do not persist
41 | */
42 | public Map getTransientProperties() {
43 | if (transientProperties == null) {
44 | transientProperties = new HashMap<>();
45 | }
46 | return transientProperties;
47 | }
48 |
49 | /**
50 | * @return The Block the data is attached to
51 | */
52 | public Block getBlock() {
53 | return Bukkit.getWorld(world).getBlockAt(block.getX(), block.getY(), block.getZ());
54 | }
55 |
56 | protected ChunkPosition getChunkPosition() {
57 | return new ChunkPosition(block, world);
58 | }
59 |
60 | protected BlockPosition getBlockPosition() {
61 | return block;
62 | }
63 |
64 | /**
65 | * Gets an object by key
66 | *
67 | * @param key The key the data is mapped to
68 | * @return The data as an Object
69 | */
70 | public Object getObject(String key) {
71 | return data.get(key);
72 | }
73 |
74 | /**
75 | * Gets a string by key
76 | *
77 | * @param key The key the data is mapped to
78 | * @return The data as a String
79 | */
80 | public String getString(String key) {
81 | return data.getString(key);
82 | }
83 |
84 | /**
85 | * Gets an int by key
86 | *
87 | * @param key The key the data is mapped to
88 | * @return The data as an Integer
89 | */
90 | public Integer getInt(String key) {
91 | return data.getInt(key);
92 | }
93 |
94 | /**
95 | * Gets a long by key
96 | *
97 | * @param key The key the data is mapped to
98 | * @return The data as a Long
99 | */
100 | public Long getLong(String key) {
101 | return data.getLong(key);
102 | }
103 |
104 | /**
105 | * Gets a Double by key
106 | *
107 | * @param key The key the data is mapped to
108 | * @return The data as a Double
109 | */
110 | public Double getDouble(String key) {
111 | return data.getDouble(key);
112 | }
113 |
114 | /**
115 | * Gets a Boolean by key
116 | *
117 | * @param key The key the data is mapped to
118 | * @return The data as a Boolean
119 | */
120 | public Boolean getBoolean(String key) {
121 | return data.getBoolean(key);
122 | }
123 |
124 | /**
125 | * Gets a JSONList by key
126 | *
127 | * @param key The key the data is mapped to
128 | * @return The data as a JSONList
129 | */
130 | public JSONList getList(String key) {
131 | return data.getList(key);
132 | }
133 |
134 | /**
135 | * Gets a JSONMap by key
136 | *
137 | * @param key The key the data is mapped to
138 | * @return The data as a JSONMap
139 | */
140 | public JSONMap getMap(String key) {
141 | return data.getMap(key);
142 | }
143 |
144 | /**
145 | * Checks if a certain key is used in this DataBlock
146 | *
147 | * @param key The key
148 | * @return Whether the key is used
149 | */
150 | public boolean contains(String key) {
151 | return data.containsKey(key);
152 | }
153 |
154 | /**
155 | * Clears all data from this DataBlock
156 | */
157 | public void clear() {
158 | data.clear();
159 | }
160 |
161 | /**
162 | * Sets data in this DataBlock
163 | *
164 | * @param key The key to set the data with
165 | * @param value The data
166 | */
167 | public void set(String key, Object value) {
168 | manager.setModified(new ChunkPosition(block, world));
169 | if (value == null) {
170 | data.remove(key);
171 | return;
172 | }
173 | data.put(key, value);
174 | }
175 |
176 | /**
177 | * Removes a key from this DataBlock
178 | *
179 | * @param key The key to remove
180 | */
181 | public void remove(String key) {
182 | set(key, null);
183 | }
184 |
185 | /**
186 | * @return All data stored in this DataBlock
187 | */
188 | public Map getData() {
189 | return data;
190 | }
191 |
192 | /**
193 | * @return All keys used in this DataBlock
194 | */
195 | public Set getKeys() {
196 | return data.keySet();
197 | }
198 |
199 | }
200 |
--------------------------------------------------------------------------------
/src/redempt/redlib/blockdata/backend/BlockDataBackend.java:
--------------------------------------------------------------------------------
1 | package redempt.redlib.blockdata.backend;
2 |
3 | import org.bukkit.plugin.Plugin;
4 | import redempt.redlib.blockdata.BlockDataManager;
5 | import redempt.redlib.blockdata.ChunkPosition;
6 |
7 | import java.nio.file.Path;
8 | import java.util.Map;
9 | import java.util.concurrent.CompletableFuture;
10 |
11 | /**
12 | * Represents a data backend for a BlockDataManager
13 | *
14 | * @author Redempt
15 | */
16 | public interface BlockDataBackend {
17 |
18 | /**
19 | * Creates a new BlockDataBackend backed by PersistentDataContainer
20 | *
21 | * @param plugin The plugin that owns the BlockDataManager
22 | * @return The BlockDataBackend
23 | */
24 | public static BlockDataBackend pdc(Plugin plugin) {
25 | return new PDCBackend(plugin);
26 | }
27 |
28 | /**
29 | * Creates a new BlockDataBackend backed by SQLite
30 | *
31 | * @param path The path to the SQLite database
32 | * @return The BlockDataBackend
33 | */
34 | public static BlockDataBackend sqlite(Path path) {
35 | return new SQLiteBackend(path);
36 | }
37 |
38 | /**
39 | * Loads the String data for a given chunk
40 | *
41 | * @param pos The location of the chunk
42 | * @return A CompletableFuture with the String data
43 | */
44 | public CompletableFuture load(ChunkPosition pos);
45 |
46 | /**
47 | * Saves String data for a given chunk
48 | *
49 | * @param pos The location of the chunk
50 | * @param data The data to save
51 | * @return A CompletableFuture for the saving task
52 | */
53 | public CompletableFuture save(ChunkPosition pos, String data);
54 |
55 | /**
56 | * Removes the data attached to a given chunk
57 | *
58 | * @param pos The location of the chunk
59 | * @return A CompletableFuture for the removal task
60 | */
61 | public CompletableFuture remove(ChunkPosition pos);
62 |
63 | /**
64 | * Saves all data that has been modified with this BlockDataBackend
65 | *
66 | * @return A CompletableFuture for the saving task
67 | */
68 | public CompletableFuture saveAll();
69 |
70 | /**
71 | * Closes and cleans up any connections if needed
72 | *
73 | * @return A CompletableFuture for the closing task
74 | */
75 | public CompletableFuture close();
76 |
77 | /**
78 | * Attempts to load all data stored in the backend, not supported by PDC
79 | *
80 | * @return A CompletableFuture with all the data
81 | */
82 | public CompletableFuture