15 Commits
Author SHA1 Message Date
Intelli 32fd97f768 Update build version 2024-05-13 18:06:41 -06:00
Intelli d45ac1b275 Set Maven to build against Java 21 2024-05-13 18:06:41 -06:00
Intelli cd7a71648b Set current API documentation version as v10
# Conflicts:
#	docs/api/version/v10.md
2024-05-13 18:06:41 -06:00
Intelli dc87d4fbf4 Minor refactoring on Rollback class 2024-05-13 18:06:13 -06:00
Intelli f8a8e3f657 Cleanup 2024-05-13 18:06:13 -06:00
TelesphoreoandIntelli 52c5b28b79 Fix FAWE logging on newer builds (#528)
* Fix FAWE logging on newer builds

* fix regular WE logging

* Fix registering of FAWE for event bus

* Remove jcenter

* Add missing `replaceBlocks` method

* Remove FAWE toggle entirely

* oops, i can't do it that way

---------

Co-authored-by: Intelli <6790859+Intelli@users.noreply.github.com>
2024-05-13 18:06:13 -06:00
Intelli 90a2981603 Only validate skull owner name length if using MySQL 2024-05-13 18:06:13 -06:00
Intelli fbc68766f6 Fixed MysqlDataTruncation error when logging custom skull data 2024-05-13 18:06:13 -06:00
Intelli 667061a9fe Fixed unnecessary database transactions when consumer is empty (fixes #511) 2024-05-13 18:06:13 -06:00
Intelli 2e2e5a9857 Fixed obfuscation in item names making tooltips unreadable (fixes #487) 2024-05-13 18:06:13 -06:00
Intelli 79e0ca7b13 Fixed NoSuchMethodError for arrows on MC 1.20/1.20.1 2024-05-13 18:06:13 -06:00
Intelli a3a6d398de Added required version for disabling block logging in documentation
# Conflicts:
#	docs/config.md
2024-05-13 17:54:41 -06:00
Intelli 7c7dce0048 Fixed occasional NullPointerException while processing hopper transactions (fixes #539) 2024-05-13 17:53:16 -06:00
Intelli acfb6fce7a Corrected version references in API v10 documentation 2024-05-13 17:53:16 -06:00
Intelli 152c37e85a Added thread-safe logPlacement and logRemoval API methods 2024-05-13 17:53:16 -06:00
26 changed files with 1598 additions and 839 deletions

No files matched your search

+1 -1
View File
@@ -41,7 +41,7 @@ Maven
<dependency>
<groupId>net.coreprotect</groupId>
<artifactId>coreprotect</artifactId>
<version>22.3</version>
<version>22.4</version>
<scope>provided</scope>
</dependency>
```
+7 -9
View File
@@ -2,16 +2,16 @@ import org.apache.tools.ant.filters.ReplaceTokens
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.2'
id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'com.palantir.git-version' version '0.13.0'
}
group = 'net.coreprotect'
String projectVersion = '22.3'
String projectVersion = '22.4'
String projectBranch = ''
version = projectVersion // `version` might be modified, we don't always want that (e.g. plugin.yml)
description = 'Provides block protection for your server.'
sourceCompatibility = '17'
sourceCompatibility = '21'
if (System.getenv("BUILD_NUMBER") != null) {
// Being built in Jenkins, append Build ID
@@ -23,17 +23,15 @@ if (System.getenv("BUILD_NUMBER") != null) {
logger.info("Building version $version")
repositories {
jcenter()
maven { url = 'https://hub.spigotmc.org/nexus/content/groups/public/' }
maven { url = 'https://papermc.io/repo/repository/maven-public/' }
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
maven { url = 'https://repo.codemc.org/repository/maven-public/' }
maven { url = 'https://maven.enginehub.org/repo/' }
}
dependencies {
compileOnly('com.sk89q.worldedit:worldedit-bukkit:7.0.0-SNAPSHOT') {
exclude group: 'org.bukkit'
}
implementation(platform("com.intellectualsites.bom:bom-newest:1.44")) // Ref: https://github.com/IntellectualSites/bom
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core")
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit")
compileOnly 'io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT'
implementation 'org.bstats:bstats-bukkit-lite:1.8'
implementation 'com.zaxxer:HikariCP:5.0.1'
+3 -3
View File
@@ -4,8 +4,8 @@ The CoreProtect API enables you to log your own block changes, perform lookups,
| API Details | |
| --- | --- |
| **API Version:** | 9 |
| **Plugin Version:** | v21.0+ |
| **API Version:** | 10 |
| **Plugin Version:** | v22.4+ |
| **Maven:** | [maven.playpro.com](https://maven.playpro.com) |
*Documentation for the API version 9 can be found [here](/api/version/v9/).*
*Documentation for the API version 10 can be found [here](/api/version/v10/).*
+526
View File
@@ -0,0 +1,526 @@
# API Version 10
The CoreProtect API enables you to log your own block changes, perform lookups, rollbacks, restores, and more.
| API Details | |
| --- | --- |
| **API Version:** | 10 |
| **Plugin Version:** | v22.4+ |
| **Maven:** | [maven.playpro.com](https://maven.playpro.com) |
---
## Upgrading from API v9
The changes from the previous API version are as follows:
- The following methods have been added:
```java
logPlacement(String user, BlockState blockState)
logRemoval(String user, BlockState blockState)
```
---
## Getting Started
Ensure you're using CoreProtect 22.4 or higher. Add it as an external jar to your plugin in your IDE.
Alternatively, if using Maven, you can add it via the repository [https://maven.playpro.com](https://maven.playpro.com) (net.coreprotect, 22.4).
The first thing you need to do is get access to CoreProtect. You can do this by using code similar to the following:
```java
import net.coreprotect.CoreProtect;
import net.coreprotect.CoreProtectAPI;
private CoreProtectAPI getCoreProtect() {
Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect");
// Check that CoreProtect is loaded
if (plugin == null || !(plugin instanceof CoreProtect)) {
return null;
}
// Check that the API is enabled
CoreProtectAPI CoreProtect = ((CoreProtect) plugin).getAPI();
if (CoreProtect.isEnabled() == false) {
return null;
}
// Check that a compatible version of the API is loaded
if (CoreProtect.APIVersion() < 10) {
return null;
}
return CoreProtect;
}
```
With this code, you can then access the API with a call like the following:
```java
CoreProtectAPI api = getCoreProtect();
if (api != null){ // Ensure we have access to the API
api.testAPI(); // Will print out "[CoreProtect] API test successful." in the console.
}
```
Yay, you're now using the CoreProtect API!
---
## API Overview
### Available Methods
```java
boolean isEnabled()
void testAPI()
List<String[]> performLookup(int time, List<String> restrict_users, List<String> exclude_users, List<Object> restrict_blocks, List<Object> exclude_blocks, List<Integer> action_list, int radius, Location radius_location)
List<String[]> performRollback(int time, List<String> restrict_users, List<String> exclude_users, List<Object> restrict_blocks, List<Object> exclude_blocks, List<Integer> action_list, int radius, Location radius_location)
List<String[]> performRestore(int time, List<String> restrict_users, List<String> exclude_users, List<Object> restrict_blocks, List<Object> exclude_blocks, List<Integer> action_list, int radius, Location radius_location)
List<String[]> blockLookup(Block block, int time)
List<String[]> sessionLookup(String user, int time)
List<String[]> queueLookup(Block block)
ParseResult parseResult(String[] result)
boolean logChat(Player player, String message)
boolean logCommand(Player player, String command)
boolean logPlacement(String user, BlockState blockState)
boolean logPlacement(String user, Location location, Material type, BlockData blockData)
boolean logRemoval(String user, BlockState blockState)
boolean logRemoval(String user, Location location, Material type, BlockData blockData)
boolean logContainerTransaction(String user, Location location)
boolean logInteraction(String user, Location location)
boolean hasPlaced(String user, Block block, int time, int offset)
boolean hasRemoved(String user, Block block, int time, int offset)
void performPurge(int time)
```
---
### Available Events
*The following events are emitted by CoreProtect.*
#### CoreProtectPreLogEvent
Fired when a CoreProtect logger is about to log an action. Cancellable.
| Property | Description | Mutable |
| --- | --- | --- |
| User | The name of the user under which this action will be logged. | Yes |
| Cancelled | If cancelled, the action won't be logged to the database. | Yes |
---
### Method Usage
*Detailed method information is listed below.*
#### `isEnabled()`
Calling this will return true if the server has the CoreProtect API enabled, and false if it does not.
---
#### `testAPI()`
Running this will print out "[CoreProtect] API Test Successful." in the server console.
---
#### `performLookup(int time, List<String> restrict_users, List<String> exclude_users, List<Object> restrict_blocks, List<Object> exclude_blocks, List<Integer> action_list, int radius, Location radius_location)`
This will perform a lookup.
* **time:** Specify the amount of time to search back. "5" would return results from the last 5 seconds.
* **restrict_users:** Specify any usernames to perform the lookup on. Can be set to "null" if both a radius and a location are specified.
* **exclude_users:** Specify any usernames to exclude from the lookup. Can be set to "null".
* **restrict_blocks:** Specify a list of EntityType's or Material's to restrict the search to. Can be set to "null".
* **exclude_blocks:** Specify a list of EntityType's or Material's to exclude from the search. Can be set to "null".
* **action_list:** Specify a list of action types to restrict the search to. Can be set to "null"
* **radius:** Specify a radius to restrict the search to. A location must be specified if using this. Set to "0" to disable.
* **radius_location:** Specify a location to search around. Can be set to "null" if no radius is specified, and a user is specified.
---
#### `performRollback(int time, List<String> restrict_users, List<String> exclude_users, List<Object> restrict_blocks, List<Object> exclude_blocks, List<Integer> action_list, int radius, Location radius_location)`
This will perform a rollback. Method must be called async.
* **time:** Specify the amount of time to rollback. "5" would return results from the last 5 seconds.
* **restrict_users:** Specify any usernames to perform the rollback on. Can be set to "null" if both a radius and a location are specified.
* **exclude_users:** Specify any usernames to exclude from the rollback. Can be set to "null".
* **restrict_blocks:** Specify a list of EntityType's or Material's to restrict the rollback to. Can be set to "null".
* **exclude_blocks:** Specify a list of EntityType's or Material's to exclude from the rollback. Can be set to "null".
* **action_list:** Specify a list of action types to restrict the rollback to. Can be set to "null"
* **radius:** Specify a radius to restrict the rollback to. A location must be specified if using this. Set to "0" to disable.
* **radius_location:** Specify a location to rollback around. Can be set to "null" if no radius is specified, and a user is specified.
---
#### `performRestore(int time, List<String> restrict_users, List<String> exclude_users, List<Object> restrict_blocks, List<Object> exclude_blocks, List<Integer> action_list, int radius, Location radius_location)`
This will perform a restore.
* **time:** Specify the amount of time to restore. "5" would return results from the last 5 seconds.
* **restrict_users:** Specify any usernames to perform the restore on. Can be set to "null" if both a radius and a location are specified.
* **exclude_users:** Specify any usernames to exclude from the restore. Can be set to "null".
* **restrict_blocks:** Specify a list of EntityType's or Material's to restrict the restore to. Can be set to "null".
* **exclude_blocks:** Specify a list of EntityType's or Material's to exclude from the restore. Can be set to "null".
* **action_list:** Specify a list of action types to restrict the restore to. Can be set to "null"
* **radius:** Specify a radius to restrict the restore to. A location must be specified if using this. Set to "0" to disable.
* **radius_location:** Specify a location to restore around. Can be set to "null" if no radius is specified, and a user is specified.
---
#### `blockLookup(Block block, int time)`
This will perform a full lookup on a single block.
* **block:** The block to perform the lookup on.
* **time:** Specify the amount of time to lookup. "5" would return results from the last 5 seconds.
---
#### `queueLookup(Block block)`
This will search the consumer queue for changes on a block not yet saved in the database.
* **block:** The block to perform the lookup on.
---
#### `sessionLookup(String user, int time)`
This will perform a session lookup on a single player.
* **user:** The username to perform the lookup on.
* **time:** Specify the amount of time to lookup. "5" would return results from the last 5 seconds.
---
#### `ParseResult parseResult(String[] result)`
This will parse results from a lookup. You'll then be able to view the following:
* **getX():** Get the X coordinate of the block.
* **getY():** Get the Y coordinate of the block.
* **getZ():** Get the Z coordinate of the block.
* **getType():** Get the Material of the block.
* **getBlockData():** Get the BlockData of the block.
* **getPlayer():** Get the username as a string.
* **getTimestamp():** Get the time of the action.
* **getActionId():** Get the action ID. (0=removed, 1=placed, 2=interaction)
* **getActionString():** Get the action as a string. (Removal, Placement, Interaction)
* **isRolledBack():** If the block is currently rolled back or not.
* **worldName():** The name of the world the block is located in.
---
#### `logPlacement(String user, BlockState blockState)`
This will log a block as being placed. *(Thread safe)*
* **user:** Specify the username to log as having placed the block.
* **blockState:** Specify the BlockState of the block you're logging.
---
#### `logPlacement(String user, Location location, Material type, BlockData blockData)`
This will log a block as being placed.
* **user:** Specify the username to log as having placed the block.
* **location:** Specify the location of the block you're logging.
* **type:** Specify the Material of the block you're logging.
* **blockData:** Specify the BlockData of the block you're logging. Can be set to "null".
---
#### `logRemoval(String user, BlockState blockState)`
This will log a block as being removed/broken. *(Thread safe)*
* **user:** Specify the username to log as having removed the block.
* **blockState:** Specify the BlockState of the block you're logging.
---
#### `logRemoval(String user, Location location, Material type, BlockData blockData)`
This will log a block as being removed/broken, and will log the block's inventory (if applicable).
* **user:** Specify the username to log as having removed the block.
* **location:** Specify the location of the block you're logging.
* **type:** Specify the Material of the block you're logging.
* **blockData:** Specify the BlockData of the block you're logging. Can be set to "null".
---
#### `logContainerTransaction(String user, Location location)`
This will log any transactions made to a block's inventory immediately after calling the method.
* **user:** Specify the username to log as having added/removed the items.
* **location:** Specify the location of the block inventory you're logging.
---
#### `logInteraction(String user, Location location)`
This will log a block as having been interacted with.
* **user:** Specify the username to log as having caused the interaction.
* **location:** Specify the location of the interaction you're logging.
---
#### `hasPlaced(String user, Block block, int time, int offset)`
This will return true if a user has already placed a block at the location within the specified time limit.
* **user:** The username you're checking to see if they've placed a block already.
* **block:** The block you're checking.
* **time:** How far back to check. "5" would only check through the last 5 seconds of logged blocks.
* **offset:** A time offset. "2" would ignore the last 2 seconds of most recently ignored data. (0 = no offset)
---
#### `hasRemoved(String user, Block block, int time, int offset)`
This will return true if a user has already removed a block at the location within the specified time limit.
* **user:** The username you're checking to see if they've removed a block already.
* **block:** The block you're checking.
* **time:** How far back to check. "5" would only check through the last 5 seconds of logged blocks.
* **offset:** A time offset. "2" would ignore the last 2 seconds of most recently ignored data. (0 = no offset)
---
#### `performPurge(int time)`
This will perform a purge on the CoreProtect database.
* **time:** Purge any data earlier than this. "120" would purge any data older than 120 seconds (2 minutes).
---
### Examples
- Get the last 60 seconds of block data for the user "Notch".
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
List<String[]> lookup = CoreProtect.performLookup(60, Arrays.asList("Notch"), null, null, null, null, 0, null);
if (lookup != null){
for (String[] result : lookup){
ParseResult parseResult = CoreProtect.parseResult(result);
int x = parseResult.getX();
int y = parseResult.getY();
int z = parseResult.getZ();
// ...
}
}
}
```
---
- Get the last 60 seconds of block data for the user "Notch", excluding dirt and grass blocks.
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
List<Object> exclude = Arrays.asList(Material.DIRT, Material.GRASS);
List<String[]> lookup = CoreProtect.performLookup(60, Arrays.asList("Notch"), null, null, exclude, null, 0, null);
if (lookup != null){
for (String[] value : lookup){
ParseResult result = CoreProtect.parseResult(value);
int x = result.getX();
int y = result.getY();
int z = result.getZ();
// ...
}
}
}
```
---
- Get the last 60 seconds of block data within 5 blocks of a location.
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
List<String[]> lookup = CoreProtect.performLookup(60, null, null, null, null, null, 5, location);
if (lookup != null){
for (String[] value : lookup){
ParseResult result = CoreProtect.parseResult(value);
int x = result.getX();
int y = result.getY();
int z = result.getZ();
// ...
}
}
}
```
---
- Rollbacks / restores use the same code structure as the above examples. For example:
```java
class BasicThread implements Runnable {
@Override
public void run() {
try {
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
List<String[]> lookup = CoreProtect.performRollback(60, Arrays.asList("Notch"), null, null, null, null, 0, null);
if (lookup != null){
for (String[] value : lookup){
ParseResult result = CoreProtect.parseResult(value);
int x = result.getX();
int y = result.getY();
int z = result.getZ();
// ...
}
}
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
Runnable runnable = new BasicThread();
Thread thread = new Thread(runnable);
thread.start();
```
---
- Check if the user "Notch" has already placed a block at a location within the last 60 seconds.
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
boolean hasPlaced = CoreProtect.hasPlaced("Notch", block, 60, 0);
// Search queue for pending changes
if (!hasPlaced){
List<String[]> lookup = CoreProtect.queueLookup(block);
for (String[] result : lookup){
ParseResult parseResult = CoreProtect.parseResult(result);
if (parseResult.getActionId()==1 && parseResult.getPlayer().equals("Notch")){
hasPlaced = true;
break;
}
}
}
}
```
---
- Get the last 60 seconds of block data for a specific block.
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
List<String[]> lookup = CoreProtect.blockLookup(block, 60);
if (lookup != null){
for (String[] result : lookup){
ParseResult parseResult = CoreProtect.parseResult(result);
int x = parseResult.getX();
int y = parseResult.getY();
int z = parseResult.getZ();
// ...
}
}
}
```
---
- Get the last 1 day of session data for the user "Notch".
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
List<String[]> lookup = CoreProtect.sessionLookup("Notch", (24 * 60 * 60));
if (lookup != null){
for (String[] result : lookup){
ParseResult parseResult = CoreProtect.parseResult(result);
int x = parseResult.getX();
int y = parseResult.getY();
int z = parseResult.getZ();
int action = parseResult.getActionId(); // 0 = logout, 1 = login
// ...
}
}
}
```
---
- Log the placement of a block at a location by the user "Notch".
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
boolean success = CoreProtect.logPlacement("Notch", block.getLocation(), block.getType(), block.getData());
}
```
---
- Log adding/remove items in a chest (or some other block inventory).
```java
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
boolean success = CoreProtect.logContainerTransaction("Notch", inventory.getLocation());
// modify your container contents immediately after (e.g. [i]inventory.addItem(itemStack);[/i])
}
```
---
- Perform a multi-threaded placement check to see if the user "Notch" has already placed a block at a location within the last 60 seconds. This ignores the most recent 1 second of logged data, to account for the fact that that new block data may have already been logged, depending on your code.
```java
final Block block = null; //Should be an actual block
class BasicThread implements Runnable {
@Override
public void run() {
try {
CoreProtectAPI CoreProtect = getCoreProtect();
if (CoreProtect != null){ // Ensure we have access to the API
boolean hasPlaced = CoreProtect.hasPlaced("Notch", block, 60, 1);
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
Runnable runnable = new BasicThread();
Thread thread = new Thread(runnable);
thread.start();
```
---
+6 -3
View File
@@ -18,15 +18,18 @@ Secondary configuration files override the value specified in config.yml. If you
## Disabling Logging
To disable logging for specific users or commands, simply do the following:
To disable logging for specific users, blocks or commands, simply do the following:
1. In the CoreProtect plugin directory, create a file named `blacklist.txt`.
2. Enter the names of the users (or commands) you'd like to disable logging for (each username on a new line).
3. Either restart your server, or type "/co reload" in-game.
This can be used to disable logging for non-player users, such as "#tnt". For example, if you'd like to disable logging for the user "Notch", TNT explosions, and the "/help" command, the blacklist.txt file would look like this:
This can be used to disable logging for non-player users, such as "#creeper". For example, if you'd like to disable logging for the user "Notch", TNT explosions, stone blocks, and the "/help" command, the blacklist.txt file would look like this:
```text
Notch
#tnt
/help
```
minecraft:stone
```
*Please note that to disable logging for blocks, CoreProtect v23+ is required, and you must include the namespace. For example, to disable logging for dirt, you must add it as "minecraft:dirt".*
+3 -3
View File
@@ -22,7 +22,7 @@ Log your own block changes, perform lookups, rollbacks, restores, and more.
A list of plugins and tools that are compatible with CoreProtect.
[**Per-World Configuration Files**](/config/#per-world-configuration)
Log your own block changes, perform lookups, rollbacks, restores, and more.
Modify the logging settings for a specific world on your server.
[**Disable Logging for Specific Users or Commands**](/config/#disabling-logging)
Log your own block changes, perform lookups, rollbacks, restores, and more.
[**Disable Logging With a Blacklist**](/config/#disabling-logging)
Disable logging for specific users, blocks or commands.
+21 -10
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.coreprotect</groupId>
<artifactId>CoreProtect</artifactId>
<version>22.3</version>
<version>22.4</version>
<properties>
<project.branch></project.branch>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -88,11 +88,18 @@
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
<repository>
<id>enginehub-repo</id>
<url>https://maven.enginehub.org/repo/</url>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.intellectualsites.bom</groupId>
<artifactId>bom-newest</artifactId> <!-- Ref: https://github.com/IntellectualSites/bom -->
<version>1.44</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--
paper-api: io.papermc.paper
@@ -113,14 +120,18 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.0.0-SNAPSHOT</version>
<groupId>com.fastasyncworldedit</groupId>
<artifactId>FastAsyncWorldEdit-Core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fastasyncworldedit</groupId>
<artifactId>FastAsyncWorldEdit-Bukkit</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<artifactId>FastAsyncWorldEdit-Core</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
@@ -25,7 +25,7 @@ import net.coreprotect.config.Config;
import net.coreprotect.consumer.Queue;
import net.coreprotect.database.Database;
import net.coreprotect.database.Lookup;
import net.coreprotect.database.Rollback;
import net.coreprotect.database.rollback.Rollback;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.player.InventoryChangeListener;
import net.coreprotect.utility.Chat;
@@ -168,7 +168,7 @@ public class CoreProtectAPI extends Queue {
}
public int APIVersion() {
return 9;
return 10;
}
public List<String[]> blockLookup(Block block, int time) {
@@ -282,6 +282,19 @@ public class CoreProtectAPI extends Queue {
return false;
}
public boolean logPlacement(String user, BlockState blockState) {
if (!Config.getGlobal().API_ENABLED) {
return false;
}
if (blockState == null || user == null || user.length() == 0) {
return false;
}
Queue.queueBlockPlace(user, blockState, blockState.getType(), null, blockState.getType(), -1, 0, blockState.getBlockData().getAsString());
return true;
}
public boolean logPlacement(String user, Location location, Material type, BlockData blockData) {
if (Config.getGlobal().API_ENABLED) {
if (user != null && location != null) {
@@ -316,6 +329,19 @@ public class CoreProtectAPI extends Queue {
return false;
}
public boolean logRemoval(String user, BlockState blockState) {
if (!Config.getGlobal().API_ENABLED) {
return false;
}
if (blockState == null || user == null || user.length() == 0) {
return false;
}
Queue.queueBlockBreak(user, blockState, blockState.getType(), blockState.getBlockData().getAsString(), 0);
return true;
}
public boolean logRemoval(String user, Location location, Material type, BlockData blockData) {
if (Config.getGlobal().API_ENABLED) {
if (user != null && location != null) {
@@ -24,6 +24,7 @@ import net.coreprotect.model.BlockGroup;
public class Bukkit_v1_20 extends Bukkit_v1_19 implements BukkitInterface {
private Boolean hasClickedPosition = null;
private Boolean hasBasePotionType = null;
public Bukkit_v1_20() {
BlockGroup.CONTAINERS = new HashSet<>(Arrays.asList(Material.JUKEBOX, Material.DISPENSER, Material.CHEST, Material.FURNACE, Material.BREWING_STAND, Material.TRAPPED_CHEST, Material.HOPPER, Material.DROPPER, Material.ARMOR_STAND, Material.ITEM_FRAME, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.SMOKER, Material.LECTERN, Material.CHISELED_BOOKSHELF));
@@ -255,20 +256,34 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 implements BukkitInterface {
@Override
public ItemStack getArrowMeta(Arrow arrow, ItemStack itemStack) {
PotionType potionType = arrow.getBasePotionType();
Color color = arrow.getColor();
if (potionType != null || color != null) {
itemStack = new ItemStack(Material.TIPPED_ARROW);
PotionMeta meta = (PotionMeta) itemStack.getItemMeta();
meta.setBasePotionType(potionType);
meta.setColor(color);
for (PotionEffect effect : arrow.getCustomEffects()) {
meta.addCustomEffect(effect, false);
try {
if (hasBasePotionType == null) {
hasBasePotionType = true;
Arrow.class.getMethod("getBasePotionType"); // Bukkit 1.20.2+
}
else if (Boolean.FALSE.equals(hasBasePotionType)) {
return super.getArrowMeta(arrow, itemStack);
}
itemStack.setItemMeta(meta);
}
return itemStack;
PotionType potionType = arrow.getBasePotionType();
Color color = arrow.getColor();
if (potionType != null || color != null) {
itemStack = new ItemStack(Material.TIPPED_ARROW);
PotionMeta meta = (PotionMeta) itemStack.getItemMeta();
meta.setBasePotionType(potionType);
meta.setColor(color);
for (PotionEffect effect : arrow.getCustomEffects()) {
meta.addCustomEffect(effect, false);
}
itemStack.setItemMeta(meta);
}
return itemStack;
}
catch (Exception e) {
hasBasePotionType = false;
return super.getArrowMeta(arrow, itemStack);
}
}
}
@@ -23,8 +23,8 @@ import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.ContainerRollback;
import net.coreprotect.database.Database;
import net.coreprotect.database.Rollback;
import net.coreprotect.database.lookup.PlayerLookup;
import net.coreprotect.database.rollback.Rollback;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
@@ -41,7 +41,6 @@ public class Config extends Language {
public String MYSQL_USERNAME;
public String MYSQL_PASSWORD;
public String LANGUAGE;
public boolean ENABLE_AWE;
public boolean ENABLE_SSL;
public boolean DISABLE_WAL;
public boolean HOVER_EVENTS;
@@ -189,7 +188,6 @@ public class Config extends Language {
}
private void readValues() {
this.ENABLE_AWE = this.getBoolean("enable-awe", false);
this.ENABLE_SSL = this.getBoolean("enable-ssl", false);
this.DISABLE_WAL = this.getBoolean("disable-wal", false);
this.HOVER_EVENTS = this.getBoolean("hover-events", true);
@@ -1,7 +1,9 @@
package net.coreprotect.consumer.process;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -46,8 +48,9 @@ class ContainerTransactionProcess {
}
}
else if (loggingChestId.startsWith("#hopper")) {
if (force_size == 0 && ConfigHandler.oldContainer.get(loggingChestId).size() == 1 && ConfigHandler.transactingChest.get(transactingChestId).isEmpty()) {
int loopCount = ConfigHandler.loggingChest.get(loggingChestId);
List<Object> transactingChest = ConfigHandler.transactingChest.get(transactingChestId);
if (force_size == 0 && ConfigHandler.oldContainer.getOrDefault(loggingChestId, Collections.synchronizedList(new ArrayList<>())).size() == 1 && transactingChest != null && transactingChest.isEmpty()) {
int loopCount = ConfigHandler.loggingChest.getOrDefault(loggingChestId, 0);
int maxInventorySize = (99 * 54);
try {
Inventory checkInventory = (Inventory) inventory;
@@ -83,6 +83,14 @@ public class Process {
int consumerDataSize = consumerData.size();
currentConsumerSize = consumerDataSize;
if (currentConsumerSize == 0) { // No data, skip processing
updateLockTable(statement, (lastRun ? 0 : 1));
statement.close();
Consumer.consumer_id.put(processId, new Integer[] { 0, 0 });
Consumer.isPaused = false;
return;
}
Database.beginTransaction(statement);
// Scan through usernames, ensure everything is loaded in memory.
for (Entry<Integer, String[]> entry : users.entrySet()) {
@@ -225,6 +233,7 @@ public class Process {
consumerData.remove(index);
}
currentConsumerSize = 0;
Consumer.consumer_id.put(processId, new Integer[] { 0, 0 });
Consumer.isPaused = false;
return;
}
@@ -21,13 +21,15 @@ import net.coreprotect.CoreProtect;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Queue;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.database.rollback.Rollback;
import net.coreprotect.database.rollback.RollbackComplete;
import net.coreprotect.language.Phrase;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.thread.Scheduler;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Util;
public class ContainerRollback extends Queue {
public class ContainerRollback extends Rollback {
public static void performContainerRollbackRestore(Statement statement, CommandSender user, List<String> checkUuids, List<String> checkUsers, String timeString, List<Object> restrictList, Map<Object, Boolean> excludeList, List<String> excludeUserList, List<Integer> actionList, final Location location, Integer[] radius, long startTime, long endTime, boolean restrictWorld, boolean lookup, boolean verbose, final int rollbackType) {
try {
@@ -176,7 +178,7 @@ public class ContainerRollback extends Queue {
int itemCount = 0;
int entityCount = 0;
Rollback.finishRollbackRestore(user, location, checkUsers, restrictList, excludeList, excludeUserList, actionList, timeString, file, totalSeconds, itemCount, blockCount, entityCount, rollbackType, radius, verbose, restrictWorld, 0);
RollbackComplete.output(user, location, checkUsers, restrictList, excludeList, excludeUserList, actionList, timeString, file, totalSeconds, itemCount, blockCount, entityCount, rollbackType, radius, verbose, restrictWorld, 0);
}
}
catch (Exception e) {
@@ -372,7 +372,7 @@ public class Database extends Queue {
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "session(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, action tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "sign(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int, z int, action tinyint, color int, color_secondary int, data tinyint, waxed tinyint, face tinyint, line_1 varchar(100), line_2 varchar(100), line_3 varchar(100), line_4 varchar(100), line_5 varchar(100), line_6 varchar(100), line_7 varchar(100), line_8 varchar(100)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "skull(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, owner varchar(64)) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "skull(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, owner varchar(255)) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(user), INDEX(uuid)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "user(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,user varchar(100),uuid varchar(64)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(uuid,user)";
@@ -29,7 +29,7 @@ import net.coreprotect.utility.Util;
public class Lookup extends Queue {
static List<String[]> convertRawLookup(Statement statement, List<Object[]> list) {
protected static List<String[]> convertRawLookup(Statement statement, List<Object[]> list) {
List<String[]> newList = new ArrayList<>();
if (list == null) {
@@ -122,7 +122,7 @@ public class Lookup extends Queue {
return newList;
}
static List<Object[]> performLookupRaw(Statement statement, CommandSender user, List<String> checkUuids, List<String> checkUsers, List<Object> restrictList, Map<Object, Boolean> excludeList, List<String> excludeUserList, List<Integer> actionList, Location location, Integer[] radius, Long[] rowData, long startTime, long endTime, int limitOffset, int limitCount, boolean restrictWorld, boolean lookup) {
protected static List<Object[]> performLookupRaw(Statement statement, CommandSender user, List<String> checkUuids, List<String> checkUsers, List<Object> restrictList, Map<Object, Boolean> excludeList, List<String> excludeUserList, List<Integer> actionList, Location location, Integer[] radius, Long[] rowData, long startTime, long endTime, int limitOffset, int limitCount, boolean restrictWorld, boolean lookup) {
List<Object[]> list = new ArrayList<>();
List<Integer> invalidRollbackActions = new ArrayList<>();
invalidRollbackActions.add(2);
@@ -1,10 +1,7 @@
package net.coreprotect.database;
package net.coreprotect.database.rollback;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Statement;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -20,14 +17,9 @@ import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.FireworkEffect.Builder;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.block.Banner;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@@ -35,7 +27,6 @@ import org.bukkit.block.BlockState;
import org.bukkit.block.CommandBlock;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Jukebox;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.Bisected.Half;
@@ -65,18 +56,6 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.BannerMeta;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.CrossbowMeta;
import org.bukkit.inventory.meta.FireworkEffectMeta;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.inventory.meta.SuspiciousStewMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.io.BukkitObjectInputStream;
import net.coreprotect.CoreProtect;
@@ -85,6 +64,7 @@ import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Queue;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.database.Lookup;
import net.coreprotect.database.logger.ItemLogger;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
@@ -100,7 +80,7 @@ import net.coreprotect.utility.Teleport;
import net.coreprotect.utility.Util;
import net.coreprotect.utility.entity.HangingUtil;
public class Rollback extends Queue {
public class Rollback extends RollbackUtil {
public static List<String[]> performRollbackRestore(Statement statement, CommandSender user, List<String> checkUuids, List<String> checkUsers, String timeString, List<Object> restrictList, Map<Object, Boolean> excludeList, List<String> excludeUserList, List<Integer> actionList, Location location, Integer[] radius, long startTime, long endTime, boolean restrictWorld, boolean lookup, boolean verbose, final int rollbackType, final int preview) {
List<String[]> list = new ArrayList<>();
@@ -1337,7 +1317,7 @@ public class Rollback extends Queue {
double totalSeconds = (timeFinish - timeStart) / 1000.0;
if (user != null) {
finishRollbackRestore(user, location, checkUsers, restrictList, excludeList, excludeUserList, actionList, timeString, chunkCount, totalSeconds, itemCount, blockCount, entityCount, rollbackType, radius, verbose, restrictWorld, preview);
RollbackComplete.output(user, location, checkUsers, restrictList, excludeList, excludeUserList, actionList, timeString, chunkCount, totalSeconds, itemCount, blockCount, entityCount, rollbackType, radius, verbose, restrictWorld, preview);
}
list = Lookup.convertRawLookup(statement, lookupList);
@@ -1350,733 +1330,4 @@ public class Rollback extends Queue {
return null;
}
static void finishRollbackRestore(CommandSender user, Location location, List<String> checkUsers, List<Object> restrictList, Map<Object, Boolean> excludeList, List<String> excludeUserList, List<Integer> actionList, String timeString, Integer chunkCount, Double seconds, Integer itemCount, Integer blockCount, Integer entityCount, int rollbackType, Integer[] radius, boolean verbose, boolean restrictWorld, int preview) {
try {
if (preview == 2) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.PREVIEW_CANCELLED));
return;
}
Chat.sendMessage(user, "-----");
StringBuilder usersBuilder = new StringBuilder();
for (String value : checkUsers) {
if (usersBuilder.length() == 0) {
usersBuilder = usersBuilder.append("" + value + "");
}
else {
usersBuilder.append(", ").append(value);
}
}
String users = usersBuilder.toString();
if (users.equals("#global") && restrictWorld) {
users = "#" + location.getWorld().getName();
}
if (preview > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_COMPLETED, users, Selector.THIRD)); // preview
}
else if (rollbackType == 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_COMPLETED, users, Selector.FIRST)); // rollback
}
else if (rollbackType == 1) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_COMPLETED, users, Selector.SECOND)); // restore
}
if (preview == 1 || rollbackType == 0 || rollbackType == 1) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_TIME, timeString));
}
if (radius != null) {
int worldedit = radius[7];
if (worldedit == 0) {
Integer rollbackRadius = radius[0];
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_RADIUS, rollbackRadius.toString(), (rollbackRadius == 1 ? Selector.FIRST : Selector.SECOND)));
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_SELECTION, "#worldedit"));
}
}
if (restrictWorld && radius == null) {
if (location != null) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, location.getWorld().getName(), Selector.FIRST));
}
}
if (actionList.contains(4) && actionList.contains(11)) {
if (actionList.contains(0)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "+inventory", Selector.SECOND));
}
else if (actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "-inventory", Selector.SECOND));
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "inventory", Selector.SECOND));
}
}
else if (actionList.contains(4)) {
if (actionList.contains(0)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "-container", Selector.SECOND));
}
else if (actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "+container", Selector.SECOND));
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "container", Selector.SECOND));
}
}
else if (actionList.contains(0) && actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "block", Selector.SECOND));
}
else if (actionList.contains(0)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "-block", Selector.SECOND));
}
else if (actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "+block", Selector.SECOND));
}
else if (actionList.contains(3)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "kill", Selector.SECOND));
}
if (restrictList.size() > 0) {
StringBuilder restrictTargets = new StringBuilder();
boolean material = false;
boolean item = false;
boolean entity = false;
int targetCount = 0;
for (Object restrictTarget : restrictList) {
String targetName = "";
if (restrictTarget instanceof Material) {
targetName = ((Material) restrictTarget).name().toLowerCase(Locale.ROOT);
item = (!item ? !(((Material) restrictTarget).isBlock()) : item);
material = true;
}
else if (restrictTarget instanceof EntityType) {
targetName = ((EntityType) restrictTarget).name().toLowerCase(Locale.ROOT);
entity = true;
}
if (targetCount == 0) {
restrictTargets = restrictTargets.append("" + targetName + "");
}
else {
restrictTargets.append(", ").append(targetName);
}
targetCount++;
}
String targetType = Selector.THIRD;
if (material && !item && !entity) {
targetType = Selector.FIRST;
}
else if (material && item && !entity) {
targetType = Selector.THIRD;
}
else if (entity && !material) {
targetType = Selector.SECOND;
}
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_INCLUDE, restrictTargets.toString(), Selector.FIRST, targetType, (targetCount == 1 ? Selector.FIRST : Selector.SECOND))); // include
}
if (excludeList.size() > 0) {
StringBuilder excludeTargets = new StringBuilder();
boolean material = false;
boolean item = false;
boolean entity = false;
int excludeCount = 0;
for (Map.Entry<Object, Boolean> entry : excludeList.entrySet()) {
Object excludeTarget = entry.getKey();
Boolean excludeTargetInternal = entry.getValue();
// don't display default block excludes
if (Boolean.TRUE.equals(excludeTargetInternal)) {
continue;
}
// don't display that excluded water/fire/farmland in inventory rollbacks
if (actionList.contains(4) && actionList.contains(11)) {
if (excludeTarget.equals(Material.FIRE) || excludeTarget.equals(Material.WATER) || excludeTarget.equals(Material.FARMLAND)) {
continue;
}
}
String targetName = "";
if (excludeTarget instanceof Material) {
targetName = ((Material) excludeTarget).name().toLowerCase(Locale.ROOT);
item = (!item ? !(((Material) excludeTarget).isBlock()) : item);
material = true;
}
else if (excludeTarget instanceof EntityType) {
targetName = ((EntityType) excludeTarget).name().toLowerCase(Locale.ROOT);
entity = true;
}
if (excludeCount == 0) {
excludeTargets = excludeTargets.append("" + targetName + "");
}
else {
excludeTargets.append(", ").append(targetName);
}
excludeCount++;
}
String targetType = Selector.THIRD;
if (material && !item && !entity) {
targetType = Selector.FIRST;
}
else if (material && item && !entity) {
targetType = Selector.THIRD;
}
else if (entity && !material) {
targetType = Selector.SECOND;
}
if (excludeCount > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_INCLUDE, excludeTargets.toString(), Selector.SECOND, targetType, (excludeCount == 1 ? Selector.FIRST : Selector.SECOND))); // exclude
}
}
if (excludeUserList.size() > 0) {
StringBuilder excludeUsers = new StringBuilder();
int excludeCount = 0;
for (String excludeUser : excludeUserList) {
// don't display that excluded #hopper in inventory rollbacks
if (actionList.contains(4) && actionList.contains(11)) {
if (excludeUser.equals("#hopper")) {
continue;
}
}
if (excludeCount == 0) {
excludeUsers = excludeUsers.append("" + excludeUser + "");
}
else {
excludeUsers.append(", ").append(excludeUser);
}
excludeCount++;
}
if (excludeCount > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_EXCLUDED_USERS, excludeUsers.toString(), (excludeCount == 1 ? Selector.FIRST : Selector.SECOND)));
}
}
StringBuilder modifiedData = new StringBuilder();
Integer modifyCount = 0;
if (actionList.contains(5)) {
modifiedData = modifiedData.append(Phrase.build(Phrase.AMOUNT_ITEM, NumberFormat.getInstance().format(blockCount), (blockCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
else {
if (itemCount > 0 || actionList.contains(4)) {
modifiedData = modifiedData.append(Phrase.build(Phrase.AMOUNT_ITEM, NumberFormat.getInstance().format(itemCount), (itemCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
if (entityCount > 0) {
if (modifyCount > 0) {
modifiedData.append(", ");
}
modifiedData.append(Phrase.build(Phrase.AMOUNT_ENTITY, NumberFormat.getInstance().format(entityCount), (entityCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
if (blockCount > 0 || !actionList.contains(4) || preview > 0) {
if (modifyCount > 0) {
modifiedData.append(", ");
}
modifiedData.append(Phrase.build(Phrase.AMOUNT_BLOCK, NumberFormat.getInstance().format(blockCount), (blockCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
}
StringBuilder modifiedDataVerbose = new StringBuilder();
if (verbose && preview == 0 && !actionList.contains(11)) {
if (chunkCount > -1 && modifyCount < 3) {
if (modifyCount > 0) {
modifiedData.append(", ");
}
modifiedData.append(Phrase.build(Phrase.AMOUNT_CHUNK, NumberFormat.getInstance().format(chunkCount), (chunkCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
else if (chunkCount > 1) {
modifiedDataVerbose.append(Phrase.build(Phrase.AMOUNT_CHUNK, NumberFormat.getInstance().format(chunkCount), (chunkCount == 1 ? Selector.FIRST : Selector.SECOND)));
}
}
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_MODIFIED, modifiedData.toString(), (preview == 0 ? Selector.FIRST : Selector.SECOND)));
if (modifiedDataVerbose.length() > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_MODIFIED, modifiedDataVerbose.toString(), (preview == 0 ? Selector.FIRST : Selector.SECOND)));
}
if (preview == 0) {
BigDecimal decimalSeconds = new BigDecimal(seconds).setScale(1, RoundingMode.HALF_EVEN);
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_LENGTH, decimalSeconds.stripTrailingZeros().toPlainString(), (decimalSeconds.doubleValue() == 1 ? Selector.FIRST : Selector.SECOND)));
}
Chat.sendMessage(user, "-----");
if (preview > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.PLEASE_SELECT, "/co apply", "/co cancel"));
}
}
catch (Exception e) {
e.printStackTrace();
}
}
static int modifyContainerItems(Material type, Object container, int slot, ItemStack itemstack, int action) {
int modifiedArmor = -1;
try {
ItemStack[] contents = null;
if (type != null && type.equals(Material.ARMOR_STAND)) {
EntityEquipment equipment = (EntityEquipment) container;
if (equipment != null) {
if (action == 1) {
itemstack.setAmount(1);
}
else {
itemstack.setType(Material.AIR);
itemstack.setAmount(0);
}
if (slot < 4) {
contents = equipment.getArmorContents();
if (slot >= 0) {
contents[slot] = itemstack;
}
equipment.setArmorContents(contents);
}
else {
ArmorStand armorStand = (ArmorStand) equipment.getHolder();
armorStand.setArms(true);
switch (slot) {
case 4:
equipment.setItemInMainHand(itemstack);
break;
case 5:
equipment.setItemInOffHand(itemstack);
break;
}
}
}
}
else if (type != null && type.equals(Material.ITEM_FRAME)) {
ItemFrame frame = (ItemFrame) container;
if (frame != null) {
if (action == 1) {
itemstack.setAmount(1);
}
else {
itemstack.setType(Material.AIR);
itemstack.setAmount(0);
}
frame.setItem(itemstack);
}
}
else if (type != null && type.equals(Material.JUKEBOX)) {
Jukebox jukebox = (Jukebox) container;
if (jukebox != null) {
if (action == 1 && Tag.ITEMS_MUSIC_DISCS.isTagged(itemstack.getType())) {
itemstack.setAmount(1);
}
else {
itemstack.setType(Material.AIR);
itemstack.setAmount(0);
}
jukebox.setRecord(itemstack);
jukebox.update();
}
}
else {
Inventory inventory = (Inventory) container;
if (inventory != null) {
boolean isPlayerInventory = (inventory instanceof PlayerInventory);
if (action == 1) {
int count = 0;
int amount = itemstack.getAmount();
itemstack.setAmount(1);
while (count < amount) {
boolean addedItem = false;
if (isPlayerInventory) {
int setArmor = Util.setPlayerArmor((PlayerInventory) inventory, itemstack);
addedItem = (setArmor > -1);
modifiedArmor = addedItem ? setArmor : modifiedArmor;
}
if (!addedItem) {
if (BukkitAdapter.ADAPTER.isChiseledBookshelf(type)) {
ItemStack[] inventoryContents = inventory.getStorageContents();
int i = 0;
for (ItemStack stack : inventoryContents) {
if (stack == null) {
inventoryContents[i] = itemstack;
addedItem = true;
break;
}
i++;
}
if (addedItem) {
inventory.setStorageContents(inventoryContents);
}
else {
addedItem = (inventory.addItem(itemstack).size() == 0);
}
}
else {
addedItem = (inventory.addItem(itemstack).size() == 0);
}
}
if (!addedItem && isPlayerInventory) {
PlayerInventory playerInventory = (PlayerInventory) inventory;
ItemStack offhand = playerInventory.getItemInOffHand();
if (offhand == null || offhand.getType() == Material.AIR || (itemstack.isSimilar(offhand) && offhand.getAmount() < offhand.getMaxStackSize())) {
ItemStack setOffhand = itemstack.clone();
if (itemstack.isSimilar(offhand)) {
setOffhand.setAmount(offhand.getAmount() + 1);
}
playerInventory.setItemInOffHand(setOffhand);
}
}
count++;
}
}
else {
int removeAmount = itemstack.getAmount();
ItemStack removeMatch = itemstack.clone();
removeMatch.setAmount(1);
ItemStack[] inventoryContents = (isPlayerInventory ? inventory.getContents() : inventory.getStorageContents()).clone();
for (int i = inventoryContents.length - 1; i >= 0; i--) {
if (inventoryContents[i] != null) {
ItemStack itemStack = inventoryContents[i].clone();
int maxAmount = itemStack.getAmount();
int currentAmount = maxAmount;
itemStack.setAmount(1);
if (itemStack.toString().equals(removeMatch.toString())) {
for (int scan = 0; scan < maxAmount; scan++) {
if (removeAmount > 0) {
currentAmount--;
itemStack.setAmount(currentAmount);
removeAmount--;
}
else {
break;
}
}
}
else {
itemStack.setAmount(maxAmount);
}
if (itemStack.getAmount() == 0) {
inventoryContents[i] = null;
}
else {
inventoryContents[i] = itemStack;
}
}
if (removeAmount == 0) {
break;
}
}
if (isPlayerInventory) {
inventory.setContents(inventoryContents);
}
else {
inventory.setStorageContents(inventoryContents);
}
int count = 0;
while (count < removeAmount) {
inventory.removeItem(removeMatch);
count++;
}
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return modifiedArmor;
}
public static void sortContainerItems(PlayerInventory inventory, List<Integer> modifiedArmorSlots) {
try {
ItemStack[] armorContents = inventory.getArmorContents();
ItemStack[] storageContents = inventory.getStorageContents();
for (int armor = 0; armor < armorContents.length; armor++) {
ItemStack armorItem = armorContents[armor];
if (armorItem == null || !modifiedArmorSlots.contains(armor)) {
continue;
}
for (int storage = 0; storage < storageContents.length; storage++) {
ItemStack storageItem = storageContents[storage];
if (storageItem == null) {
storageContents[storage] = armorItem;
armorContents[armor] = null;
break;
}
}
}
inventory.setArmorContents(armorContents);
inventory.setStorageContents(storageContents);
}
catch (Exception e) {
e.printStackTrace();
}
}
private static void buildFireworkEffect(Builder effectBuilder, Material rowType, ItemStack itemstack) {
try {
FireworkEffect effect = effectBuilder.build();
if ((rowType == Material.FIREWORK_ROCKET)) {
FireworkMeta meta = (FireworkMeta) itemstack.getItemMeta();
meta.addEffect(effect);
itemstack.setItemMeta(meta);
}
else if ((rowType == Material.FIREWORK_STAR)) {
FireworkEffectMeta meta = (FireworkEffectMeta) itemstack.getItemMeta();
meta.setEffect(effect);
itemstack.setItemMeta(meta);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static Object[] populateItemStack(ItemStack itemstack, Object list) {
int slot = 0;
String faceData = "";
try {
/*
if (list instanceof Object[]) {
slot = (int) ((Object[]) list)[0];
ItemMeta itemMeta = (ItemMeta) ((Object[]) list)[1];
itemstack.setItemMeta(itemMeta);
return new Object[] { slot, itemstack };
}
*/
Material rowType = itemstack.getType();
List<Object> metaList = (List<Object>) list;
if (metaList.size() > 0 && !(metaList.get(0) instanceof List<?>)) {
if (rowType.name().endsWith("_BANNER")) {
BannerMeta meta = (BannerMeta) itemstack.getItemMeta();
for (Object value : metaList) {
if (value instanceof Map) {
Pattern pattern = new Pattern((Map<String, Object>) value);
meta.addPattern(pattern);
}
}
itemstack.setItemMeta(meta);
}
else if (BlockGroup.SHULKER_BOXES.contains(rowType)) {
BlockStateMeta meta = (BlockStateMeta) itemstack.getItemMeta();
ShulkerBox shulkerBox = (ShulkerBox) meta.getBlockState();
for (Object value : metaList) {
ItemStack item = Util.unserializeItemStackLegacy(value);
if (item != null) {
shulkerBox.getInventory().addItem(item);
}
}
meta.setBlockState(shulkerBox);
itemstack.setItemMeta(meta);
}
return new Object[] { slot, faceData, itemstack };
}
int itemCount = 0;
Builder effectBuilder = FireworkEffect.builder();
for (List<Map<String, Object>> map : (List<List<Map<String, Object>>>) list) {
if (map.size() == 0) {
if (itemCount == 3 && (rowType == Material.FIREWORK_ROCKET || rowType == Material.FIREWORK_STAR)) {
buildFireworkEffect(effectBuilder, rowType, itemstack);
itemCount = 0;
}
itemCount++;
continue;
}
Map<String, Object> mapData = map.get(0);
if (mapData.get("slot") != null) {
slot = (Integer) mapData.get("slot");
}
else if (mapData.get("facing") != null) {
faceData = (String) mapData.get("facing");
}
else if (mapData.get("modifiers") != null) {
ItemMeta itemMeta = itemstack.getItemMeta();
if (itemMeta.hasAttributeModifiers()) {
for (Map.Entry<Attribute, AttributeModifier> entry : itemMeta.getAttributeModifiers().entries()) {
itemMeta.removeAttributeModifier(entry.getKey(), entry.getValue());
}
}
List<Object> modifiers = (List<Object>) mapData.get("modifiers");
for (Object item : modifiers) {
Map<Attribute, Map<String, Object>> modifiersMap = (Map<Attribute, Map<String, Object>>) item;
for (Map.Entry<Attribute, Map<String, Object>> entry : modifiersMap.entrySet()) {
try {
Attribute attribute = entry.getKey();
AttributeModifier modifier = AttributeModifier.deserialize(entry.getValue());
itemMeta.addAttributeModifier(attribute, modifier);
}
catch (IllegalArgumentException e) {
// AttributeModifier already exists
}
}
}
itemstack.setItemMeta(itemMeta);
}
else if (itemCount == 0) {
ItemMeta meta = Util.deserializeItemMeta(itemstack.getItemMeta().getClass(), map.get(0));
itemstack.setItemMeta(meta);
if (map.size() > 1 && (rowType == Material.POTION)) {
PotionMeta subMeta = (PotionMeta) itemstack.getItemMeta();
org.bukkit.Color color = org.bukkit.Color.deserialize(map.get(1));
subMeta.setColor(color);
itemstack.setItemMeta(subMeta);
}
}
else {
if ((rowType == Material.LEATHER_HORSE_ARMOR) || (rowType == Material.LEATHER_HELMET) || (rowType == Material.LEATHER_CHESTPLATE) || (rowType == Material.LEATHER_LEGGINGS) || (rowType == Material.LEATHER_BOOTS)) { // leather armor
for (Map<String, Object> colorData : map) {
LeatherArmorMeta meta = (LeatherArmorMeta) itemstack.getItemMeta();
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
meta.setColor(color);
itemstack.setItemMeta(meta);
}
}
else if ((rowType == Material.POTION)) { // potion
for (Map<String, Object> potionData : map) {
PotionMeta meta = (PotionMeta) itemstack.getItemMeta();
PotionEffect effect = new PotionEffect(potionData);
meta.addCustomEffect(effect, true);
itemstack.setItemMeta(meta);
}
}
else if (rowType.name().endsWith("_BANNER")) {
for (Map<String, Object> patternData : map) {
BannerMeta meta = (BannerMeta) itemstack.getItemMeta();
Pattern pattern = new Pattern(patternData);
meta.addPattern(pattern);
itemstack.setItemMeta(meta);
}
}
else if ((rowType == Material.CROSSBOW)) {
CrossbowMeta meta = (CrossbowMeta) itemstack.getItemMeta();
for (Map<String, Object> itemData : map) {
ItemStack crossbowItem = Util.unserializeItemStack(itemData);
if (crossbowItem != null) {
meta.addChargedProjectile(crossbowItem);
}
}
itemstack.setItemMeta(meta);
}
else if (rowType == Material.MAP || rowType == Material.FILLED_MAP) {
for (Map<String, Object> colorData : map) {
MapMeta meta = (MapMeta) itemstack.getItemMeta();
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
meta.setColor(color);
itemstack.setItemMeta(meta);
}
}
else if ((rowType == Material.FIREWORK_ROCKET) || (rowType == Material.FIREWORK_STAR)) {
if (itemCount == 1) {
effectBuilder = FireworkEffect.builder();
for (Map<String, Object> fireworkData : map) {
org.bukkit.FireworkEffect.Type type = (org.bukkit.FireworkEffect.Type) fireworkData.getOrDefault("type", org.bukkit.FireworkEffect.Type.BALL);
boolean hasFlicker = (Boolean) fireworkData.get("flicker");
boolean hasTrail = (Boolean) fireworkData.get("trail");
effectBuilder.with(type);
effectBuilder.flicker(hasFlicker);
effectBuilder.trail(hasTrail);
}
}
else if (itemCount == 2) {
for (Map<String, Object> colorData : map) {
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
effectBuilder.withColor(color);
}
}
else if (itemCount == 3) {
for (Map<String, Object> colorData : map) {
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
effectBuilder.withFade(color);
}
buildFireworkEffect(effectBuilder, rowType, itemstack);
itemCount = 0;
}
}
else if ((rowType == Material.SUSPICIOUS_STEW)) {
for (Map<String, Object> suspiciousStewData : map) {
SuspiciousStewMeta meta = (SuspiciousStewMeta) itemstack.getItemMeta();
PotionEffect effect = new PotionEffect(suspiciousStewData);
meta.addCustomEffect(effect, true);
itemstack.setItemMeta(meta);
}
}
else {
BukkitAdapter.ADAPTER.setItemMeta(rowType, itemstack, map);
}
}
itemCount++;
}
}
catch (Exception e) {
e.printStackTrace();
}
return new Object[] { slot, faceData, itemstack };
}
public static Object[] populateItemStack(ItemStack itemstack, byte[] metadata) {
if (metadata != null) {
try {
ByteArrayInputStream metaByteStream = new ByteArrayInputStream(metadata);
BukkitObjectInputStream metaObjectStream = new BukkitObjectInputStream(metaByteStream);
Object metaList = metaObjectStream.readObject();
metaObjectStream.close();
metaByteStream.close();
return populateItemStack(itemstack, metaList);
}
catch (Exception e) {
e.printStackTrace();
}
}
return new Object[] { 0, "", itemstack };
}
}
@@ -0,0 +1,306 @@
package net.coreprotect.database.rollback;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
public class RollbackComplete {
public static void output(CommandSender user, Location location, List<String> checkUsers, List<Object> restrictList, Map<Object, Boolean> excludeList, List<String> excludeUserList, List<Integer> actionList, String timeString, Integer chunkCount, Double seconds, Integer itemCount, Integer blockCount, Integer entityCount, int rollbackType, Integer[] radius, boolean verbose, boolean restrictWorld, int preview) {
try {
if (preview == 2) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.PREVIEW_CANCELLED));
return;
}
Chat.sendMessage(user, "-----");
StringBuilder usersBuilder = new StringBuilder();
for (String value : checkUsers) {
if (usersBuilder.length() == 0) {
usersBuilder = usersBuilder.append("" + value + "");
}
else {
usersBuilder.append(", ").append(value);
}
}
String users = usersBuilder.toString();
if (users.equals("#global") && restrictWorld) {
users = "#" + location.getWorld().getName();
}
if (preview > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_COMPLETED, users, Selector.THIRD)); // preview
}
else if (rollbackType == 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_COMPLETED, users, Selector.FIRST)); // rollback
}
else if (rollbackType == 1) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_COMPLETED, users, Selector.SECOND)); // restore
}
if (preview == 1 || rollbackType == 0 || rollbackType == 1) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_TIME, timeString));
}
if (radius != null) {
int worldedit = radius[7];
if (worldedit == 0) {
Integer rollbackRadius = radius[0];
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_RADIUS, rollbackRadius.toString(), (rollbackRadius == 1 ? Selector.FIRST : Selector.SECOND)));
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_SELECTION, "#worldedit"));
}
}
if (restrictWorld && radius == null) {
if (location != null) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, location.getWorld().getName(), Selector.FIRST));
}
}
if (actionList.contains(4) && actionList.contains(11)) {
if (actionList.contains(0)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "+inventory", Selector.SECOND));
}
else if (actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "-inventory", Selector.SECOND));
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "inventory", Selector.SECOND));
}
}
else if (actionList.contains(4)) {
if (actionList.contains(0)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "-container", Selector.SECOND));
}
else if (actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "+container", Selector.SECOND));
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "container", Selector.SECOND));
}
}
else if (actionList.contains(0) && actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "block", Selector.SECOND));
}
else if (actionList.contains(0)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "-block", Selector.SECOND));
}
else if (actionList.contains(1)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "+block", Selector.SECOND));
}
else if (actionList.contains(3)) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_WORLD_ACTION, "kill", Selector.SECOND));
}
if (restrictList.size() > 0) {
StringBuilder restrictTargets = new StringBuilder();
boolean material = false;
boolean item = false;
boolean entity = false;
int targetCount = 0;
for (Object restrictTarget : restrictList) {
String targetName = "";
if (restrictTarget instanceof Material) {
targetName = ((Material) restrictTarget).name().toLowerCase(Locale.ROOT);
item = (!item ? !(((Material) restrictTarget).isBlock()) : item);
material = true;
}
else if (restrictTarget instanceof EntityType) {
targetName = ((EntityType) restrictTarget).name().toLowerCase(Locale.ROOT);
entity = true;
}
if (targetCount == 0) {
restrictTargets = restrictTargets.append("" + targetName + "");
}
else {
restrictTargets.append(", ").append(targetName);
}
targetCount++;
}
String targetType = Selector.THIRD;
if (material && !item && !entity) {
targetType = Selector.FIRST;
}
else if (material && item && !entity) {
targetType = Selector.THIRD;
}
else if (entity && !material) {
targetType = Selector.SECOND;
}
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_INCLUDE, restrictTargets.toString(), Selector.FIRST, targetType, (targetCount == 1 ? Selector.FIRST : Selector.SECOND))); // include
}
if (excludeList.size() > 0) {
StringBuilder excludeTargets = new StringBuilder();
boolean material = false;
boolean item = false;
boolean entity = false;
int excludeCount = 0;
for (Map.Entry<Object, Boolean> entry : excludeList.entrySet()) {
Object excludeTarget = entry.getKey();
Boolean excludeTargetInternal = entry.getValue();
// don't display default block excludes
if (Boolean.TRUE.equals(excludeTargetInternal)) {
continue;
}
// don't display that excluded water/fire/farmland in inventory rollbacks
if (actionList.contains(4) && actionList.contains(11)) {
if (excludeTarget.equals(Material.FIRE) || excludeTarget.equals(Material.WATER) || excludeTarget.equals(Material.FARMLAND)) {
continue;
}
}
String targetName = "";
if (excludeTarget instanceof Material) {
targetName = ((Material) excludeTarget).name().toLowerCase(Locale.ROOT);
item = (!item ? !(((Material) excludeTarget).isBlock()) : item);
material = true;
}
else if (excludeTarget instanceof EntityType) {
targetName = ((EntityType) excludeTarget).name().toLowerCase(Locale.ROOT);
entity = true;
}
if (excludeCount == 0) {
excludeTargets = excludeTargets.append("" + targetName + "");
}
else {
excludeTargets.append(", ").append(targetName);
}
excludeCount++;
}
String targetType = Selector.THIRD;
if (material && !item && !entity) {
targetType = Selector.FIRST;
}
else if (material && item && !entity) {
targetType = Selector.THIRD;
}
else if (entity && !material) {
targetType = Selector.SECOND;
}
if (excludeCount > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_INCLUDE, excludeTargets.toString(), Selector.SECOND, targetType, (excludeCount == 1 ? Selector.FIRST : Selector.SECOND))); // exclude
}
}
if (excludeUserList.size() > 0) {
StringBuilder excludeUsers = new StringBuilder();
int excludeCount = 0;
for (String excludeUser : excludeUserList) {
// don't display that excluded #hopper in inventory rollbacks
if (actionList.contains(4) && actionList.contains(11)) {
if (excludeUser.equals("#hopper")) {
continue;
}
}
if (excludeCount == 0) {
excludeUsers = excludeUsers.append("" + excludeUser + "");
}
else {
excludeUsers.append(", ").append(excludeUser);
}
excludeCount++;
}
if (excludeCount > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_EXCLUDED_USERS, excludeUsers.toString(), (excludeCount == 1 ? Selector.FIRST : Selector.SECOND)));
}
}
StringBuilder modifiedData = new StringBuilder();
Integer modifyCount = 0;
if (actionList.contains(5)) {
modifiedData = modifiedData.append(Phrase.build(Phrase.AMOUNT_ITEM, NumberFormat.getInstance().format(blockCount), (blockCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
else {
if (itemCount > 0 || actionList.contains(4)) {
modifiedData = modifiedData.append(Phrase.build(Phrase.AMOUNT_ITEM, NumberFormat.getInstance().format(itemCount), (itemCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
if (entityCount > 0) {
if (modifyCount > 0) {
modifiedData.append(", ");
}
modifiedData.append(Phrase.build(Phrase.AMOUNT_ENTITY, NumberFormat.getInstance().format(entityCount), (entityCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
if (blockCount > 0 || !actionList.contains(4) || preview > 0) {
if (modifyCount > 0) {
modifiedData.append(", ");
}
modifiedData.append(Phrase.build(Phrase.AMOUNT_BLOCK, NumberFormat.getInstance().format(blockCount), (blockCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
}
StringBuilder modifiedDataVerbose = new StringBuilder();
if (verbose && preview == 0 && !actionList.contains(11)) {
if (chunkCount > -1 && modifyCount < 3) {
if (modifyCount > 0) {
modifiedData.append(", ");
}
modifiedData.append(Phrase.build(Phrase.AMOUNT_CHUNK, NumberFormat.getInstance().format(chunkCount), (chunkCount == 1 ? Selector.FIRST : Selector.SECOND)));
modifyCount++;
}
else if (chunkCount > 1) {
modifiedDataVerbose.append(Phrase.build(Phrase.AMOUNT_CHUNK, NumberFormat.getInstance().format(chunkCount), (chunkCount == 1 ? Selector.FIRST : Selector.SECOND)));
}
}
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_MODIFIED, modifiedData.toString(), (preview == 0 ? Selector.FIRST : Selector.SECOND)));
if (modifiedDataVerbose.length() > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_MODIFIED, modifiedDataVerbose.toString(), (preview == 0 ? Selector.FIRST : Selector.SECOND)));
}
if (preview == 0) {
BigDecimal decimalSeconds = new BigDecimal(seconds).setScale(1, RoundingMode.HALF_EVEN);
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ROLLBACK_LENGTH, decimalSeconds.stripTrailingZeros().toPlainString(), (decimalSeconds.doubleValue() == 1 ? Selector.FIRST : Selector.SECOND)));
}
Chat.sendMessage(user, "-----");
if (preview > 0) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.PLEASE_SELECT, "/co apply", "/co cancel"));
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,487 @@
package net.coreprotect.database.rollback;
import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Map;
import org.bukkit.FireworkEffect;
import org.bukkit.FireworkEffect.Builder;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.block.Jukebox;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.banner.Pattern;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.ItemFrame;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.BannerMeta;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.CrossbowMeta;
import org.bukkit.inventory.meta.FireworkEffectMeta;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.inventory.meta.SuspiciousStewMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.io.BukkitObjectInputStream;
import net.coreprotect.bukkit.BukkitAdapter;
import net.coreprotect.database.Lookup;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.utility.Util;
public class RollbackUtil extends Lookup {
protected static int modifyContainerItems(Material type, Object container, int slot, ItemStack itemstack, int action) {
int modifiedArmor = -1;
try {
ItemStack[] contents = null;
if (type != null && type.equals(Material.ARMOR_STAND)) {
EntityEquipment equipment = (EntityEquipment) container;
if (equipment != null) {
if (action == 1) {
itemstack.setAmount(1);
}
else {
itemstack.setType(Material.AIR);
itemstack.setAmount(0);
}
if (slot < 4) {
contents = equipment.getArmorContents();
if (slot >= 0) {
contents[slot] = itemstack;
}
equipment.setArmorContents(contents);
}
else {
ArmorStand armorStand = (ArmorStand) equipment.getHolder();
armorStand.setArms(true);
switch (slot) {
case 4:
equipment.setItemInMainHand(itemstack);
break;
case 5:
equipment.setItemInOffHand(itemstack);
break;
}
}
}
}
else if (type != null && type.equals(Material.ITEM_FRAME)) {
ItemFrame frame = (ItemFrame) container;
if (frame != null) {
if (action == 1) {
itemstack.setAmount(1);
}
else {
itemstack.setType(Material.AIR);
itemstack.setAmount(0);
}
frame.setItem(itemstack);
}
}
else if (type != null && type.equals(Material.JUKEBOX)) {
Jukebox jukebox = (Jukebox) container;
if (jukebox != null) {
if (action == 1 && Tag.ITEMS_MUSIC_DISCS.isTagged(itemstack.getType())) {
itemstack.setAmount(1);
}
else {
itemstack.setType(Material.AIR);
itemstack.setAmount(0);
}
jukebox.setRecord(itemstack);
jukebox.update();
}
}
else {
Inventory inventory = (Inventory) container;
if (inventory != null) {
boolean isPlayerInventory = (inventory instanceof PlayerInventory);
if (action == 1) {
int count = 0;
int amount = itemstack.getAmount();
itemstack.setAmount(1);
while (count < amount) {
boolean addedItem = false;
if (isPlayerInventory) {
int setArmor = Util.setPlayerArmor((PlayerInventory) inventory, itemstack);
addedItem = (setArmor > -1);
modifiedArmor = addedItem ? setArmor : modifiedArmor;
}
if (!addedItem) {
if (BukkitAdapter.ADAPTER.isChiseledBookshelf(type)) {
ItemStack[] inventoryContents = inventory.getStorageContents();
int i = 0;
for (ItemStack stack : inventoryContents) {
if (stack == null) {
inventoryContents[i] = itemstack;
addedItem = true;
break;
}
i++;
}
if (addedItem) {
inventory.setStorageContents(inventoryContents);
}
else {
addedItem = (inventory.addItem(itemstack).size() == 0);
}
}
else {
addedItem = (inventory.addItem(itemstack).size() == 0);
}
}
if (!addedItem && isPlayerInventory) {
PlayerInventory playerInventory = (PlayerInventory) inventory;
ItemStack offhand = playerInventory.getItemInOffHand();
if (offhand == null || offhand.getType() == Material.AIR || (itemstack.isSimilar(offhand) && offhand.getAmount() < offhand.getMaxStackSize())) {
ItemStack setOffhand = itemstack.clone();
if (itemstack.isSimilar(offhand)) {
setOffhand.setAmount(offhand.getAmount() + 1);
}
playerInventory.setItemInOffHand(setOffhand);
}
}
count++;
}
}
else {
int removeAmount = itemstack.getAmount();
ItemStack removeMatch = itemstack.clone();
removeMatch.setAmount(1);
ItemStack[] inventoryContents = (isPlayerInventory ? inventory.getContents() : inventory.getStorageContents()).clone();
for (int i = inventoryContents.length - 1; i >= 0; i--) {
if (inventoryContents[i] != null) {
ItemStack itemStack = inventoryContents[i].clone();
int maxAmount = itemStack.getAmount();
int currentAmount = maxAmount;
itemStack.setAmount(1);
if (itemStack.toString().equals(removeMatch.toString())) {
for (int scan = 0; scan < maxAmount; scan++) {
if (removeAmount > 0) {
currentAmount--;
itemStack.setAmount(currentAmount);
removeAmount--;
}
else {
break;
}
}
}
else {
itemStack.setAmount(maxAmount);
}
if (itemStack.getAmount() == 0) {
inventoryContents[i] = null;
}
else {
inventoryContents[i] = itemStack;
}
}
if (removeAmount == 0) {
break;
}
}
if (isPlayerInventory) {
inventory.setContents(inventoryContents);
}
else {
inventory.setStorageContents(inventoryContents);
}
int count = 0;
while (count < removeAmount) {
inventory.removeItem(removeMatch);
count++;
}
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return modifiedArmor;
}
public static void sortContainerItems(PlayerInventory inventory, List<Integer> modifiedArmorSlots) {
try {
ItemStack[] armorContents = inventory.getArmorContents();
ItemStack[] storageContents = inventory.getStorageContents();
for (int armor = 0; armor < armorContents.length; armor++) {
ItemStack armorItem = armorContents[armor];
if (armorItem == null || !modifiedArmorSlots.contains(armor)) {
continue;
}
for (int storage = 0; storage < storageContents.length; storage++) {
ItemStack storageItem = storageContents[storage];
if (storageItem == null) {
storageContents[storage] = armorItem;
armorContents[armor] = null;
break;
}
}
}
inventory.setArmorContents(armorContents);
inventory.setStorageContents(storageContents);
}
catch (Exception e) {
e.printStackTrace();
}
}
private static void buildFireworkEffect(Builder effectBuilder, Material rowType, ItemStack itemstack) {
try {
FireworkEffect effect = effectBuilder.build();
if ((rowType == Material.FIREWORK_ROCKET)) {
FireworkMeta meta = (FireworkMeta) itemstack.getItemMeta();
meta.addEffect(effect);
itemstack.setItemMeta(meta);
}
else if ((rowType == Material.FIREWORK_STAR)) {
FireworkEffectMeta meta = (FireworkEffectMeta) itemstack.getItemMeta();
meta.setEffect(effect);
itemstack.setItemMeta(meta);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static Object[] populateItemStack(ItemStack itemstack, Object list) {
int slot = 0;
String faceData = "";
try {
/*
if (list instanceof Object[]) {
slot = (int) ((Object[]) list)[0];
ItemMeta itemMeta = (ItemMeta) ((Object[]) list)[1];
itemstack.setItemMeta(itemMeta);
return new Object[] { slot, itemstack };
}
*/
Material rowType = itemstack.getType();
List<Object> metaList = (List<Object>) list;
if (metaList.size() > 0 && !(metaList.get(0) instanceof List<?>)) {
if (rowType.name().endsWith("_BANNER")) {
BannerMeta meta = (BannerMeta) itemstack.getItemMeta();
for (Object value : metaList) {
if (value instanceof Map) {
Pattern pattern = new Pattern((Map<String, Object>) value);
meta.addPattern(pattern);
}
}
itemstack.setItemMeta(meta);
}
else if (BlockGroup.SHULKER_BOXES.contains(rowType)) {
BlockStateMeta meta = (BlockStateMeta) itemstack.getItemMeta();
ShulkerBox shulkerBox = (ShulkerBox) meta.getBlockState();
for (Object value : metaList) {
ItemStack item = Util.unserializeItemStackLegacy(value);
if (item != null) {
shulkerBox.getInventory().addItem(item);
}
}
meta.setBlockState(shulkerBox);
itemstack.setItemMeta(meta);
}
return new Object[] { slot, faceData, itemstack };
}
int itemCount = 0;
Builder effectBuilder = FireworkEffect.builder();
for (List<Map<String, Object>> map : (List<List<Map<String, Object>>>) list) {
if (map.size() == 0) {
if (itemCount == 3 && (rowType == Material.FIREWORK_ROCKET || rowType == Material.FIREWORK_STAR)) {
buildFireworkEffect(effectBuilder, rowType, itemstack);
itemCount = 0;
}
itemCount++;
continue;
}
Map<String, Object> mapData = map.get(0);
if (mapData.get("slot") != null) {
slot = (Integer) mapData.get("slot");
}
else if (mapData.get("facing") != null) {
faceData = (String) mapData.get("facing");
}
else if (mapData.get("modifiers") != null) {
ItemMeta itemMeta = itemstack.getItemMeta();
if (itemMeta.hasAttributeModifiers()) {
for (Map.Entry<Attribute, AttributeModifier> entry : itemMeta.getAttributeModifiers().entries()) {
itemMeta.removeAttributeModifier(entry.getKey(), entry.getValue());
}
}
List<Object> modifiers = (List<Object>) mapData.get("modifiers");
for (Object item : modifiers) {
Map<Attribute, Map<String, Object>> modifiersMap = (Map<Attribute, Map<String, Object>>) item;
for (Map.Entry<Attribute, Map<String, Object>> entry : modifiersMap.entrySet()) {
try {
Attribute attribute = entry.getKey();
AttributeModifier modifier = AttributeModifier.deserialize(entry.getValue());
itemMeta.addAttributeModifier(attribute, modifier);
}
catch (IllegalArgumentException e) {
// AttributeModifier already exists
}
}
}
itemstack.setItemMeta(itemMeta);
}
else if (itemCount == 0) {
ItemMeta meta = Util.deserializeItemMeta(itemstack.getItemMeta().getClass(), map.get(0));
itemstack.setItemMeta(meta);
if (map.size() > 1 && (rowType == Material.POTION)) {
PotionMeta subMeta = (PotionMeta) itemstack.getItemMeta();
org.bukkit.Color color = org.bukkit.Color.deserialize(map.get(1));
subMeta.setColor(color);
itemstack.setItemMeta(subMeta);
}
}
else {
if ((rowType == Material.LEATHER_HORSE_ARMOR) || (rowType == Material.LEATHER_HELMET) || (rowType == Material.LEATHER_CHESTPLATE) || (rowType == Material.LEATHER_LEGGINGS) || (rowType == Material.LEATHER_BOOTS)) { // leather armor
for (Map<String, Object> colorData : map) {
LeatherArmorMeta meta = (LeatherArmorMeta) itemstack.getItemMeta();
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
meta.setColor(color);
itemstack.setItemMeta(meta);
}
}
else if ((rowType == Material.POTION)) { // potion
for (Map<String, Object> potionData : map) {
PotionMeta meta = (PotionMeta) itemstack.getItemMeta();
PotionEffect effect = new PotionEffect(potionData);
meta.addCustomEffect(effect, true);
itemstack.setItemMeta(meta);
}
}
else if (rowType.name().endsWith("_BANNER")) {
for (Map<String, Object> patternData : map) {
BannerMeta meta = (BannerMeta) itemstack.getItemMeta();
Pattern pattern = new Pattern(patternData);
meta.addPattern(pattern);
itemstack.setItemMeta(meta);
}
}
else if ((rowType == Material.CROSSBOW)) {
CrossbowMeta meta = (CrossbowMeta) itemstack.getItemMeta();
for (Map<String, Object> itemData : map) {
ItemStack crossbowItem = Util.unserializeItemStack(itemData);
if (crossbowItem != null) {
meta.addChargedProjectile(crossbowItem);
}
}
itemstack.setItemMeta(meta);
}
else if (rowType == Material.MAP || rowType == Material.FILLED_MAP) {
for (Map<String, Object> colorData : map) {
MapMeta meta = (MapMeta) itemstack.getItemMeta();
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
meta.setColor(color);
itemstack.setItemMeta(meta);
}
}
else if ((rowType == Material.FIREWORK_ROCKET) || (rowType == Material.FIREWORK_STAR)) {
if (itemCount == 1) {
effectBuilder = FireworkEffect.builder();
for (Map<String, Object> fireworkData : map) {
org.bukkit.FireworkEffect.Type type = (org.bukkit.FireworkEffect.Type) fireworkData.getOrDefault("type", org.bukkit.FireworkEffect.Type.BALL);
boolean hasFlicker = (Boolean) fireworkData.get("flicker");
boolean hasTrail = (Boolean) fireworkData.get("trail");
effectBuilder.with(type);
effectBuilder.flicker(hasFlicker);
effectBuilder.trail(hasTrail);
}
}
else if (itemCount == 2) {
for (Map<String, Object> colorData : map) {
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
effectBuilder.withColor(color);
}
}
else if (itemCount == 3) {
for (Map<String, Object> colorData : map) {
org.bukkit.Color color = org.bukkit.Color.deserialize(colorData);
effectBuilder.withFade(color);
}
buildFireworkEffect(effectBuilder, rowType, itemstack);
itemCount = 0;
}
}
else if ((rowType == Material.SUSPICIOUS_STEW)) {
for (Map<String, Object> suspiciousStewData : map) {
SuspiciousStewMeta meta = (SuspiciousStewMeta) itemstack.getItemMeta();
PotionEffect effect = new PotionEffect(suspiciousStewData);
meta.addCustomEffect(effect, true);
itemstack.setItemMeta(meta);
}
}
else {
BukkitAdapter.ADAPTER.setItemMeta(rowType, itemstack, map);
}
}
itemCount++;
}
}
catch (Exception e) {
e.printStackTrace();
}
return new Object[] { slot, faceData, itemstack };
}
public static Object[] populateItemStack(ItemStack itemstack, byte[] metadata) {
if (metadata != null) {
try {
ByteArrayInputStream metaByteStream = new ByteArrayInputStream(metadata);
BukkitObjectInputStream metaObjectStream = new BukkitObjectInputStream(metaByteStream);
Object metaList = metaObjectStream.readObject();
metaObjectStream.close();
metaByteStream.close();
return populateItemStack(itemstack, metaList);
}
catch (Exception e) {
e.printStackTrace();
}
}
return new Object[] { 0, "", itemstack };
}
}
@@ -5,6 +5,7 @@ import org.bukkit.block.Sign;
import org.bukkit.block.Skull;
import org.bukkit.block.sign.Side;
import net.coreprotect.config.Config;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
public class Paper_v1_20 extends Paper_v1_17 implements PaperInterface {
@@ -22,7 +23,17 @@ public class Paper_v1_20 extends Paper_v1_17 implements PaperInterface {
@Override
public String getSkullOwner(Skull skull) {
return skull.getPlayerProfile().getName();
String owner = skull.getPlayerProfile().getName();
if (Config.getGlobal().MYSQL) {
if (owner.length() > 255 && skull.getPlayerProfile().getId() != null) {
return skull.getPlayerProfile().getId().toString();
}
else if (owner.length() > 255) {
return owner.substring(0, 255);
}
}
return owner;
}
@Override
@@ -0,0 +1,31 @@
package net.coreprotect.patch.script;
import java.sql.Statement;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
public class __2_23_0 {
protected static boolean patch(Statement statement) {
try {
if (Config.getGlobal().MYSQL) {
try {
statement.executeUpdate("ALTER TABLE " + ConfigHandler.prefix + "skull MODIFY owner VARCHAR(255);");
}
catch (Exception e) {
Chat.console(Phrase.build(Phrase.PATCH_SKIP_UPDATE, ConfigHandler.prefix + "skull", Selector.FIRST, Selector.FIRST));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
@@ -3,6 +3,7 @@ package net.coreprotect.spigot;
import net.coreprotect.config.Config;
import net.coreprotect.utility.Color;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
@@ -18,8 +19,46 @@ public class Spigot_v1_16 extends SpigotHandler implements SpigotInterface {
public void addHoverComponent(Object message, String[] data) {
try {
if (Config.getGlobal().HOVER_EVENTS) {
String tooltipText = data[1]; // text displayed inside tooltip
TextComponent component = new TextComponent(TextComponent.fromLegacyText(data[2]));
component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(TextComponent.fromLegacyText(processComponent(data[1])))));
// BaseComponent[] displayComponent = TextComponent.fromLegacyText(processComponent(tooltipText));
if (tooltipText.contains(Color.MAGIC)) {
tooltipText = tooltipText.replace(Color.MAGIC, "");
// to-do
/*
ComponentBuilder formattedComponent = new ComponentBuilder();
StringBuilder messageTest = new StringBuilder();
String colorChar = String.valueOf(ChatColor.COLOR_CHAR);
boolean isObfuscated = false;
String[] tooltip = tooltipText.split(colorChar);
for (String splitText : tooltip) {
boolean setObfuscated = splitText.startsWith("k");
splitText = setObfuscated ? splitText.substring(1) : (splitText.length() > 0 ? colorChar : "") + splitText;
if ((setObfuscated && !isObfuscated) || (!setObfuscated && isObfuscated)) {
formattedComponent.append(TextComponent.fromLegacyText(processComponent(messageTest.toString())));
formattedComponent.obfuscated(false); // setObfuscated
formattedComponent.append(TextComponent.fromLegacyText(processComponent(splitText)));
messageTest.setLength(0);
isObfuscated = !isObfuscated;
}
else {
messageTest.append(splitText);
}
}
if (messageTest.length() > 0) {
formattedComponent.append(TextComponent.fromLegacyText(processComponent(messageTest.toString())));
}
displayComponent = formattedComponent.create();
*/
}
BaseComponent[] displayComponent = TextComponent.fromLegacyText(processComponent(tooltipText));
component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(displayComponent)));
((TextComponent) message).addExtra(component);
}
else {
@@ -56,7 +56,7 @@ import net.coreprotect.bukkit.BukkitAdapter;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Queue;
import net.coreprotect.database.Rollback;
import net.coreprotect.database.rollback.Rollback;
import net.coreprotect.language.Phrase;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.thread.CacheHandler;
@@ -57,7 +57,7 @@ import org.bukkit.inventory.meta.LeatherArmorMeta;
import net.coreprotect.CoreProtect;
import net.coreprotect.bukkit.BukkitAdapter;
import net.coreprotect.database.Rollback;
import net.coreprotect.database.rollback.Rollback;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.thread.Scheduler;
import net.coreprotect.utility.Util;
@@ -5,12 +5,9 @@ import org.bukkit.Bukkit;
import com.sk89q.worldedit.EditSession.Stage;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.world.World;
import net.coreprotect.CoreProtect;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
@@ -18,7 +15,6 @@ import net.coreprotect.thread.Scheduler;
import net.coreprotect.utility.Chat;
public class CoreProtectEditSessionEvent {
private static boolean initialized = false;
private static boolean isFAWE = false;
private static CoreProtectEditSessionEvent event = new CoreProtectEditSessionEvent();
@@ -37,12 +33,17 @@ public class CoreProtectEditSessionEvent {
}
try {
if (Bukkit.getServer().getPluginManager().getPlugin("AsyncWorldEdit") == null || Config.getGlobal().ENABLE_AWE) {
WorldEdit.getInstance().getEventBus().register(event);
initialized = true;
ConfigHandler.worldeditEnabled = true;
isFAWE = (Bukkit.getServer().getPluginManager().getPlugin("FastAsyncWorldEdit") != null);
}
WorldEdit.getInstance().getEventBus().register(new Object() {
@Subscribe
public void onEditSessionEvent(EditSessionEvent event) {
if (event.getActor() != null && event.getStage() == Stage.BEFORE_CHANGE) {
event.setExtent(new CoreProtectLogger(event.getActor(), event.getWorld(), event.getExtent()));
}
}
});
initialized = true;
ConfigHandler.worldeditEnabled = true;
isFAWE = (Bukkit.getServer().getPluginManager().getPlugin("FastAsyncWorldEdit") != null);
}
catch (Exception e) {
// Failed to initialize WorldEdit logging
@@ -51,10 +52,10 @@ public class CoreProtectEditSessionEvent {
Scheduler.runTask(CoreProtect.getInstance(), () -> {
try {
if (isInitialized()) {
Chat.console(Phrase.build(Phrase.INTEGRATION_SUCCESS, "WorldEdit", Selector.FIRST));
Chat.console(Phrase.build(Phrase.INTEGRATION_SUCCESS, isFAWE() ? "FastAsyncWorldEdit" : "WorldEdit", Selector.FIRST));
}
else {
Chat.console(Phrase.build(Phrase.INTEGRATION_ERROR, "WorldEdit", Selector.FIRST));
Chat.console(Phrase.build(Phrase.INTEGRATION_ERROR, isFAWE() ? "FastAsyncWorldEdit" : "WorldEdit", Selector.FIRST));
}
}
catch (Exception e) {
@@ -72,19 +73,10 @@ public class CoreProtectEditSessionEvent {
WorldEdit.getInstance().getEventBus().unregister(event);
initialized = false;
ConfigHandler.worldeditEnabled = false;
Chat.console(Phrase.build(Phrase.INTEGRATION_SUCCESS, "WorldEdit", Selector.SECOND));
Chat.console(Phrase.build(Phrase.INTEGRATION_SUCCESS, isFAWE() ? "FastAsyncWorldEdit" : "WorldEdit", Selector.SECOND));
}
catch (Exception e) {
Chat.console(Phrase.build(Phrase.INTEGRATION_ERROR, "WorldEdit", Selector.SECOND));
}
}
@Subscribe
public void wrapForLogging(EditSessionEvent event) {
Actor actor = event.getActor();
World world = event.getWorld();
if (actor != null && event.getStage() == (isFAWE ? Stage.BEFORE_HISTORY : Stage.BEFORE_CHANGE)) {
event.setExtent(new CoreProtectLogger(actor, world, event.getExtent()));
Chat.console(Phrase.build(Phrase.INTEGRATION_ERROR, isFAWE() ? "FastAsyncWorldEdit" : "WorldEdit", Selector.SECOND));
}
}
}
@@ -4,12 +4,16 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@@ -19,7 +23,6 @@ import net.coreprotect.config.Config;
import net.coreprotect.utility.Util;
public class CoreProtectLogger extends AbstractDelegateExtent {
private final Actor eventActor;
private final World eventWorld;
private final Extent eventExtent;
@@ -35,7 +38,12 @@ public class CoreProtectLogger extends AbstractDelegateExtent {
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) throws WorldEditException {
org.bukkit.World world = BukkitAdapter.adapt(eventWorld);
if (!Config.getConfig(world).WORLDEDIT) {
return eventExtent.setBlock(position, block);
if (CoreProtectEditSessionEvent.isFAWE()) {
return eventExtent.setBlock(position.getX(), position.getY(), position.getZ(), block);
}
else {
return eventExtent.setBlock(position, block);
}
}
BlockState oldBlock = eventExtent.getBlock(position);
@@ -48,16 +56,59 @@ public class CoreProtectLogger extends AbstractDelegateExtent {
// e.g. BaseBlock block = eventWorld.getBlock(position);
ItemStack[] containerData = CoreProtectEditSessionEvent.isFAWE() ? null : Util.getContainerContents(oldType, null, location);
if (eventExtent.setBlock(position, block)) {
WorldEditLogger.postProcess(eventExtent, eventActor, position, location, block, baseBlock, oldType, oldBlock, containerData);
return true;
if (CoreProtectEditSessionEvent.isFAWE()) {
if (eventExtent.setBlock(position.getX(), position.getY(), position.getZ(), block)) {
WorldEditLogger.postProcess(eventExtent, eventActor, position, location, block, baseBlock, oldType, oldBlock, containerData);
return true;
}
}
else {
if (eventExtent.setBlock(position, block)) {
WorldEditLogger.postProcess(eventExtent, eventActor, position, location, block, baseBlock, oldType, oldBlock, containerData);
return true;
}
}
return false;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block) throws WorldEditException {
return setBlock(BlockVector3.at(x,y,z), block);
return this.setBlock(BlockVector3.at(x, y, z), block);
}
@Override
public int replaceBlocks(final Region region, final Mask mask, final Pattern pattern) throws MaxChangedBlocksException {
org.bukkit.World world = BukkitAdapter.adapt(eventWorld);
if (!Config.getConfig(world).WORLDEDIT) {
return eventExtent.replaceBlocks(region, mask, pattern);
}
processPatternToBlocks(world, region, pattern);
return eventExtent.replaceBlocks(region, mask, pattern);
}
@Override
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
org.bukkit.World world = BukkitAdapter.adapt(eventWorld);
if (!Config.getConfig(world).WORLDEDIT) {
return eventExtent.setBlocks(region, pattern);
}
processPatternToBlocks(world, region, pattern);
return eventExtent.setBlocks(region, pattern);
}
private void processPatternToBlocks(org.bukkit.World world, Region region, Pattern pattern) {
for (BlockVector3 position : region.clone()) {
BlockState oldBlock = eventExtent.getBlock(position);
Material oldType = BukkitAdapter.adapt(oldBlock.getBlockType());
Location location = new Location(world, position.getBlockX(), position.getBlockY(), position.getBlockZ());
BaseBlock baseBlock = WorldEditLogger.getBaseBlock(eventExtent, position, location, oldType, oldBlock);
// No clear way to get container content data from within the WorldEdit API
// Data may be available by converting oldBlock.toBaseBlock().getNbtData()
// e.g. BaseBlock block = eventWorld.getBlock(position);
ItemStack[] containerData = CoreProtectEditSessionEvent.isFAWE() ? null : Util.getContainerContents(oldType, null, location);
WorldEditLogger.postProcess(eventExtent, eventActor, position, location, pattern.applyBlock(position), baseBlock, oldType, oldBlock, containerData);
}
}
}