118 Commits
Author SHA1 Message Date
Intelli b5f534fd2c CoreProtect Community Edition v24.0 2026-07-07 13:22:19 -06:00
Intelli 4ecab0b101 Added extended logging support for sulfur spikes 2026-07-06 20:38:41 -06:00
Intelli 2f196fb385 Fixed dripstone logging duplicate #gravity break on attached block break 2026-07-06 19:07:05 -06:00
Intelli 32e074666d Always set air blocks with physics false 2026-07-06 17:13:37 -06:00
Intelli 6f86e08849 Apply blocks with physics updates in second pass 2026-07-06 17:02:39 -06:00
Intelli 3a95881ea4 Log all entity explosions by name rather than #explosion
E.g. #sulfur_cube
2026-07-06 16:44:12 -06:00
Intelli 04575029c9 Target Paper 26.2 2026-07-05 16:01:55 -06:00
Intelli 9d04c025be Optimize rollback chunk batching and prefetching 2026-07-05 15:31:17 -06:00
Intelli a0ae242dac Fixed incorrect logging of typed block events (II) (fixes #917) 2026-07-03 16:37:08 -06:00
Intelli 4c2c304329 Fixed compatibility issues with older MC versions (fixes #921) 2026-07-03 13:23:43 -06:00
Intelli 943d471269 Fixed FallingBlock being logged when block-movement: false (fixes #918) 2026-07-03 12:41:00 -06:00
Intelli 948ba32e77 Force transaction snapshots on item-type boundary 2026-07-03 12:11:26 -06:00
Intelli 7d47684afb Improve container transaction logging performance 2026-07-03 11:35:00 -06:00
Intelli 3da2bc554d Improved hopper logging logic 2026-07-03 10:37:46 -06:00
Intelli ec699a5a34 Stop bundling OSHI 2026-07-02 16:05:25 -06:00
Intelli 9a37a0d33a Added additional validation for armor stand damage events 2026-07-01 14:46:39 -06:00
Intelli 5ed0863a87 Improve rollback performance + Folia hardening 2026-06-29 20:09:37 -06:00
Intelli 2f4eeeffca Update supported version in README 2026-06-23 14:16:35 -06:00
Intelli b3f5959af4 Fixed incorrect logging of typed block events (fixes #917) 2026-06-09 12:24:33 -06:00
Intelli eee8d1c39b Update blacklist version requirements in documentation 2026-06-01 20:16:55 -06:00
Intelli 15aaaf8051 Harden v24 patch script 2026-05-30 14:43:09 -06:00
Intelli 2429967b79 Added logging for all Silverfish infestations 2026-05-27 20:33:34 -06:00
Intelli 68d3f19d93 Added Ghast fireball attribution 2026-05-27 19:30:18 -06:00
Intelli e2f8da9070 Mention snowballs, potions, ender pearls, tridents, and wind charges in README 2026-05-27 18:04:50 -06:00
Intelli b7a662d137 Remove bucket usage line from README 2026-05-27 17:56:27 -06:00
Intelli cddbc398a6 README cleanup 2026-05-27 17:54:39 -06:00
Intelli 1893eac47a Extended features + logged actions info sections in README 2026-05-27 17:33:19 -06:00
Intelli 305e6de3ac Update README.md 2026-05-27 14:06:50 -06:00
Intelli 5a8b0f93d3 Unify README.md 2026-05-27 13:58:29 -06:00
Intelli 1a9b542517 Link to other versions 2026-05-27 12:11:38 -06:00
Intelli 8d5b0a20b6 Changed minimum MC version to 1.16.5 2026-05-27 11:04:13 -06:00
1wairesd 39e82953b4 feat: add & color code support in Chat and Language (#907) 2026-05-27 10:53:35 -06:00
TWME bdfd6b1576 Log pattern setBlocks for block sets (#908)
Add handling for setBlocks calls that use block sets and generic BlockStateHolder patterns. Imported java.util.Set and added an override for the generic <B extends BlockStateHolder<B>> setBlocks to delegate to the Pattern variant, plus a new setBlocks(Set<BlockVector3>, Pattern) override that checks the WORLDEDIT config, processes each target position to record previous block state and container contents (unless FAWE), and posts WorldEditLogger events before delegating to eventExtent. Includes a new helper processPatternToBlocks and documents limitations around reading container/NBT data from the WorldEdit API.
2026-05-27 10:51:11 -06:00
2291e0d9c7 #810 Add option to give looked up items into inventory (#811)
* Add givable items to ItemUtils

* Improve performance of givable items methods

* Add ItemUtils#getItemStack

* Add ChatUtils#createGiveItemComponent

* Fix ChatUtils#createGiveItemComponent not returning empty String when no id is given

* Add 'give item' components to StandardLookupThread

* Add GivableItemIdParser

* Add CommandParser#parseGivableItemId

* Add Phrase#INVALID_ITEM_ID

* Add GiveCommand

* Update permissions.md

* Fix itemId parsing

* Improve performance of givable items methods

* Update coreprotect.give permission to be false by default

* Only show give component if player has permission to use the command

---------

Co-authored-by: Leonard Steppy <leonard.steppy@outlook.de>
Co-authored-by: Intelli <6790859+Intelli@users.noreply.github.com>
2026-05-27 10:47:57 -06:00
Intelli a8aeeca62c Bump version info 2026-05-26 13:04:51 -06:00
Intelli e7197123aa Fixed update notice issue 2026-05-26 13:02:29 -06:00
Intelli 6e6f8d203b Added logging for custom skull textures (fixes #70) 2026-05-21 14:59:52 -06:00
Intelli cb09ddeb0b Added automatic error reporting 2026-05-21 13:54:39 -06:00
Intelli b7a452bf03 Added logging for villagers killed by lightning (fixes #674) 2026-05-20 19:25:50 -06:00
Intelli 7f7de03f54 Fixed MysqlDataTruncation error when logging large bundles (fixes #799) 2026-05-20 18:40:37 -06:00
Intelli ec96019bc2 Fixed custom block rollbacks (fixes #895) 2026-05-20 13:52:52 -06:00
Intelli 5b2e8883ea Improve auto purge documentation 2026-05-20 13:01:12 -06:00
Intelli 6571e91c56 Formatting improvements 2026-05-20 12:56:31 -06:00
Intelli 434d42b547 Added auto-purge documentation 2026-05-20 12:45:54 -06:00
Intelli ba96dd1d19 Added auto-purge-time config value 2026-05-20 11:54:02 -06:00
Intelli 7a730a76fc Merge branch 'master' of github.com:PlayPro/CoreProtect 2026-05-19 17:12:21 -06:00
Intelli 6994ec2ac4 Bump supported MC version to 26.1.2 2026-05-19 17:12:14 -06:00
Intelli 3914e5e989 Update API doc plugin version to v24.0 2026-05-15 13:15:03 -06:00
Intelli ab939cfa6f Update API version from 11 to 12 in documentation 2026-05-15 11:39:36 -06:00
Intelli 39005ee978 UI improvements 2026-05-14 12:51:02 -06:00
Intelli acadd24c70 Share PURGE_TABLES outside of manual purges 2026-05-14 12:35:22 -06:00
Intelli ab4c405dd2 Add auto purge config + status information 2026-05-14 12:30:30 -06:00
Intelli fe0274b069 Add BackgroundService extension 2026-05-13 18:23:39 -06:00
Intelli 1bd0a0f8b6 Fixed jukebox rollback cast issue 2026-05-13 13:29:48 -06:00
Intelli b6acf109d4 Fix Folia falling block entity change handling 2026-05-13 13:29:36 -06:00
Intelli 6d1ddb8580 Added refreshBrain reflection (fixes #905) 2026-05-13 12:36:09 -06:00
Intelli 6d60951cb9 Properly handle physics update exceptions 2026-05-13 11:55:52 -06:00
Intelli 3f7c892153 Drop "specialPrice" from villager rollbacks/restores 2026-05-12 20:30:37 -06:00
Intelli 962ab485ee Properly log villager trade and gossip data (fixes #904) 2026-05-12 16:06:42 -06:00
Intelli 559ee73edf Fixed BlockResult not handling entity kill rows properly 2026-05-12 12:28:19 -06:00
Intelli 5c561c866d Replace magic action numbers with constants 2026-05-12 10:38:27 -06:00
Intelli 78d8301751 Utilize internal model for shared APIs 2026-05-11 15:32:22 -06:00
Intelli 688b4b930d Added inventoryLookup API method 2026-05-11 13:28:08 -06:00
Intelli cf04a42d3e Added itemLookup API method 2026-05-11 12:56:05 -06:00
Intelli bd5c1f33b7 API cleanup 2026-05-07 16:17:38 -06:00
Intelli a658c32ce4 Added usernameLookup API method 2026-05-06 15:49:02 -06:00
Intelli 592a4f25e4 Added typed block lookup methods 2026-05-06 15:27:14 -06:00
Intelli 29256b47e6 Added typed session lookups 2026-05-06 15:04:45 -06:00
Intelli 9924a9376e Added typed API helpers 2026-05-06 13:41:46 -06:00
Intelli cebcc8655a Added signLookup API methods 2026-05-06 13:31:39 -06:00
Intelli 3be769ed96 Added Tatar language file 2026-05-06 13:09:18 -06:00
Intelli 3ffece26a3 Added chatLookup and commandLookup API methods 2026-05-05 16:01:14 -06:00
Intelli 7eaa88eb7f Added radius support for container lookup API 2026-05-05 13:58:24 -06:00
RestitutorandIntelli c4d3dda0ad Added Container Lookup API (#854)
* Add ContainerResult and BoxAPI

* Added area container lookup and "v12" docs

* Revert v11.md

* Simplify container API

---------

Co-authored-by: Intelli <contact@intelli.software>
2026-05-05 13:00:55 -06:00
Intelli 8b0e735313 Fixed NullPointerException on MC 26 servers 2026-05-04 19:10:15 -06:00
Intelli 34ada262c2 Restore villager job-site memory on rollback (fixes #753) 2026-05-04 18:41:51 -06:00
Intelli d7aa696c28 Added noteblock normalization (fixes #712) 2026-04-24 20:46:56 -06:00
Intelli 67033ac08d Improve WorldEdit / FAWE version parsing (fixes #678) 2026-04-24 20:18:44 -06:00
Intelli 2c30ba626a Fixed Folia death logging crash (fixes #750) 2026-04-24 19:51:10 -06:00
Intelli 4ae0affe4b Next-generation sand/gravel logging (fixes #762)
- Sand/gravel that breaks (e.g. landing on a torch) no longer logs a phantom placement.
- Falls now log at the actual landing coord, even when blocks like torches or grass are in the column.
- Naturally-triggered falls (mobs, world gen, plugins, explosions) are now logged.
- Falls caused by a player breaking the support are now attributed to the breaker at the real landing coord.
- Falls without a player cause are now attributed to a new #gravity tag.
- Rollback and restore of sand/gravel falls are now symmetric, leaving no phantom blocks in either direction.
2026-04-24 16:08:45 -06:00
Intelli 0d47338038 Fixed beds not always rolling back in correct state (fixes #856) 2026-04-24 14:33:04 -06:00
Intelli afbbbd5aab Fixed armor stand and end crystal breaks logging as air 2026-04-24 14:21:32 -06:00
Intelli cce8c9eb51 Improved painting variant handling 2026-04-24 14:10:02 -06:00
Intelli eaae2afaf8 Fixed duplicate TNT prime events being logged 2026-04-24 13:15:55 -06:00
Intelli a1458a38be Fixed ConcurrentModificationException when using queueLookup in API (fixes #481) 2026-04-24 12:14:49 -06:00
Intelli 7ccb3eff34 Fixed fire being logged as air 2026-04-24 12:05:10 -06:00
Intelli def5a99096 Added logging for removal of primed TNT & fire fade (implements #824) 2026-04-24 12:04:54 -06:00
Intelli a92a050d2f Extended CoreProtectPreLogEvent with Action, actionId, material, entityType, and message metadata (implements #846) 2026-04-24 11:03:38 -06:00
Intelli 14b0a712de Add v12.md template 2026-04-24 10:31:06 -06:00
Intelli cdc8082c3e Added logging for dropping items into a hopper 2026-04-24 09:50:00 -06:00
Intelli 829bcc530d Fixed books placed in lecterns not being logged (fixes #761) 2026-04-24 09:31:16 -06:00
Intelli aa2a3b9e8e Fixed incorrect string value error on legacy MySQL databases (fixes #826) 2026-04-23 22:05:22 -06:00
Intelli eee96fb5f9 Added BlockType support for custom block support (implements #801) 2026-04-23 18:28:10 -06:00
Intelli fc91bc558c Further improved attribute handling 2026-04-23 17:39:45 -06:00
Intelli 127170d7b6 Fixed NullPointerException when performing a preview with invalid data (fixes #862) 2026-04-23 15:31:16 -06:00
Intelli 7caa617a34 Added argument validation to purge command (fixes #848) 2026-04-23 15:10:06 -06:00
Intelli 7c7013f49f Added logging for flowers being placed in flower pots (fixes #509) 2026-04-23 14:22:54 -06:00
Intelli 4d311f5248 Improved Folia support (fixes #892) 2026-04-23 13:45:30 -06:00
Intelli f5ac148b57 Added logging for Zombie's breaking doors (fixes #865) 2026-04-23 13:10:14 -06:00
Intelli e852d75264 Fixed IllegalArgumentException for lava/water in inventory rollbacks (fixes #802) 2026-04-23 13:00:42 -06:00
Intelli 383caedff5 Changed blacklist.txt comment character to ';' (fixes #891) 2026-04-23 12:36:52 -06:00
Intelli bd449d1b89 Extended de-dupe logic to include droppers/dispensers/fluids/kills 2026-04-23 12:36:14 -06:00
Intelli c706cf5b18 Added #bundle tag (implements #855) 2026-04-23 10:25:49 -06:00
Intelli d69fffbce0 Improved MySQL index handling (fixes #867) 2026-04-23 09:42:21 -06:00
Intelli ff36b6e0e6 Fixed AdvancedChests causing circular load order (fixes #831) 2026-04-22 23:00:49 -06:00
Intelli a90b0ea18a Fixed NoSuchMethodError on transaction events when using Arclight (fixes #864) 2026-04-22 20:41:54 -06:00
Intelli 7dbd928edc Fixed Crimson/Warped fungus growth not respecting mushroom-growth (fixes #866) 2026-04-22 20:21:25 -06:00
Intelli 99130fdcdb Improve metadata sanitization 2026-04-22 20:04:01 -06:00
Intelli 42a2965cd1 Fixed water incorrectly being logged in Nether (fixes #857) 2026-04-22 19:46:44 -06:00
Intelli 971ff57496 Added byte data sanitization to resolve NoSuchElementException (fixes #890) 2026-04-22 18:31:19 -06:00
Intelli 6c04867eb8 Fixed MySQL warnings when logging paintings on MC 1.21+ (fixes #829) 2026-04-22 17:47:32 -06:00
Intelli b83b39feae Formatting fixes 2026-04-22 16:52:53 -06:00
Intelli 80a0f24e10 Merge branch 'master' of github.com:PlayPro/CoreProtect 2026-04-22 16:50:06 -06:00
Intelli 9cadca9acb Fix NullPointerException on PurPur servers when destination hopper has moved (fixes #885) 2026-04-22 16:49:59 -06:00
Warrior 0c389e92f3 Fix wind charge/add new egg throw logging (#884) 2026-04-22 16:40:19 -06:00
Alisa GusmeroliandIntelli db94ad70eb Blacklist improvements (#847)
* add new blacklist features

* update documentation to include new blacklist additions

---------

Co-authored-by: Intelli <6790859+Intelli@users.noreply.github.com>
2026-04-22 16:36:15 -06:00
Alisa Gusmeroli eff43b7d6f fix waterlogged bucket incorrect logging (#860) 2026-04-22 16:15:51 -06:00
Intelli f0aad273f1 Update excludes 2026-04-22 15:46:45 -06:00
235 changed files with 10382 additions and 1692 deletions

No files matched your search

+12
View File
@@ -173,6 +173,9 @@ Desktop.ini
## Misc.
#############
.claude
AGENTS.md
CLAUDE.md
.cursorrules
.windsurfrules
.clinerules
@@ -213,8 +216,17 @@ hs_err_pid*
# Documentation dev folder
docs/dev/
# symlinks
CoreProtect-TestAPI
CoreProtect-Fabric
CoreProtect-Hytale
publish/
# Extensions
/src/main/java/net/coreprotect/utility/extensions
!/src/main/java/net/coreprotect/utility/extensions/Extensions.java
/.apt_generated/
/.apt_generated_tests/
# Server side files
server/*
+167 -16
View File
@@ -1,55 +1,206 @@
![CoreProtect](https://userfolio.com/uploads/coreprotect-banner-v19.png)
[![Artistic License 2.0](https://img.shields.io/github/license/PlayPro/CoreProtect?&logo=github)](LICENSE)
[![Artistic License 2.0](https://img.shields.io/github/license/PlayPro/CoreProtect?&logo=github)](https://github.com/PlayPro/CoreProtect/blob/master/LICENSE)
[![GitHub Workflows](https://github.com/PlayPro/CoreProtect/actions/workflows/build.yml/badge.svg)](https://github.com/PlayPro/CoreProtect/actions)
[![Netlify Status](https://img.shields.io/netlify/c1d26a0f-65c5-4e4b-95d7-e08af671ab67)](https://app.netlify.com/sites/coreprotect/deploys)
[![CodeFactor](https://www.codefactor.io/repository/github/playpro/coreprotect/badge)](https://www.codefactor.io/repository/github/playpro/coreprotect)
[![Join us on Discord](https://img.shields.io/discord/348680641560313868.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/b4DZ4jy)
CoreProtect
===========
# CoreProtect
CoreProtect is a blazing fast data logging and anti-griefing tool for Minecraft servers.
CoreProtect is a fast, efficient data logging and anti-griefing tool. Inspect, lookup, rollback, and restore any amount of damage without impacting your server performance.
For a detailed description of the plugin, please visit [coreprotect.net](https://coreprotect.net).
CoreProtect is the [#1 anti-griefing plugin](https://bstats.org/plugin/bukkit/CoreProtect), and has been actively developed since early 2012.
| Quick Links | |
| --- | --- |
| CoreProtect Discord: | [discord.gg/b4DZ4jy](https://discord.gg/b4DZ4jy) |
| CoreProtect Patreon: | [patreon.com/coreprotect](https://www.patreon.com/coreprotect) |
| CoreProtect Documentation: | [docs.coreprotect.net](https://docs.coreprotect.net) |
| Downloads for MC 1.14 - 26.1: | [coreprotect.net/latest](https://coreprotect.net/latest/) |
| Downloads for MC 1.14 - 26.2: | [coreprotect.net/latest](https://coreprotect.net/latest/) |
| Downloads for MC 1.8 - 1.12: | [coreprotect.net/legacy](https://coreprotect.net/legacy/) |
| Downloads for Fabric: | [coreprotect.net/fabric](https://coreprotect.net/fabric) |
| Downloads for Hytale: | [coreprotect.net/hytale](https://coreprotect.net/hytale) |
bStats
------
[![bStats Graph Data](https://bstats.org/signatures/bukkit/CoreProtect.svg)](https://bstats.org/plugin/bukkit/CoreProtect)
## API
API
------
### [API Documentation](https://docs.coreprotect.net/api/)
### Dependency Information
Maven
Maven:
```xml
<repository>
<id>playpro-repo</id>
<url>https://maven.playpro.com</url>
</repository>
```
```xml
<dependency>
<groupId>net.coreprotect</groupId>
<artifactId>coreprotect</artifactId>
<version>23.2</version>
<version>24.0</version>
<scope>provided</scope>
</dependency>
```
Contributing
------
## Donation Keys
To support the project and obtain a donation key, visit [coreprotect.net/donate](https://coreprotect.net/donate/).
## Other Plugins
* DarkerNights: [spigotmc.org/resources/darkernights.87814](https://www.spigotmc.org/resources/darkernights.87814/)
* TransitTubes: [patreon.com/posts/75731668](https://www.patreon.com/posts/75731668)
## Video Tutorial
[![CoreProtect video tutorial](https://www.userfolio.com/uploads/coreprotect-video-tutorial.png)](https://youtu.be/JwijCiueZ3Y)
## Core Features
* Fast, efficient data logging.
* Rollbacks and restores with lag-free processing.
* Multi-threaded to ensure server performance is never impacted.
* No configuration required. Install the plugin, and you're good to go.
* SQLite storage by default, with optional MySQL support.
* Supports Bukkit, Spigot, Paper, Folia, MultiPaper, and more.
* Permission system support and advanced lookup permissions.
* Easy-to-use commands and inspector.
* Advanced lookup filters and operation limits by radius, world, or WorldEdit selection.
* Paginated results with clickable pagination.
* Preview rollbacks and restores, and undo rollbacks by restoring the same data.
* Rollback or restore specific users, multiple users, or global activity.
* Inventory rollback support.
* Purge old data by time, world, and block type.
* Multi-world support.
* Configurable global and per-world logging settings.
* Safe default parameters.
* Include or exclude specific blocks, items, entities, or users, plus logging blacklists.
* WorldEdit and supported FAWE logging.
* Enhanced item lookup tooltips.
* Localization and translation support.
* Automatic update checking and error reporting.
* Developer and networking API support.
* *...and much more!*
## What does it log?
### Blocks and World Changes
* Blocks placed or broken by players.
* Natural block breakage, such as attached blocks breaking when their support is removed.
* Block movement, including falling sand, gravel, and piston movement.
* Water and lava placement, removal, and flow.
* Liquid tracking, associating flowing liquids with the player who placed the source.
* Fire ignition from flint and steel or fire charges, block burning, and fire fade.
* Optional natural fire extinguishing.
* TNT, Creeper, Ghast, and other explosions, plus primed TNT removal.
* Entities changing blocks, including Endermen, Ender Dragons, and zombies breaking doors.
* Leaf decay.
* Tree growth linked back to the player who planted the sapling.
* Mushroom, vine, amethyst, chorus, and bamboo growth.
* Sculk spread from sculk catalysts.
* Nether portal and other natural portal generation.
* Crops trampled by players and turtle eggs trampled by players or entities.
* Snow generated by snow golems.
* Liquid-formed blocks such as obsidian, cobblestone, and concrete.
* Flowers placed in flower pots.
* Dragon egg teleportation.
* Suspicious sand and gravel brushing or destruction.
* Custom blocks, such as CraftEngine blocks.
### Containers, Inventories, and Items
* Items taken from or placed into vanilla or supported third-party containers.
* Hopper, dropper, and dispenser transactions, including container transfers.
* Player inventory transactions, including items dropped, thrown, shot, or picked up.
* Items broken, created, destroyed, deposited, or withdrawn by players.
* Items placed on campfires and lectern book transactions.
* Chiseled bookshelf, decorated pot, and shelf inventory transactions.
* Copper Golem chest and jukebox transactions, plus crafter slot changes.
* Bundle actions through the `#bundle` tag.
* Items crafted or traded with villagers.
* Allay item exchanges.
* Paintings and item frames.
### Entities and Player Activity
* Entity deaths and detailed death reasons.
* Player-caused entity kills, including animals and monsters.
* Armor stands and End Crystals.
* Villagers killed by lightning, gossip data, and job-site memories.
* Thrown eggs, snowballs, potions, ender pearls, tridents, and wind charges.
* Player interactions with doors, buttons, levers, containers, bookshelves, and jukeboxes.
* Sign text, color, glow, wax, and modern double-sided signs.
* Player chat messages and commands.
* Player sessions including logins and logouts, player deaths, and username changes.
* Skull skin texture data on Paper servers and custom skull textures.
* WorldEdit changes and supported FAWE clipboard pastes.
* *...and more!*
## How to use the inspector
Once you have the inspector enabled with `/core inspect` or `/co i`, you can do the following:
* Left-click a block to see who placed that block.
* Right-click a block to see what adjacent block was removed.
* Right-click while placing a block in a location to see what block was removed at that location.
* Right-click while placing a block in another block to see who placed it. For example, place dirt in water to see who placed the water.
* Right-click a door, button, lever, container, or similar block to see who last used it.
## A Few Reviews
* *"It's easy to use and lightning fast when it comes to rollbacks."*
* *"I've been running a MC server since before Bukkit, so I've used just about every block logger out there. CoreProtect is the best and the fastest."*
* *"Go with CoreProtect. It's fast, updated frequently, and logs WorldEdit."*
* *"Overall it felt more natural, simpler, and much faster to use CoreProtect than Prism, which just doesn't compare."*
* *"CoreProtect brings complex logging and rollbacks, whilst at the same time keeping a low profile."*
* *Featured on [Linus Tech Tips](https://www.userfolio.com/uploads/coreprotect-linus.png).*
## Useful Links
**Documentation**
https://docs.coreprotect.net
**Commands**
https://docs.coreprotect.net/commands/
**Permissions**
https://docs.coreprotect.net/permissions/
**API Documentation**
https://docs.coreprotect.net/api/
**Feedback & Support**
https://github.com/PlayPro/CoreProtect/issues
**Discord**
Join us on Discord: https://discord.gg/b4DZ4jy
**Donate**
Enjoy using CoreProtect and want to show your support? [Join our Patreon!](https://www.patreon.com/coreprotect)
**Sponsors**
Thanks to [HostHorde](https://www.hosthorde.com) for sponsoring CoreProtect!
## Bug Reports
For any bug reports, please submit a ticket here:
https://github.com/PlayPro/CoreProtect/issues
Thanks for your support!
## bStats
[![bStats Graph Data](https://bstats.org/signatures/bukkit/CoreProtect.svg)](https://bstats.org/plugin/bukkit/CoreProtect)
## Contributing
CoreProtect is an open source project, and gladly accepts community contributions.
If you'd like to contribute, please read our contributing guidelines here: [CONTRIBUTING.md](CONTRIBUTING.md)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](CONTRIBUTING.md#code-of-conduct)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](CONTRIBUTING.md#code-of-conduct)
+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:** | 11 |
| **Plugin Version:** | v23.1+ |
| **API Version:** | 12 |
| **Plugin Version:** | v24.0+ |
| **Maven:** | [maven.playpro.com](https://maven.playpro.com) |
*Documentation for the API version 10 can be found [here](/api/version/v11/).*
*Documentation for the API version 12 can be found [here](/api/version/v12/).*
File diff suppressed because it is too large. Load diff
+72
View File
@@ -0,0 +1,72 @@
# Automatic Purging
Automatic purging removes old CoreProtect data on a daily schedule, helping keep database growth under control without requiring manual `/co purge` runs.
> **Note:** Automatic purging is not enabled by default. This feature is exclusive to CoreProtect 24.0+ [Patreon builds](http://patreon.com/coreprotect).
## Configuration
To enable automatic purging, set `auto-purge` in `config.yml` to the amount of data you want to keep:
```yaml
auto-purge: 180d
```
This example keeps the most recent 180 days of CoreProtect data and automatically removes older data.
Supported values use the same style as CoreProtect command times, such as `30d`, `12w`, or `6mo`. The minimum automatic purge value is `30d`. Set `auto-purge: false` to disable automatic purging.
## Schedule
Automatic purging runs once per day using your server's local time. By default, it runs at midnight.
To change the daily runtime, manually add `auto-purge-time: 03:30` to `config.yml`.<br>
Use 24-hour `HH:mm` server time.
After changing `auto-purge` or `auto-purge-time`, use `/co reload` or restart the server. Changes apply to the next scheduled run.
When automatic purging is enabled, CoreProtect logs the next scheduled run when the server starts and again after an automatic purge completes.
## How It Works
Automatic purging runs in the background and removes old data incrementally in small chunks, with short pauses between database work. The server can continue to be used normally while it runs.
Automatic purging uses the same CoreProtect data tables as manual purging, but it does not rebuild the SQLite database or optimize MySQL tables. It deletes old rows in place, which helps maintain the current database size over time but may not immediately reduce the database file size or table size on disk.
Only one automatic purge can run at a time. If the server shuts down, a manual purge starts, a database migration or conversion starts, or the consumer is manually paused, the automatic purge stops safely and can continue during the next scheduled run.
## Important Notes
* **Patreon exclusive:** Only available in CoreProtect 24.0+ [Patreon builds](http://patreon.com/coreprotect)
* **Not enabled by default:** Set `auto-purge` in `config.yml` to enable automatic purging
* **Background cleanup:** Automatic purging is designed to run while the server remains usable
## Existing Databases
If enabling automatic purging on a new database, no additional action is required.
If enabling automatic purging on an existing database, it is recommended to run a manual purge first using the same time value:
```text
/co purge t:180d
```
For MySQL, add `#optimize` if you want to reclaim disk space during the initial manual purge:
```text
/co purge t:180d #optimize
```
This lets the manual purge reduce the existing database size, while automatic purging helps keep the database from growing beyond the configured retention period afterward.
## Status
Use `/co status` to see how many rows have been automatically purged since the last server restart.
## Troubleshooting
**Automatic purging won't start:**
* Verify you're using a CoreProtect 24.0+ [Patreon build](http://patreon.com/coreprotect)
* Verify `auto-purge` is set to a valid value of at least `30d`
* Check the server console for automatic purge scheduling messages
+23 -7
View File
@@ -21,15 +21,31 @@ Secondary configuration files override the value specified in config.yml. If you
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).
2. Enter the names of the users, commands, blocks, or entities you'd like to disable logging for (each entry 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 "#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:
The blacklist supports disabling logs for:
- Users, which includes Players and non-player users, such as "#creeper"
- Commands, such as `/help`
- Blocks, such as minecraft:stone. Only `block` actions are affected.
- Entities, such as minecraft:creeper, which will disable logging the death for that entity. *Note: renamed entities will be logged even if blacklisted.*
- Filters can also be specified for a particular user, by using the `@` symbol after the specific item, block, or entity namespaced ID. The format is `id@user`. This will filter all `block`, `kill`, `item` and `container` actions involving that particular block, item or mob, only when caused by the specified player or non-player user.
- Items and container actions are only affected by filtered blacklist entries, not by generic item or block IDs.
*Please note that you must include the namespace (e.g. minecraft:) for blocks, entities and items.*
An example blacklist.txt file would look like this:
```text
Notch
#tnt
/help
minecraft:stone
Notch ; User
#tnt ; TNT explosions
/help ; Help command
minecraft:stone ; Stone blocks
minecraft:creeper ; Creeper entity
minecraft:shears@#dispenser ; Shears being dispensed
```
*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".*
*Please note that to disable logging for blocks, CoreProtect v23+ is required.*
*To disable logging for entities or to use filtering, CoreProtect v24+ is required.*
+3 -3
View File
@@ -2,7 +2,7 @@
CoreProtect 23.0+ includes the ability to migrate your database between SQLite and MySQL without losing any data.
> **Note:** Database migration functionality is exclusive to CoreProtect 23.0+ Patreon builds for Patron supporters.
> **Note:** Database migration functionality is exclusive to CoreProtect 23.0+ [Patreon builds](http://patreon.com/coreprotect) for Patron supporters.
## Overview
@@ -82,7 +82,7 @@ The `/co migrate-db` command allows you to seamlessly transfer all your CoreProt
* **Console only:** Cannot be executed from in-game chat
* **Interruption handling:** If interrupted, the target database must be manually wiped before restarting
* **Patreon exclusive:** Only available in CoreProtect 23.0+ Patreon builds
* **Patreon exclusive:** Only available in CoreProtect 23.0+ [Patreon builds](http://patreon.com/coreprotect)
---
@@ -92,7 +92,7 @@ The `/co migrate-db` command allows you to seamlessly transfer all your CoreProt
**Migration won't start:**
* Verify you're using a CoreProtect 23.0+ Patreon build
* Verify you're using a CoreProtect 23.0+ [Patreon build](http://patreon.com/coreprotect)
* Ensure you're not trying to migrate to the same database type
* Check that no other CoreProtect operations are running
+5
View File
@@ -2,6 +2,8 @@
For more information about CoreProtect, visit [coreprotect.net](http://coreprotect.net).
Looking for another platform? Visit [CoreProtect for Fabric](https://coreprotect.net/fabric) or [CoreProtect for Hytale](https://coreprotect.net/hytale).
## Getting Started
Please visit one of the following links for more information.
@@ -21,6 +23,9 @@ Log your own block changes, perform lookups, rollbacks, restores, and more.
[**Database Migration**](/database-migration/)
Migrate your CoreProtect database between SQLite and MySQL.
[**Automatic Purging**](/auto-purge/)
Automatically remove old CoreProtect data on a daily schedule.
[**Compatible Third-Party Plugins & Tools**](/tools-integrations/)
A list of plugins and tools that are compatible with CoreProtect.
+4 -1
View File
@@ -39,6 +39,9 @@ The following permissions can be used to restrict functionality within the plugi
* **coreprotect.consumer** *(default: op)*
Allows access to the CoreProtect consumer command.
&nbsp;
* **coreprotect.give** *(default: false)*
Allows access to the CoreProtect give command.
&nbsp;
* **coreprotect.networking** *(default: op)*
Allows access to the CoreProtect networking API.
@@ -46,7 +49,7 @@ The following permissions can be used to restrict functionality within the plugi
## Child Permissions
> **Note:** Child permissions are not presently supported by CoreProtect Hytale Edition.
> **Note:** Child permissions are not presently supported by [CoreProtect for Hytale](https://coreprotect.net/hytale).
* **coreprotect.lookup.block** *(default: op)*
Can be optionally used as a negative permission to prevent block lookups.
+8
View File
@@ -66,6 +66,9 @@ HELP_PARAMS_6: "Include specific blocks/entities in the {lookup|rollback|restore
HELP_PARAMS_7: "Exclude blocks/users from the {lookup|rollback|restore}."
HELP_PURGE_1: "Delete data older than specified time."
HELP_PURGE_2: "For example, \"{0}\" will delete all data older than one month, and only keep the last 30 days of data."
HELP_PURGE_3: "Specify the amount of time to purge."
HELP_PURGE_4: "Specify a world to limit the purge to."
HELP_PURGE_5: "Include specific blocks in the purge."
HELP_PURGE_COMMAND: "Delete old block data."
HELP_RADIUS_1: "Specify a radius area."
HELP_RADIUS_2: "Examples: [r:10] (Only make changes within 10 blocks of you)"
@@ -94,6 +97,8 @@ INVALID_CONTAINER: "Please inspect a valid container first."
INVALID_DONATION_KEY: "Invalid donation key."
INVALID_INCLUDE: "\"{0}\" is an invalid block/entity name."
INVALID_INCLUDE_COMBO: "That is an invalid block/entity combination."
INVALID_ITEM_ID: "Please enter a valid item id."
INVALID_PARAMETER: "\"{0}\" is not a supported parameter."
INVALID_RADIUS: "Please enter a valid radius."
INVALID_SELECTION: "{0} selection not found."
INVALID_USERNAME: "\"{0}\" is an invalid username."
@@ -142,6 +147,8 @@ PATCH_PROCESSING: "Processing new data. Please wait..."
PATCH_SKIP_UPDATE: "Skipping {table|index} {update|creation|removal} on {0}."
PATCH_STARTED: "Performing {0} upgrade. Please wait..."
PATCH_SUCCESS: "Successfully upgraded to {0}."
PATCH_TABLE_COMPLETED: "Successfully updated {0} table."
PATCH_TABLE_STARTED: "Updating {0} table. Please wait..."
PATCH_UPGRADING: "Database upgrade in progress. Please wait..."
PLEASE_SELECT: "Please select: \"{0}\" or \"{1}\"."
PREVIEW_CANCELLED: "Preview cancelled."
@@ -180,6 +187,7 @@ ROLLBACK_STARTED: "{Rollback|Restore|Preview} started on \"{0}\"."
ROLLBACK_TIME: "Time range: {0}."
ROLLBACK_WORLD_ACTION: "Restricted to {world|action} \"{0}\"."
SIGN_HEADER: "Sign Messages"
STATUS_AUTO_PURGE: "Cleanup: {0} {row|rows} auto purged since restart."
STATUS_CONSUMER: "Consumer: {0} {item|items} in queue."
STATUS_DATABASE: "Database: Using {0}."
STATUS_INTEGRATION: "{0}: Integration {enabled|disabled}."
+207
View File
@@ -0,0 +1,207 @@
# CoreProtect v24.0 Language Cache (tt)
ACTION_NOT_SUPPORTED: "Бу гамәл хупланмый."
AMOUNT_BLOCK: "{0} {блок|блоклар}"
AMOUNT_CHUNK: "{0} {кисәк|кисәкчәләр}"
AMOUNT_ENTITY: "{0} {зат|затлар}"
AMOUNT_ITEM: "{0} {әйбер|әйберләр}"
API_TEST: "API тесты уңышлы үтте."
CACHE_ERROR: "КИСӘТҮ: Валидацияләү вакытында хата килеп чыкты {0} кэш."
CACHE_RELOAD: "Мәҗбүри яңадан йөкләү {картага төшерү|дөнья} мәгълүмат базасыннан алынган кэшлар."
CHECK_CONFIG: "Зинһар, config.yml файлын тикшерегез"
COMMAND_CONSOLE: "Зинһар, команданы консольдән башкарыгыз."
COMMAND_NOT_FOUND: "Команда \"{0}\" табылмады.\""
COMMAND_THROTTLED: "Зинһар, бераз көтегез һәм кабатлап карагыз."
CONSUMER_ERROR: "Кулланучылар чиратлары эшкәртелә инде {туктатылган|дәвам иттерелгән}."
CONSUMER_TOGGLED: "Кулланучылар чиратларын эшкәртү {туктатылган|дәвам иттерелгән}."
CONTAINER_HEADER: "Контейнер транзакцияләре"
CPU_CORES: "Үзәк процессор үзәкләре."
DATABASE_BUSY: "Мәгълүмат базасы мәшгуль. Зинһар, соңрак кабатлап карагыз."
DATABASE_INDEX_ERROR: "Мәгълүмат базасы индексларын тикшереп булмый."
DATABASE_LOCKED_1: "Мәгълүмат базасы бикләнгән. 15 секундка кадәр көтәм..."
DATABASE_LOCKED_2: "Мәгълүмат базасы инде кулланыла. Зинһар, кабатлап карагыз."
DATABASE_LOCKED_3: "Мәгълүмат базасын блоклауны сүндерү өчен, \"database-lock: false\" куегыз."
DATABASE_LOCKED_4: "Мәгълүмат базасын блоклауны сүндерү мәгълүматларның бозылуына китерергә мөмкин."
DATABASE_UNREACHABLE: "Мәгълүматлар базасына кереп булмый. Мәгълүматларны юкка чыгаралар һәм сүндерәләр."
DEVELOPMENT_BRANCH: "Үсеш тармагы ачыкланды, патч скриптларын үткәреп җибәрә."
DIRT_BLOCK: "Сезнең астыгызга вакытлыча куркынычсызлык блогы куйдылар."
DISABLE_SUCCESS: "Уңышлы! Инвалид {0}"
ENABLE_FAILED: "{0} башлый алмады."
ENABLE_SUCCESS: "{0} хәзер активлаштырылган!"
ENJOY_COREPROTECT: "Рәхәтләнегез {0}Безнең белән кушылыгыз Discord!"
FINISHING_CONVERSION: "Мәгълүматларны үзгәртү тәмамлана. Зинһар, көтегез..."
FINISHING_LOGGING: "Мәгълүматларны теркәү тәмамлана. Зинһар, көтегез..."
FIRST_VERSION: "Башлангыч мәгълүмат базасы: {0}"
GLOBAL_LOOKUP: "Глобаль эзләү өчен радиус күрсәтмәгез."
GLOBAL_ROLLBACK: "Куллану \"{0}\" глобаль эш башкарырга {кире кайтару|торгызу}"
HELP_ACTION_1: "Эзләүне гамәл белән чикләгез."
HELP_ACTION_2: "Мисаллар: [a:block], [a:+block], [a:-block] [a:click], [a:container], [a:inventory], [a:item], [a:kill], [a:chat], [a:command], [a:sign], [a:session], [a:username]"
HELP_COMMAND: "Өстәмә мәгълүматны күрсәтегез."
HELP_EXCLUDE_1: "Блокларны/кулланучыларны чыгарыгыз."
HELP_EXCLUDE_2: "Мисаллар: [e:stone], [e:Notch], [e:stone,Notch]"
HELP_HEADER: "{0} Ярдәм"
HELP_INCLUDE_1: "Блокларны/объектларны кертегез."
HELP_INCLUDE_2: "Мисаллар: [i:stone], [i:zombie], [i:stone,wood,bedrock]"
HELP_INSPECT_1: "Инспекторны кабызганда, сез:"
HELP_INSPECT_2: "Урынны карау өчен сул төймә белән басыгыз."
HELP_INSPECT_3: "Күршедәге бетерүләрне карау өчен уң төймә белән басыгыз."
HELP_INSPECT_4: "Алып ташлауны күрү өчен блок урнаштырыгыз."
HELP_INSPECT_5: "Урынын күрү өчен, сыеклыкка блок салыгыз."
HELP_INSPECT_6: "Күкрәк транзакцияләрен карау өчен уң төймә белән басыгыз."
HELP_INSPECT_7: "Киңәш: Сез бары тик \"/co i\" куллана аласыз."
HELP_INSPECT_COMMAND: "Блок инспекторын кабыза/яба."
HELP_LIST: "Барлык командалар исемлеген күрсәтә."
HELP_LOOKUP_1: "Команда кыска юлы"
HELP_LOOKUP_2: "Өстәмә битләрне карау."
HELP_LOOKUP_COMMAND: "Блок мәгълүматларын эзләү."
HELP_NO_INFO: "Команда өчен мәгълүмат \"{0}\" табылмады.\""
HELP_PARAMETER: "Зинһар, карагыз \"{0}\" параметрлар турында тулырак мәгълүмат алу өчен."
HELP_PARAMS_1: "Башкарыгыз {эзләү|кайтару|торгызу}."
HELP_PARAMS_2: "Кулланучыларны күрсәтегез {эзләү|кайтару|торгызу}."
HELP_PARAMS_3: "Вакытны күрсәтегез {эзләү|кайтару|торгызу}."
HELP_PARAMS_4: "Чикләү {эзләү|кайтару|торгызу} радиуска кадәр."
HELP_PARAMS_5: "Чикләү {эзләү|кайтару|торгызу} гамәленә."
HELP_PARAMS_6: "Блокларны/объектларны кертегез {эзләү|кайтару|торгызу}."
HELP_PARAMS_7: "Блокларны/кулланучыларны чыгарыгыз {эзләү|кайтару|торгызу}."
HELP_PURGE_1: "Иске мәгълүматларны бетерегез."
HELP_PURGE_2: "Мәсәлән, \"{0}\" бер айдан иске барлык мәгълүматларны бетерәчәк һәм соңгы 30 көнлек мәгълүматларны гына саклаячак.\""
HELP_PURGE_COMMAND: "Иске блок мәгълүматларын бетерегез."
HELP_RADIUS_1: "Радиус мәйданын күрсәтегез."
HELP_RADIUS_2: "Мисаллар: [r:10] (Үзгәрешләрне сездән 10 квартал эчендә генә кертегез)"
HELP_RELOAD_COMMAND: "Конфигурация файлын яңадан йөкли."
HELP_RESTORE_COMMAND: "Блок мәгълүматларын торгызу."
HELP_ROLLBACK_COMMAND: "Кире кайтару блогы мәгълүматлары."
HELP_STATUS: "Плагинның статусын карагыз."
HELP_STATUS_COMMAND: "Плагин статусын күрсәтә."
HELP_TELEPORT: "Телепорт."
HELP_TIME_1: "Вакытны күрсәтегез."
HELP_TIME_2: "Мисаллар: [t:2w,5d,7h,2m,10s], [t:5d2h], [t:2.50h]"
HELP_USER_1: "Кулланучыларны күрсәтегез."
HELP_USER_2: "Мисаллар: [u:Notch], [u:Notch,#enderman]"
INCOMPATIBLE_ACTION: "\"{0}\" бу гамәл белән кулланыла алмый."
INSPECTOR_ERROR: "Инспектор инде {активлаштырылган|сүндерелгән}."
INSPECTOR_TOGGLED: "Инспектор хәзер {активлаштырылган|сүндерелгән}."
INTEGRATION_ERROR: "Мөмкин түгел {башлангыч хәлгә китерү|сүндерү} {0} агач эшкәртү"
INTEGRATION_SUCCESS: "{0} уңышлы теркәлү {башлангыч хәлгә китерелгән|сүндерелгән}."
INTEGRATION_VERSION: "Яраксыз {0} версиясе табылды."
INTERACTIONS_HEADER: "Уенчыларның үзара бәйләнеше"
INVALID_ACTION: "Бу дөрес гамәл түгел."
INVALID_BRANCH_1: "Плагин версиясе дөрес түгел (тармак куелмаган)."
INVALID_BRANCH_2: "Дәвам итү өчен, проект тармагын \"эшләү\"гә куегыз."
INVALID_BRANCH_3: "Эшләү кодын эшләтеп җибәрү мәгълүматларның бозылуына китерергә мөмкин."
INVALID_CONTAINER: "Зинһар, башта яраклы контейнерны тикшерегез."
INVALID_DONATION_KEY: "Иганә ачкычы дөрес түгел."
INVALID_INCLUDE: "\"{0}\" - яраксыз кыйммәт."
INVALID_INCLUDE_COMBO: "Бу яраксыз тип комбинациясе."
INVALID_RADIUS: "Зинһар, дөрес радиус кертегез."
INVALID_SELECTION: "{0} сайлау табылмады."
INVALID_USERNAME: "\"{0}\" - яраксыз кулланучы исеме."
INVALID_WORLD: "Зинһар, дөрес дөнья күрсәтегез."
LATEST_VERSION: "Соңгы версия: {0}"
LINK_DISCORD: "Discord: {0}"
LINK_DOWNLOAD: "Йөкләү: {0}"
LINK_PATREON: "Patreon: {0}"
LINK_WIKI_BLOCK: "Блок исемнәре: {0}"
LINK_WIKI_ENTITY: "Объект исемнәре: {0}"
LOGGING_ITEMS: "{0} Элемтәгә кертергә калган әйберләр. Зинһар, көтегез..."
LOGGING_TIME_LIMIT: "Журналлаштыру вакыты чикләнде. Мәгълүматлар юкка чыгарыла һәм сүндерелә."
LOOKUP_BLOCK: "{0} {урнаштырылган|ватык} {1}."
LOOKUP_CONTAINER: "{0} {өстәлде|алып ташланды} {1} {2}."
LOOKUP_HEADER: "{0} Нәтиҗәләр"
LOOKUP_INTERACTION: "{0} {басылды|үтерелде} {1}."
LOOKUP_ITEM: "{0} {алды|ташлады} {1} {2}."
LOOKUP_LOGIN: "{0} теркәлгән {керү|чыгу}."
LOOKUP_PAGE: "Бит {0}"
LOOKUP_PROJECTILE: "{0} {ыргытты|атты} {1} {2}."
LOOKUP_ROWS_FOUND: "{0} {рәт|рәтләр} табылган."
LOOKUP_SEARCHING: "Эзләү эзләнә. Зинһар, көтегез..."
LOOKUP_STORAGE: "{0} {салынган|алынган} {1} {2}."
LOOKUP_TIME: "{0} элек"
LOOKUP_USERNAME: "{0} буларак керде {1}."
MAXIMUM_RADIUS: "Максималь {эзләү|кайтару|торгызу} радиус {0}."
MISSING_ACTION_USER: "Бу гамәлне куллану өчен, зинһар, кулланучыны күрсәтегез."
MISSING_LOOKUP_TIME: "Зинһар, вакытны күрсәтегез {эзләү|кайтару|торгызу}."
MISSING_LOOKUP_USER: "Зинһар, кулланучыны күрсәтегез яки {блок|радиус}."
MISSING_PARAMETERS: "Зинһар, \" кулланыгыз{0}\"."
MISSING_ROLLBACK_RADIUS: "Сез күрсәтмәдегез {кире кайтару|торгызу} радиус."
MISSING_ROLLBACK_USER: "Сез күрсәтмәдегез {кире кайтару|торгызу} кулланучы."
MYSQL_UNAVAILABLE: "Тоташып булмый MySQL сервер."
NETWORK_CONNECTION: "Тоташу {0} {уңышлы|уңышсыз}Куллану {1} {2}."
NETWORK_TEST: "Челтәр сынау мәгълүматлары уңышлы җибәрелде."
NO_DATA: "Бернинди мәгълүмат табылмады {0}."
NO_DATA_LOCATION: "Юк {мәгълүматлар|транзакцияләр|үзара бәйләнешләр|хәбәрләр} табылган."
NO_PERMISSION: "Сезнең моны эшләргә рөхсәтегез юк."
NO_RESULTS: "Нәтиҗәләр табылмады."
NO_RESULTS_PAGE: "Юк {нәтиҗәләр|мәгълүматлар} шул бит өчен табылды."
NO_ROLLBACK: "Юк {көтелгән|алдагы} кире кайтару/торгызу табылды."
PATCH_INTERRUPTED: "Яңарту өзелде. Кабат эшләтеп җибәргәндә тагын бер кат тырышып карыйм."
PATCH_OUTDATED_1: "Искерәк мәгълүмат базаларын яңартып булмый {0}."
PATCH_OUTDATED_2: "Зинһар, ярдәм ителә торган версия белән яңартыгыз CoreProtect."
PATCH_PROCESSING: "Яңа мәгълүматлар эшкәртелә. Зинһар, көтегез..."
PATCH_SKIP_UPDATE: "Сикереп бару {таблица|индекс} {яңарту|булдыру|бетерү} өстендә {0}."
PATCH_STARTED: "Башкару {0} яңарту. Зинһар, көтегез..."
PATCH_SUCCESS: "Уңышлы рәвештә яңартылды {0}."
PATCH_UPGRADING: "Мәгълүмат базасы яңартыла. Зинһар, көтегез..."
PLEASE_SELECT: "Зинһар, сайлагыз: \"{0}\" яки \"{1}\"."
PREVIEW_CANCELLED: "Алдан карау юкка чыгарылды."
PREVIEW_CANCELLING: "Алдан карауны юкка чыгару..."
PREVIEW_IN_GAME: "Сез кире кайтаруларны уен эчендә генә карый аласыз."
PREVIEW_TRANSACTION: "Алдан карап булмый {контейнер|инвентаризация} транзакцияләр."
PRIMARY_THREAD_ERROR: "Бу API ысулын төп җептә кулланып булмый."
PURGE_ABORTED: "Чистарту уңышсыз тәмамланды. Мәгълүмат базасы бозылган булырга мөмкин."
PURGE_ERROR: "Эшкәртеп булмый {0} мәгълүматлар!"
PURGE_FAILED: "Чистарту уңышсыз тәмамланды. Зинһар, соңрак кабатлап карагыз."
PURGE_IN_PROGRESS: "Чистарту бара. Зинһар, соңрак кабатлап карагыз."
PURGE_MINIMUM_TIME: "Сез бары тик искерәк мәгълүматларны гына бетерә аласыз {0} {көннәр|сәгатьләр}."
PURGE_NOTICE_1: "Зинһар, игътибар итегез, бу бераз вакыт алырга мөмкин."
PURGE_NOTICE_2: "Серверны тәмамланганчы яңадан эшләтеп җибәрмәгез."
PURGE_OPTIMIZING: "Мәгълүмат базасы оптимальләштерелә. Зинһар, көтегез..."
PURGE_PROCESSING: "Эшкәртү {0} мәгълүматлар..."
PURGE_REPAIRING: "Төзәтергә тырышам. Бу бераз вакыт алырга мөмкин..."
PURGE_ROWS: "{0} {рәт|рәтләр} бетерелгән мәгълүматлар саны."
PURGE_STARTED: "Мәгълүматларны чистарту башланды \"{0}\"."
PURGE_SUCCESS: "Мәгълүматларны чистарту уңышлы тәмамланды."
RAM_STATS: "{0}ГБ / {1}ГБ оператив хәтер"
RELOAD_STARTED: "Конфигурация яңадан йөкләнә - зинһар, көтегез."
RELOAD_SUCCESS: "Конфигурация уңышлы яңадан йөкләнде."
ROLLBACK_ABORTED: "Кире кайтару яки торгызу туктатылды."
ROLLBACK_CHUNKS_FOUND: "Табылды {0} {кисәк|кисәк} үзгәртү өчен."
ROLLBACK_CHUNKS_MODIFIED: "Үзгәртелгән {0}/{1} {кисәк|кисәкчәләр}."
ROLLBACK_COMPLETED: "{Кире кайтару|Төзетү|Алдан карау} өчен тәмамланды \"{0}\"."
ROLLBACK_EXCLUDED_USERS: "Чыгарылган {кулланучы|кулланучылар}: \"{0}\"."
ROLLBACK_INCLUDE: "{Кертелгән|Чыгарылган} {блок|объект|максат} {төр|төрләр}: \"{0}\"."
ROLLBACK_IN_PROGRESS: "Кире кайтару/торгызу процессы инде бара."
ROLLBACK_LENGTH: "Кирәкле вакыт: {0} {секунд|секунд}."
ROLLBACK_MODIFIED: "{Үзгәртелгән|Үзгәртелә} {0}."
ROLLBACK_RADIUS: "Радиус: {0} {блок|блоклар}."
ROLLBACK_SELECTION: "Радиус \"га куелды{0}\"."
ROLLBACK_STARTED: "{Кире кайтару|Төзетү|Алдан карау} башланды \"{0}\"."
ROLLBACK_TIME: "Вакыт диапазоны: {0}."
ROLLBACK_WORLD_ACTION: "Чикләнгән {дөнья|гамәл} \"{0}\"."
SIGN_HEADER: "Хәбәрләргә кул кую"
STATUS_CONSUMER: "Кулланучы: {0} {әйбер|әйберләр} чиратта"
STATUS_DATABASE: "Мәгълүмат базасы: Куллану {0}."
STATUS_INTEGRATION: "{0}: Интеграция {активлаштырылган|сүндерелгән}."
STATUS_LICENSE: "Лицензия: {0}"
STATUS_SYSTEM: "Система: {0}"
STATUS_VERSION: "Версия: {0}"
TELEPORTED: "Телепортацияләнгән {0}."
TELEPORTED_SAFETY: "Сезне куркынычсыз урынга телепортладылар."
TELEPORT_PLAYERS: "Телепорт командасын бары тик уенчылар гына куллана ала."
TIME_DAYS: "{0} {көн|көннәр}"
TIME_HOURS: "{0} {сәгать|сәгатьләр}"
TIME_MINUTES: "{0} {минут|минут}"
TIME_SECONDS: "{0} {секунд|секунд}"
TIME_WEEKS: "{0} {атна|атналар}"
UPDATE_ERROR: "Яңартуларны тикшергәндә хата килеп чыкты."
UPDATE_HEADER: "{0} Яңарту"
UPDATE_NOTICE: "Игътибар: {0} хәзер мөмкин."
UPGRADE_IN_PROGRESS: "Яңарту бара. Зинһар, соңрак кабатлап карагыз."
USER_NOT_FOUND: "Кулланучы \"{0}\" табылмады.\""
USER_OFFLINE: "Кулланучы \"{0}\" онлайн түгел.\""
USING_MYSQL: "Куллану MySQL мәгълүматларны саклау өчен."
USING_SQLITE: "Куллану SQLite мәгълүматларны саклау өчен."
VALID_DONATION_KEY: "Гамәлдәге иганә ачкычы."
VERSION_NOTICE: "Версия {0} хәзер мөмкин."
VERSION_REQUIRED: "{0} {1} яки аннан да югарырак таләп ителә."
WORLD_NOT_FOUND: "Дөнья \"{0}\" табылмады.\""
+4 -7
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.coreprotect</groupId>
<artifactId>CoreProtect</artifactId>
<version>23.2</version>
<version>24.0</version>
<properties>
<project.branch></project.branch>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -73,6 +73,8 @@
<excludes>
<exclude>**/*.java</exclude>
<exclude>**/*.c</exclude>
<exclude>module-info.class</exclude>
<exclude>META-INF/versions/**/module-info.class</exclude>
<exclude>META-INF/maven/**/pom.properties</exclude>
<exclude>META-INF/services/**</exclude>
</excludes>
@@ -216,7 +218,7 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>26.1.2.build.9-alpha</version>
<version>26.2.build.48-alpha</version> <!-- https://repo.papermc.io/repository/maven-public/ -->
<scope>provided</scope>
</dependency>
<dependency>
@@ -248,11 +250,6 @@
<artifactId>HikariCP</artifactId>
<version>7.0.2</version>
</dependency>
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
@@ -2,6 +2,7 @@ package net.coreprotect;
import java.io.File;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import net.coreprotect.config.ConfigHandler;
@@ -16,8 +17,6 @@ import net.coreprotect.utility.Chat;
public final class CoreProtect extends JavaPlugin {
private static CoreProtect instance;
private boolean advancedChestsEnabled = false;
/**
* Get the instance of CoreProtect
*
@@ -44,7 +43,6 @@ public final class CoreProtect extends JavaPlugin {
instance = this;
ConfigHandler.path = this.getDataFolder().getPath() + File.separator;
advancedChestsEnabled = getServer().getPluginManager().getPlugin("AdvancedChests") != null;
// Initialize plugin using the initialization service
boolean initialized = PluginInitializationService.initializePlugin(this);
@@ -61,6 +59,7 @@ public final class CoreProtect extends JavaPlugin {
}
public boolean isAdvancedChestsEnabled() {
return advancedChestsEnabled;
Plugin advancedChests = getServer().getPluginManager().getPlugin("AdvancedChests");
return advancedChests != null && advancedChests.isEnabled();
}
}
@@ -18,8 +18,22 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import net.coreprotect.api.BlockAPI;
import net.coreprotect.api.InventoryAPI;
import net.coreprotect.api.ItemAPI;
import net.coreprotect.api.LookupOptions;
import net.coreprotect.api.MessageAPI;
import net.coreprotect.api.QueueLookup;
import net.coreprotect.api.SessionLookup;
import net.coreprotect.api.SignAPI;
import net.coreprotect.api.UsernameAPI;
import net.coreprotect.api.result.BlockResult;
import net.coreprotect.api.result.ContainerResult;
import net.coreprotect.api.result.InventoryResult;
import net.coreprotect.api.result.ItemResult;
import net.coreprotect.api.result.MessageResult;
import net.coreprotect.api.result.SignResult;
import net.coreprotect.api.result.SessionResult;
import net.coreprotect.api.result.UsernameResult;
import net.coreprotect.config.Config;
import net.coreprotect.consumer.Queue;
import net.coreprotect.database.Database;
@@ -29,6 +43,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.listener.player.InventoryChangeListener;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* The main API class for CoreProtect.
@@ -41,7 +56,7 @@ public class CoreProtectAPI extends Queue {
/**
* Current version of the API
*/
private static final int API_VERSION = 11;
private static final int API_VERSION = 12;
public static class ParseResult extends net.coreprotect.api.result.ParseResult {
@@ -68,7 +83,7 @@ public class CoreProtectAPI extends Queue {
if (list != null) {
for (Object value : list) {
if (value instanceof Material || value instanceof EntityType) {
if (value instanceof Material || value instanceof EntityType || value instanceof String) {
result.put(value, false);
}
else if (value instanceof Integer) {
@@ -106,6 +121,22 @@ public class CoreProtectAPI extends Queue {
return null;
}
/**
* Performs a typed block lookup at the specified block.
*
* @param block
* The block to look up
* @param options
* Lookup options. User, time, and limit are applied; location and radius are ignored because the block supplies the exact location.
* @return List of results or null if API is disabled
*/
public List<BlockResult> blockLookup(Block block, LookupOptions options) {
if (isEnabled()) {
return BlockAPI.performLookup(block, options);
}
return null;
}
/**
* Performs a lookup on the queue data for the specified block.
*
@@ -117,6 +148,64 @@ public class CoreProtectAPI extends Queue {
return QueueLookup.performLookup(block);
}
/**
* Performs a container lookup at the specified location.
*
* @param location
* The location to look up
* @param time
* Time constraint in seconds
* @return List of results or null if API is disabled
*/
public List<ContainerResult> containerLookup(Location location, int time) {
if (isEnabled()) {
return BlockAPI.performContainerLookup(location, time);
}
return null;
}
/**
* Performs a container lookup with shared lookup options.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<ContainerResult> containerLookup(LookupOptions options) {
if (isEnabled()) {
return BlockAPI.performContainerLookup(options);
}
return null;
}
/**
* Performs a typed lookup on world item transactions.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<ItemResult> itemLookup(LookupOptions options) {
if (isEnabled()) {
return ItemAPI.performLookup(options);
}
return null;
}
/**
* Performs a typed lookup on player inventory transactions.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<InventoryResult> inventoryLookup(LookupOptions options) {
if (isEnabled()) {
return InventoryAPI.performLookup(options);
}
return null;
}
/**
* Performs a lookup on session data for the specified user.
*
@@ -130,6 +219,140 @@ public class CoreProtectAPI extends Queue {
return SessionLookup.performLookup(user, time);
}
/**
* Performs a typed lookup on session data.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<SessionResult> sessionLookup(LookupOptions options) {
if (isEnabled()) {
return SessionLookup.performLookup(options);
}
return null;
}
/**
* Performs a username history lookup for the specified user.
*
* @param user
* The user or UUID to look up, or #global/null for all users
* @param time
* Time constraint in seconds
* @return List of results or null if API is disabled
*/
public List<UsernameResult> usernameLookup(String user, int time) {
if (isEnabled()) {
return UsernameAPI.performLookup(user, time);
}
return null;
}
/**
* Performs a username history lookup with shared lookup options.
*
* @param options
* Lookup options. User, time, and limit are applied; location and radius are ignored.
* @return List of results or null if API is disabled
*/
public List<UsernameResult> usernameLookup(LookupOptions options) {
if (isEnabled()) {
return UsernameAPI.performLookup(options);
}
return null;
}
/**
* Performs a chat message lookup for the specified user.
*
* @param user
* The user to look up, or #global/null for all users
* @param time
* Time constraint in seconds
* @return List of results or null if API is disabled
*/
public List<MessageResult> chatLookup(String user, int time) {
if (isEnabled()) {
return MessageAPI.performChatLookup(user, time);
}
return null;
}
/**
* Performs a chat message lookup with shared lookup options.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<MessageResult> chatLookup(LookupOptions options) {
if (isEnabled()) {
return MessageAPI.performChatLookup(options);
}
return null;
}
/**
* Performs a command lookup for the specified user.
*
* @param user
* The user to look up, or #global/null for all users
* @param time
* Time constraint in seconds
* @return List of results or null if API is disabled
*/
public List<MessageResult> commandLookup(String user, int time) {
if (isEnabled()) {
return MessageAPI.performCommandLookup(user, time);
}
return null;
}
/**
* Performs a command lookup with shared lookup options.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<MessageResult> commandLookup(LookupOptions options) {
if (isEnabled()) {
return MessageAPI.performCommandLookup(options);
}
return null;
}
/**
* Performs a sign text lookup at the specified location.
*
* @param location
* The location to look up
* @param time
* Time constraint in seconds
* @return List of results or null if API is disabled
*/
public List<SignResult> signLookup(Location location, int time) {
if (isEnabled()) {
return SignAPI.performLookup(location, time);
}
return null;
}
/**
* Performs a sign text lookup with shared lookup options.
*
* @param options
* Lookup options
* @return List of results or null if API is disabled
*/
public List<SignResult> signLookup(LookupOptions options) {
if (isEnabled()) {
return SignAPI.performLookup(options);
}
return null;
}
/**
* Determines if a user has placed a block at the specified location.
*
@@ -341,6 +564,27 @@ public class CoreProtectAPI extends Queue {
return true;
}
/**
* Logs a block placement by a user with specific block data.
*
* @param user
* The username
* @param location
* The location
* @param blockData
* The block data
* @return True if the placement was logged
*/
public boolean logPlacement(String user, Location location, BlockData blockData) {
if (!isEnabled() || !isValidUserAndLocation(user, location) || blockData == null) {
return false;
}
Block block = location.getBlock();
Queue.queueBlockPlace(user, block.getState(), block.getType(), null, block.getType(), -1, 0, blockData.getAsString());
return true;
}
/**
* Logs a block placement by a user with a specific material and data value.
*
@@ -412,6 +656,28 @@ public class CoreProtectAPI extends Queue {
return true;
}
/**
* Logs a block removal by a user with specific block data.
*
* @param user
* The username
* @param location
* The location
* @param blockData
* The block data
* @return True if the removal was logged
*/
public boolean logRemoval(String user, Location location, BlockData blockData) {
if (!isEnabled() || !isValidUserAndLocation(user, location) || blockData == null) {
return false;
}
Block block = location.getBlock();
Database.containerBreakCheck(user, block.getType(), block, null, location);
Queue.queueBlockBreak(user, block.getState(), block.getType(), blockData.getAsString(), 0);
return true;
}
/**
* Logs a block removal by a user with a specific material and data value.
*
@@ -830,7 +1096,7 @@ public class CoreProtectAPI extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
+184 -1
View File
@@ -1,13 +1,17 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.block.Block;
import net.coreprotect.api.result.BlockResult;
import net.coreprotect.api.result.ContainerResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
@@ -15,6 +19,7 @@ import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for block-related lookups in the CoreProtect database.
@@ -93,9 +98,187 @@ public class BlockAPI {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
}
/**
* Performs a typed lookup of block-related actions at the specified block.
*
* @param block
* The block to look up
* @param options
* Lookup options. User, time, and limit are applied; location and radius are ignored because the block supplies the exact location.
* @return List of results in a BlockResult format
*/
public static List<BlockResult> performLookup(Block block, LookupOptions options) {
List<BlockResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
if (block == null || block.getWorld() == null) {
return result;
}
if (options == null) {
options = LookupOptions.builder().build();
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
Integer userId = MessageAPI.getUserId(connection, options.getUser());
if (userId != null && userId == -1) {
return result;
}
int checkTime = 0;
if (options.getTime() > 0) {
checkTime = (int) (System.currentTimeMillis() / 1000L) - options.getTime();
}
int x = block.getX();
int y = block.getY();
int z = block.getZ();
String worldName = block.getWorld().getName();
int worldId = WorldUtils.getWorldId(worldName);
StringBuilder query = new StringBuilder("SELECT time,user,action,type,data,blockdata,rolled_back,wid,x,y,z FROM ");
query.append(ConfigHandler.prefix).append("block ").append(WorldUtils.getWidIndex("block"));
query.append("WHERE wid = ? AND x = ? AND z = ? AND y = ? AND time > ?");
if (userId != null) {
query.append(" AND user = ?");
}
query.append(" ORDER BY rowid DESC");
if (options.hasLimit()) {
query.append(" LIMIT ").append(options.getLimitOffset()).append(", ").append(options.getLimitCount());
}
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
statement.setInt(1, worldId);
statement.setInt(2, x);
statement.setInt(3, z);
statement.setInt(4, y);
statement.setInt(5, checkTime);
if (userId != null) {
statement.setInt(6, userId);
}
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseBlockResult(connection, results, worldName));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
/**
* Performs a lookup of container transactions at the specified location.
*
* @param location
* The location to look up
* @param offset
* Time constraint in seconds (0 means no time constraint)
* @return List of results in a ContainerResult format
*/
public static List<ContainerResult> performContainerLookup(Location location, int offset) {
if (location == null) {
return new ArrayList<>();
}
return performContainerLookup(LookupOptions.builder().time(offset).location(location).build());
}
/**
* Performs a lookup of container transactions using shared lookup options.
*
* @param options
* Lookup options
* @return List of results in a ContainerResult format
*/
public static List<ContainerResult> performContainerLookup(LookupOptions options) {
List<ContainerResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
LookupFilter filter = LookupFilter.fromOptions(connection, options);
if (filter.hasInvalidUser() || filter.hasInvalidLocation()) {
return result;
}
StringBuilder query = new StringBuilder("SELECT time,user,wid,x,y,z,action,type,data,amount,metadata,rolled_back FROM ");
query.append(ConfigHandler.prefix).append("container ");
if (filter.hasLocation()) {
query.append(WorldUtils.getWidIndex("container"));
}
filter.appendWhere(query);
query.append(" ORDER BY rowid DESC");
filter.appendLimit(query);
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
filter.bind(statement);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseContainerResult(connection, results));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
private static ContainerResult parseContainerResult(Connection connection, ResultSet results) throws Exception {
int resultUserId = results.getInt("user");
String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
if (resultUser == null) {
resultUser = UserStatement.loadName(connection, resultUserId);
}
return new ContainerResult(
results.getLong("time"), resultUser, WorldUtils.getWorldName(results.getInt("wid")), results.getInt("x"), results.getInt("y"), results.getInt("z"),
results.getInt("type"), results.getInt("data"), results.getInt("amount"), results.getBytes("metadata"),
results.getInt("action"), results.getInt("rolled_back")
);
}
private static BlockResult parseBlockResult(Connection connection, ResultSet results, String worldName) throws Exception {
int resultUserId = results.getInt("user");
String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
if (resultUser == null) {
resultUser = UserStatement.loadName(connection, resultUserId);
}
int resultType = results.getInt("type");
String blockData = BlockUtils.byteDataToString(results.getBytes("blockdata"), resultType);
return new BlockResult(
results.getLong("time"), resultUser, worldName, results.getInt("x"), results.getInt("y"), results.getInt("z"),
resultType, results.getInt("data"), blockData, results.getInt("action"), results.getInt("rolled_back")
);
}
}
@@ -0,0 +1,45 @@
package net.coreprotect.api;
import net.coreprotect.model.action.LookupActions;
/**
* CoreProtect action identifiers used by lookup filters.
*/
public enum CoreProtectAction {
BLOCK_BREAK(LookupActions.BLOCK_BREAK),
BLOCK_PLACE(LookupActions.BLOCK_PLACE),
INTERACTION(LookupActions.INTERACTION),
ENTITY_KILL(LookupActions.ENTITY_KILL),
CONTAINER(LookupActions.CONTAINER),
CHAT(LookupActions.CHAT),
COMMAND(LookupActions.COMMAND),
SESSION(LookupActions.SESSION),
USERNAME(LookupActions.USERNAME),
SIGN(LookupActions.SIGN),
ITEM(LookupActions.ITEM),
UNKNOWN(-1);
private final int id;
CoreProtectAction(int id) {
this.id = id;
}
public int id() {
return id;
}
public String actionString() {
return LookupActions.getActionString(id);
}
public static CoreProtectAction fromId(int id) {
for (CoreProtectAction action : values()) {
if (action.id == id) {
return action;
}
}
return UNKNOWN;
}
}
@@ -0,0 +1,107 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import net.coreprotect.api.result.InventoryResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for normalized player inventory transaction lookups.
*/
public class InventoryAPI {
private InventoryAPI() {
throw new IllegalStateException("API class");
}
public static List<InventoryResult> performLookup(LookupOptions options) {
List<InventoryResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
if (options == null) {
options = LookupOptions.builder().build();
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
LookupFilter filter = LookupFilter.fromOptions(connection, options);
if (filter.hasInvalidUser() || filter.hasInvalidLocation()) {
return result;
}
StringBuilder whereBuilder = new StringBuilder();
filter.appendWhere(whereBuilder);
String where = whereBuilder.toString();
String query = buildQuery(where, options.hasLimit());
try (PreparedStatement statement = connection.prepareStatement(query)) {
int parameterIndex = filter.bind(statement);
parameterIndex = filter.bind(statement, parameterIndex);
parameterIndex = filter.bind(statement, parameterIndex);
if (options.hasLimit()) {
statement.setInt(parameterIndex++, options.getLimitOffset());
statement.setInt(parameterIndex, options.getLimitCount());
}
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseInventoryResult(connection, results));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
private static String buildQuery(String where, boolean hasLimit) {
StringBuilder query = new StringBuilder("SELECT * FROM (");
query.append("SELECT 0 AS source,rowid AS id,time,user,wid,x,y,z,type,data,1 AS amount,meta AS metadata,action,rolled_back FROM ")
.append(ConfigHandler.prefix).append("block ").append(where).append(" AND action = 1");
query.append(" UNION ALL ");
query.append("SELECT 1 AS source,rowid AS id,time,user,wid,x,y,z,type,data,amount,metadata,action,rolled_back FROM ")
.append(ConfigHandler.prefix).append("container ").append(where);
query.append(" UNION ALL ");
query.append("SELECT 2 AS source,rowid AS id,time,user,wid,x,y,z,type,0 AS data,amount,data AS metadata,action,rolled_back FROM ")
.append(ConfigHandler.prefix).append("item ").append(where);
query.append(") AS inventory_lookup ORDER BY time DESC, source DESC, id DESC");
if (hasLimit) {
query.append(" LIMIT ?, ?");
}
return query.toString();
}
private static InventoryResult parseInventoryResult(Connection connection, ResultSet results) throws Exception {
int userId = results.getInt("user");
String username = ConfigHandler.playerIdCacheReversed.get(userId);
if (username == null) {
username = UserStatement.loadName(connection, userId);
}
return new InventoryResult(
results.getLong("time"), username, WorldUtils.getWorldName(results.getInt("wid")),
results.getInt("x"), results.getInt("y"), results.getInt("z"),
results.getInt("type"), results.getInt("data"), results.getInt("amount"), results.getBytes("metadata"),
results.getInt("action"), results.getInt("rolled_back"), results.getInt("source")
);
}
}
@@ -0,0 +1,90 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import net.coreprotect.api.result.ItemResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.logger.ItemLogger;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for world item transaction lookups.
*/
public class ItemAPI {
private ItemAPI() {
throw new IllegalStateException("API class");
}
public static List<ItemResult> performLookup(LookupOptions options) {
List<ItemResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
LookupFilter filter = LookupFilter.fromOptions(connection, options);
if (filter.hasInvalidUser() || filter.hasInvalidLocation()) {
return result;
}
StringBuilder query = new StringBuilder("SELECT time,user,wid,x,y,z,type,data,amount,action,rolled_back FROM ");
query.append(ConfigHandler.prefix).append("item ");
if (filter.hasLocation()) {
query.append(WorldUtils.getWidIndex("item"));
}
filter.appendWhere(query);
query.append(" AND action NOT IN (")
.append(ItemLogger.ITEM_BREAK).append(",")
.append(ItemLogger.ITEM_DESTROY).append(",")
.append(ItemLogger.ITEM_CREATE).append(",")
.append(ItemLogger.ITEM_SELL).append(",")
.append(ItemLogger.ITEM_BUY).append(")");
query.append(" ORDER BY rowid DESC");
filter.appendLimit(query);
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
filter.bind(statement);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseItemResult(connection, results));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
private static ItemResult parseItemResult(Connection connection, ResultSet results) throws Exception {
int userId = results.getInt("user");
String username = ConfigHandler.playerIdCacheReversed.get(userId);
if (username == null) {
username = UserStatement.loadName(connection, userId);
}
return new ItemResult(
results.getLong("time"), username, WorldUtils.getWorldName(results.getInt("wid")),
results.getInt("x"), results.getInt("y"), results.getInt("z"),
results.getInt("type"), results.getInt("amount"), results.getBytes("data"),
results.getInt("action"), results.getInt("rolled_back")
);
}
}
@@ -0,0 +1,109 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.bukkit.Location;
import net.coreprotect.utility.WorldUtils;
final class LookupFilter {
private final Integer userId;
private final int checkTime;
private final Location location;
private final int radius;
private final int limitOffset;
private final int limitCount;
private LookupFilter(Integer userId, int checkTime, Location location, int radius, int limitOffset, int limitCount) {
this.userId = userId;
this.checkTime = checkTime;
this.location = location;
this.radius = radius;
this.limitOffset = limitOffset;
this.limitCount = limitCount;
}
static LookupFilter fromOptions(Connection connection, LookupOptions options) throws Exception {
if (options == null) {
options = LookupOptions.builder().build();
}
Integer userId = MessageAPI.getUserId(connection, options.getUser());
int checkTime = 0;
if (options.getTime() > 0) {
checkTime = (int) (System.currentTimeMillis() / 1000L) - options.getTime();
}
return new LookupFilter(userId, checkTime, options.getLocation(), options.getRadius(), options.getLimitOffset(), options.getLimitCount());
}
boolean hasInvalidUser() {
return userId != null && userId == -1;
}
boolean hasInvalidLocation() {
return location != null && location.getWorld() == null;
}
boolean hasLocation() {
return location != null;
}
void appendWhere(StringBuilder query) {
query.append("WHERE time > ?");
if (userId != null) {
query.append(" AND user = ?");
}
if (location != null) {
query.append(" AND wid = ?");
if (radius > 0) {
query.append(" AND x >= ? AND x <= ? AND z >= ? AND z <= ?");
}
else {
query.append(" AND x = ? AND y = ? AND z = ?");
}
}
}
void appendLimit(StringBuilder query) {
if (limitOffset >= 0 && limitCount >= 0) {
query.append(" LIMIT ").append(limitOffset).append(", ").append(limitCount);
}
}
int bind(PreparedStatement statement) throws Exception {
return bind(statement, 1);
}
int bind(PreparedStatement statement, int parameterIndex) throws Exception {
statement.setInt(parameterIndex++, checkTime);
if (userId != null) {
statement.setInt(parameterIndex++, userId);
}
if (location != null) {
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
statement.setInt(parameterIndex++, WorldUtils.getWorldId(location.getWorld().getName()));
if (radius > 0) {
statement.setInt(parameterIndex++, MessageAPI.clampToInt((long) x - radius));
statement.setInt(parameterIndex++, MessageAPI.clampToInt((long) x + radius));
statement.setInt(parameterIndex++, MessageAPI.clampToInt((long) z - radius));
statement.setInt(parameterIndex++, MessageAPI.clampToInt((long) z + radius));
}
else {
statement.setInt(parameterIndex++, x);
statement.setInt(parameterIndex++, y);
statement.setInt(parameterIndex++, z);
}
}
return parameterIndex;
}
}
@@ -0,0 +1,100 @@
package net.coreprotect.api;
import org.bukkit.Location;
/**
* Shared options for typed lookup API methods.
*/
public final class LookupOptions {
private final String user;
private final int time;
private final int radius;
private final Location location;
private final int limitOffset;
private final int limitCount;
private LookupOptions(Builder builder) {
this.user = builder.user;
this.time = builder.time;
this.radius = builder.radius;
this.location = builder.location;
this.limitOffset = builder.limitOffset;
this.limitCount = builder.limitCount;
}
public static Builder builder() {
return new Builder();
}
public String getUser() {
return user;
}
public int getTime() {
return time;
}
public int getRadius() {
return radius;
}
public Location getLocation() {
return location;
}
public int getLimitOffset() {
return limitOffset;
}
public int getLimitCount() {
return limitCount;
}
public boolean hasLimit() {
return limitOffset >= 0 && limitCount >= 0;
}
public static final class Builder {
private String user;
private int time;
private int radius = -1;
private Location location;
private int limitOffset = -1;
private int limitCount = -1;
private Builder() {
}
public Builder user(String user) {
this.user = user;
return this;
}
public Builder time(int time) {
this.time = time;
return this;
}
public Builder location(Location location) {
this.location = location;
this.radius = 0;
return this;
}
public Builder radius(Location location, int radius) {
this.location = location;
this.radius = radius;
return this;
}
public Builder limit(int offset, int count) {
this.limitOffset = offset;
this.limitCount = count;
return this;
}
public LookupOptions build() {
return new LookupOptions(this);
}
}
}
@@ -0,0 +1,134 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import net.coreprotect.api.result.MessageResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for player chat and command lookups.
*/
public class MessageAPI {
private MessageAPI() {
throw new IllegalStateException("API class");
}
public static List<MessageResult> performChatLookup(String user, int offset) {
return performChatLookup(LookupOptions.builder().user(user).time(offset).build());
}
public static List<MessageResult> performChatLookup(LookupOptions options) {
return performLookup("chat", CoreProtectAction.CHAT, options);
}
public static List<MessageResult> performCommandLookup(String user, int offset) {
return performCommandLookup(LookupOptions.builder().user(user).time(offset).build());
}
public static List<MessageResult> performCommandLookup(LookupOptions options) {
return performLookup("command", CoreProtectAction.COMMAND, options);
}
private static List<MessageResult> performLookup(String table, CoreProtectAction action, LookupOptions options) {
List<MessageResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
LookupFilter filter = LookupFilter.fromOptions(connection, options);
if (filter.hasInvalidUser() || filter.hasInvalidLocation()) {
return result;
}
StringBuilder query = new StringBuilder("SELECT time,user,wid,x,y,z,message FROM ");
query.append(ConfigHandler.prefix).append(table).append(" ");
if (filter.hasLocation()) {
query.append(WorldUtils.getWidIndex(table));
}
filter.appendWhere(query);
query.append(" ORDER BY rowid DESC");
filter.appendLimit(query);
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
filter.bind(statement);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseMessageResult(connection, results, action.id()));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
static Integer getUserId(Connection connection, String user) throws Exception {
if (user == null || user.isEmpty() || user.equalsIgnoreCase("#global")) {
return null;
}
Integer cachedId = ConfigHandler.playerIdCache.get(user.toLowerCase(java.util.Locale.ROOT));
if (cachedId != null) {
return cachedId;
}
String collate = Config.getGlobal().MYSQL ? "" : " COLLATE NOCASE";
try (PreparedStatement statement = connection.prepareStatement("SELECT rowid FROM " + ConfigHandler.prefix + "user WHERE user = ?" + collate + " ORDER BY rowid ASC LIMIT 0, 1")) {
statement.setString(1, user);
try (ResultSet results = statement.executeQuery()) {
if (results.next()) {
int id = results.getInt("rowid");
ConfigHandler.playerIdCache.put(user.toLowerCase(java.util.Locale.ROOT), id);
ConfigHandler.playerIdCacheReversed.put(id, user);
return id;
}
}
}
return -1;
}
private static MessageResult parseMessageResult(Connection connection, ResultSet results, int actionId) throws Exception {
int userId = results.getInt("user");
String username = ConfigHandler.playerIdCacheReversed.get(userId);
if (username == null) {
username = UserStatement.loadName(connection, userId);
}
return new MessageResult(
results.getLong("time"), username, WorldUtils.getWorldName(results.getInt("wid")),
results.getInt("x"), results.getInt("y"), results.getInt("z"),
results.getString("message"), actionId
);
}
static int clampToInt(long value) {
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
else if (value < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) value;
}
}
@@ -3,7 +3,6 @@ package net.coreprotect.api;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.bukkit.Location;
@@ -18,6 +17,7 @@ import net.coreprotect.consumer.process.Process;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for looking up block-related actions in the processing queue.
@@ -70,9 +70,7 @@ public class QueueLookup extends Queue {
Location blockLocation = block.getLocation();
// Check for block actions in the processing queue
ListIterator<Object[]> iterator = consumerData.listIterator();
while (iterator.hasNext()) {
Object[] data = iterator.next();
for (Object[] data : consumerData.toArray(Object[][]::new)) {
int id = (int) data[0];
int action = (int) data[1];
@@ -106,7 +104,7 @@ public class QueueLookup extends Queue {
Collections.reverse(result);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
@@ -1,16 +1,20 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import net.coreprotect.api.result.SessionResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for looking up player session data in the CoreProtect database.
@@ -78,7 +82,57 @@ public class SessionLookup {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
}
/**
* Performs a typed lookup of session-related actions.
*
* @param options
* Lookup options
* @return List of typed session results, empty list if API is disabled or no results found
*/
public static List<SessionResult> performLookup(LookupOptions options) {
List<SessionResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
LookupFilter filter = LookupFilter.fromOptions(connection, options);
if (filter.hasInvalidUser() || filter.hasInvalidLocation()) {
return result;
}
StringBuilder query = new StringBuilder("SELECT time,user,wid,x,y,z,action FROM ");
query.append(ConfigHandler.prefix).append("session ");
if (filter.hasLocation()) {
query.append(WorldUtils.getWidIndex("session"));
}
filter.appendWhere(query);
query.append(" ORDER BY rowid DESC");
filter.appendLimit(query);
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
filter.bind(statement);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseSessionResult(connection, results));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
@@ -161,4 +215,17 @@ public class SessionLookup {
// Create and return the session data array
return new String[] { resultTime, resultUser, resultX, resultY, resultZ, resultWorldId, type, resultAction };
}
private static SessionResult parseSessionResult(Connection connection, ResultSet results) throws Exception {
int userId = results.getInt("user");
String username = ConfigHandler.playerIdCacheReversed.get(userId);
if (username == null) {
username = UserStatement.loadName(connection, userId);
}
return new SessionResult(
results.getLong("time"), username, WorldUtils.getWorldName(results.getInt("wid")),
results.getInt("x"), results.getInt("y"), results.getInt("z"), results.getInt("action")
);
}
}
@@ -0,0 +1,110 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import net.coreprotect.api.result.SignResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.model.action.SignActions;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for sign text lookups.
*/
public class SignAPI {
private SignAPI() {
throw new IllegalStateException("API class");
}
public static List<SignResult> performLookup(Location location, int offset) {
if (location == null) {
return new ArrayList<>();
}
return performLookup(LookupOptions.builder().time(offset).location(location).build());
}
public static List<SignResult> performLookup(LookupOptions options) {
List<SignResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
LookupFilter filter = LookupFilter.fromOptions(connection, options);
if (filter.hasInvalidUser() || filter.hasInvalidLocation()) {
return result;
}
StringBuilder query = new StringBuilder("SELECT time,user,wid,x,y,z,action,color,color_secondary,data,waxed,face,line_1,line_2,line_3,line_4,line_5,line_6,line_7,line_8 FROM ");
query.append(ConfigHandler.prefix).append("sign ");
if (filter.hasLocation()) {
query.append(WorldUtils.getWidIndex("sign"));
}
filter.appendWhere(query);
query.append(" AND action = '").append(SignActions.PLACE).append("' AND (LENGTH(line_1) > 0 OR LENGTH(line_2) > 0 OR LENGTH(line_3) > 0 OR LENGTH(line_4) > 0 OR LENGTH(line_5) > 0 OR LENGTH(line_6) > 0 OR LENGTH(line_7) > 0 OR LENGTH(line_8) > 0)");
query.append(" ORDER BY rowid DESC");
filter.appendLimit(query);
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
filter.bind(statement);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseSignResult(connection, results));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
private static SignResult parseSignResult(Connection connection, ResultSet results) throws Exception {
int userId = results.getInt("user");
String username = ConfigHandler.playerIdCacheReversed.get(userId);
if (username == null) {
username = UserStatement.loadName(connection, userId);
}
String[] lines = new String[] {
valueOrEmpty(results.getString("line_1")),
valueOrEmpty(results.getString("line_2")),
valueOrEmpty(results.getString("line_3")),
valueOrEmpty(results.getString("line_4")),
valueOrEmpty(results.getString("line_5")),
valueOrEmpty(results.getString("line_6")),
valueOrEmpty(results.getString("line_7")),
valueOrEmpty(results.getString("line_8"))
};
return new SignResult(
results.getLong("time"), username, WorldUtils.getWorldName(results.getInt("wid")),
results.getInt("x"), results.getInt("y"), results.getInt("z"),
results.getInt("action"), results.getInt("color"), results.getInt("color_secondary"),
results.getInt("data"), results.getInt("waxed") == 1, results.getInt("face") == 0, lines
);
}
private static String valueOrEmpty(String value) {
return value == null ? "" : value;
}
}
@@ -0,0 +1,151 @@
package net.coreprotect.api;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import net.coreprotect.api.result.UsernameResult;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.utility.ErrorReporter;
/**
* Provides API methods for username history lookups.
*/
public class UsernameAPI {
private UsernameAPI() {
throw new IllegalStateException("API class");
}
public static List<UsernameResult> performLookup(String user, int offset) {
return performLookup(LookupOptions.builder().user(user).time(offset).build());
}
public static List<UsernameResult> performLookup(LookupOptions options) {
List<UsernameResult> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
if (options == null) {
options = LookupOptions.builder().build();
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
Set<String> uuids = getUuids(connection, options.getUser());
if (uuids == null) {
return result;
}
int checkTime = 0;
if (options.getTime() > 0) {
checkTime = (int) (System.currentTimeMillis() / 1000L) - options.getTime();
}
StringBuilder query = new StringBuilder("SELECT time,uuid,user FROM ");
query.append(ConfigHandler.prefix).append("username_log WHERE time > ?");
if (!uuids.isEmpty()) {
query.append(" AND uuid IN (");
appendPlaceholders(query, uuids.size());
query.append(")");
}
query.append(" ORDER BY rowid DESC");
if (options.hasLimit()) {
query.append(" LIMIT ").append(options.getLimitOffset()).append(", ").append(options.getLimitCount());
}
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
int parameterIndex = 1;
statement.setInt(parameterIndex++, checkTime);
for (String uuid : uuids) {
statement.setString(parameterIndex++, uuid);
}
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(parseUsernameResult(results));
}
}
}
}
catch (Exception e) {
ErrorReporter.report(e);
}
return result;
}
private static void appendPlaceholders(StringBuilder query, int count) {
for (int index = 0; index < count; index++) {
if (index > 0) {
query.append(",");
}
query.append("?");
}
}
private static Set<String> getUuids(Connection connection, String user) throws Exception {
Set<String> result = new LinkedHashSet<>();
if (user == null || user.isEmpty() || user.equalsIgnoreCase("#global")) {
return result;
}
String cachedUuid = ConfigHandler.uuidCache.get(user.toLowerCase(Locale.ROOT));
if (cachedUuid != null) {
result.add(cachedUuid);
}
String collate = Config.getGlobal().MYSQL ? "" : " COLLATE NOCASE";
try (PreparedStatement statement = connection.prepareStatement("SELECT uuid FROM " + ConfigHandler.prefix + "user WHERE user = ?" + collate)) {
statement.setString(1, user);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(results.getString("uuid"));
}
}
}
try (PreparedStatement statement = connection.prepareStatement("SELECT uuid FROM " + ConfigHandler.prefix + "username_log WHERE user = ?" + collate)) {
statement.setString(1, user);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
result.add(results.getString("uuid"));
}
}
}
if (looksLikeUuid(user)) {
result.add(user);
}
return result.isEmpty() ? null : result;
}
private static boolean looksLikeUuid(String value) {
return value.length() == 36 && value.charAt(8) == '-' && value.charAt(13) == '-' && value.charAt(18) == '-' && value.charAt(23) == '-';
}
private static UsernameResult parseUsernameResult(ResultSet results) throws Exception {
String uuid = results.getString("uuid");
String username = results.getString("user");
String player = ConfigHandler.uuidCacheReversed.get(uuid);
if (player == null) {
player = username;
}
return new UsernameResult(results.getLong("time"), uuid, username, player);
}
}
@@ -0,0 +1,131 @@
package net.coreprotect.api.result;
import java.util.Locale;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.BlockTypeUtils;
import net.coreprotect.utility.EntityUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils;
/**
* Represents a logged block action.
*/
public class BlockResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final int type;
private final int data;
private final String blockData;
private final int actionId;
private final int rolledBack;
public BlockResult(long time, String username, String world, int x, int y, int z, int type, int data, String blockData, int actionId, int rolledBack) {
this.time = time;
this.username = username;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.type = type;
this.data = data;
this.blockData = blockData;
this.actionId = actionId;
this.rolledBack = rolledBack;
}
public int getActionId() {
return actionId;
}
public String getActionString() {
return LookupActions.getActionString(actionId);
}
@Deprecated
public int getData() {
return data;
}
public String getPlayer() {
return username;
}
public long getTimestamp() {
return time * 1000L;
}
public Material getType() {
if (actionId == LookupActions.ENTITY_KILL) {
return null;
}
Material material = MaterialUtils.getType(type);
if (material == null) {
return null;
}
String typeName = material.name().toLowerCase(Locale.ROOT);
return MaterialUtils.getType(StringUtils.nameFilter(typeName, data));
}
public EntityType getEntityType() {
if (actionId != LookupActions.ENTITY_KILL) {
return null;
}
if (type == 0) {
return EntityType.PLAYER;
}
return EntityUtils.getEntityType(type);
}
public BlockData getBlockData() {
if (actionId == LookupActions.ENTITY_KILL) {
return null;
}
if (blockData == null || blockData.isEmpty()) {
Material material = getType();
if (material != null) {
return material.createBlockData();
}
return BlockUtils.createBlockData(type);
}
BlockData result = BlockTypeUtils.createBlockDataFromString(blockData);
return result != null ? result : Bukkit.getServer().createBlockData(blockData);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public boolean isRolledBack() {
return rolledBack == 1 || rolledBack == 3;
}
public String worldName() {
return world;
}
}
@@ -0,0 +1,173 @@
package net.coreprotect.api.result;
import org.bukkit.Material;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.MaterialUtils;
/**
* Represents the result of a container action lookup with typed fields.
*/
public class ContainerResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final int type;
private final int data;
private final int amount;
private final byte[] metadata;
private final int action;
private final int rolledBack;
/**
* Creates a new ContainerResult with the specified parameters.
*
* @param time The timestamp in seconds
* @param username The username of the player who performed the action
* @param world The world name where the action occurred
* @param x The X coordinate
* @param y The Y coordinate
* @param z The Z coordinate
* @param type The material type ID
* @param data The data value
* @param amount The amount of items
* @param metadata The item metadata
* @param action The action ID
* @param rolledBack Whether the action has been rolled back
*/
public ContainerResult(long time, String username, String world, int x, int y, int z,
int type, int data, int amount, byte[] metadata, int action, int rolledBack) {
this.time = time;
this.username = username != null ? username : "";
this.world = world != null ? world : "";
this.x = x;
this.y = y;
this.z = z;
this.type = type;
this.data = data;
this.amount = amount;
this.metadata = metadata != null ? metadata.clone() : null;
this.action = action;
this.rolledBack = rolledBack;
}
/**
* Gets the action ID.
*
* @return The action ID
*/
public int getActionId() {
return action;
}
/**
* Gets the action as a human-readable string.
*
* @return "remove", "add", or "unknown"
*/
public String getActionString() {
return ItemTransactionActions.getActionString(action);
}
/**
* Gets the data value.
*
* @return The data value
*/
public int getData() {
return data;
}
/**
* Gets the amount of items.
*
* @return The amount
*/
public int getAmount() {
return amount;
}
/**
* Gets the username of the player who performed the action.
*
* @return The player username
*/
public String getPlayer() {
return username;
}
/**
* Gets the timestamp in milliseconds.
*
* @return The timestamp in milliseconds
*/
public long getTimestamp() {
return time * 1000L;
}
/**
* Gets the material type of the item.
*
* @return The Material, or null if unknown
*/
public Material getType() {
return MaterialUtils.getType(type);
}
/**
* Gets the X coordinate.
*
* @return The X coordinate
*/
public int getX() {
return x;
}
/**
* Gets the Y coordinate.
*
* @return The Y coordinate
*/
public int getY() {
return y;
}
/**
* Gets the Z coordinate.
*
* @return The Z coordinate
*/
public int getZ() {
return z;
}
/**
* Gets the item metadata.
*
* @return A copy of the metadata array, or null if no metadata
*/
public byte[] getMetadata() {
return metadata != null ? metadata.clone() : null;
}
/**
* Checks if this action has been rolled back.
*
* @return true if rolled back, false otherwise
*/
public boolean isRolledBack() {
return rolledBack == 1 || rolledBack == 3;
}
/**
* Gets the world name where the action occurred.
*
* @return The world name
*/
public String worldName() {
return world;
}
}
@@ -0,0 +1,22 @@
package net.coreprotect.api.result;
/**
* Common fields shared by typed CoreProtect lookup results.
*/
public interface CoreProtectResult {
int getActionId();
String getActionString();
String getPlayer();
long getTimestamp();
int getX();
int getY();
int getZ();
String worldName();
}
@@ -0,0 +1,120 @@
package net.coreprotect.api.result;
import org.bukkit.Material;
import net.coreprotect.model.item.InventorySources;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.MaterialUtils;
/**
* Represents a normalized player inventory transaction.
*/
public class InventoryResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final int type;
private final int data;
private final int amount;
private final byte[] metadata;
private final int actionId;
private final int transactionActionId;
private final int rolledBack;
private final int sourceId;
public InventoryResult(long time, String username, String world, int x, int y, int z, int type, int data, int amount, byte[] metadata, int transactionActionId, int rolledBack, int sourceId) {
this.time = time;
this.username = username;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.type = type;
this.data = data;
this.amount = amount;
this.metadata = metadata != null ? metadata.clone() : null;
this.transactionActionId = transactionActionId;
this.rolledBack = rolledBack;
this.sourceId = sourceId;
this.actionId = ItemTransactionActions.getInventoryActionId(transactionActionId);
}
public int getActionId() {
return actionId;
}
public String getActionString() {
return ItemTransactionActions.getActionString(actionId);
}
public int getAmount() {
return amount;
}
@Deprecated
public int getData() {
return data;
}
public byte[] getMetadata() {
return metadata != null ? metadata.clone() : null;
}
public String getPlayer() {
return username;
}
public int getSourceId() {
return sourceId;
}
public String getSource() {
return InventorySources.getSourceString(sourceId);
}
public long getTimestamp() {
return time * 1000L;
}
public int getTransactionActionId() {
return transactionActionId;
}
public String getTransactionActionString() {
return ItemTransactionActions.getActionString(transactionActionId);
}
public Material getType() {
Material material = MaterialUtils.getType(type);
if (sourceId == InventorySources.BLOCK) {
return ItemUtils.itemFilter(material, true);
}
return material;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public boolean isRolledBack() {
return rolledBack == 2 || rolledBack == 3;
}
public String worldName() {
return world;
}
}
@@ -0,0 +1,85 @@
package net.coreprotect.api.result;
import org.bukkit.Material;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.MaterialUtils;
/**
* Represents a logged world item transaction.
*/
public class ItemResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final int type;
private final int amount;
private final byte[] metadata;
private final int actionId;
private final int rolledBack;
public ItemResult(long time, String username, String world, int x, int y, int z, int type, int amount, byte[] metadata, int actionId, int rolledBack) {
this.time = time;
this.username = username;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.type = type;
this.amount = amount;
this.metadata = metadata != null ? metadata.clone() : null;
this.actionId = actionId;
this.rolledBack = rolledBack;
}
public int getActionId() {
return actionId;
}
public String getActionString() {
return ItemTransactionActions.getActionString(actionId);
}
public int getAmount() {
return amount;
}
public byte[] getMetadata() {
return metadata != null ? metadata.clone() : null;
}
public String getPlayer() {
return username;
}
public long getTimestamp() {
return time * 1000L;
}
public Material getType() {
return MaterialUtils.getType(type);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public boolean isRolledBack() {
return rolledBack == 1 || rolledBack == 3;
}
public String worldName() {
return world;
}
}
@@ -0,0 +1,64 @@
package net.coreprotect.api.result;
import net.coreprotect.model.action.LookupActions;
/**
* Represents a logged player chat message or command.
*/
public class MessageResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final String message;
private final int actionId;
public MessageResult(long time, String username, String world, int x, int y, int z, String message, int actionId) {
this.time = time;
this.username = username;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.message = message;
this.actionId = actionId;
}
public int getActionId() {
return actionId;
}
public String getActionString() {
return LookupActions.getActionString(actionId);
}
public String getMessage() {
return message;
}
public String getPlayer() {
return username;
}
public long getTimestamp() {
return time * 1000L;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public String worldName() {
return world;
}
}
@@ -7,12 +7,16 @@ import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import net.coreprotect.api.SessionLookup;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.model.action.SessionActions;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.BlockTypeUtils;
import net.coreprotect.utility.EntityUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils;
public class ParseResult {
public class ParseResult implements CoreProtectResult {
private final String[] parse;
public ParseResult(String[] data) {
@@ -26,31 +30,10 @@ public class ParseResult {
public String getActionString() {
int actionID = Integer.parseInt(parse[7]);
if (parse.length < 13 && Integer.parseInt(parse[6]) == SessionLookup.ID) {
switch (actionID) {
case 0:
return "logout";
case 1:
return "login";
default:
return "unknown";
}
return SessionActions.getActionString(actionID);
}
String result = "unknown";
if (actionID == 0) {
result = "break";
}
else if (actionID == 1) {
result = "place";
}
else if (actionID == 2) {
result = "click";
}
else if (actionID == 3) {
result = "kill";
}
return result;
return LookupActions.getActionString(actionID);
}
@Deprecated
@@ -84,7 +67,12 @@ public class ParseResult {
typeName = EntityUtils.getEntityType(type).name();
}
else {
typeName = MaterialUtils.getType(type).name().toLowerCase(Locale.ROOT);
Material material = MaterialUtils.getType(type);
if (material == null) {
return null;
}
typeName = material.name().toLowerCase(Locale.ROOT);
typeName = StringUtils.nameFilter(typeName, this.getData());
}
@@ -98,9 +86,16 @@ public class ParseResult {
String blockData = parse[12];
if (blockData == null || blockData.length() == 0) {
return getType().createBlockData();
Material type = getType();
if (type != null) {
return type.createBlockData();
}
return BlockUtils.createBlockData(Integer.parseInt(parse[5]));
}
return Bukkit.getServer().createBlockData(blockData);
BlockData result = BlockTypeUtils.createBlockDataFromString(blockData);
return result != null ? result : Bukkit.getServer().createBlockData(blockData);
}
public int getX() {
@@ -0,0 +1,58 @@
package net.coreprotect.api.result;
import net.coreprotect.model.action.SessionActions;
/**
* Represents a logged player login or logout session event.
*/
public class SessionResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final int actionId;
public SessionResult(long time, String username, String world, int x, int y, int z, int actionId) {
this.time = time;
this.username = username;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.actionId = actionId;
}
public int getActionId() {
return actionId;
}
public String getActionString() {
return SessionActions.getActionString(actionId);
}
public String getPlayer() {
return username;
}
public long getTimestamp() {
return time * 1000L;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public String worldName() {
return world;
}
}
@@ -0,0 +1,129 @@
package net.coreprotect.api.result;
import net.coreprotect.model.action.SignActions;
import net.coreprotect.utility.BlockUtils;
/**
* Represents logged sign text.
*/
public class SignResult implements CoreProtectResult {
private final long time;
private final String username;
private final String world;
private final int x;
private final int y;
private final int z;
private final int actionId;
private final int color;
private final int colorSecondary;
private final int data;
private final boolean waxed;
private final boolean front;
private final String[] lines;
public SignResult(long time, String username, String world, int x, int y, int z, int actionId, int color, int colorSecondary, int data, boolean waxed, boolean front, String[] lines) {
this.time = time;
this.username = username;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.actionId = actionId;
this.color = color;
this.colorSecondary = colorSecondary;
this.data = data;
this.waxed = waxed;
this.front = front;
this.lines = lines.clone();
}
public int getActionId() {
return actionId;
}
public String getActionString() {
return SignActions.getActionString(actionId);
}
public int getColor() {
return color;
}
public int getColorSecondary() {
return colorSecondary;
}
public int getData() {
return data;
}
public String getLine(int line) {
if (line < 0 || line >= lines.length) {
return "";
}
return lines[line];
}
public String[] getLines() {
return lines.clone();
}
public String getMessage() {
StringBuilder message = new StringBuilder();
int startLine = front ? 0 : 4;
int endLine = front ? 4 : 8;
for (int index = startLine; index < endLine; index++) {
String line = lines[index];
if (line != null && !line.isEmpty()) {
message.append(line);
if (!line.endsWith(" ")) {
message.append(" ");
}
}
}
return message.toString();
}
public String getPlayer() {
return username;
}
public long getTimestamp() {
return time * 1000L;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public boolean isBackGlowing() {
return BlockUtils.isSideGlowing(false, data);
}
public boolean isFront() {
return front;
}
public boolean isFrontGlowing() {
return BlockUtils.isSideGlowing(true, data);
}
public boolean isWaxed() {
return waxed;
}
public String worldName() {
return world;
}
}
@@ -0,0 +1,60 @@
package net.coreprotect.api.result;
import net.coreprotect.model.action.LookupActions;
/**
* Represents a logged username used by a player UUID.
*/
public class UsernameResult implements CoreProtectResult {
private final long time;
private final String uuid;
private final String username;
private final String player;
public UsernameResult(long time, String uuid, String username, String player) {
this.time = time;
this.uuid = uuid;
this.username = username;
this.player = player;
}
public int getActionId() {
return LookupActions.USERNAME;
}
public String getActionString() {
return LookupActions.getActionString(getActionId());
}
public String getPlayer() {
return player;
}
public long getTimestamp() {
return time * 1000L;
}
public String getUsername() {
return username;
}
public String getUuid() {
return uuid;
}
public int getX() {
return 0;
}
public int getY() {
return 0;
}
public int getZ() {
return 0;
}
public String worldName() {
return "";
}
}
@@ -1,17 +1,23 @@
package net.coreprotect.bukkit;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.bukkit.Art;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
@@ -22,6 +28,8 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Villager;
import org.bukkit.event.Event;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.block.SignChangeEvent;
@@ -58,6 +66,17 @@ public class BukkitAdapter implements BukkitInterface {
public static final int BUKKIT_V1_19 = 19;
public static final int BUKKIT_V1_20 = 20;
public static final int BUKKIT_V1_21 = 21;
public static final int BUKKIT_V26_0 = 26000;
public static final int BUKKIT_V26_1 = 26010;
public static final int BUKKIT_V26_2 = 26020;
public static int getAdapterVersion(int major, int minor) {
return getAdapterVersion(major, minor, 0);
}
public static int getAdapterVersion(int major, int minor, int patch) {
return major == 1 ? minor : (major * 1000) + (minor * 10) + patch;
}
/**
* Initializes the appropriate Bukkit adapter based on the server version.
@@ -84,9 +103,16 @@ public class BukkitAdapter implements BukkitInterface {
ADAPTER = new Bukkit_v1_20();
break;
case BUKKIT_V1_21:
default:
case BUKKIT_V26_0:
case BUKKIT_V26_1:
ADAPTER = new Bukkit_v1_21();
break;
case BUKKIT_V26_2:
ADAPTER = new Bukkit_v26_2();
break;
default:
ADAPTER = ConfigHandler.SERVER_VERSION >= BUKKIT_V26_2 ? new Bukkit_v26_2() : new Bukkit_v1_21();
break;
}
}
@@ -115,6 +141,25 @@ public class BukkitAdapter implements BukkitInterface {
return false;
}
@Override
public void addMerchantRecipeMeta(MerchantRecipe recipe, List<Object> recipeData) {
}
@Override
public void setMerchantRecipeMeta(MerchantRecipe recipe, List<?> recipeData) {
}
@Override
public void refreshVillagerBrain(Villager villager) {
try {
Object handle = villager.getClass().getMethod("getHandle").invoke(villager);
Object level = villager.getWorld().getClass().getMethod("getHandle").invoke(villager.getWorld());
invokeSingleArgumentMethod(handle, "refreshBrain", level);
}
catch (Exception e) {
}
}
@Override
public void getWolfVariant(org.bukkit.entity.Wolf wolf, List<Object> info) {
// Base implementation does nothing - Wolf variants only exist in 1.21+
@@ -184,6 +229,24 @@ public class BukkitAdapter implements BukkitInterface {
return itemStack;
}
private static void invokeSingleArgumentMethod(Object target, String methodName, Object argument) {
if (target == null || argument == null) {
return;
}
for (Method method : target.getClass().getMethods()) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getName().equals(methodName) && parameterTypes.length == 1 && parameterTypes[0].isInstance(argument)) {
try {
method.invoke(target, argument);
}
catch (Exception e) {
}
return;
}
}
}
// -------------------- Block methods --------------------
@Override
@@ -223,6 +286,21 @@ public class BukkitAdapter implements BukkitInterface {
return Material.AIR;
}
@Override
public boolean hasBlockType(String key) {
return false;
}
@Override
public BlockData createBlockData(String key) {
return null;
}
@Override
public BlockData createBlockDataFromString(String blockData) {
return null;
}
@Override
public boolean isInvisible(Material material) {
return BlockUtils.isAir(material);
@@ -369,6 +447,25 @@ public class BukkitAdapter implements BukkitInterface {
return null;
}
@Override
public String getPaintingArtKey(Painting painting) {
try {
return painting.getArt().name();
}
catch (IncompatibleClassChangeError e) {
return painting.getArt().toString();
}
}
@Override
public Art getPaintingArt(String name) {
if (name == null || name.isBlank()) {
return null;
}
return Art.getByName(name.toUpperCase(Locale.ROOT));
}
@Override
public boolean isCrafter(InventoryType type) {
return false;
@@ -390,6 +487,11 @@ public class BukkitAdapter implements BukkitInterface {
return false;
}
@Override
public List<Location> getShelfInteractionLocations(Block block, BlockFace blockFace) {
return Collections.emptyList();
}
@Override
public Set<Material> copperChestMaterials() {
return EMPTY_SET;
@@ -4,9 +4,12 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.Art;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
@@ -14,6 +17,8 @@ import org.bukkit.entity.Arrow;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Villager;
import org.bukkit.event.Event;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.block.SignChangeEvent;
@@ -76,6 +81,33 @@ public interface BukkitInterface {
*/
Material getBucketContents(Material material);
/**
* Checks whether the runtime supports and contains a block type key.
*
* @param key
* The namespaced block key
* @return true if the block type exists, false otherwise
*/
boolean hasBlockType(String key);
/**
* Creates default block data for a block type key.
*
* @param key
* The namespaced block key
* @return The block data, or null if unsupported/unavailable
*/
BlockData createBlockData(String key);
/**
* Creates block data from a serialized block data string.
*
* @param blockData
* The serialized block data
* @return The block data, or null if unsupported/unavailable
*/
BlockData createBlockDataFromString(String blockData);
// --------------------------------------------------------------------------
// Material type checking methods
// --------------------------------------------------------------------------
@@ -144,6 +176,8 @@ public interface BukkitInterface {
*/
boolean isShelf(Material material);
List<Location> getShelfInteractionLocations(Block block, BlockFace blockFace);
/**
* Checks if a material is a bookshelf book.
@@ -267,6 +301,12 @@ public interface BukkitInterface {
*/
boolean setEntityMeta(Entity entity, Object value, int count);
void addMerchantRecipeMeta(MerchantRecipe recipe, List<Object> recipeData);
void setMerchantRecipeMeta(MerchantRecipe recipe, List<?> recipeData);
void refreshVillagerBrain(Villager villager);
/**
* Gets the wolf variant and adds it to the info list.
* Only implemented in Minecraft 1.21+.
@@ -471,6 +511,10 @@ public interface BukkitInterface {
*/
Object getRegistryValue(String key, Object tClass);
String getPaintingArtKey(Painting painting);
Art getPaintingArt(String name);
/**
* Parses a legacy material name.
*
@@ -2,6 +2,7 @@ package net.coreprotect.bukkit;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.Color;
@@ -17,6 +18,7 @@ import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.MerchantRecipe;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionType;
@@ -304,4 +306,17 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 {
// accoding to the Bukkit docs this will always return air
return event.getExplodedBlockState().getType();
}
@Override
public void addMerchantRecipeMeta(MerchantRecipe recipe, List<Object> recipeData) {
recipeData.add(recipe.getDemand());
}
@Override
public void setMerchantRecipeMeta(MerchantRecipe recipe, List<?> recipeData) {
if (recipeData.size() > 7 && recipeData.get(7) instanceof Number) {
recipe.setDemand(((Number) recipeData.get(7)).intValue());
}
}
}
@@ -1,17 +1,28 @@
package net.coreprotect.bukkit;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.bukkit.Art;
import org.bukkit.Bukkit;
import org.bukkit.ExplosionResult;
import org.bukkit.Keyed;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockType;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Painting;
import org.bukkit.event.Event;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
@@ -19,6 +30,7 @@ import org.bukkit.event.inventory.InventoryType;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.utility.BlockTypeUtils;
/**
* Bukkit adapter implementation for Minecraft 1.21.
@@ -81,9 +93,13 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 {
*/
public void initializeBundles(){
if (BUNDLES.isEmpty()) {
Material bundle = Material.getMaterial("RED_BUNDLE");
if (bundle != null) {
BUNDLES.addAll(Tag.ITEMS_BUNDLES.getValues());
Tag<Material> bundleTag = getMaterialTag(Tag.REGISTRY_ITEMS, "bundles");
if (bundleTag != null) {
BUNDLES.addAll(bundleTag.getValues());
}
if (BUNDLES.isEmpty()) {
addMaterialsEndingWith(BUNDLES, "_BUNDLE");
}
BUNDLES.add(Material.BUNDLE);
}
@@ -103,6 +119,43 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 {
}
}
@Override
public boolean hasBlockType(String key) {
return getBlockType(key) != null;
}
@Override
public BlockData createBlockData(String key) {
try {
BlockType blockType = getBlockType(key);
return blockType == null ? null : blockType.createBlockData();
}
catch (Exception e) {
return null;
}
}
@Override
public BlockData createBlockDataFromString(String blockData) {
try {
BlockType blockType = getBlockType(BlockTypeUtils.getBlockDataKey(blockData));
if (blockType == null) {
return null;
}
String states = BlockTypeUtils.getBlockDataStates(blockData);
return states == null ? blockType.createBlockData() : blockType.createBlockData(states);
}
catch (Exception e) {
return null;
}
}
private BlockType getBlockType(String key) {
NamespacedKey namespacedKey = NamespacedKey.fromString(BlockTypeUtils.normalizeKey(key));
return namespacedKey == null ? null : Registry.BLOCK.get(namespacedKey);
}
/**
* Gets the EntityType corresponding to a Material.
* Maps Material to its equivalent EntityType for entity handling.
@@ -153,6 +206,51 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 {
return Bukkit.getRegistry((Class) tClass).get(namespacedKey);
}
@Override
public String getPaintingArtKey(Painting painting) {
try {
NamespacedKey key = Registry.ART.getKey(painting.getArt());
if (key != null) {
return normalizePaintingArtKey(key.toString());
}
}
catch (Exception e) {
}
return normalizePaintingArtKey(super.getPaintingArtKey(painting));
}
@Override
public Art getPaintingArt(String name) {
NamespacedKey key = NamespacedKey.fromString(normalizePaintingArtLookupKey(name));
if (key != null) {
Art art = Registry.ART.get(key);
if (art != null) {
return art;
}
}
return super.getPaintingArt(name);
}
private String normalizePaintingArtKey(String name) {
if (name == null) {
return "";
}
String normalized = name.toLowerCase(Locale.ROOT).trim();
if (normalized.startsWith("minecraft:")) {
return normalized.substring("minecraft:".length());
}
return normalized;
}
private String normalizePaintingArtLookupKey(String name) {
String normalized = normalizePaintingArtKey(name);
return normalized.contains(":") ? normalized : "minecraft:" + normalized;
}
/**
* Gets the wolf variant and adds it to the info list.
* This functionality is specific to Minecraft 1.21+.
@@ -208,7 +306,7 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 {
@Override
public boolean isBundle(Material material) {
return Tag.ITEMS_BUNDLES.getValues().contains(material);
return BUNDLES.contains(material);
}
@@ -237,15 +335,102 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 {
@Override
public Set<Material> shelfMaterials() {
if (SHELVES.isEmpty()) {
Material shelf = Material.getMaterial("OAK_SHELF");
if (shelf != null) {
SHELVES.addAll(Tag.WOODEN_SHELVES.getValues());
Tag<Material> shelfTag = getMaterialTag(Tag.REGISTRY_BLOCKS, "wooden_shelves");
if (shelfTag != null) {
SHELVES.addAll(shelfTag.getValues());
}
if (SHELVES.isEmpty()) {
addMaterialsEndingWith(SHELVES, "_SHELF");
}
}
return SHELVES;
}
@Override
public List<Location> getShelfInteractionLocations(Block block, BlockFace blockFace) {
List<Location> locations = new ArrayList<>();
BlockData blockData = block.getBlockData();
BlockFace facing = getShelfFacing(blockData);
if (facing == null) {
locations.add(block.getLocation());
return locations;
}
if (blockFace != facing) {
return locations;
}
String sideChain = getShelfSideChain(blockData);
if ("UNCONNECTED".equals(sideChain)) {
locations.add(block.getLocation());
return locations;
}
Block center = block;
int directionX = facing.getModX();
int directionZ = facing.getModZ();
if ("LEFT".equals(sideChain)) {
center = center.getRelative(directionZ, 0, -directionX);
}
else if ("RIGHT".equals(sideChain)) {
center = center.getRelative(-directionZ, 0, directionX);
}
String centerSideChain = getShelfSideChain(center.getBlockData());
if (centerSideChain == null) {
locations.add(block.getLocation());
return locations;
}
locations.add(center.getLocation());
if (!"CENTER".equals(centerSideChain)) {
locations.add(block.getLocation());
return locations;
}
locations.add(center.getRelative(-directionZ, 0, directionX).getLocation());
locations.add(center.getRelative(directionZ, 0, -directionX).getLocation());
return locations;
}
private static Tag<Material> getMaterialTag(String registry, String key) {
return Bukkit.getTag(registry, NamespacedKey.minecraft(key), Material.class);
}
private static void addMaterialsEndingWith(Set<Material> materials, String suffix) {
for (Material material : Material.values()) {
if (material.name().endsWith(suffix)) {
materials.add(material);
}
}
}
private static BlockFace getShelfFacing(BlockData blockData) {
Object facing = invokeNoArgumentMethod(blockData, "getFacing");
return facing instanceof BlockFace ? (BlockFace) facing : null;
}
private static String getShelfSideChain(BlockData blockData) {
Object sideChain = invokeNoArgumentMethod(blockData, "getSideChain");
return sideChain == null ? null : sideChain.toString();
}
private static Object invokeNoArgumentMethod(Object target, String methodName) {
if (target == null) {
return null;
}
try {
Method method = target.getClass().getMethod(methodName);
return method.invoke(target);
}
catch (ReflectiveOperationException | LinkageError e) {
return null;
}
}
@Override
public boolean shouldLogExplosion(Event event){
ExplosionResult result = null;
@@ -0,0 +1,35 @@
package net.coreprotect.bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Speleothem;
import net.coreprotect.model.BlockGroup;
/**
* Bukkit adapter implementation for Minecraft 26.2.
*/
public class Bukkit_v26_2 extends Bukkit_v1_21 {
public Bukkit_v26_2() {
initializeBlockGroups();
}
private void initializeBlockGroups() {
BlockGroup.TRACK_TOP_BOTTOM.add(Material.SULFUR_SPIKE);
}
@Override
public boolean isAttached(Block block, Block scanBlock, BlockData blockData, int scanMin) {
if (blockData instanceof Speleothem) {
Speleothem speleothem = (Speleothem) blockData;
BlockFace blockFace = speleothem.getVerticalDirection();
return scanBlock.getRelative(blockFace.getOppositeFace()).getLocation().equals(block.getLocation());
}
return super.isAttached(block, scanBlock, blockData, scanMin);
}
}
@@ -11,6 +11,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class ApplyCommand {
protected static void runCommand(CommandSender user, Command command, boolean permission, String[] args) {
@@ -41,7 +42,7 @@ public class ApplyCommand {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -11,6 +11,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class CancelCommand {
protected static void runCommand(CommandSender user, Command command, boolean permission, String[] args) {
@@ -41,7 +42,7 @@ public class CancelCommand {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -14,6 +14,7 @@ import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Extensions;
import net.coreprotect.utility.VersionUtils;
import net.coreprotect.utility.ErrorReporter;
public class CommandHandler implements CommandExecutor {
private static CommandHandler instance;
@@ -75,6 +76,9 @@ public class CommandHandler implements CommandExecutor {
else if (user.hasPermission("coreprotect.networking") && corecommand.equals("network-debug")) {
permission = true;
}
else if (user.hasPermission("coreprotect.give") && corecommand.equals("give")) {
permission = true;
}
}
if (corecommand.equals("rollback") || corecommand.equals("restore") || corecommand.equals("rb") || corecommand.equals("rs") || corecommand.equals("ro") || corecommand.equals("re")) {
@@ -119,6 +123,9 @@ public class CommandHandler implements CommandExecutor {
else if (corecommand.equals("network-debug")) {
NetworkDebugCommand.runCommand(user, permission, argumentArray);
}
else if (corecommand.equals("give")) {
GiveCommand.runCommand(user, command, permission, argumentArray);
}
else if (corecommand.equals("migrate-db")) {
if (!VersionUtils.validDonationKey()) {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.DONATION_KEY_REQUIRED));
@@ -138,25 +145,26 @@ public class CommandHandler implements CommandExecutor {
if (user.isOp() && versionAlert.get(user.getName()) == null) {
String latestVersion = NetworkHandler.latestVersion();
String latestEdgeVersion = NetworkHandler.latestEdgeVersion();
if (latestVersion != null || latestEdgeVersion != null) {
boolean communityEdition = VersionUtils.isCommunityEdition();
if (latestVersion != null || (latestEdgeVersion != null && !communityEdition)) {
versionAlert.put(user.getName(), true);
class updateAlert implements Runnable {
@Override
public void run() {
try {
Thread.sleep(5000);
Chat.sendMessage(user, Color.WHITE + "----- " + Color.DARK_AQUA + Phrase.build(Phrase.UPDATE_HEADER, "CoreProtect" + (VersionUtils.isCommunityEdition() ? " " + ConfigHandler.COMMUNITY_EDITION : "")) + Color.WHITE + " -----");
Chat.sendMessage(user, Color.WHITE + "----- " + Color.DARK_AQUA + Phrase.build(Phrase.UPDATE_HEADER, "CoreProtect" + (communityEdition ? " " + ConfigHandler.COMMUNITY_EDITION : "")) + Color.WHITE + " -----");
if (latestVersion != null) {
Chat.sendMessage(user, Color.DARK_AQUA + Phrase.build(Phrase.UPDATE_NOTICE, Color.WHITE, "CoreProtect CE v" + latestVersion));
Chat.sendMessage(user, Color.DARK_AQUA + Phrase.build(Phrase.LINK_DOWNLOAD, Color.WHITE, "www.coreprotect.net/download/"));
}
else if (!VersionUtils.isCommunityEdition()) {
else {
Chat.sendMessage(user, Color.DARK_AQUA + Phrase.build(Phrase.UPDATE_NOTICE, Color.WHITE, "CoreProtect v" + latestEdgeVersion));
Chat.sendMessage(user, Color.DARK_AQUA + Phrase.build(Phrase.LINK_DOWNLOAD, Color.WHITE, "www.coreprotect.net/latest/"));
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -5,17 +5,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import net.coreprotect.command.parser.*;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import net.coreprotect.command.parser.ActionParser;
import net.coreprotect.command.parser.LocationParser;
import net.coreprotect.command.parser.MaterialParser;
import net.coreprotect.command.parser.TimeParser;
import net.coreprotect.command.parser.UserParser;
import net.coreprotect.command.parser.WorldParser;
/**
* Main parser class for CoreProtect commands.
* Delegates to specialized parser classes for specific functionality.
@@ -326,4 +320,7 @@ public class CommandParser {
return input.stripTrailingZeros().toPlainString();
}
protected static Integer parseGivableItemId(String[] inputArguments) {
return GivableItemIdParser.parseGivableItemId(inputArguments);
}
}
@@ -0,0 +1,40 @@
package net.coreprotect.command;
import net.coreprotect.language.Phrase;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatMessage;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ItemUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class GiveCommand {
public static void runCommand(CommandSender sender, Command command, boolean permission, String[] args) {
if (!permission) {
Chat.sendMessage(sender, new ChatMessage(Phrase.build(Phrase.NO_PERMISSION)).build());
return;
}
Integer itemId = CommandParser.parseGivableItemId(args);
if (itemId == null) {
Chat.sendMessage(sender, new ChatMessage(Phrase.build(Phrase.MISSING_PARAMETERS, Color.WHITE, "/" + command.getName() + " give <itemId>")).build());
return;
}
ItemStack item = ItemUtils.getGivableItem(itemId);
if (item == null) {
Chat.sendMessage(sender, new ChatMessage(Phrase.build(Phrase.INVALID_ITEM_ID)).build());
return;
}
if (!(sender instanceof Player)) {
Chat.sendMessage(sender, new ChatMessage(Phrase.build(Phrase.ACTION_NOT_SUPPORTED)).build());
return;
}
Player player = (Player) sender;
player.getInventory().addItem(item);
}
}
@@ -67,8 +67,11 @@ public class HelpCommand {
Chat.sendMessage(player, Color.GREY + Color.ITALIC + Phrase.build(Phrase.HELP_PARAMETER, "/co help params"));
}
else if (helpcommand.equals("purge") || helpcommand.equals("purges")) {
Chat.sendMessage(player, Color.DARK_AQUA + "/co purge t:<time> " + Color.WHITE + "- " + Phrase.build(Phrase.HELP_PURGE_1));
Chat.sendMessage(player, Color.GREY + Color.ITALIC + "" + Phrase.build(Phrase.HELP_PURGE_2, "/co purge t:30d"));
Chat.sendMessage(player, Color.DARK_AQUA + "/co purge " + Color.GREY + "<params> " + Color.WHITE + "- " + Phrase.build(Phrase.HELP_PURGE_1));
Chat.sendMessage(player, Color.DARK_AQUA + "| " + Color.GREY + "t:<time> " + Color.WHITE + "- " + Phrase.build(Phrase.HELP_PURGE_3));
Chat.sendMessage(player, Color.DARK_AQUA + "| " + Color.GREY + "r:<world> " + Color.WHITE + "- " + Phrase.build(Phrase.HELP_PURGE_4));
Chat.sendMessage(player, Color.DARK_AQUA + "| " + Color.GREY + "i:<include> " + Color.WHITE + "- " + Phrase.build(Phrase.HELP_PURGE_5));
Chat.sendMessage(player, Color.GREY + Color.ITALIC + Phrase.build(Phrase.HELP_PURGE_2, "/co purge t:30d"));
}
else if (helpcommand.equals("reload")) {
Chat.sendMessage(player, Color.DARK_AQUA + "/co reload " + Color.WHITE + "- " + Phrase.build(Phrase.HELP_RELOAD_COMMAND));
@@ -22,10 +22,12 @@ import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatMessage;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class LookupCommand {
public static void runCommand(CommandSender player, Command command, boolean permission, String[] args) {
@@ -67,15 +69,15 @@ public class LookupCommand {
boolean hasBlock = false;
boolean hasEntity = false;
for (Object arg : argBlocks) {
if (arg instanceof Material) {
if (arg instanceof Material || arg instanceof String) {
hasBlock = true;
}
else if (arg instanceof EntityType) {
hasEntity = true;
if (argAction.size() == 0) {
argAction.add(3);
argAction.add(LookupActions.ENTITY_KILL);
}
else if (!argAction.contains(3)) {
else if (!argAction.contains(LookupActions.ENTITY_KILL)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_INCLUDE_COMBO));
return;
}
@@ -84,15 +86,15 @@ public class LookupCommand {
/* check for invalid block/entity combinations (exclude) */
for (Object arg : argExclude.keySet()) {
if (arg instanceof Material) {
if (arg instanceof Material || arg instanceof String) {
hasBlock = true;
}
else if (arg instanceof EntityType) {
hasEntity = true;
if (argAction.size() == 0) {
argAction.add(3);
argAction.add(LookupActions.ENTITY_KILL);
}
else if (!argAction.contains(3)) {
else if (!argAction.contains(LookupActions.ENTITY_KILL)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_INCLUDE_COMBO));
return;
}
@@ -143,7 +145,7 @@ public class LookupCommand {
}
}
}
if (argAction.contains(6) || argAction.contains(7) || argAction.contains(8) || argAction.contains(9) || argAction.contains(10)) {
if (argAction.contains(LookupActions.CHAT) || argAction.contains(LookupActions.COMMAND) || argAction.contains(LookupActions.SESSION) || argAction.contains(LookupActions.USERNAME) || argAction.contains(LookupActions.SIGN)) {
pageLookup = true;
}
@@ -189,53 +191,53 @@ public class LookupCommand {
allPermission = true;
}
if (!allPermission) {
if (!pageLookup && (argAction.size() == 0 || (argAction.size() == 1 && (argAction.contains(0) || argAction.contains(1)))) && !player.hasPermission("coreprotect.lookup.block")) {
if (!pageLookup && (argAction.size() == 0 || (argAction.size() == 1 && (argAction.contains(LookupActions.BLOCK_BREAK) || argAction.contains(LookupActions.BLOCK_PLACE)))) && !player.hasPermission("coreprotect.lookup.block")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(2) && !player.hasPermission("coreprotect.lookup.click")) {
if (argAction.contains(LookupActions.INTERACTION) && !player.hasPermission("coreprotect.lookup.click")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(3) && !player.hasPermission("coreprotect.lookup.kill")) {
if (argAction.contains(LookupActions.ENTITY_KILL) && !player.hasPermission("coreprotect.lookup.kill")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(4) && !argAction.contains(11) && !player.hasPermission("coreprotect.lookup.container")) {
if (argAction.contains(LookupActions.CONTAINER) && !argAction.contains(LookupActions.ITEM) && !player.hasPermission("coreprotect.lookup.container")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(6) && !player.hasPermission("coreprotect.lookup.chat")) {
if (argAction.contains(LookupActions.CHAT) && !player.hasPermission("coreprotect.lookup.chat")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(7) && !player.hasPermission("coreprotect.lookup.command")) {
if (argAction.contains(LookupActions.COMMAND) && !player.hasPermission("coreprotect.lookup.command")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(8) && !player.hasPermission("coreprotect.lookup.session")) {
if (argAction.contains(LookupActions.SESSION) && !player.hasPermission("coreprotect.lookup.session")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(9) && !player.hasPermission("coreprotect.lookup.username")) {
if (argAction.contains(LookupActions.USERNAME) && !player.hasPermission("coreprotect.lookup.username")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(10) && !player.hasPermission("coreprotect.lookup.sign")) {
if (argAction.contains(LookupActions.SIGN) && !player.hasPermission("coreprotect.lookup.sign")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(11) && !argAction.contains(4) && !player.hasPermission("coreprotect.lookup.item")) {
if (argAction.contains(LookupActions.ITEM) && !argAction.contains(LookupActions.CONTAINER) && !player.hasPermission("coreprotect.lookup.item")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
if (argAction.contains(4) && argAction.contains(11) && !player.hasPermission("coreprotect.lookup.inventory")) {
if (LookupActions.isInventoryLookup(argAction) && !player.hasPermission("coreprotect.lookup.inventory")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
}
if (argAction.contains(6) || argAction.contains(7) || argAction.contains(8) || argAction.contains(9) || argAction.contains(10)) {
if (argAction.contains(9) && (argRadius != null || argWid > 0 || worldedit)) {
if (argAction.contains(LookupActions.CHAT) || argAction.contains(LookupActions.COMMAND) || argAction.contains(LookupActions.SESSION) || argAction.contains(LookupActions.USERNAME) || argAction.contains(LookupActions.SIGN)) {
if (argAction.contains(LookupActions.USERNAME) && (argRadius != null || argWid > 0 || worldedit)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INCOMPATIBLE_ACTION, "r:"));
return;
}
@@ -254,7 +256,7 @@ public class LookupCommand {
return;
}
if (argAction.contains(4) && argAction.contains(11)) { // a:inventory
if (LookupActions.isInventoryLookup(argAction)) {
if (argUsers.size() == 0) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_ACTION_USER));
return;
@@ -404,7 +406,7 @@ public class LookupCommand {
boolean defaultRe = true;
int pa = 1;
int re = 4;
if (argAction.contains(6) || argAction.contains(7) || argAction.contains(9) || (argAction.contains(4) && argAction.contains(11))) {
if (argAction.contains(LookupActions.CHAT) || argAction.contains(LookupActions.COMMAND) || argAction.contains(LookupActions.USERNAME) || LookupActions.isInventoryLookup(argAction)) {
re = 7;
}
if (parseRows > 0) {
@@ -480,7 +482,7 @@ public class LookupCommand {
}
c++;
if (argAction.contains(4) && argAction.contains(11)) {
if (LookupActions.isInventoryLookup(argAction)) {
if (ruser.startsWith("#")) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_USERNAME, ruser));
return;
@@ -531,13 +533,13 @@ public class LookupCommand {
}
}
if (rollbackusers.size() == 1 && rollbackusers.contains("#global") && argAction.contains(9)) {
if (rollbackusers.size() == 1 && rollbackusers.contains("#global") && argAction.contains(LookupActions.USERNAME)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_PARAMETERS, "/co l a:username u:<user>"));
return;
}
if (rollbackusers.contains("#container")) {
if (argAction.contains(6) || argAction.contains(7) || argAction.contains(8) || argAction.contains(9) || argAction.contains(10) || argAction.contains(11)) {
if (argAction.contains(LookupActions.CHAT) || argAction.contains(LookupActions.COMMAND) || argAction.contains(LookupActions.SESSION) || argAction.contains(LookupActions.USERNAME) || argAction.contains(LookupActions.SIGN) || argAction.contains(LookupActions.ITEM)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_USERNAME, "#container"));
return;
}
@@ -600,7 +602,7 @@ public class LookupCommand {
thread.start();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
else {
@@ -7,6 +7,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class NetworkDebugCommand {
protected static void runCommand(CommandSender player, boolean permission, String[] args) {
@@ -19,7 +20,7 @@ public class NetworkDebugCommand {
PluginChannelListener.getInstance().sendTest(player, args.length == 2 ? args[1] : "");
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -31,9 +31,55 @@ import net.coreprotect.utility.Color;
import net.coreprotect.utility.EntityUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.VersionUtils;
import net.coreprotect.utility.ErrorReporter;
public class PurgeCommand extends Consumer {
public static final List<String> PURGE_TABLES = Arrays.asList("sign", "container", "item", "skull", "session", "chat", "command", "entity", "block");
private static String findUnsupportedPurgeArgument(String[] args) {
boolean includeContinuation = false;
for (int i = 1; i < args.length; i++) {
String token = args[i].trim();
if (token.length() == 0) {
continue;
}
String argument = token.toLowerCase(Locale.ROOT);
argument = argument.replaceAll("\\\\", "");
argument = argument.replaceAll("'", "");
if (includeContinuation) {
includeContinuation = argument.endsWith(",");
continue;
}
if (argument.equals("#optimize")) {
continue;
}
if (argument.startsWith("i:") || argument.startsWith("include:") || argument.startsWith("item:") || argument.startsWith("items:") || argument.startsWith("b:") || argument.startsWith("block:") || argument.startsWith("blocks:")) {
String includeValues = argument.replaceAll("include:", "").replaceAll("i:", "").replaceAll("items:", "").replaceAll("item:", "").replaceAll("blocks:", "").replaceAll("block:", "").replaceAll("b:", "");
includeContinuation = includeValues.length() == 0 || includeValues.endsWith(",");
continue;
}
if (argument.startsWith("t:") || argument.startsWith("time:")) {
continue;
}
if (argument.startsWith("r:") || argument.startsWith("radius:")) {
continue;
}
if (argument.contains(":")) {
return token;
}
}
return null;
}
protected static void runCommand(final CommandSender player, boolean permission, String[] args) {
int resultc = args.length;
Location location = CommandParser.parseLocation(player, args);
@@ -68,6 +114,12 @@ public class PurgeCommand extends Consumer {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_PARAMETERS, "/co purge t:<time>"));
return;
}
String unsupportedArgument = findUnsupportedPurgeArgument(args);
if (unsupportedArgument != null) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_PARAMETER, unsupportedArgument));
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_PARAMETERS, "/co help purge"));
return;
}
if (endTime <= 0) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_PARAMETERS, "/co purge t:<time>"));
return;
@@ -143,6 +195,18 @@ public class PurgeCommand extends Consumer {
targetName = ((EntityType) restrictTarget).name().toLowerCase(Locale.ROOT);
entity = true;
}
else if (restrictTarget instanceof String) {
int blockId = MaterialUtils.getBlockId((String) restrictTarget, false);
if (includeListMaterial.length() == 0) {
includeListMaterial = includeListMaterial.append(blockId);
}
else {
includeListMaterial.append(",").append(blockId);
}
targetName = ((String) restrictTarget).toLowerCase(Locale.ROOT);
hasBlock = true;
}
if (restrictCount == 0) {
restrict = restrict.append("" + targetName + "");
@@ -253,14 +317,13 @@ public class PurgeCommand extends Consumer {
preparedStmt.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
Database.createDatabaseTables(purgePrefix, false, null, Config.getGlobal().MYSQL, true);
}
List<String> purgeTables = Arrays.asList("sign", "container", "item", "skull", "session", "chat", "command", "entity", "block");
List<String> worldTables = Arrays.asList("sign", "container", "item", "session", "chat", "command", "block");
List<String> restrictTables = Arrays.asList("block");
List<String> excludeTables = Arrays.asList("database_lock"); // don't insert data into these tables
@@ -289,7 +352,7 @@ public class PurgeCommand extends Consumer {
try {
boolean purge = true;
String timeLimit = "";
if (purgeTables.contains(table)) {
if (PURGE_TABLES.contains(table)) {
String blockRestriction = "(";
if (hasBlockRestriction && restrictTables.contains(table)) {
blockRestriction = "type NOT IN(" + includeBlockFinal + ") OR (type IN(" + includeBlockFinal + ") AND ";
@@ -312,7 +375,7 @@ public class PurgeCommand extends Consumer {
}
catch (Exception e) {
error = true;
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -327,7 +390,7 @@ public class PurgeCommand extends Consumer {
preparedStmt.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
try {
@@ -337,7 +400,7 @@ public class PurgeCommand extends Consumer {
preparedStmt.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
try {
@@ -348,13 +411,13 @@ public class PurgeCommand extends Consumer {
preparedStmt.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
abort = true;
break;
}
try {
boolean purge = purgeTables.contains(table);
boolean purge = PURGE_TABLES.contains(table);
String blockRestriction = "";
if (hasBlockRestriction && restrictTables.contains(table)) {
@@ -380,11 +443,11 @@ public class PurgeCommand extends Consumer {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
if (purgeTables.contains(table)) {
if (PURGE_TABLES.contains(table)) {
int oldCount = 0;
try {
query = "SELECT COUNT(*) as count FROM " + ConfigHandler.prefix + table + " LIMIT 0, 1";
@@ -397,7 +460,7 @@ public class PurgeCommand extends Consumer {
preparedStmt.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
int new_count = 0;
@@ -412,7 +475,7 @@ public class PurgeCommand extends Consumer {
preparedStmt.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
removed = removed + (oldCount - new_count);
@@ -421,7 +484,7 @@ public class PurgeCommand extends Consumer {
if (Config.getGlobal().MYSQL) {
try {
boolean purge = purgeTables.contains(table);
boolean purge = PURGE_TABLES.contains(table);
String blockRestriction = "";
if (hasBlockRestriction && restrictTables.contains(table)) {
@@ -453,7 +516,7 @@ public class PurgeCommand extends Consumer {
return;
}
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -493,7 +556,7 @@ public class PurgeCommand extends Consumer {
}
catch (Exception e) {
Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_FAILED));
e.printStackTrace();
ErrorReporter.report(e);
}
Consumer.isPaused = false;
@@ -8,6 +8,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.thread.NetworkHandler;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class ReloadCommand {
protected static void runCommand(final CommandSender player, boolean permission, String[] args) {
@@ -48,7 +49,7 @@ public class ReloadCommand {
networkHandler.start();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
Consumer.isPaused = false;
@@ -27,9 +27,11 @@ 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.model.action.LookupActions;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class RollbackRestoreCommand {
public static void runCommand(CommandSender player, Command command, boolean permission, String[] args, Location argLocation, long forceStart, long forceEnd) {
@@ -61,15 +63,15 @@ public class RollbackRestoreCommand {
boolean hasBlock = false;
boolean hasEntity = false;
for (Object arg : argBlocks) {
if (arg instanceof Material) {
if (arg instanceof Material || arg instanceof String) {
hasBlock = true;
}
else if (arg instanceof EntityType) {
hasEntity = true;
if (argAction.size() == 0) {
argAction.add(3);
argAction.add(LookupActions.ENTITY_KILL);
}
else if (!argAction.contains(3)) {
else if (!argAction.contains(LookupActions.ENTITY_KILL)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_INCLUDE_COMBO));
return;
}
@@ -78,15 +80,15 @@ public class RollbackRestoreCommand {
/* check for invalid block/entity combinations (exclude) */
for (Object arg : argExclude.keySet()) {
if (arg instanceof Material) {
if (arg instanceof Material || arg instanceof String) {
hasBlock = true;
}
else if (arg instanceof EntityType) {
hasEntity = true;
if (argAction.size() == 0) {
argAction.add(3);
argAction.add(LookupActions.ENTITY_KILL);
}
else if (!argAction.contains(3)) {
else if (!argAction.contains(LookupActions.ENTITY_KILL)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_INCLUDE_COMBO));
return;
}
@@ -154,7 +156,7 @@ public class RollbackRestoreCommand {
final int finalAction = a;
int DEFAULT_RADIUS = Config.getGlobal().DEFAULT_RADIUS;
if ((player instanceof Player || player instanceof BlockCommandSender) && argRadius == null && DEFAULT_RADIUS > 0 && !forceglobal && !argAction.contains(11)) {
if ((player instanceof Player || player instanceof BlockCommandSender) && argRadius == null && DEFAULT_RADIUS > 0 && !forceglobal && !argAction.contains(LookupActions.ITEM)) {
Location location = lo;
int xmin = location.getBlockX() - DEFAULT_RADIUS;
int xmax = location.getBlockX() + DEFAULT_RADIUS;
@@ -181,7 +183,7 @@ public class RollbackRestoreCommand {
return;
}
if (argAction.contains(4) && argAction.contains(11)) { // a:inventory
if (LookupActions.isInventoryLookup(argAction)) {
if (argUsers.size() == 0) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_ACTION_USER));
return;
@@ -192,7 +194,7 @@ public class RollbackRestoreCommand {
argExclude.put(Material.FARMLAND, false);
argExcludeUsers.add("#hopper");
}
else if (!argAction.contains(4) && Config.getGlobal().EXCLUDE_TNT && !argExclude.containsKey(Material.TNT) && !argBlocks.contains(Material.TNT)) {
else if (!argAction.contains(LookupActions.CONTAINER) && Config.getGlobal().EXCLUDE_TNT && !argExclude.containsKey(Material.TNT) && !argBlocks.contains(Material.TNT)) {
argExclude.put(Material.TNT, true);
}
@@ -207,17 +209,17 @@ public class RollbackRestoreCommand {
}
}
if (argAction.size() > 0) {
if (argAction.contains(4)) {
if (argAction.contains(LookupActions.CONTAINER)) {
if (argUsers.contains("#global") || (argUsers.size() == 0 && argRadius == null)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.MISSING_ACTION_USER));
return;
}
else if (preview > 0) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.PREVIEW_TRANSACTION, !argAction.contains(11) ? Selector.FIRST : Selector.SECOND));
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.PREVIEW_TRANSACTION, !argAction.contains(LookupActions.ITEM) ? Selector.FIRST : Selector.SECOND));
return;
}
}
if (argAction.contains(8) || (argAction.contains(11) && !argAction.contains(4)) || (!argAction.contains(0) && !argAction.contains(1) && !argAction.contains(3) && !argAction.contains(4))) {
if (argAction.contains(LookupActions.SESSION) || (argAction.contains(LookupActions.ITEM) && !argAction.contains(LookupActions.CONTAINER)) || (!argAction.contains(LookupActions.BLOCK_BREAK) && !argAction.contains(LookupActions.BLOCK_PLACE) && !argAction.contains(LookupActions.ENTITY_KILL) && !argAction.contains(LookupActions.CONTAINER))) {
if (finalAction == 0) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.ACTION_NOT_SUPPORTED));
}
@@ -244,7 +246,7 @@ public class RollbackRestoreCommand {
}
c++;
if (argAction.contains(4) && argAction.contains(11)) {
if (LookupActions.isInventoryLookup(argAction)) {
Player onlineUser = Bukkit.getServer().getPlayer(ruser);
if (onlineUser == null || !onlineUser.isOnline()) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.USER_OFFLINE, ruser));
@@ -258,7 +260,7 @@ public class RollbackRestoreCommand {
int y = 0;
int z = 0;
if (rollbackusers.contains("#container")) {
if (argAction.contains(11)) {
if (argAction.contains(LookupActions.ITEM)) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.INVALID_USERNAME, "#container"));
return;
}
@@ -449,7 +451,7 @@ public class RollbackRestoreCommand {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
if (ConfigHandler.activeRollbacks.get(player2.getName()) != null) {
ConfigHandler.activeRollbacks.remove(player2.getName());
@@ -462,7 +464,7 @@ public class RollbackRestoreCommand {
thread.start();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
else {
@@ -19,6 +19,7 @@ import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.SystemUtils;
import net.coreprotect.utility.VersionUtils;
import net.coreprotect.utility.ErrorReporter;
public class StatusCommand {
private static ConcurrentHashMap<String, Boolean> alert = new ConcurrentHashMap<>();
@@ -104,13 +105,16 @@ public class StatusCommand {
Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_CONSUMER, Color.WHITE, String.format("%,d", consumerCount), (consumerCount == 1 ? Selector.FIRST : Selector.SECOND)));
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
long autoPurgeRowsPurged = ConfigHandler.autoPurgeRowsPurged.get();
Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_AUTO_PURGE, Color.WHITE, String.format("%,d", autoPurgeRowsPurged), (autoPurgeRowsPurged == 1 ? Selector.FIRST : Selector.SECOND)));
try {
String cpuInfo = "";
String cpuInfo = "x" + Runtime.getRuntime().availableProcessors() + " " + Phrase.build(Phrase.CPU_CORES);
if (ConfigHandler.processorInfo != null) {
String modelName = ConfigHandler.processorInfo.getProcessorIdentifier().getName();
String modelName = ConfigHandler.processorInfo.getName();
if (modelName.contains(" CPU")) {
String[] split = modelName.split(" CPU")[0].split(" ");
modelName = split[split.length - 1];
@@ -120,7 +124,7 @@ public class StatusCommand {
modelName = split[split.length - 1];
}
String cpuSpeed = String.valueOf(ConfigHandler.processorInfo.getMaxFreq());
String cpuSpeed = String.valueOf(ConfigHandler.processorInfo.getMaxFrequency());
double speedVal = Long.valueOf(cpuSpeed) / 1000000000.0;
// Fix for Apple Silicon processors reporting 0 GHz
@@ -132,10 +136,9 @@ public class StatusCommand {
}
cpuSpeed = String.format("%.2f", speedVal);
cpuInfo = "x" + Runtime.getRuntime().availableProcessors() + " " + cpuSpeed + "GHz " + modelName + ".";
}
else {
cpuInfo = "x" + Runtime.getRuntime().availableProcessors() + " " + Phrase.build(Phrase.CPU_CORES);
if (speedVal >= 0.01) {
cpuInfo = "x" + Runtime.getRuntime().availableProcessors() + " " + cpuSpeed + "GHz " + modelName + ".";
}
}
int mb = 1024 * 1024;
@@ -150,7 +153,7 @@ public class StatusCommand {
Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_SYSTEM, Color.WHITE, systemInformation));
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
// Functions.sendMessage(player, Color.DARK_AQUA + "Website: " + Color.WHITE + "www.coreprotect.net/updates/");
@@ -173,7 +176,7 @@ public class StatusCommand {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -14,7 +14,6 @@ import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatMessage;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Teleport;
import net.coreprotect.utility.Util;
import net.coreprotect.utility.WorldUtils;
public class TeleportCommand {
@@ -56,6 +55,10 @@ public class TeleportCommand {
World world = location.getWorld();
if (wid > -1) {
world = Bukkit.getServer().getWorld(WorldUtils.getWorldName(wid));
if (world == null) {
Chat.sendMessage(player, new ChatMessage(Phrase.build(Phrase.WORLD_NOT_FOUND, worldName)).build());
return;
}
}
String x = null;
@@ -11,6 +11,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class UndoCommand {
protected static void runCommand(CommandSender user, Command command, boolean permission, String[] args) {
@@ -47,7 +48,7 @@ public class UndoCommand {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -10,6 +10,7 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.World;
import net.coreprotect.worldedit.WorldEditLogger;
import net.coreprotect.utility.ErrorReporter;
public class WorldEditHandler {
@@ -49,7 +50,7 @@ public class WorldEditHandler {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
}
@@ -16,6 +16,7 @@ import net.coreprotect.database.lookup.SignMessageLookup;
import net.coreprotect.language.Phrase;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class BlockLookupThread implements Runnable {
private final CommandSender player;
@@ -82,7 +83,7 @@ public class BlockLookupThread implements Runnable {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
ConfigHandler.lookupThrottle.put(player.getName(), new Object[] { false, System.currentTimeMillis() });
@@ -14,6 +14,7 @@ import net.coreprotect.database.lookup.ChestTransactionLookup;
import net.coreprotect.language.Phrase;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
public class ChestTransactionLookupThread implements Runnable {
private final CommandSender player;
@@ -47,7 +48,7 @@ public class ChestTransactionLookupThread implements Runnable {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
ConfigHandler.lookupThrottle.put(player.getName(), new Object[] { false, System.currentTimeMillis() });
@@ -20,13 +20,15 @@ import com.google.common.base.Strings;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.Lookup;
import net.coreprotect.database.logger.ItemLogger;
import net.coreprotect.database.lookup.PlayerLookup;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelHandshakeListener;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.model.action.SessionActions;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatUtils;
import net.coreprotect.utility.Color;
@@ -35,6 +37,7 @@ import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class StandardLookupThread implements Runnable {
private final CommandSender player;
@@ -113,13 +116,13 @@ public class StandardLookupThread implements Runnable {
Statement statement = connection.createStatement();
String baduser = "";
for (String check : rollbackUsers) {
if ((!check.equals("#global") && !check.equals("#container")) || actions.contains(9)) {
if ((!check.equals("#global") && !check.equals("#container")) || actions.contains(LookupActions.USERNAME)) {
exists = PlayerLookup.playerExists(connection, check);
if (!exists) {
baduser = check;
break;
}
else if (actions.contains(9)) {
else if (actions.contains(LookupActions.USERNAME)) {
if (ConfigHandler.uuidCache.get(check.toLowerCase(Locale.ROOT)) != null) {
String uuid = ConfigHandler.uuidCache.get(check.toLowerCase(Locale.ROOT));
uuidList.add(uuid);
@@ -148,7 +151,7 @@ public class StandardLookupThread implements Runnable {
if (exists) {
List<String> userList = new ArrayList<>();
if (!actions.contains(9)) {
if (!actions.contains(LookupActions.USERNAME)) {
userList = rollbackUsers;
}
@@ -196,7 +199,7 @@ public class StandardLookupThread implements Runnable {
List<String[]> lookupList = Lookup.performPartialLookup(statement, player, uuidList, userList, blockList, excludedBlocks, excludedUsers, actions, finalLocation, radius, rowData, timeStart, timeEnd, (int) pageStart, displayResults, restrict_world, true);
Chat.sendMessage(player, Color.WHITE + "----- " + Color.DARK_AQUA + Phrase.build(Phrase.LOOKUP_HEADER, "CoreProtect" + Color.WHITE + " | " + Color.DARK_AQUA) + Color.WHITE + " -----");
if (actions.contains(6) || actions.contains(7)) { // Chat/command
if (actions.contains(LookupActions.CHAT) || actions.contains(LookupActions.COMMAND)) {
for (String[] data : lookupList) {
String time = data[0];
String dplayer = data[1];
@@ -212,7 +215,7 @@ public class StandardLookupThread implements Runnable {
}
}
}
else if (actions.contains(8)) { // login/logouts
else if (actions.contains(LookupActions.SESSION)) {
for (String[] data : lookupList) {
String time = data[0];
String dplayer = data[1];
@@ -231,13 +234,13 @@ public class StandardLookupThread implements Runnable {
leftPadding = leftPadding + Color.WHITE + Strings.padStart("", (timeLength - 50) / 4, ' ');
}
String tag = (action != 0 ? Color.GREEN + "+" : Color.RED + "-");
Chat.sendComponent(player, timeago + " " + tag + " " + Color.DARK_AQUA + Phrase.build(Phrase.LOOKUP_LOGIN, Color.DARK_AQUA + dplayer + Color.WHITE, (action != 0 ? Selector.FIRST : Selector.SECOND)));
String tag = (action != SessionActions.LOGOUT ? Color.GREEN + "+" : Color.RED + "-");
Chat.sendComponent(player, timeago + " " + tag + " " + Color.DARK_AQUA + Phrase.build(Phrase.LOOKUP_LOGIN, Color.DARK_AQUA + dplayer + Color.WHITE, (action != SessionActions.LOGOUT ? Selector.FIRST : Selector.SECOND)));
Chat.sendComponent(player, Color.WHITE + leftPadding + Color.GREY + "^ " + ChatUtils.getCoordinates(command.getName(), wid, dataX, dataY, dataZ, true, true) + "");
PluginChannelListener.getInstance().sendInfoData(player, Integer.parseInt(time), Phrase.LOOKUP_LOGIN, (action != 0 ? Selector.FIRST : Selector.SECOND), dplayer, -1, dataX, dataY, dataZ, wid);
PluginChannelListener.getInstance().sendInfoData(player, Integer.parseInt(time), Phrase.LOOKUP_LOGIN, (action != SessionActions.LOGOUT ? Selector.FIRST : Selector.SECOND), dplayer, -1, dataX, dataY, dataZ, wid);
}
}
else if (actions.contains(9)) { // username-changes
else if (actions.contains(LookupActions.USERNAME)) {
for (String[] data : lookupList) {
String time = data[0];
String user = ConfigHandler.uuidCacheReversed.get(data[1]);
@@ -247,7 +250,7 @@ public class StandardLookupThread implements Runnable {
PluginChannelListener.getInstance().sendUsernameData(player, Integer.parseInt(time), user, username);
}
}
else if (actions.contains(10)) { // sign messages
else if (actions.contains(LookupActions.SIGN)) {
for (String[] data : lookupList) {
String time = data[0];
String dplayer = data[1];
@@ -271,7 +274,7 @@ public class StandardLookupThread implements Runnable {
PluginChannelListener.getInstance().sendMessageData(player, Integer.parseInt(time), dplayer, message, true, dataX, dataY, dataZ, wid);
}
}
else if (actions.contains(4) && actions.contains(11)) { // inventory transactions
else if (LookupActions.isInventoryLookup(actions)) {
for (String[] data : lookupList) {
String time = data[0];
String dplayer = data[1];
@@ -289,35 +292,36 @@ public class StandardLookupThread implements Runnable {
String dname = StringUtils.nameFilter(blockType.name().toLowerCase(Locale.ROOT), ddata);
byte[] metadata = data[11] == null ? null : data[11].getBytes(StandardCharsets.ISO_8859_1);
String tooltip = ItemUtils.getEnchantments(metadata, dtype, amount);
Integer itemId = ItemUtils.makeGivableItem(ItemUtils.getItemStack(metadata, dtype, amount));
String selector = Selector.FIRST;
String tag = Color.WHITE + "-";
if (daction == 2 || daction == 3) { // LOOKUP_ITEM
selector = (daction != 2 ? Selector.FIRST : Selector.SECOND);
tag = (daction != 2 ? Color.GREEN + "+" : Color.RED + "-");
if (daction == ItemTransactionActions.DROP || daction == ItemTransactionActions.PICKUP) {
selector = (daction != ItemTransactionActions.DROP ? Selector.FIRST : Selector.SECOND);
tag = (daction != ItemTransactionActions.DROP ? Color.GREEN + "+" : Color.RED + "-");
}
else if (daction == 4 || daction == 5) { // LOOKUP_STORAGE
selector = (daction == 4 ? Selector.FIRST : Selector.SECOND);
tag = (daction == 4 ? Color.GREEN + "+" : Color.RED + "-");
else if (daction == ItemTransactionActions.REMOVE_ENDER || daction == ItemTransactionActions.ADD_ENDER) {
selector = (daction == ItemTransactionActions.REMOVE_ENDER ? Selector.FIRST : Selector.SECOND);
tag = (daction == ItemTransactionActions.REMOVE_ENDER ? Color.GREEN + "+" : Color.RED + "-");
}
else if (daction == 6 || daction == 7) { // LOOKUP_PROJECTILE
else if (daction == ItemTransactionActions.THROW || daction == ItemTransactionActions.SHOOT) {
selector = Selector.SECOND;
tag = Color.RED + "-";
}
else if (daction == ItemLogger.ITEM_BREAK || daction == ItemLogger.ITEM_DESTROY || daction == ItemLogger.ITEM_CREATE) {
selector = (daction == ItemLogger.ITEM_CREATE ? Selector.FIRST : Selector.SECOND);
tag = (daction == ItemLogger.ITEM_CREATE ? Color.GREEN + "+" : Color.RED + "-");
else if (daction == ItemTransactionActions.BREAK || daction == ItemTransactionActions.DESTROY || daction == ItemTransactionActions.CREATE) {
selector = (daction == ItemTransactionActions.CREATE ? Selector.FIRST : Selector.SECOND);
tag = (daction == ItemTransactionActions.CREATE ? Color.GREEN + "+" : Color.RED + "-");
}
else if (daction == ItemLogger.ITEM_SELL || daction == ItemLogger.ITEM_BUY) { // LOOKUP_TRADE
selector = (daction == ItemLogger.ITEM_BUY ? Selector.FIRST : Selector.SECOND);
tag = (daction == ItemLogger.ITEM_BUY ? Color.GREEN + "+" : Color.RED + "-");
else if (daction == ItemTransactionActions.SELL || daction == ItemTransactionActions.BUY) { // LOOKUP_TRADE
selector = (daction == ItemTransactionActions.BUY ? Selector.FIRST : Selector.SECOND);
tag = (daction == ItemTransactionActions.BUY ? Color.GREEN + "+" : Color.RED + "-");
}
else { // LOOKUP_CONTAINER
selector = (daction == 0 ? Selector.FIRST : Selector.SECOND);
tag = (daction == 0 ? Color.GREEN + "+" : Color.RED + "-");
selector = (daction == ItemTransactionActions.REMOVE ? Selector.FIRST : Selector.SECOND);
tag = (daction == ItemTransactionActions.REMOVE ? Color.GREEN + "+" : Color.RED + "-");
}
Chat.sendComponent(player, timeago + " " + tag + " " + Phrase.build(Phrase.LOOKUP_CONTAINER, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, "x" + amount, ChatUtils.createTooltip(Color.DARK_AQUA + rbd + dname, tooltip) + Color.WHITE, selector));
Chat.sendComponent(player, timeago + " " + tag + " " + Phrase.build(Phrase.LOOKUP_CONTAINER, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, "x" + amount, ChatUtils.createTooltip(Color.DARK_AQUA + rbd + dname, tooltip) + ChatUtils.filterComponent(player.hasPermission("coreprotect.give"), ChatUtils.createGiveItemComponent(Color.GREY + "(↓)", command.getName(), itemId)) + Color.WHITE, selector));
PluginChannelListener.getInstance().sendData(player, Integer.parseInt(time), Phrase.LOOKUP_CONTAINER, selector, dplayer, dname, amount, dataX, dataY, dataZ, wid, rbd, true, tag.contains("+"));
}
}
@@ -353,7 +357,7 @@ public class StandardLookupThread implements Runnable {
String dname = "";
boolean isPlayer = false;
if (daction == 3 && !actions.contains(11) && amount == -1) {
if (daction == LookupActions.ENTITY_KILL && !actions.contains(LookupActions.ITEM) && amount == -1) {
if (dtype == 0) {
if (ConfigHandler.playerIdCacheReversed.get(ddata) == null) {
UserStatement.loadName(connection, ddata);
@@ -366,10 +370,9 @@ public class StandardLookupThread implements Runnable {
}
}
else {
dname = MaterialUtils.getType(dtype).name().toLowerCase(Locale.ROOT);
dname = StringUtils.nameFilter(dname, ddata);
dname = MaterialUtils.getBlockDisplayName(dtype, ddata);
}
if (dname.length() > 0 && !isPlayer) {
if (dname.length() > 0 && !isPlayer && !dname.contains(":")) {
dname = "minecraft:" + dname.toLowerCase(Locale.ROOT) + "";
}
@@ -384,49 +387,50 @@ public class StandardLookupThread implements Runnable {
Phrase phrase = Phrase.LOOKUP_BLOCK;
String selector = Selector.FIRST;
String action = "a:block";
if (actions.contains(4) || actions.contains(5) || actions.contains(11) || amount > -1) {
if (actions.contains(LookupActions.CONTAINER) || actions.contains(5) || actions.contains(LookupActions.ITEM) || amount > -1) {
byte[] metadata = data[11] == null ? null : data[11].getBytes(StandardCharsets.ISO_8859_1);
String tooltip = ItemUtils.getEnchantments(metadata, dtype, amount);
Integer itemId = ItemUtils.makeGivableItem(ItemUtils.getItemStack(metadata, dtype, amount));
if (daction == 2 || daction == 3) {
if (daction == ItemTransactionActions.DROP || daction == ItemTransactionActions.PICKUP) {
phrase = Phrase.LOOKUP_ITEM; // {picked up|dropped}
selector = (daction != 2 ? Selector.FIRST : Selector.SECOND);
tag = (daction != 2 ? Color.GREEN + "+" : Color.RED + "-");
selector = (daction != ItemTransactionActions.DROP ? Selector.FIRST : Selector.SECOND);
tag = (daction != ItemTransactionActions.DROP ? Color.GREEN + "+" : Color.RED + "-");
action = "a:item";
}
else if (daction == 4 || daction == 5) {
else if (daction == ItemTransactionActions.REMOVE_ENDER || daction == ItemTransactionActions.ADD_ENDER) {
phrase = Phrase.LOOKUP_STORAGE; // {deposited|withdrew}
selector = (daction != 4 ? Selector.FIRST : Selector.SECOND);
tag = (daction != 4 ? Color.RED + "-" : Color.GREEN + "+");
selector = (daction != ItemTransactionActions.REMOVE_ENDER ? Selector.FIRST : Selector.SECOND);
tag = (daction != ItemTransactionActions.REMOVE_ENDER ? Color.RED + "-" : Color.GREEN + "+");
action = "a:item";
}
else if (daction == 6 || daction == 7) {
else if (daction == ItemTransactionActions.THROW || daction == ItemTransactionActions.SHOOT) {
phrase = Phrase.LOOKUP_PROJECTILE; // {threw|shot}
selector = (daction != 7 ? Selector.FIRST : Selector.SECOND);
selector = (daction != ItemTransactionActions.SHOOT ? Selector.FIRST : Selector.SECOND);
tag = Color.RED + "-";
action = "a:item";
}
else {
phrase = Phrase.LOOKUP_CONTAINER; // {added|removed}
selector = (daction != 0 ? Selector.FIRST : Selector.SECOND);
tag = (daction != 0 ? Color.GREEN + "+" : Color.RED + "-");
selector = (daction != ItemTransactionActions.REMOVE ? Selector.FIRST : Selector.SECOND);
tag = (daction != ItemTransactionActions.REMOVE ? Color.GREEN + "+" : Color.RED + "-");
action = "a:container";
}
Chat.sendComponent(player, timeago + " " + tag + " " + Phrase.build(phrase, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, "x" + amount, ChatUtils.createTooltip(Color.DARK_AQUA + rbd + dname, tooltip) + Color.WHITE, selector));
Chat.sendComponent(player, timeago + " " + tag + " " + Phrase.build(phrase, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, "x" + amount, ChatUtils.createTooltip(Color.DARK_AQUA + rbd + dname, tooltip) + ChatUtils.filterComponent(player.hasPermission("coreprotect.give"), ChatUtils.createGiveItemComponent(Color.GREY + "(↓)", command.getName(), itemId)) + Color.WHITE, selector));
PluginChannelListener.getInstance().sendData(player, Integer.parseInt(time), phrase, selector, dplayer, dname, (tag.contains("+") ? 1 : -1), dataX, dataY, dataZ, wid, rbd, action.contains("container"), tag.contains("+"));
}
else {
if (daction == 2 || daction == 3) {
if (daction == LookupActions.INTERACTION || daction == LookupActions.ENTITY_KILL) {
phrase = Phrase.LOOKUP_INTERACTION; // {clicked|killed}
selector = (daction != 3 ? Selector.FIRST : Selector.SECOND);
tag = (daction != 3 ? Color.WHITE + "-" : Color.RED + "-");
action = (daction == 2 ? "a:click" : "a:kill");
selector = (daction != LookupActions.ENTITY_KILL ? Selector.FIRST : Selector.SECOND);
tag = (daction != LookupActions.ENTITY_KILL ? Color.WHITE + "-" : Color.RED + "-");
action = (daction == LookupActions.INTERACTION ? "a:click" : "a:kill");
}
else {
phrase = Phrase.LOOKUP_BLOCK; // {placed|broke}
selector = (daction != 0 ? Selector.FIRST : Selector.SECOND);
tag = (daction != 0 ? Color.GREEN + "+" : Color.RED + "-");
selector = (daction != LookupActions.BLOCK_BREAK ? Selector.FIRST : Selector.SECOND);
tag = (daction != LookupActions.BLOCK_BREAK ? Color.GREEN + "+" : Color.RED + "-");
}
Chat.sendComponent(player, timeago + " " + tag + " " + Phrase.build(phrase, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, Color.DARK_AQUA + rbd + dname + Color.WHITE, selector));
@@ -439,7 +443,7 @@ public class StandardLookupThread implements Runnable {
}
if (rows > displayResults) {
int total_pages = (int) Math.ceil(rows / (displayResults + 0.0));
if (actions.contains(6) || actions.contains(7) || actions.contains(9) || (actions.contains(4) && actions.contains(11))) {
if (actions.contains(LookupActions.CHAT) || actions.contains(LookupActions.COMMAND) || actions.contains(LookupActions.USERNAME) || LookupActions.isInventoryLookup(actions)) {
Chat.sendMessage(player, "-----");
}
Chat.sendComponent(player, ChatUtils.getPageNavigation(command.getName(), page, total_pages));
@@ -462,7 +466,7 @@ public class StandardLookupThread implements Runnable {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
ConfigHandler.lookupThrottle.put(player.getName(), new Object[] { false, System.currentTimeMillis() });
@@ -4,6 +4,10 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.model.action.SessionActions;
import net.coreprotect.model.item.ItemTransactionActions;
/**
* Parser for action-related command arguments
*/
@@ -53,79 +57,79 @@ public class ActionParser {
argument = argument.replaceFirst("#", "");
}
if (argument.equals("broke") || argument.equals("break") || argument.equals("remove") || argument.equals("destroy") || argument.equals("block-break") || argument.equals("block-remove") || argument.equals("-block") || argument.equals("-blocks") || argument.equals("block-")) {
result.add(0);
result.add(LookupActions.BLOCK_BREAK);
}
else if (argument.equals("placed") || argument.equals("place") || argument.equals("block-place") || argument.equals("+block") || argument.equals("+blocks") || argument.equals("block+")) {
result.add(1);
result.add(LookupActions.BLOCK_PLACE);
}
else if (argument.equals("block") || argument.equals("blocks") || argument.equals("block-change") || argument.equals("change") || argument.equals("changes")) {
result.add(0);
result.add(1);
result.add(LookupActions.BLOCK_BREAK);
result.add(LookupActions.BLOCK_PLACE);
}
else if (argument.equals("click") || argument.equals("clicks") || argument.equals("interact") || argument.equals("interaction") || argument.equals("player-interact") || argument.equals("player-interaction") || argument.equals("player-click")) {
result.add(2);
result.add(LookupActions.INTERACTION);
}
else if (argument.equals("death") || argument.equals("deaths") || argument.equals("entity-death") || argument.equals("entity-deaths") || argument.equals("kill") || argument.equals("kills") || argument.equals("entity-kill") || argument.equals("entity-kills")) {
result.add(3);
result.add(LookupActions.ENTITY_KILL);
}
else if (argument.equals("container") || argument.equals("container-change") || argument.equals("containers") || argument.equals("chest") || argument.equals("transaction") || argument.equals("transactions")) {
result.add(4);
result.add(LookupActions.CONTAINER);
}
else if (argument.equals("-container") || argument.equals("container-") || argument.equals("remove-container")) {
result.add(4);
result.add(0);
result.add(LookupActions.CONTAINER);
result.add(ItemTransactionActions.REMOVE);
}
else if (argument.equals("+container") || argument.equals("container+") || argument.equals("container-add") || argument.equals("add-container")) {
result.add(4);
result.add(1);
result.add(LookupActions.CONTAINER);
result.add(ItemTransactionActions.ADD);
}
else if (argument.equals("chat") || argument.equals("chats")) {
result.add(6);
result.add(LookupActions.CHAT);
}
else if (argument.equals("command") || argument.equals("commands")) {
result.add(7);
result.add(LookupActions.COMMAND);
}
else if (argument.equals("logins") || argument.equals("login") || argument.equals("+session") || argument.equals("+sessions") || argument.equals("session+") || argument.equals("+connection") || argument.equals("connection+")) {
result.add(8);
result.add(1);
result.add(LookupActions.SESSION);
result.add(SessionActions.LOGIN);
}
else if (argument.equals("logout") || argument.equals("logouts") || argument.equals("-session") || argument.equals("-sessions") || argument.equals("session-") || argument.equals("-connection") || argument.equals("connection-")) {
result.add(8);
result.add(0);
result.add(LookupActions.SESSION);
result.add(SessionActions.LOGOUT);
}
else if (argument.equals("session") || argument.equals("sessions") || argument.equals("connection") || argument.equals("connections")) {
result.add(8);
result.add(LookupActions.SESSION);
}
else if (argument.equals("username") || argument.equals("usernames") || argument.equals("user") || argument.equals("users") || argument.equals("name") || argument.equals("names") || argument.equals("uuid") || argument.equals("uuids") || argument.equals("username-change") || argument.equals("username-changes") || argument.equals("name-change") || argument.equals("name-changes")) {
result.add(9);
result.add(LookupActions.USERNAME);
}
else if (argument.equals("sign") || argument.equals("signs")) {
result.add(10);
result.add(LookupActions.SIGN);
}
else if (argument.equals("inv") || argument.equals("inventory") || argument.equals("inventories")) {
result.add(4); // container
result.add(11); // item
result.add(LookupActions.CONTAINER);
result.add(LookupActions.ITEM);
}
else if (argument.equals("-inv") || argument.equals("inv-") || argument.equals("-inventory") || argument.equals("inventory-") || argument.equals("-inventories")) {
result.add(4);
result.add(11);
result.add(1);
result.add(LookupActions.CONTAINER);
result.add(LookupActions.ITEM);
result.add(ItemTransactionActions.ADD);
}
else if (argument.equals("+inv") || argument.equals("inv+") || argument.equals("+inventory") || argument.equals("inventory+") || argument.equals("+inventories")) {
result.add(4);
result.add(11);
result.add(0);
result.add(LookupActions.CONTAINER);
result.add(LookupActions.ITEM);
result.add(ItemTransactionActions.REMOVE);
}
else if (argument.equals("item") || argument.equals("items")) {
result.add(11);
result.add(LookupActions.ITEM);
}
else if (argument.equals("-item") || argument.equals("item-") || argument.equals("-items") || argument.equals("items-") || argument.equals("drop") || argument.equals("drops") || argument.equals("deposit") || argument.equals("deposits") || argument.equals("deposited")) {
result.add(11);
result.add(0);
result.add(LookupActions.ITEM);
result.add(ItemTransactionActions.REMOVE);
}
else if (argument.equals("+item") || argument.equals("item+") || argument.equals("+items") || argument.equals("items+") || argument.equals("pickup") || argument.equals("pickups") || argument.equals("withdraw") || argument.equals("withdraws") || argument.equals("withdrew")) {
result.add(11);
result.add(1);
result.add(LookupActions.ITEM);
result.add(ItemTransactionActions.ADD);
}
else {
result.add(-1);
@@ -0,0 +1,19 @@
package net.coreprotect.command.parser;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GivableItemIdParser {
protected static final Pattern PATTERN = Pattern.compile("#([0-9]+)");
public static Integer parseGivableItemId(String[] inputArguments) {
for (String argument : inputArguments) {
Matcher matcher = PATTERN.matcher(argument);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
}
return null;
}
}
@@ -14,6 +14,8 @@ import org.bukkit.entity.EntityType;
import net.coreprotect.language.Phrase;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.utility.BlockTypeUtils;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.EntityUtils;
@@ -62,9 +64,12 @@ public class MaterialParser {
for (String i3 : i2) {
if (!checkTags(i3, restricted)) {
Material i3_material = MaterialUtils.getType(i3);
if (i3_material != null && (i3_material.isBlock() || argAction.contains(4))) {
if (i3_material != null && (i3_material.isBlock() || argAction.contains(LookupActions.CONTAINER))) {
restricted.add(i3_material);
}
else if (!argAction.contains(LookupActions.CONTAINER) && BlockTypeUtils.hasBlockType(i3)) {
restricted.add(BlockTypeUtils.normalizeKey(i3));
}
else {
EntityType i3_entity = EntityUtils.getEntityType(i3);
if (i3_entity != null) {
@@ -91,9 +96,12 @@ public class MaterialParser {
else {
if (!checkTags(argument, restricted)) {
Material material = MaterialUtils.getType(argument);
if (material != null && (material.isBlock() || argAction.contains(4))) {
if (material != null && (material.isBlock() || argAction.contains(LookupActions.CONTAINER))) {
restricted.add(material);
}
else if (!argAction.contains(LookupActions.CONTAINER) && BlockTypeUtils.hasBlockType(argument)) {
restricted.add(BlockTypeUtils.normalizeKey(argument));
}
else {
EntityType entityType = EntityUtils.getEntityType(argument);
if (entityType != null) {
@@ -154,9 +162,12 @@ public class MaterialParser {
for (String i3 : i2) {
if (!checkTags(i3, excluded)) {
Material i3_material = MaterialUtils.getType(i3);
if (i3_material != null && (i3_material.isBlock() || argAction.contains(4))) {
if (i3_material != null && (i3_material.isBlock() || argAction.contains(LookupActions.CONTAINER))) {
excluded.put(i3_material, false);
}
else if (!argAction.contains(LookupActions.CONTAINER) && BlockTypeUtils.hasBlockType(i3)) {
excluded.put(BlockTypeUtils.normalizeKey(i3), false);
}
else {
EntityType i3_entity = EntityUtils.getEntityType(i3);
if (i3_entity != null) {
@@ -178,9 +189,12 @@ public class MaterialParser {
else {
if (!checkTags(argument, excluded)) {
Material iMaterial = MaterialUtils.getType(argument);
if (iMaterial != null && (iMaterial.isBlock() || argAction.contains(4))) {
if (iMaterial != null && (iMaterial.isBlock() || argAction.contains(LookupActions.CONTAINER))) {
excluded.put(iMaterial, false);
}
else if (!argAction.contains(LookupActions.CONTAINER) && BlockTypeUtils.hasBlockType(argument)) {
excluded.put(BlockTypeUtils.normalizeKey(argument), false);
}
else {
EntityType iEntity = EntityUtils.getEntityType(argument);
if (iEntity != null) {
@@ -216,6 +230,9 @@ public class MaterialParser {
tagMap.put("#natural", BlockGroup.NATURAL_BLOCKS);
tagMap.put("#pressure_plate", BlockGroup.PRESSURE_PLATES);
tagMap.put("#shulker_box", BlockGroup.SHULKER_BOXES);
if (!BlockGroup.BUNDLES.isEmpty()) {
tagMap.put("#bundle", BlockGroup.BUNDLES);
}
return tagMap;
}
@@ -296,6 +313,9 @@ public class MaterialParser {
if (material != null) {
isBlock = true;
}
else if (BlockTypeUtils.hasBlockType(argument)) {
isBlock = true;
}
else {
EntityType entityType = EntityUtils.getEntityType(argument);
if (entityType != null) {
@@ -20,6 +20,7 @@ import org.bukkit.World;
import net.coreprotect.CoreProtect;
import net.coreprotect.language.Language;
import net.coreprotect.thread.Scheduler;
import net.coreprotect.utility.VersionUtils;
public class Config extends Language {
@@ -40,16 +41,20 @@ public class Config extends Language {
public String MYSQL_USERNAME;
public String MYSQL_PASSWORD;
public String LANGUAGE;
public String AUTO_PURGE;
public String AUTO_PURGE_TIME;
public boolean ENABLE_SSL;
public boolean DISABLE_WAL;
public boolean HOVER_EVENTS;
public boolean DATABASE_LOCK;
public boolean LOG_CANCELLED_CHAT;
public boolean HOPPER_FILTER_META;
public boolean DUPLICATE_SUPPRESSION;
public boolean EXCLUDE_TNT;
public boolean NETWORK_DEBUG;
public boolean MYSQL;
public boolean CHECK_UPDATES;
public boolean ERROR_REPORTING;
public boolean API_ENABLED;
public boolean VERBOSE;
public boolean ROLLBACK_ITEMS;
@@ -62,6 +67,7 @@ public class Config extends Language {
public boolean PISTONS;
public boolean BLOCK_BURN;
public boolean BLOCK_IGNITE;
public boolean FIRE_EXTINGUISH;
public boolean EXPLOSIONS;
public boolean ENTITY_CHANGE;
public boolean ENTITY_KILLS;
@@ -102,7 +108,9 @@ public class Config extends Language {
DEFAULT_VALUES.put("mysql-username", "root");
DEFAULT_VALUES.put("mysql-password", "");
DEFAULT_VALUES.put("language", "en");
DEFAULT_VALUES.put("auto-purge", "false");
DEFAULT_VALUES.put("check-updates", "true");
DEFAULT_VALUES.put("error-reporting", "true");
DEFAULT_VALUES.put("api-enabled", "true");
DEFAULT_VALUES.put("verbose", "true");
DEFAULT_VALUES.put("default-radius", "10");
@@ -117,6 +125,7 @@ public class Config extends Language {
DEFAULT_VALUES.put("pistons", "true");
DEFAULT_VALUES.put("block-burn", "true");
DEFAULT_VALUES.put("block-ignite", "true");
DEFAULT_VALUES.put("fire-extinguish", "false");
DEFAULT_VALUES.put("explosions", "true");
DEFAULT_VALUES.put("entity-change", "true");
DEFAULT_VALUES.put("entity-kills", "true");
@@ -145,7 +154,9 @@ public class Config extends Language {
HEADERS.put("donation-key", new String[] { "# CoreProtect is donationware. Obtain a donation key from coreprotect.net/donate/" });
HEADERS.put("use-mysql", new String[] { "# MySQL is optional and not required.", "# If you prefer to use MySQL, enable the following and fill out the fields." });
HEADERS.put("language", new String[] { "# If modified, will automatically attempt to translate languages phrases.", "# List of language codes: https://coreprotect.net/languages/" });
HEADERS.put("auto-purge", new String[] { "# Automatically purge data older than the configured time.", "# Examples: 30d, 12w, 6mo. Set to false to disable." });
HEADERS.put("check-updates", new String[] { "# If enabled, CoreProtect will check for updates when your server starts up.", "# If an update is available, you'll be notified via your server console.", });
HEADERS.put("error-reporting", new String[] { "# Automatically sends errors to the plugin author." });
HEADERS.put("api-enabled", new String[] { "# If enabled, other plugins will be able to utilize the CoreProtect API.", });
HEADERS.put("verbose", new String[] { "# If enabled, extra data is displayed during rollbacks and restores.", "# Can be manually triggered by adding \"#verbose\" to your rollback command." });
HEADERS.put("default-radius", new String[] { "# If no radius is specified in a rollback or restore, this value will be", "# used as the radius. Set to \"0\" to disable automatically adding a radius." });
@@ -160,6 +171,7 @@ public class Config extends Language {
HEADERS.put("pistons", new String[] { "# Properly track blocks moved by pistons." });
HEADERS.put("block-burn", new String[] { "# Logs blocks that burn up in a fire." });
HEADERS.put("block-ignite", new String[] { "# Logs when a block naturally ignites, such as from fire spreading." });
HEADERS.put("fire-extinguish", new String[] { "# Logs when fire naturally extinguishes." });
HEADERS.put("explosions", new String[] { "# Logs explosions, such as TNT and Creepers." });
HEADERS.put("entity-change", new String[] { "# Track when an entity changes a block, such as an Enderman destroying blocks." });
HEADERS.put("entity-kills", new String[] { "# Logs killed entities, such as killed cows and enderman." });
@@ -193,6 +205,7 @@ public class Config extends Language {
this.DATABASE_LOCK = this.getBoolean("database-lock", true);
this.LOG_CANCELLED_CHAT = this.getBoolean("log-cancelled-chat", true);
this.HOPPER_FILTER_META = this.getBoolean("hopper-filter-meta", false);
this.DUPLICATE_SUPPRESSION = this.getBoolean("duplicate-suppression", true);
this.EXCLUDE_TNT = this.getBoolean("exclude-tnt", false);
this.NETWORK_DEBUG = this.getBoolean("network-debug", false);
this.UNKNOWN_LOGGING = this.getBoolean("unknown-logging", false);
@@ -206,7 +219,10 @@ public class Config extends Language {
this.MYSQL_USERNAME = this.getString("mysql-username");
this.MYSQL_PASSWORD = this.getString("mysql-password");
this.LANGUAGE = this.getString("language");
this.AUTO_PURGE = this.getString("auto-purge");
this.AUTO_PURGE_TIME = this.getString("auto-purge-time");
this.CHECK_UPDATES = this.getBoolean("check-updates");
this.ERROR_REPORTING = this.getBoolean("error-reporting");
this.API_ENABLED = this.getBoolean("api-enabled");
this.VERBOSE = this.getBoolean("verbose");
this.DEFAULT_RADIUS = this.getInt("default-radius");
@@ -221,6 +237,7 @@ public class Config extends Language {
this.PISTONS = this.getBoolean("pistons");
this.BLOCK_BURN = this.getBoolean("block-burn");
this.BLOCK_IGNITE = this.getBoolean("block-ignite");
this.FIRE_EXTINGUISH = this.getBoolean("fire-extinguish");
this.EXPLOSIONS = this.getBoolean("explosions");
this.ENTITY_CHANGE = this.getBoolean("entity-change");
this.ENTITY_KILLS = this.getBoolean("entity-kills");
@@ -463,6 +480,9 @@ public class Config extends Language {
if (configuredValue != null) {
continue;
}
if (key.equals("auto-purge") && VersionUtils.isCommunityEdition()) {
continue;
}
final String[] header = HEADERS.get(key);
@@ -26,6 +26,7 @@ import java.util.TreeMap;
import net.coreprotect.CoreProtect;
import net.coreprotect.language.Language;
import net.coreprotect.language.Phrase;
import net.coreprotect.utility.ErrorReporter;
public class ConfigFile extends Config {
@@ -201,7 +202,7 @@ public class ConfigFile extends Config {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -222,7 +223,7 @@ public class ConfigFile extends Config {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -8,10 +8,13 @@ import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -35,9 +38,9 @@ import net.coreprotect.patch.Patch;
import net.coreprotect.spigot.SpigotAdapter;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.ErrorReporter;
import net.coreprotect.utility.SystemUtils;
import net.coreprotect.utility.VersionUtils;
import oshi.hardware.CentralProcessor;
public class ConfigHandler extends Queue {
@@ -51,9 +54,9 @@ public class ConfigHandler extends Queue {
public static final String EDITION_NAME = VersionUtils.getPluginName();
public static final String COMMUNITY_EDITION = "Community Edition";
public static final String JAVA_VERSION = "11.0";
public static final String MINECRAFT_VERSION = "1.16";
public static final String PATCH_VERSION = "23.2";
public static final String LATEST_VERSION = "26.1";
public static final String MINECRAFT_VERSION = "1.16.5";
public static final String PATCH_VERSION = "24.0";
public static final String LATEST_VERSION = "26.2";
public static String path = "plugins/CoreProtect/";
public static String sqlite = "database.db";
public static String host = "127.0.0.1";
@@ -65,8 +68,12 @@ public class ConfigHandler extends Queue {
public static String prefixConfig = "co_";
public static int maximumPoolSize = 10;
public static final String BLACKLIST_COMMENT_SEPARATOR = ";";
public static final String BLACKLIST_FILTER_SEPARATOR = "@";
public static final String BLACKLIST_FILENAME = "blacklist.txt";
public static HikariDataSource hikariDataSource = null;
public static final CentralProcessor processorInfo = SystemUtils.getProcessorInfo();
public static final SystemUtils.ProcessorInfo processorInfo = SystemUtils.getProcessorInfo();
public static final boolean isSpigot = VersionUtils.isSpigot();
public static final boolean isPaper = VersionUtils.isPaper();
public static final boolean isFolia = VersionUtils.isFolia();
@@ -82,6 +89,7 @@ public class ConfigHandler extends Queue {
public static volatile int blockdataId = 0;
public static volatile int entityId = 0;
public static volatile int artId = 0;
public static final AtomicLong autoPurgeRowsPurged = new AtomicLong(0);
private static <K, V> Map<K, V> syncMap() {
return Collections.synchronizedMap(new HashMap<>());
@@ -100,10 +108,11 @@ public class ConfigHandler extends Queue {
public static Map<String, int[]> rollbackHash = syncMap();
public static Map<String, Boolean> inspecting = syncMap();
public static Map<String, Boolean> blacklist = syncMap();
public static Map<String, HashSet<String>> FilteredBlacklist = syncMap();
public static Map<String, Integer> loggingChest = syncMap();
public static Map<String, Integer> loggingItem = syncMap();
public static ConcurrentHashMap<String, List<Object>> transactingChest = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, List<ItemStack[]>> oldContainer = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, Set<String>> oldContainerViewers = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, List<ItemStack>> itemsPickup = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, List<ItemStack>> itemsDrop = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, List<ItemStack>> itemsThrown = new ConcurrentHashMap<>();
@@ -152,27 +161,73 @@ public class ConfigHandler extends Queue {
}
}
public static void addOldContainerViewer(String locationSuffix, String loggingId) {
ConfigHandler.oldContainerViewers.compute(locationSuffix, (key, viewers) -> {
if (viewers == null) {
viewers = ConcurrentHashMap.newKeySet();
}
viewers.add(loggingId);
return viewers;
});
}
public static void removeOldContainerViewer(String locationSuffix, String loggingId) {
ConfigHandler.oldContainerViewers.computeIfPresent(locationSuffix, (key, viewers) -> {
viewers.remove(loggingId);
return viewers.isEmpty() ? null : viewers;
});
}
public static boolean isBlacklisted(String user) {
return ConfigHandler.blacklist.containsKey(user.toLowerCase(Locale.ROOT));
}
public static boolean isBlacklisted(String user, String object) {
if (ConfigHandler.blacklist.containsKey(object) || ConfigHandler.blacklist.containsKey(user.toLowerCase(Locale.ROOT))) {
return true;
}
return isFilterBlacklisted(user, object);
}
public static boolean isFilterBlacklisted(String user, String object) {
HashSet<String> blUserSet = FilteredBlacklist.get(object);
if (blUserSet == null) {
return false;
}
return blUserSet.contains(user.toLowerCase(Locale.ROOT));
}
private static void loadBlacklist() {
try {
ConfigHandler.blacklist.clear();
String blacklist = ConfigHandler.path + "blacklist.txt";
boolean exists = (new File(blacklist)).exists();
if (exists) {
RandomAccessFile blfile = new RandomAccessFile(blacklist, "rw");
long blc = blfile.length();
if (blc > 0) {
while (blfile.getFilePointer() < blfile.length()) {
String blacklistUser = blfile.readLine().replaceAll(" ", "").toLowerCase(Locale.ROOT);
if (blacklistUser.length() > 0) {
ConfigHandler.blacklist.put(blacklistUser, true);
}
ConfigHandler.FilteredBlacklist.clear();
File file = new File(ConfigHandler.path, BLACKLIST_FILENAME);
if (!file.exists()) {
return;
}
try (RandomAccessFile blfile = new RandomAccessFile(file, "r")) {
if (blfile.length() == 0) {
return;
}
String blLine;
while ((blLine = blfile.readLine()) != null) {
blLine = blLine.replace(" ", "").toLowerCase(Locale.ROOT).split(BLACKLIST_COMMENT_SEPARATOR)[0];
if (blLine.isEmpty()) {
continue;
}
String[] blSplit = blLine.split(BLACKLIST_FILTER_SEPARATOR);
if (blSplit.length == 1) {
ConfigHandler.blacklist.put(blLine, true);
}
else {
ConfigHandler.FilteredBlacklist.computeIfAbsent(blSplit[0], k -> new HashSet<>()).add(blSplit[1]);
}
}
blfile.close();
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -199,7 +254,7 @@ public class ConfigHandler extends Queue {
ConfigHandler.loadBlacklist(); // Load the blacklist file if it exists.
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -234,7 +289,7 @@ public class ConfigHandler extends Queue {
Class.forName("org.sqlite.JDBC");
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
else {
@@ -294,7 +349,7 @@ public class ConfigHandler extends Queue {
rs.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -318,7 +373,7 @@ public class ConfigHandler extends Queue {
rs.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -342,7 +397,7 @@ public class ConfigHandler extends Queue {
rs.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -366,7 +421,7 @@ public class ConfigHandler extends Queue {
rs.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -425,7 +480,7 @@ public class ConfigHandler extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return -1;
@@ -463,7 +518,7 @@ public class ConfigHandler extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -502,7 +557,7 @@ public class ConfigHandler extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return true;
@@ -523,7 +578,7 @@ public class ConfigHandler extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
try (Connection connection = Database.getConnection(true, 0)) {
@@ -558,7 +613,7 @@ public class ConfigHandler extends Queue {
return validVersion && databaseLock;
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return false;
@@ -570,7 +625,7 @@ public class ConfigHandler extends Queue {
ListenerHandler.unregisterNetworking(); // Unregister channels for networking API
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -14,6 +14,7 @@ import org.bukkit.inventory.ItemStack;
import net.coreprotect.CoreProtect;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.utility.ErrorReporter;
public class Consumer extends Process implements Runnable, Thread.UncaughtExceptionHandler {
@@ -51,7 +52,7 @@ public class Consumer extends Process implements Runnable, Thread.UncaughtExcept
Thread.sleep(30000); // 30 seconds
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -106,7 +107,7 @@ public class Consumer extends Process implements Runnable, Thread.UncaughtExcept
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
pausedSuccess = false;
}
@@ -133,7 +134,7 @@ public class Consumer extends Process implements Runnable, Thread.UncaughtExcept
Process.processConsumer(process_id, lastRun);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
errorDelay();
}
}
@@ -141,7 +142,7 @@ public class Consumer extends Process implements Runnable, Thread.UncaughtExcept
@Override
public void uncaughtException(Thread thread, Throwable e) {
e.printStackTrace();
ErrorReporter.report(e);
Bukkit.getPluginManager().disablePlugin(CoreProtect.getInstance());
}
@@ -2,6 +2,7 @@ package net.coreprotect.consumer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -9,8 +10,10 @@ import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.Bisected.Half;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Bed;
import org.bukkit.block.data.type.Bed.Part;
import org.bukkit.entity.EntityType;
@@ -25,8 +28,11 @@ import net.coreprotect.consumer.process.Process;
import net.coreprotect.listener.block.BlockUtil;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.thread.Scheduler;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.EntityUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class Queue {
@@ -68,6 +74,10 @@ public class Queue {
Consumer.consumer_id.put(currentConsumer, new Integer[] { Consumer.consumer_id.get(currentConsumer)[0], 0 });
}
private static Location getBlockLocation(Location location) {
return new Location(location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
protected static void queueAdvancedBreak(String user, BlockState block, Material type, String blockData, int data, Material breakType, int blockNumber) {
int currentConsumer = Consumer.currentConsumer;
int consumerId = Consumer.newConsumerId(currentConsumer);
@@ -89,12 +99,12 @@ public class Queue {
protected static void queueBlockBreakValidate(final String user, final Block block, final BlockState blockState, final Material type, final String blockData, final int extraData, int ticks) {
Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> {
try {
if (!block.getType().equals(type)) {
if (!Objects.equals(block.getType(), type)) {
queueBlockBreak(user, blockState, type, blockData, null, extraData, 0);
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}, block.getLocation(), ticks);
}
@@ -104,7 +114,7 @@ public class Queue {
CreatureSpawner mobSpawner = (CreatureSpawner) block;
extraData = EntityUtils.getSpawnerType(mobSpawner.getSpawnedType());
}
else if (type == Material.IRON_DOOR || BlockGroup.DOORS.contains(type) || type.equals(Material.SUNFLOWER) || type.equals(Material.LILAC) || type.equals(Material.TALL_GRASS) || type.equals(Material.LARGE_FERN) || type.equals(Material.ROSE_BUSH) || type.equals(Material.PEONY)) { // Double plant
else if (type != null && (type == Material.IRON_DOOR || BlockGroup.DOORS.contains(type) || type.equals(Material.SUNFLOWER) || type.equals(Material.LILAC) || type.equals(Material.TALL_GRASS) || type.equals(Material.LARGE_FERN) || type.equals(Material.ROSE_BUSH) || type.equals(Material.PEONY))) { // Double plant
if (block.getBlockData() instanceof Bisected) {
if (((Bisected) block.getBlockData()).getHalf().equals(Half.TOP)) {
if (blockNumber == 5) {
@@ -122,7 +132,7 @@ public class Queue {
}
}
}
else if (type.name().endsWith("_BED") && block.getBlockData() instanceof Bed) {
else if (type != null && type.name().endsWith("_BED") && block.getBlockData() instanceof Bed) {
if (((Bed) block.getBlockData()).getPart().equals(Part.HEAD)) {
return;
}
@@ -151,7 +161,7 @@ public class Queue {
replaceType = blockReplaced.getType();
replaceData = 0;
if ((replaceType == Material.IRON_DOOR || BlockGroup.DOORS.contains(replaceType) || replaceType.equals(Material.SUNFLOWER) || replaceType.equals(Material.LILAC) || replaceType.equals(Material.TALL_GRASS) || replaceType.equals(Material.LARGE_FERN) || replaceType.equals(Material.ROSE_BUSH) || replaceType.equals(Material.PEONY)) && replaceData >= 8) { // Double plant top half
if (replaceType != null && (replaceType == Material.IRON_DOOR || BlockGroup.DOORS.contains(replaceType) || replaceType.equals(Material.SUNFLOWER) || replaceType.equals(Material.LILAC) || replaceType.equals(Material.TALL_GRASS) || replaceType.equals(Material.LARGE_FERN) || replaceType.equals(Material.ROSE_BUSH) || replaceType.equals(Material.PEONY)) && replaceData >= 8) { // Double plant top half
BlockState blockBelow = blockReplaced.getWorld().getBlockAt(blockReplaced.getX(), blockReplaced.getY() - 1, blockReplaced.getZ()).getState();
Material belowType = blockBelow.getType();
Queue.queueBlockBreak(user, blockBelow, belowType, blockBelow.getBlockData().getAsString(), 0);
@@ -185,44 +195,64 @@ public class Queue {
queueBlockPlace(user, placed.getBlock().getState(), type, replaced, null, -1, 0, blockData);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}, placed, ticks);
}
protected static void queueBlockPlaceValidate(final String user, final BlockState blockLocation, final Block block, final BlockState blockReplaced, final Material forceT, final int forceD, final int forceData, final String blockData, int ticks) {
queueBlockPlaceValidate(user, blockLocation, block, blockReplaced, forceT, forceD, forceData, blockData, ticks, false);
}
protected static void queueBlockPlaceValidate(final String user, final BlockState blockLocation, final Block block, final BlockState blockReplaced, final Material forceT, final int forceD, final int forceData, final String blockData, int ticks, boolean cacheLookup) {
Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> {
try {
Material blockType = block.getType();
if (blockType.equals(forceT)) {
BlockState replacedBlock = blockReplaced;
boolean placed = Objects.equals(blockType, forceT);
if (!placed && forceT == Material.WATER) {
BlockData currentBlockData = block.getBlockData();
if (currentBlockData instanceof Waterlogged) {
Waterlogged waterlogged = (Waterlogged) currentBlockData;
if (waterlogged.isWaterlogged()) {
boolean wasWaterlogged = false;
if (blockReplaced != null) {
BlockData replacedBlockData = blockReplaced.getBlockData();
if (replacedBlockData instanceof Waterlogged) {
wasWaterlogged = ((Waterlogged) replacedBlockData).isWaterlogged();
}
}
if (!wasWaterlogged) {
placed = true;
replacedBlock = null;
}
}
}
}
if (placed) {
BlockState blockStateLocation = blockLocation;
if (Config.getConfig(blockLocation.getWorld()).BLOCK_MOVEMENT) {
if (blockType != null && Objects.equals(blockType, forceT) && Config.getConfig(blockLocation.getWorld()).BLOCK_MOVEMENT) {
blockStateLocation = BlockUtil.gravityScan(blockLocation.getLocation(), blockType, user).getState();
}
queueBlockPlace(user, blockStateLocation, blockType, blockReplaced, forceT, forceD, forceData, blockData);
if (cacheLookup) {
Location cacheLocation = blockStateLocation.getLocation();
int worldId = WorldUtils.getWorldId(cacheLocation.getWorld().getName());
int unixTimestamp = (int) (System.currentTimeMillis() / 1000L);
CacheHandler.lookupCache.put(cacheLocation.getBlockX() + "." + cacheLocation.getBlockY() + "." + cacheLocation.getBlockZ() + "." + worldId, new Object[] { unixTimestamp, user, forceT });
}
queueBlockPlace(user, blockStateLocation, blockType, replacedBlock, forceT, forceD, forceData, blockData);
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}, blockLocation.getLocation(), ticks);
}
protected static void queueBlockGravityValidate(final String user, final Location location, final Block block, final Material blockType, int ticks) {
Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> {
try {
Block placementBlock = BlockUtil.gravityScan(location, blockType, user);
if (!block.equals(placementBlock)) {
queueBlockPlace(user, placementBlock.getState(), blockType, null, blockType, -1, 0, null);
}
}
catch (Exception e) {
e.printStackTrace();
}
}, location, ticks);
}
protected static void queueContainerBreak(String user, Location location, Material type, ItemStack[] oldInventory) {
int currentConsumer = Consumer.currentConsumer;
int consumerId = Consumer.newConsumerId(currentConsumer);
@@ -258,7 +288,7 @@ public class Queue {
int consumerId = Consumer.newConsumerId(currentConsumer);
addConsumer(currentConsumer, new Object[] { consumerId, Process.ENTITY_KILL, null, 0, null, 0, 0 });
Consumer.consumerObjectList.get(currentConsumer).put(consumerId, data);
queueStandardData(consumerId, currentConsumer, new String[] { user, null }, new Object[] { location.getBlock().getState(), type, null });
queueStandardData(consumerId, currentConsumer, new String[] { user, null }, new Object[] { getBlockLocation(location), type, null });
}
protected static void queueEntitySpawn(String user, BlockState block, EntityType type, int data) {
@@ -322,7 +352,7 @@ public class Queue {
int currentConsumer = Consumer.currentConsumer;
int consumerId = Consumer.newConsumerId(currentConsumer);
addConsumer(currentConsumer, new Object[] { consumerId, Process.PLAYER_KILL, null, 0, null, 0, 0, null });
queueStandardData(consumerId, currentConsumer, new String[] { user, null }, new Object[] { location.getBlock().getState(), player });
queueStandardData(consumerId, currentConsumer, new String[] { user, null }, new Object[] { getBlockLocation(location), player });
}
protected static void queuePlayerLogin(Player player, int time, int configSessions, int configUsernames) {
@@ -18,11 +18,11 @@ class BlockBreakProcess {
if (object instanceof BlockState) {
BlockState block = (BlockState) object;
List<Object> meta = BlockUtils.processMeta(block);
if (block instanceof Skull) {
if (block instanceof Skull && blockType != null && blockType.equals(block.getType())) {
SkullBreakLogger.log(preparedStmt, preparedStmtSkulls, batchCount, user, block);
}
else {
BlockBreakLogger.log(preparedStmt, batchCount, user, block.getLocation(), MaterialUtils.getBlockId(blockType), blockDataId, meta, block.getBlockData().getAsString(), blockData);
BlockBreakLogger.log(preparedStmt, batchCount, user, block.getLocation(), MaterialUtils.getBlockId(blockType), blockDataId, meta, blockData, blockData);
}
}
}
@@ -17,7 +17,7 @@ class BlockPlaceProcess {
if (object instanceof BlockState) {
BlockState block = (BlockState) object;
List<Object> meta = BlockUtils.processMeta(block);
if (blockType.equals(Material.SKELETON_SKULL) || blockType.equals(Material.SKELETON_WALL_SKULL) || blockType.equals(Material.WITHER_SKELETON_SKULL) || blockType.equals(Material.WITHER_SKELETON_WALL_SKULL) || blockType.equals(Material.ZOMBIE_HEAD) || blockType.equals(Material.ZOMBIE_WALL_HEAD) || blockType.equals(Material.PLAYER_HEAD) || blockType.equals(Material.PLAYER_WALL_HEAD) || blockType.equals(Material.CREEPER_HEAD) || blockType.equals(Material.CREEPER_WALL_HEAD) || blockType.equals(Material.DRAGON_HEAD) || blockType.equals(Material.DRAGON_WALL_HEAD)) {
if (blockType != null && (blockType.equals(Material.SKELETON_SKULL) || blockType.equals(Material.SKELETON_WALL_SKULL) || blockType.equals(Material.WITHER_SKELETON_SKULL) || blockType.equals(Material.WITHER_SKELETON_WALL_SKULL) || blockType.equals(Material.ZOMBIE_HEAD) || blockType.equals(Material.ZOMBIE_WALL_HEAD) || blockType.equals(Material.PLAYER_HEAD) || blockType.equals(Material.PLAYER_WALL_HEAD) || blockType.equals(Material.CREEPER_HEAD) || blockType.equals(Material.CREEPER_WALL_HEAD) || blockType.equals(Material.DRAGON_HEAD) || blockType.equals(Material.DRAGON_WALL_HEAD))) {
SkullPlaceLogger.log(preparedStmt, preparedStmtSkulls, batchCount, user, block, MaterialUtils.getBlockId(replaceType), replaceData);
}
else if (forceData == 1) {
@@ -6,7 +6,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -18,6 +17,7 @@ import org.bukkit.inventory.ItemStack;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.database.logger.ContainerLogger;
import net.coreprotect.utility.HopperTransactionUtils;
class ContainerTransactionProcess {
@@ -25,13 +25,18 @@ class ContainerTransactionProcess {
if (object instanceof Location) {
Location location = (Location) object;
Map<Integer, Object> inventories = Consumer.consumerInventories.get(processId);
if (inventories.get(id) != null) {
Object inventory = inventories.get(id);
String transactingChestId = location.getWorld().getUID().toString() + "." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ();
String loggingChestId = user.toLowerCase(Locale.ROOT) + "." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ();
Object inventory = inventories.remove(id);
if (inventory != null) {
String transactingChestId = HopperTransactionUtils.getTransactionId(location);
String loggingChestIdSuffix = HopperTransactionUtils.getLoggingIdSuffix(location);
String loggingChestId = HopperTransactionUtils.getLoggingId(user, loggingChestIdSuffix);
if (ConfigHandler.loggingChest.get(loggingChestId) != null) {
int current_chest = ConfigHandler.loggingChest.get(loggingChestId);
if (ConfigHandler.oldContainer.get(loggingChestId) == null) {
ConfigHandler.removeOldContainerViewer(loggingChestIdSuffix, loggingChestId);
ConfigHandler.loggingChest.remove(loggingChestId);
ConfigHandler.forceContainer.remove(loggingChestId);
HopperTransactionUtils.removeOwner(transactingChestId, loggingChestId);
return;
}
int force_size = 0;
@@ -43,13 +48,14 @@ class ContainerTransactionProcess {
List<ItemStack[]> old = ConfigHandler.oldContainer.get(loggingChestId);
if (old.size() == 0) {
ConfigHandler.oldContainer.remove(loggingChestId);
ConfigHandler.removeOldContainerViewer(loggingChestIdSuffix, loggingChestId);
ConfigHandler.loggingChest.remove(loggingChestId);
ConfigHandler.transactingChest.remove(transactingChestId);
ConfigHandler.forceContainer.remove(loggingChestId);
HopperTransactionUtils.removeOwner(transactingChestId, loggingChestId);
}
}
else if (loggingChestId.startsWith("#hopper")) {
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()) {
if (force_size == 0 && ConfigHandler.oldContainer.getOrDefault(loggingChestId, Collections.synchronizedList(new ArrayList<>())).size() == 1 && HopperTransactionUtils.pendingDeltaCount(transactingChestId) == 0) {
int loopCount = ConfigHandler.loggingChest.getOrDefault(loggingChestId, 0);
int maxInventorySize = (99 * 54);
try {
@@ -84,7 +90,6 @@ class ContainerTransactionProcess {
}
}
}
inventories.remove(id);
}
}
}
@@ -4,27 +4,45 @@ import java.sql.PreparedStatement;
import java.util.List;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.entity.EntityType;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.database.logger.EntityKillLogger;
import net.coreprotect.utility.EntityUtils;
import net.coreprotect.utility.Util;
class EntityKillProcess {
static void process(PreparedStatement preparedStmt, PreparedStatement preparedStmtEntities, int batchCount, int processId, int id, Object object, String user) {
if (object instanceof Object[]) {
BlockState block = (BlockState) ((Object[]) object)[0];
EntityType type = (EntityType) ((Object[]) object)[1];
Object[] values = (Object[]) object;
if (values.length <= 1 || !isLocationData(values[0]) || !(values[1] instanceof EntityType)) {
return;
}
Location location = getLocation(values[0]);
EntityType type = (EntityType) values[1];
Map<Integer, List<Object>> objectLists = Consumer.consumerObjectList.get(processId);
if (objectLists.get(id) != null) {
if (objectLists != null && objectLists.get(id) != null) {
List<Object> objectList = objectLists.get(id);
int entityId = EntityUtils.getEntityId(type);
EntityKillLogger.log(preparedStmt, preparedStmtEntities, batchCount, user, block, objectList, entityId);
EntityKillLogger.log(preparedStmt, preparedStmtEntities, batchCount, user, location, objectList, entityId);
objectLists.remove(id);
}
}
}
private static boolean isLocationData(Object value) {
return value instanceof Location || value instanceof BlockState;
}
private static Location getLocation(Object value) {
if (value instanceof Location) {
return ((Location) value).clone();
}
BlockState block = (BlockState) value;
return new Location(block.getWorld(), block.getX(), block.getY(), block.getZ());
}
}
@@ -2,6 +2,7 @@ package net.coreprotect.consumer.process;
import java.sql.PreparedStatement;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import net.coreprotect.database.logger.PlayerKillLogger;
@@ -10,9 +11,27 @@ class PlayerKillProcess {
static void process(PreparedStatement preparedStmt, int batchCount, int id, Object object, String user) {
if (object instanceof Object[]) {
BlockState block = (BlockState) ((Object[]) object)[0];
String player = (String) ((Object[]) object)[1];
PlayerKillLogger.log(preparedStmt, batchCount, user, block, player);
Object[] values = (Object[]) object;
if (values.length <= 1 || !isLocationData(values[0]) || !(values[1] instanceof String)) {
return;
}
Location location = getLocation(values[0]);
String player = (String) values[1];
PlayerKillLogger.log(preparedStmt, batchCount, user, location, player);
}
}
private static boolean isLocationData(Object value) {
return value instanceof Location || value instanceof BlockState;
}
private static Location getLocation(Object value) {
if (value instanceof Location) {
return ((Location) value).clone();
}
BlockState block = (BlockState) value;
return new Location(block.getWorld(), block.getX(), block.getY(), block.getZ());
}
}
@@ -9,6 +9,7 @@ import org.bukkit.Location;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.database.logger.PlayerSessionLogger;
import net.coreprotect.database.logger.UsernameLogger;
import net.coreprotect.model.action.SessionActions;
class PlayerLoginProcess {
@@ -20,7 +21,7 @@ class PlayerLoginProcess {
Location location = (Location) object;
UsernameLogger.log(connection, user, uuid, configUsernames, time);
if (configSessions == 1) {
PlayerSessionLogger.log(preparedStmt, batchCount, user, location, time, 1);
PlayerSessionLogger.log(preparedStmt, batchCount, user, location, time, SessionActions.LOGIN);
}
strings.remove(id);
}
@@ -5,13 +5,14 @@ import java.sql.PreparedStatement;
import org.bukkit.Location;
import net.coreprotect.database.logger.PlayerSessionLogger;
import net.coreprotect.model.action.SessionActions;
class PlayerLogoutProcess {
static void process(PreparedStatement preparedStmt, int batchCount, Object object, int time, String user) {
if (object instanceof Location) {
Location location = (Location) object;
PlayerSessionLogger.log(preparedStmt, batchCount, user, location, time, 0);
PlayerSessionLogger.log(preparedStmt, batchCount, user, location, time, SessionActions.LOGOUT);
}
}
}
@@ -15,6 +15,8 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.model.rollback.RollbackUpdateTargets;
import net.coreprotect.utility.ErrorReporter;
public class Process {
@@ -64,7 +66,7 @@ public class Process {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -167,19 +169,19 @@ public class Process {
StructureGrowthProcess.process(statement, preparedStmtBlocks, i, processId, id, user, object, forceData);
break;
case Process.ROLLBACK_UPDATE:
RollbackUpdateProcess.process(statement, processId, id, forceData, 0);
RollbackUpdateProcess.process(statement, processId, id, forceData, RollbackUpdateTargets.BLOCK);
break;
case Process.CONTAINER_ROLLBACK_UPDATE:
RollbackUpdateProcess.process(statement, processId, id, forceData, 1);
RollbackUpdateProcess.process(statement, processId, id, forceData, RollbackUpdateTargets.CONTAINER);
break;
case Process.INVENTORY_ROLLBACK_UPDATE:
RollbackUpdateProcess.process(statement, processId, id, forceData, 2);
RollbackUpdateProcess.process(statement, processId, id, forceData, RollbackUpdateTargets.INVENTORY_ITEM);
break;
case Process.INVENTORY_CONTAINER_ROLLBACK_UPDATE:
RollbackUpdateProcess.process(statement, processId, id, forceData, 3);
RollbackUpdateProcess.process(statement, processId, id, forceData, RollbackUpdateTargets.INVENTORY_CONTAINER);
break;
case Process.BLOCK_INVENTORY_ROLLBACK_UPDATE:
RollbackUpdateProcess.process(statement, processId, id, forceData, 4);
RollbackUpdateProcess.process(statement, processId, id, forceData, RollbackUpdateTargets.BLOCK_INVENTORY);
break;
case Process.WORLD_INSERT:
WorldInsertProcess.process(preparedStmtWorlds, i, statement, object, forceData);
@@ -247,7 +249,7 @@ public class Process {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -280,7 +282,7 @@ public class Process {
consumerData.clear();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
Consumer.consumer_id.put(processId, new Integer[] { 0, 0 });
@@ -306,7 +308,7 @@ public class Process {
Database.commitTransaction(statement, Config.getGlobal().MYSQL);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -1,11 +1,15 @@
package net.coreprotect.consumer.process;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.database.Database;
import net.coreprotect.model.rollback.RollbackUpdateTargets;
import net.coreprotect.utility.MaterialUtils;
class RollbackUpdateProcess {
@@ -14,13 +18,19 @@ class RollbackUpdateProcess {
Map<Integer, List<Object[]>> updateLists = Consumer.consumerObjectArrayList.get(processId);
if (updateLists.get(id) != null) {
List<Object[]> list = updateLists.get(id);
boolean inventoryState = RollbackUpdateTargets.usesInventoryRollbackState(table);
Map<Integer, List<Long>> rowIdsByValue = new HashMap<>();
for (Object[] listRow : list) {
long rowid = (Long) listRow[0];
int rolledBack = (Integer) listRow[9];
if (MaterialUtils.rolledBack(rolledBack, (table == 2 || table == 3 || table == 4)) == action) { // 1 = restore, 0 = rollback
Database.performUpdate(statement, rowid, rolledBack, table);
if (MaterialUtils.rolledBack(rolledBack, inventoryState) == action) { // 1 = restore, 0 = rollback
int toggledValue = MaterialUtils.toggleRolledBack(rolledBack, inventoryState);
rowIdsByValue.computeIfAbsent(toggledValue, key -> new ArrayList<>()).add(rowid);
}
}
for (Entry<Integer, List<Long>> entry : rowIdsByValue.entrySet()) {
Database.performRolledBackUpdate(statement, entry.getKey(), entry.getValue(), table);
}
updateLists.remove(id);
}
}
@@ -12,6 +12,7 @@ import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class BlockLookup {
@@ -48,7 +49,7 @@ public class BlockLookup {
results.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
@@ -83,7 +84,7 @@ public class BlockLookup {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
@@ -111,7 +112,7 @@ public class BlockLookup {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
@@ -30,6 +30,7 @@ import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.ErrorReporter;
public class ContainerRollback extends Rollback {
@@ -147,7 +148,7 @@ public class ContainerRollback extends Rollback {
ConfigHandler.rollbackHash.put(finalUserString, new int[] { itemCount, modifyCount, entityCount, 1, 1 });
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}, location, 0);
@@ -184,7 +185,7 @@ public class ContainerRollback extends Rollback {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -24,10 +25,12 @@ import net.coreprotect.consumer.Queue;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.language.Phrase;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.model.rollback.RollbackUpdateTargets;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.HopperTransactionUtils;
import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.ErrorReporter;
public class Database extends Queue {
@@ -46,6 +49,8 @@ public class Database extends Queue {
public static final int BLOCKDATA = 12;
public static final int ITEM = 13;
private static final int ROLLED_BACK_UPDATE_BATCH_SIZE = 1000;
private static final Map<Integer, String> SQL_QUERIES = new HashMap<>();
static {
@@ -78,7 +83,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -102,7 +107,7 @@ public class Database extends Queue {
continue;
}
else {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -125,7 +130,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -143,12 +148,12 @@ public class Database extends Queue {
if (contents != null) {
List<ItemStack[]> forceList = new ArrayList<>();
forceList.add(ItemUtils.getContainerState(contents));
ConfigHandler.forceContainer.put(user.toLowerCase(Locale.ROOT) + "." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ(), forceList);
ConfigHandler.forceContainer.put(HopperTransactionUtils.getLoggingId(user, location), forceList);
Queue.queueContainerBreak(user, location, type, contents);
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -177,7 +182,7 @@ public class Database extends Queue {
catch (Exception e) {
ConfigHandler.databaseReachable = false;
Chat.sendConsoleMessage(Color.RED + "[CoreProtect] " + Phrase.build(Phrase.MYSQL_UNAVAILABLE));
e.printStackTrace();
ErrorReporter.report(e);
}
}
else {
@@ -202,7 +207,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return connection;
@@ -216,25 +221,39 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
public static void performUpdate(Statement statement, long id, int rb, int table) {
public static void performRolledBackUpdate(Statement statement, int rolledBack, List<Long> rowIds, int table) {
String tableName;
if (RollbackUpdateTargets.updatesContainerTable(table)) {
tableName = "container";
}
else if (RollbackUpdateTargets.updatesItemTable(table)) {
tableName = "item";
}
else {
tableName = "block";
}
try {
int rolledBack = MaterialUtils.toggleRolledBack(rb, (table == 2 || table == 3 || table == 4)); // co_item, co_container, co_block
if (table == 1 || table == 3) {
statement.executeUpdate("UPDATE " + ConfigHandler.prefix + "container SET rolled_back='" + rolledBack + "' WHERE rowid='" + id + "'");
}
else if (table == 2) {
statement.executeUpdate("UPDATE " + ConfigHandler.prefix + "item SET rolled_back='" + rolledBack + "' WHERE rowid='" + id + "'");
}
else {
statement.executeUpdate("UPDATE " + ConfigHandler.prefix + "block SET rolled_back='" + rolledBack + "' WHERE rowid='" + id + "'");
int listSize = rowIds.size();
for (int startIndex = 0; startIndex < listSize; startIndex += ROLLED_BACK_UPDATE_BATCH_SIZE) {
int endIndex = Math.min(startIndex + ROLLED_BACK_UPDATE_BATCH_SIZE, listSize);
StringBuilder query = new StringBuilder("UPDATE " + ConfigHandler.prefix + tableName + " SET rolled_back='" + rolledBack + "' WHERE rowid IN(");
for (int index = startIndex; index < endIndex; index++) {
if (index > startIndex) {
query.append(",");
}
query.append(rowIds.get(index).longValue());
}
query.append(")");
statement.executeUpdate(query.toString());
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -248,7 +267,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return preparedStatement;
@@ -270,7 +289,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return preparedStatement;
@@ -302,7 +321,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -326,6 +345,7 @@ public class Database extends Queue {
if (connection != null) {
Statement statement = connection.createStatement();
createMySQLTableStructures(prefix, statement);
createMySQLIndexes(prefix, statement, purge);
if (!purge && forceConnection == null) {
initializeTables(prefix, statement);
}
@@ -334,7 +354,7 @@ public class Database extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
if (!success && forceConnection == null) {
Config.getGlobal().MYSQL = false;
@@ -362,11 +382,11 @@ public class Database extends Queue {
// Container
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "container(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data int, amount int, metadata blob, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "container(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data int, amount int, metadata mediumblob, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Item
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "item(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data blob, amount int, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "item(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data mediumblob, amount int, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Database lock
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "database_lock(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),status tinyint,time int) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
@@ -395,7 +415,7 @@ public class Database extends Queue {
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");
// Skull
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "skull(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, owner varchar(255), skin varchar(255)) 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), skin text) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// User
index = ", INDEX(user), INDEX(uuid)";
@@ -413,6 +433,103 @@ public class Database extends Queue {
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,world varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
}
private static void createMySQLIndexes(String prefix, Statement statement, boolean purge) {
try {
ensureMySQLIndex(statement, prefix + "block", "wid", "x", "z", "time");
ensureMySQLIndex(statement, prefix + "block", "user", "time");
ensureMySQLIndex(statement, prefix + "block", "type", "time");
ensureMySQLIndex(statement, prefix + "container", "wid", "x", "z", "time");
ensureMySQLIndex(statement, prefix + "container", "user", "time");
ensureMySQLIndex(statement, prefix + "container", "type", "time");
ensureMySQLIndex(statement, prefix + "item", "wid", "x", "z", "time");
ensureMySQLIndex(statement, prefix + "item", "user", "time");
ensureMySQLIndex(statement, prefix + "item", "type", "time");
}
catch (Exception e) {
Chat.console(Phrase.build(Phrase.DATABASE_INDEX_ERROR));
if (purge) {
ErrorReporter.report(e);
}
}
}
private static void ensureMySQLIndex(Statement statement, String tableName, String... columns) throws SQLException {
if (hasMySQLIndex(statement, tableName, columns)) {
return;
}
String indexName = createMySQLIndexName(tableName, columns);
String indexColumns = String.join(",", columns);
statement.executeUpdate("CREATE INDEX " + indexName + " ON " + tableName + "(" + indexColumns + ")");
}
private static boolean hasMySQLIndex(Statement statement, String tableName, String... columns) {
Map<String, TreeMap<Integer, String>> indexData = new HashMap<>();
try (ResultSet resultSet = statement.executeQuery("SHOW INDEX FROM " + tableName)) {
while (resultSet.next()) {
String keyName = resultSet.getString("Key_name");
int sequence = resultSet.getInt("Seq_in_index");
String columnName = resultSet.getString("Column_name");
if (keyName == null || columnName == null) {
continue;
}
indexData.computeIfAbsent(keyName, key -> new TreeMap<>()).put(sequence, columnName.toLowerCase(Locale.ROOT));
}
}
catch (Exception e) {
return false;
}
List<String> expected = new ArrayList<>(columns.length);
for (String column : columns) {
expected.add(column.toLowerCase(Locale.ROOT));
}
for (TreeMap<Integer, String> indexColumns : indexData.values()) {
if (indexColumns.size() < expected.size()) {
continue;
}
boolean matchesPrefix = true;
int position = 0;
for (String column : indexColumns.values()) {
if (!column.equals(expected.get(position))) {
matchesPrefix = false;
break;
}
position++;
if (position == expected.size()) {
break;
}
}
if (matchesPrefix && position == expected.size()) {
return true;
}
}
return false;
}
private static String createMySQLIndexName(String tableName, String... columns) {
String normalizedTable = tableName.replaceAll("[^A-Za-z0-9_]", "_");
String joinedColumns = String.join("_", columns);
String candidate = normalizedTable + "_" + joinedColumns + "_idx";
if (candidate.length() <= 64) {
return candidate;
}
String hash = Integer.toHexString(candidate.hashCode());
int maxPrefixLength = 64 - (hash.length() + 1);
if (maxPrefixLength < 1) {
maxPrefixLength = 1;
}
return candidate.substring(0, maxPrefixLength) + "_" + hash;
}
private static void createSQLiteTables(String prefix, boolean forcePrefix, Connection forceConnection, boolean purge) {
try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, 0))) {
Statement statement = connection.createStatement();
@@ -438,7 +555,7 @@ public class Database extends Queue {
statement.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -550,7 +667,7 @@ public class Database extends Queue {
catch (Exception e) {
Chat.console(Phrase.build(Phrase.DATABASE_INDEX_ERROR));
if (purge) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
}
@@ -13,6 +13,7 @@ import org.bukkit.command.CommandSender;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.consumer.Queue;
import net.coreprotect.utility.ErrorReporter;
public class Lookup extends Queue {
@@ -35,7 +36,7 @@ public class Lookup extends Queue {
results.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
Consumer.isPaused = false;
@@ -51,7 +52,7 @@ public class Lookup extends Queue {
newList = LookupConverter.convertRawLookup(statement, lookupList);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return newList;
@@ -65,7 +66,7 @@ public class Lookup extends Queue {
newList = LookupConverter.convertRawLookup(statement, lookupList);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return newList;
@@ -8,6 +8,7 @@ import java.util.List;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.ErrorReporter;
public class LookupConverter {
@@ -54,7 +55,7 @@ public class LookupConverter {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
newList.add(results);
@@ -18,25 +18,28 @@ import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.consumer.Queue;
import net.coreprotect.database.logger.ItemLogger;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.listener.channel.PluginChannelHandshakeListener;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.model.action.SignActions;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.EntityUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class LookupRaw extends Queue {
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);
invalidRollbackActions.add(LookupActions.INTERACTION);
if (!Config.getGlobal().ROLLBACK_ENTITIES && !actionList.contains(3)) {
invalidRollbackActions.add(3);
if (!Config.getGlobal().ROLLBACK_ENTITIES && !actionList.contains(LookupActions.ENTITY_KILL)) {
invalidRollbackActions.add(LookupActions.ENTITY_KILL);
}
if (actionList.contains(4) && actionList.contains(11)) {
if (LookupActions.isInventoryLookup(actionList)) {
invalidRollbackActions.clear();
}
@@ -50,7 +53,7 @@ public class LookupRaw extends Queue {
ResultSet results = rawLookupResultSet(statement, user, checkUuids, checkUsers, restrictList, excludeList, excludeUserList, actionList, location, radius, rowData, startTime, endTime, limitOffset, limitCount, restrictWorld, lookup, false);
while (results.next()) {
if (actionList.contains(6) || actionList.contains(7)) {
if (actionList.contains(LookupActions.CHAT) || actionList.contains(LookupActions.COMMAND)) {
long resultId = results.getLong("id");
int resultTime = results.getInt("time");
int resultUserId = results.getInt("user");
@@ -66,7 +69,7 @@ public class LookupRaw extends Queue {
}
list.add(dataArray);
}
else if (actionList.contains(8)) {
else if (actionList.contains(LookupActions.SESSION)) {
long resultId = results.getLong("id");
int resultTime = results.getInt("time");
int resultUserId = results.getInt("user");
@@ -79,7 +82,7 @@ public class LookupRaw extends Queue {
Object[] dataArray = new Object[] { resultId, resultTime, resultUserId, resultWorldId, resultX, resultY, resultZ, resultAction };
list.add(dataArray);
}
else if (actionList.contains(9)) {
else if (actionList.contains(LookupActions.USERNAME)) {
long resultId = results.getLong("id");
int resultTime = results.getInt("time");
String resultUuid = results.getString("uuid");
@@ -88,7 +91,7 @@ public class LookupRaw extends Queue {
Object[] dataArray = new Object[] { resultId, resultTime, resultUuid, resultUser };
list.add(dataArray);
}
else if (actionList.contains(10)) {
else if (actionList.contains(LookupActions.SIGN)) {
long resultId = results.getLong("id");
int resultTime = results.getInt("time");
int resultUserId = results.getInt("user");
@@ -177,7 +180,7 @@ public class LookupRaw extends Queue {
int resultWorldId = results.getInt("wid");
boolean hasTbl = false;
if ((lookup && actionList.size() == 0) || actionList.contains(4) || actionList.contains(5) || actionList.contains(11)) {
if ((lookup && actionList.size() == 0) || actionList.contains(LookupActions.CONTAINER) || actionList.contains(5) || actionList.contains(LookupActions.ITEM)) {
resultData = results.getInt("data");
resultAmount = results.getInt("amount");
resultMeta = results.getBytes("metadata");
@@ -212,7 +215,7 @@ public class LookupRaw extends Queue {
results.close();
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
Consumer.isPaused = false;
@@ -223,12 +226,12 @@ public class LookupRaw extends Queue {
ResultSet results = null;
try {
List<Integer> validActions = Arrays.asList(0, 1, 2, 3);
List<Integer> validActions = Arrays.asList(LookupActions.BLOCK_BREAK, LookupActions.BLOCK_PLACE, LookupActions.INTERACTION, LookupActions.ENTITY_KILL);
if (radius != null) {
restrictWorld = true;
}
boolean inventoryQuery = (actionList.contains(4) && actionList.contains(11));
boolean inventoryQuery = LookupActions.isInventoryLookup(actionList);
boolean validAction = false;
String queryBlock = "";
String queryEntity = "";
@@ -314,6 +317,15 @@ public class LookupRaw extends Queue {
includeListEntity.append(",").append(EntityUtils.getEntityId(targetName, false));
}
}
else if (restrictTarget instanceof String) {
int blockId = MaterialUtils.getBlockId((String) restrictTarget, false);
if (includeListMaterial.length() == 0) {
includeListMaterial = includeListMaterial.append(blockId);
}
else {
includeListMaterial.append(",").append(blockId);
}
}
}
includeBlock = includeListMaterial.toString();
@@ -351,6 +363,17 @@ public class LookupRaw extends Queue {
excludeListEntity.append(",").append(EntityUtils.getEntityId(targetName, false));
}
}
else if (restrictTarget instanceof String) {
int blockId = MaterialUtils.getBlockId((String) restrictTarget, false);
if (blockId > -1) {
if (excludeListMaterial.length() == 0) {
excludeListMaterial = excludeListMaterial.append(blockId);
}
else {
excludeListMaterial.append(",").append(blockId);
}
}
}
}
excludeBlock = excludeListMaterial.toString();
@@ -378,13 +401,13 @@ public class LookupRaw extends Queue {
}
// Specify actions to exclude from a:item
if ((lookup && actionList.size() == 0) || (actionList.contains(11) && actionList.size() == 1)) {
if ((lookup && actionList.size() == 0) || (actionList.contains(LookupActions.ITEM) && actionList.size() == 1)) {
StringBuilder actionText = new StringBuilder();
actionText = actionText.append(ItemLogger.ITEM_BREAK);
actionText.append(",").append(ItemLogger.ITEM_DESTROY);
actionText.append(",").append(ItemLogger.ITEM_CREATE);
actionText.append(",").append(ItemLogger.ITEM_SELL);
actionText.append(",").append(ItemLogger.ITEM_BUY);
actionText = actionText.append(ItemTransactionActions.BREAK);
actionText.append(",").append(ItemTransactionActions.DESTROY);
actionText.append(",").append(ItemTransactionActions.CREATE);
actionText.append(",").append(ItemTransactionActions.SELL);
actionText.append(",").append(ItemTransactionActions.BUY);
actionExclude = actionText.toString();
}
@@ -393,12 +416,12 @@ public class LookupRaw extends Queue {
for (Integer actionTarget : actionList) {
if (validActions.contains(actionTarget)) {
// If just looking up drops/pickups, remap the actions to the correct values
if (actionList.contains(11) && !actionList.contains(4)) {
if (actionTarget == ItemLogger.ITEM_REMOVE && !actionList.contains(ItemLogger.ITEM_DROP)) {
actionTarget = ItemLogger.ITEM_DROP;
if (actionList.contains(LookupActions.ITEM) && !actionList.contains(LookupActions.CONTAINER)) {
if (actionTarget == ItemTransactionActions.REMOVE && !actionList.contains(ItemTransactionActions.DROP)) {
actionTarget = ItemTransactionActions.DROP;
}
else if (actionTarget == ItemLogger.ITEM_ADD && !actionList.contains(ItemLogger.ITEM_PICKUP)) {
actionTarget = ItemLogger.ITEM_PICKUP;
else if (actionTarget == ItemTransactionActions.ADD && !actionList.contains(ItemTransactionActions.PICKUP)) {
actionTarget = ItemTransactionActions.PICKUP;
}
}
@@ -410,32 +433,32 @@ public class LookupRaw extends Queue {
}
// If selecting from co_item & co_container, add in actions for both transaction types
if (actionList.contains(11) && actionList.contains(4)) {
if (actionTarget == ItemLogger.ITEM_REMOVE) {
actionText.append(",").append(ItemLogger.ITEM_PICKUP);
actionText.append(",").append(ItemLogger.ITEM_REMOVE_ENDER);
actionText.append(",").append(ItemLogger.ITEM_CREATE);
actionText.append(",").append(ItemLogger.ITEM_BUY);
if (LookupActions.isInventoryLookup(actionList)) {
if (actionTarget == ItemTransactionActions.REMOVE) {
actionText.append(",").append(ItemTransactionActions.PICKUP);
actionText.append(",").append(ItemTransactionActions.REMOVE_ENDER);
actionText.append(",").append(ItemTransactionActions.CREATE);
actionText.append(",").append(ItemTransactionActions.BUY);
}
if (actionTarget == ItemLogger.ITEM_ADD) {
actionText.append(",").append(ItemLogger.ITEM_DROP);
actionText.append(",").append(ItemLogger.ITEM_ADD_ENDER);
actionText.append(",").append(ItemLogger.ITEM_THROW);
actionText.append(",").append(ItemLogger.ITEM_SHOOT);
actionText.append(",").append(ItemLogger.ITEM_BREAK);
actionText.append(",").append(ItemLogger.ITEM_DESTROY);
actionText.append(",").append(ItemLogger.ITEM_SELL);
if (actionTarget == ItemTransactionActions.ADD) {
actionText.append(",").append(ItemTransactionActions.DROP);
actionText.append(",").append(ItemTransactionActions.ADD_ENDER);
actionText.append(",").append(ItemTransactionActions.THROW);
actionText.append(",").append(ItemTransactionActions.SHOOT);
actionText.append(",").append(ItemTransactionActions.BREAK);
actionText.append(",").append(ItemTransactionActions.DESTROY);
actionText.append(",").append(ItemTransactionActions.SELL);
}
}
// If just looking up drops/pickups, include ender chest transactions
else if (actionList.contains(11) && !actionList.contains(4)) {
if (actionTarget == ItemLogger.ITEM_DROP) {
actionText.append(",").append(ItemLogger.ITEM_ADD_ENDER);
actionText.append(",").append(ItemLogger.ITEM_THROW);
actionText.append(",").append(ItemLogger.ITEM_SHOOT);
else if (actionList.contains(LookupActions.ITEM) && !actionList.contains(LookupActions.CONTAINER)) {
if (actionTarget == ItemTransactionActions.DROP) {
actionText.append(",").append(ItemTransactionActions.ADD_ENDER);
actionText.append(",").append(ItemTransactionActions.THROW);
actionText.append(",").append(ItemTransactionActions.SHOOT);
}
if (actionTarget == ItemLogger.ITEM_PICKUP) {
actionText.append(",").append(ItemLogger.ITEM_REMOVE_ENDER);
if (actionTarget == ItemTransactionActions.PICKUP) {
actionText.append(",").append(ItemTransactionActions.REMOVE_ENDER);
}
}
}
@@ -515,8 +538,8 @@ public class LookupRaw extends Queue {
queryBlock = queryBlock + " time <= '" + endTime + "' AND";
}
if (actionList.contains(10)) {
queryBlock = queryBlock + " action = '1' AND (LENGTH(line_1) > 0 OR LENGTH(line_2) > 0 OR LENGTH(line_3) > 0 OR LENGTH(line_4) > 0 OR LENGTH(line_5) > 0 OR LENGTH(line_6) > 0 OR LENGTH(line_7) > 0 OR LENGTH(line_8) > 0) AND";
if (actionList.contains(LookupActions.SIGN)) {
queryBlock = queryBlock + " action = '" + SignActions.PLACE + "' AND (LENGTH(line_1) > 0 OR LENGTH(line_2) > 0 OR LENGTH(line_3) > 0 OR LENGTH(line_4) > 0 OR LENGTH(line_5) > 0 OR LENGTH(line_6) > 0 OR LENGTH(line_7) > 0 OR LENGTH(line_8) > 0) AND";
}
if (queryBlock.length() > 0) {
@@ -544,34 +567,34 @@ public class LookupRaw extends Queue {
String rows = "rowid as id,time,user,wid,x,y,z,action,type,data,meta,blockdata,rolled_back";
String queryOrder = " ORDER BY rowid DESC";
if (actionList.contains(4) || actionList.contains(5)) {
if (actionList.contains(LookupActions.CONTAINER) || actionList.contains(5)) {
queryTable = "container";
rows = "rowid as id,time,user,wid,x,y,z,action,type,data,rolled_back,amount,metadata";
}
else if (actionList.contains(6) || actionList.contains(7)) {
else if (actionList.contains(LookupActions.CHAT) || actionList.contains(LookupActions.COMMAND)) {
queryTable = "chat";
rows = "rowid as id,time,user,message";
if (PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(user)) {
rows += ",wid,x,y,z";
}
if (actionList.contains(7)) {
if (actionList.contains(LookupActions.COMMAND)) {
queryTable = "command";
}
}
else if (actionList.contains(8)) {
else if (actionList.contains(LookupActions.SESSION)) {
queryTable = "session";
rows = "rowid as id,time,user,wid,x,y,z,action";
}
else if (actionList.contains(9)) {
else if (actionList.contains(LookupActions.USERNAME)) {
queryTable = "username_log";
rows = "rowid as id,time,uuid,user";
}
else if (actionList.contains(10)) {
else if (actionList.contains(LookupActions.SIGN)) {
queryTable = "sign";
rows = "rowid as id,time,user,wid,x,y,z,face,line_1,line_2,line_3,line_4,line_5,line_6,line_7,line_8";
}
else if (actionList.contains(11)) {
else if (actionList.contains(LookupActions.ITEM)) {
queryTable = "item";
rows = "rowid as id,time,user,wid,x,y,z,type,data as metadata,0 as data,amount,action,0 as rolled_back";
}
@@ -586,17 +609,17 @@ public class LookupRaw extends Queue {
String unionSelect = "SELECT * FROM (";
if (Config.getGlobal().MYSQL) {
if (queryTable.equals("block")) {
if (includeBlock.length() > 0 || includeEntity.length() > 0) {
index = "USE INDEX(type) IGNORE INDEX(user,wid) ";
}
if (users.length() > 0) {
index = "USE INDEX(user) IGNORE INDEX(type,wid) ";
}
if (radius != null && (radius[2] - radius[1]) <= 50 && (radius[6] - radius[5]) <= 50) {
index = "USE INDEX(wid) IGNORE INDEX(type,user) ";
index = "USE INDEX(wid) ";
}
if ((restrictWorld && (users.length() > 0 || includeBlock.length() > 0 || includeEntity.length() > 0))) {
index = "IGNORE INDEX(PRIMARY) ";
else if (users.length() > 0) {
index = "USE INDEX(user) ";
}
else if (includeBlock.length() > 0 || includeEntity.length() > 0) {
index = "USE INDEX(type) ";
}
else if (restrictWorld) {
index = "USE INDEX(wid) ";
}
}
@@ -620,17 +643,17 @@ public class LookupRaw extends Queue {
}
boolean itemLookup = inventoryQuery;
if ((lookup && actionList.size() == 0) || (itemLookup && !actionList.contains(0))) {
if ((lookup && actionList.size() == 0) || (itemLookup && !actionList.contains(LookupActions.BLOCK_BREAK))) {
if (!count) {
rows = "rowid as id,time,user,wid,x,y,z,type,meta as metadata,data,-1 as amount,action,rolled_back";
}
if (inventoryQuery) {
if (validAction) {
baseQuery = baseQuery.replace("action IN(" + action + ")", "action IN(1)");
baseQuery = baseQuery.replace("action IN(" + action + ")", "action IN(" + LookupActions.BLOCK_PLACE + ")");
}
else {
baseQuery = baseQuery.replace("action NOT IN(-1)", "action IN(1)");
baseQuery = baseQuery.replace("action NOT IN(-1)", "action IN(" + LookupActions.BLOCK_PLACE + ")");
}
if (!count) {
@@ -639,7 +662,7 @@ public class LookupRaw extends Queue {
}
if (includeBlock.length() > 0 || excludeBlock.length() > 0) {
baseQuery = baseQuery.replace("action NOT IN(-1)", "action NOT IN(3)"); // if block specified for include/exclude, filter out entity data
baseQuery = baseQuery.replace("action NOT IN(-1)", "action NOT IN(" + LookupActions.ENTITY_KILL + ")"); // if block specified for include/exclude, filter out entity data
}
query = unionSelect + "SELECT " + "'0' as tbl," + rows + " FROM " + ConfigHandler.prefix + "block " + index + "WHERE" + baseQuery + unionLimit + ") UNION ALL ";
@@ -676,7 +699,7 @@ public class LookupRaw extends Queue {
results = statement.executeQuery(query);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return results;
@@ -15,8 +15,12 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.BlockStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.utility.BlockTypeUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class BlockBreakLogger {
@@ -26,19 +30,30 @@ public class BlockBreakLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, String user, Location location, int type, int data, List<Object> meta, String blockData, String overrideData) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null || location == null) {
Material checkType = MaterialUtils.getType(type);
String blockKey = BlockTypeUtils.getBlockDataKey(blockData);
if (blockKey.length() == 0 && checkType != null) {
blockKey = checkType.getKey().toString();
}
else if (checkType != null && (checkType == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(checkType) || checkType == Material.ARMOR_STAND || checkType == Material.END_CRYSTAL)) {
blockKey = checkType.getKey().toString();
}
if (checkType != null && blockKey.length() > 0) {
Material blockDataType = MaterialUtils.getType(blockKey);
if (blockDataType != null && !blockDataType.equals(checkType)) {
blockKey = checkType.getKey().toString();
blockData = null;
}
}
if (checkType == null && blockKey.length() == 0) {
return;
}
else if (checkType != null && (checkType.equals(Material.AIR) || checkType.equals(Material.CAVE_AIR)) && BlockTypeUtils.isAir(blockKey)) {
return;
}
Material checkType = net.coreprotect.utility.MaterialUtils.getType(type);
if (checkType == null) {
return;
}
else if (checkType.equals(Material.AIR) || checkType.equals(Material.CAVE_AIR)) {
return;
}
if (ConfigHandler.blacklist.get(checkType.getKey().toString()) != null) {
if (ConfigHandler.isBlacklisted(user, blockKey)) {
return;
}
@@ -47,14 +62,14 @@ public class BlockBreakLogger {
CacheHandler.spreadCache.remove(cacheId);
}
if (checkType == Material.LECTERN) {
if (checkType == Material.LECTERN && blockData != null) {
blockData = blockData.replaceFirst("has_book=true", "has_book=false");
}
else if (checkType == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(checkType)) {
else if (checkType != null && (checkType == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(checkType))) {
blockData = overrideData;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location);
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location, CoreProtectPreLogEvent.Action.BLOCK_BREAK, LookupActions.BLOCK_BREAK, checkType, null, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -72,10 +87,11 @@ public class BlockBreakLogger {
return;
}
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, data, meta, blockData, 0, 0);
int internalType = blockKey.length() > 0 ? MaterialUtils.getBlockId(blockKey, true) : type;
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, internalType, data, meta, blockData, LookupActions.BLOCK_BREAK, 0);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -16,9 +16,12 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.BlockStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.utility.BlockTypeUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class BlockPlaceLogger {
@@ -28,17 +31,14 @@ public class BlockPlaceLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, String user, BlockState block, int replacedType, int replacedData, Material forceType, int forceData, boolean force, List<Object> meta, String blockData, String replaceBlockData) {
try {
if (user == null || ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
return;
}
Material type = block.getType();
if (blockData == null && (forceType == null || (!forceType.equals(Material.WATER)) && (!forceType.equals(Material.LAVA)))) {
blockData = block.getBlockData().getAsString();
if (blockData.equals("minecraft:air")) {
if (BlockTypeUtils.isAir(BlockTypeUtils.getBlockDataKey(blockData))) {
blockData = null;
}
}
String blockKey = BlockTypeUtils.getBlockDataKey(blockData);
int data = 0;
if (forceType != null && force) {
type = forceType;
@@ -49,16 +49,32 @@ public class BlockPlaceLogger {
data = forceData;
}
}
else if (forceType != null && !type.equals(forceType)) {
else if (forceType != null && (type == null || !type.equals(forceType))) {
type = forceType;
data = forceData;
}
if (forceType != null && type != null && blockKey.length() > 0) {
Material blockDataType = MaterialUtils.getType(blockKey);
if (blockDataType != null && !blockDataType.equals(type)) {
blockKey = type.getKey().toString();
blockData = null;
}
}
if (blockKey.length() == 0) {
if (type == null) {
return;
}
blockKey = type.getKey().toString();
}
else if (type != null && (type == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(type))) {
blockKey = type.getKey().toString();
}
if (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR)) {
if (type != null && (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR)) && BlockTypeUtils.isAir(blockKey)) {
return;
}
if (ConfigHandler.blacklist.get(type.getKey().toString()) != null) {
if (ConfigHandler.isBlacklisted(user, blockKey)){
return;
}
@@ -86,7 +102,7 @@ public class BlockPlaceLogger {
}
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, block.getLocation());
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, block.getLocation(), CoreProtectPreLogEvent.Action.BLOCK_PLACE, LookupActions.BLOCK_PLACE, type, null, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -109,15 +125,16 @@ public class BlockPlaceLogger {
return;
}
int internalType = MaterialUtils.getBlockId(type.name(), true);
if (replacedType > 0 && MaterialUtils.getType(replacedType) != Material.AIR && MaterialUtils.getType(replacedType) != Material.CAVE_AIR) {
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, replacedType, replacedData, null, replaceBlockData, 0, 0);
int internalType = MaterialUtils.getBlockId(blockKey, true);
int replacedInternalType = MaterialUtils.getBlockId(replaceBlockData, MaterialUtils.getType(replacedType), true);
if (replacedInternalType > 0 && !BlockTypeUtils.isAir(MaterialUtils.getBlockName(replacedInternalType))) {
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, replacedInternalType, replacedData, null, replaceBlockData, LookupActions.BLOCK_BREAK, 0);
}
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, internalType, data, meta, blockData, 1, 0);
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, internalType, data, meta, blockData, LookupActions.BLOCK_PLACE, 0);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -8,6 +8,7 @@ import org.bukkit.Location;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.ChatStatement;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class ChatLogger {
@@ -17,7 +18,7 @@ public class ChatLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, long time, Location location, String user, String message) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
int x = location.getBlockX();
@@ -28,7 +29,7 @@ public class ChatLogger {
ChatStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, message);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -13,6 +13,7 @@ import net.coreprotect.database.statement.CommandStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class CommandLogger {
@@ -22,14 +23,14 @@ public class CommandLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, long time, Location location, String user, String message) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
if (ConfigHandler.blacklist.get(((message + " ").split(" "))[0].toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(((message + " ").split(" "))[0])) {
return;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location);
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location, CoreProtectPreLogEvent.Action.PLAYER_COMMAND, -1, null, null, message);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -47,7 +48,7 @@ public class CommandLogger {
CommandStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, message);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -1,14 +1,16 @@
package net.coreprotect.database.logger;
import java.sql.PreparedStatement;
import java.util.Locale;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.HopperTransactionUtils;
import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.ErrorReporter;
public class ContainerBreakLogger {
@@ -19,8 +21,8 @@ public class ContainerBreakLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, String player, Location l, Material type, ItemStack[] oldInventory) {
try {
ItemUtils.mergeItems(type, oldInventory);
ContainerLogger.logTransaction(preparedStmt, batchCount, player, type, null, oldInventory, 0, l);
String loggingContainerId = player.toLowerCase(Locale.ROOT) + "." + l.getBlockX() + "." + l.getBlockY() + "." + l.getBlockZ();
ContainerLogger.logTransaction(preparedStmt, batchCount, player, type, null, oldInventory, ItemTransactionActions.REMOVE, l);
String loggingContainerId = HopperTransactionUtils.getLoggingId(player, l);
// If there was a pending chest transaction, it would have already been processed.
if (ConfigHandler.forceContainer.get(loggingContainerId) != null) {
@@ -28,7 +30,7 @@ public class ContainerBreakLogger {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -1,11 +1,10 @@
package net.coreprotect.database.logger;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
@@ -22,14 +21,22 @@ import net.coreprotect.consumer.Queue;
import net.coreprotect.database.statement.ContainerStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.HopperTransactionUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.serialize.ItemMetaHandler;
import net.coreprotect.utility.ErrorReporter;
public class ContainerLogger extends Queue {
private static final int CONTAINER_DUPLICATE_THRESHOLD_DROPPER = 512;
private static final int CONTAINER_DUPLICATE_THRESHOLD_DISPENSER = 256;
private static final int CONTAINER_DUPLICATE_WINDOW_SECONDS = 1200;
private ContainerLogger() {
throw new IllegalStateException("Database class");
}
@@ -46,6 +53,9 @@ public class ContainerLogger extends Queue {
else if (type == Material.JUKEBOX || type == Material.ARMOR_STAND) {
contents = (ItemStack[]) ((Object[]) container)[1];
}
else if (container instanceof ItemStack[]) {
contents = (ItemStack[]) container;
}
else {
Inventory inventory = (Inventory) container;
if (inventory != null) {
@@ -57,7 +67,8 @@ public class ContainerLogger extends Queue {
return;
}
String loggingContainerId = player.toLowerCase(Locale.ROOT) + "." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ();
String loggingContainerId = HopperTransactionUtils.getLoggingId(player, location);
String transactingChestId = HopperTransactionUtils.getTransactionId(location);
List<ItemStack[]> oldList = ConfigHandler.oldContainer.get(loggingContainerId);
ItemStack[] oi1 = oldList.get(0);
ItemStack[] oldInventory = ItemUtils.getContainerState(oi1);
@@ -65,9 +76,10 @@ public class ContainerLogger extends Queue {
if (oldInventory == null || newInventory == null) {
return;
}
boolean duplicateSuppression = Config.getConfig(location.getWorld()).DUPLICATE_SUPPRESSION;
// Check if this is a dispenser with no actual changes
if ("#dispenser".equals(player) && ItemUtils.compareContainers(oldInventory, newInventory)) {
if (duplicateSuppression && "#dispenser".equals(player) && ItemUtils.compareContainers(oldInventory, newInventory)) {
// No changes detected, mark this dispenser in the dispenserNoChange map
// Extract the location key from the loggingContainerId
// Format: #dispenser.x.y.z
@@ -95,7 +107,7 @@ public class ContainerLogger extends Queue {
// If we reach here, the dispenser event resulted in changes
// Remove any pending event for this dispenser
if ("#dispenser".equals(player)) {
if (duplicateSuppression && "#dispenser".equals(player)) {
String[] parts = loggingContainerId.split("\\.");
if (parts.length >= 4) {
int x = Integer.parseInt(parts[1]);
@@ -124,46 +136,20 @@ public class ContainerLogger extends Queue {
}
}
else {
String transactingChestId = location.getWorld().getUID().toString() + "." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ();
if (ConfigHandler.transactingChest.get(transactingChestId) != null) {
List<Object> list = Collections.synchronizedList(new ArrayList<>(ConfigHandler.transactingChest.get(transactingChestId)));
if (list.size() > 0) {
ItemStack[] newMerge = new ItemStack[newInventory.length + list.size()];
int count = 0;
for (int i = 0; i < newInventory.length; i++) {
newMerge[i] = newInventory[i];
count++;
}
for (Object item : list) {
ItemStack addItem = null;
ItemStack removeItem = null;
if (item instanceof ItemStack) {
addItem = (ItemStack) item;
}
else if (item != null) {
addItem = ((ItemStack[]) item)[0];
removeItem = ((ItemStack[]) item)[1];
}
long snapshotMark = HopperTransactionUtils.peekSnapshotMark(transactingChestId, loggingContainerId);
newInventory = HopperTransactionUtils.applyPendingChanges(newInventory, transactingChestId, snapshotMark);
}
// item was removed by hopper, add back to state
if (addItem != null) {
newMerge[count] = addItem;
count++;
}
// item was added by hopper, remove from state
if (removeItem != null) {
for (ItemStack check : newMerge) {
if (check != null && check.isSimilar(removeItem)) {
check.setAmount(check.getAmount() - 1);
break;
}
}
}
}
newInventory = newMerge;
}
if (duplicateSuppression && shouldSuppressContainerDuplicate(player, location, oldInventory, newInventory)) {
oldList.remove(0);
ConfigHandler.oldContainer.put(loggingContainerId, oldList);
HopperTransactionUtils.consumeSnapshot(transactingChestId, loggingContainerId);
if ("#hopper".equals(player)) {
String hopperPush = "#hopper-push." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ();
ConfigHandler.hopperSuccess.remove(hopperPush);
ConfigHandler.hopperAbort.remove(hopperPush);
}
return;
}
for (ItemStack oldi : oldInventory) {
@@ -191,25 +177,26 @@ public class ContainerLogger extends Queue {
ItemUtils.mergeItems(type, newInventory);
if (type != Material.ENDER_CHEST) {
logTransaction(preparedStmtContainer, batchCount, player, type, faceData, oldInventory, 0, location);
logTransaction(preparedStmtContainer, batchCount, player, type, faceData, newInventory, 1, location);
logTransaction(preparedStmtContainer, batchCount, player, type, faceData, oldInventory, ItemTransactionActions.REMOVE, location);
logTransaction(preparedStmtContainer, batchCount, player, type, faceData, newInventory, ItemTransactionActions.ADD, location);
}
else { // pass ender chest transactions to item logger
ItemLogger.logTransaction(preparedStmtItems, batchCount, 0, player, location, oldInventory, ItemLogger.ITEM_REMOVE_ENDER);
ItemLogger.logTransaction(preparedStmtItems, batchCount, 0, player, location, newInventory, ItemLogger.ITEM_ADD_ENDER);
ItemLogger.logTransaction(preparedStmtItems, batchCount, 0, player, location, oldInventory, ItemTransactionActions.REMOVE_ENDER);
ItemLogger.logTransaction(preparedStmtItems, batchCount, 0, player, location, newInventory, ItemTransactionActions.ADD_ENDER);
}
oldList.remove(0);
ConfigHandler.oldContainer.put(loggingContainerId, oldList);
HopperTransactionUtils.consumeSnapshot(transactingChestId, loggingContainerId);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
protected static void logTransaction(PreparedStatement preparedStmt, int batchCount, String user, Material type, String faceData, ItemStack[] items, int action, Location location) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
boolean success = false;
@@ -218,19 +205,24 @@ public class ContainerLogger extends Queue {
if (item != null) {
if (item.getAmount() > 0 && !BlockUtils.isAir(item.getType())) {
// Object[] metadata = new Object[] { slot, item.getItemMeta() };
if (ConfigHandler.isFilterBlacklisted(user, item.getType().getKey().toString())){
continue;
}
List<List<Map<String, Object>>> metadata = ItemMetaHandler.serialize(item, type, faceData, slot);
if (metadata.size() == 0) {
metadata = null;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location);
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location, CoreProtectPreLogEvent.Action.CONTAINER_TRANSACTION, action, item.getType(), null, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
if (event.isCancelled()) {
return;
}
}
int userId = UserStatement.getId(preparedStmt, event.getUser(), true);
Location eventLocation = event.getLocation();
@@ -256,8 +248,69 @@ public class ContainerLogger extends Queue {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
private static boolean shouldSuppressContainerDuplicate(String user, Location location, ItemStack[] oldInventory, ItemStack[] newInventory) {
if (!"#dropper".equals(user) && !"#dispenser".equals(user)) {
return false;
}
String oldSignature = getContainerStateSignature(oldInventory);
String newSignature = getContainerStateSignature(newInventory);
String transitionSignature = oldSignature + ">" + newSignature;
if ("#dispenser".equals(user)) {
if (oldSignature.compareTo(newSignature) <= 0) {
transitionSignature = oldSignature + "<>" + newSignature;
}
else {
transitionSignature = newSignature + "<>" + oldSignature;
}
}
int threshold = getContainerDuplicateThreshold(user);
String signature = location.getWorld().getUID().toString() + "." + location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ() + "." + user + "." + transitionSignature;
return CacheHandler.shouldSuppressRepeat(CacheHandler.containerDuplicateCache, signature, threshold, CONTAINER_DUPLICATE_WINDOW_SECONDS);
}
private static int getContainerDuplicateThreshold(String user) {
if ("#dispenser".equals(user)) {
return CONTAINER_DUPLICATE_THRESHOLD_DISPENSER;
}
return CONTAINER_DUPLICATE_THRESHOLD_DROPPER;
}
private static String getContainerStateSignature(ItemStack[] inventory) {
if (inventory == null || inventory.length == 0) {
return "-";
}
Map<String, Integer> itemCounts = new HashMap<>();
for (ItemStack itemStack : inventory) {
if (itemStack == null || itemStack.getAmount() <= 0 || BlockUtils.isAir(itemStack.getType())) {
continue;
}
ItemStack normalized = itemStack.clone();
normalized.setAmount(1);
String key = normalized.toString();
itemCounts.merge(key, itemStack.getAmount(), Integer::sum);
}
if (itemCounts.isEmpty()) {
return "-";
}
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, Integer> entry : new TreeMap<>(itemCounts).entrySet()) {
if (builder.length() > 0) {
builder.append('|');
}
builder.append(entry.getKey()).append('*').append(entry.getValue());
}
return Integer.toHexString(builder.toString().hashCode());
}
}
@@ -3,11 +3,10 @@ package net.coreprotect.database.logger;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Locale;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.entity.EntityType;
import net.coreprotect.CoreProtect;
import net.coreprotect.config.Config;
@@ -17,7 +16,9 @@ import net.coreprotect.database.statement.BlockStatement;
import net.coreprotect.database.statement.EntityStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class EntityKillLogger {
@@ -25,14 +26,25 @@ public class EntityKillLogger {
throw new IllegalStateException("Database class");
}
public static void log(PreparedStatement preparedStmt, PreparedStatement preparedStmt2, int batchCount, String user, BlockState block, List<Object> data, int type) {
public static void log(PreparedStatement preparedStmt, PreparedStatement preparedStmt2, int batchCount, String user, Location location, List<Object> data, int type) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)){
return;
}
Location initialLocation = new Location(block.getWorld(), block.getX(), block.getY(), block.getZ());
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, initialLocation);
EntityType checkType = net.coreprotect.utility.EntityUtils.getEntityType(type);
if (checkType == null) {
return;
}
// Ignore blacklist if the entity has a custom name
// data[4] contains custom name data
if (ConfigHandler.isBlacklisted(user, checkType.getKey().toString()) &&
!(data.size() > 4 && data.get(4) != null)){
return;
}
Location initialLocation = location.clone();
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, initialLocation, CoreProtectPreLogEvent.Action.ENTITY_KILL, LookupActions.ENTITY_KILL, null, checkType, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -63,10 +75,10 @@ public class EntityKillLogger {
keys.close();
}
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, entity_key, null, null, 3, 0);
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, entity_key, null, null, LookupActions.ENTITY_KILL, 0);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -16,27 +16,29 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.ItemStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.item.ItemTransactionActions;
import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.serialize.ItemMetaHandler;
import net.coreprotect.utility.ErrorReporter;
public class ItemLogger {
public static final int ITEM_REMOVE = 0;
public static final int ITEM_ADD = 1;
public static final int ITEM_DROP = 2;
public static final int ITEM_PICKUP = 3;
public static final int ITEM_REMOVE_ENDER = 4;
public static final int ITEM_ADD_ENDER = 5;
public static final int ITEM_THROW = 6;
public static final int ITEM_SHOOT = 7;
public static final int ITEM_BREAK = 8;
public static final int ITEM_DESTROY = 9;
public static final int ITEM_CREATE = 10;
public static final int ITEM_SELL = 11;
public static final int ITEM_BUY = 12;
public static final int ITEM_REMOVE = ItemTransactionActions.REMOVE;
public static final int ITEM_ADD = ItemTransactionActions.ADD;
public static final int ITEM_DROP = ItemTransactionActions.DROP;
public static final int ITEM_PICKUP = ItemTransactionActions.PICKUP;
public static final int ITEM_REMOVE_ENDER = ItemTransactionActions.REMOVE_ENDER;
public static final int ITEM_ADD_ENDER = ItemTransactionActions.ADD_ENDER;
public static final int ITEM_THROW = ItemTransactionActions.THROW;
public static final int ITEM_SHOOT = ItemTransactionActions.SHOOT;
public static final int ITEM_BREAK = ItemTransactionActions.BREAK;
public static final int ITEM_DESTROY = ItemTransactionActions.DESTROY;
public static final int ITEM_CREATE = ItemTransactionActions.CREATE;
public static final int ITEM_SELL = ItemTransactionActions.SELL;
public static final int ITEM_BUY = ItemTransactionActions.BUY;
private ItemLogger() {
throw new IllegalStateException("Database class");
@@ -44,7 +46,7 @@ public class ItemLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, Location location, int offset, String user) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
@@ -115,7 +117,7 @@ public class ItemLogger {
logTransaction(preparedStmt, batchCount, offset, user, location, itemBuys, ITEM_BUY);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -124,12 +126,16 @@ public class ItemLogger {
for (ItemStack item : items) {
if (item != null && item.getAmount() > 0 && !BlockUtils.isAir(item.getType())) {
// Object[] metadata = new Object[] { slot, item.getItemMeta() };
if (ConfigHandler.isFilterBlacklisted(user, item.getType().getKey().toString())){
continue;
}
List<List<Map<String, Object>>> data = ItemMetaHandler.serialize(item, null, null, 0);
if (data.size() == 0) {
data = null;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location);
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location, CoreProtectPreLogEvent.Action.ITEM_TRANSACTION, action, item.getType(), null, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -137,7 +143,7 @@ public class ItemLogger {
if (event.isCancelled()) {
return;
}
int userId = UserStatement.getId(preparedStmt, event.getUser(), true);
Location eventLocation = event.getLocation();
int wid = WorldUtils.getWorldId(eventLocation.getWorld().getName());
@@ -152,7 +158,7 @@ public class ItemLogger {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -1,8 +1,6 @@
package net.coreprotect.database.logger;
import java.sql.PreparedStatement;
import java.util.Locale;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Location;
@@ -14,8 +12,11 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.BlockStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.utility.BlockTypeUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class PlayerInteractLogger {
@@ -25,12 +26,28 @@ public class PlayerInteractLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, String user, BlockState block, Material blockType) {
try {
int type = MaterialUtils.getBlockId(blockType.name(), true);
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null || MaterialUtils.getType(type).equals(Material.AIR) || MaterialUtils.getType(type).equals(Material.CAVE_AIR)) {
String blockData = block.getBlockData().getAsString();
String blockKey = BlockTypeUtils.getBlockDataKey(blockData);
if (blockType != null && blockKey.length() > 0) {
Material blockDataType = MaterialUtils.getType(blockKey);
if (BlockTypeUtils.isAir(blockKey) || (blockDataType != null && !blockDataType.equals(blockType))) {
blockKey = blockType.getKey().toString();
blockData = null;
}
}
if (blockKey.length() == 0 && blockType != null) {
blockKey = blockType.getKey().toString();
}
if (blockKey.length() == 0) {
return;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, block.getLocation());
int type = MaterialUtils.getBlockId(blockKey, true);
if (ConfigHandler.isBlacklisted(user) || BlockTypeUtils.isAir(blockKey)) {
return;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, block.getLocation(), CoreProtectPreLogEvent.Action.PLAYER_INTERACTION, LookupActions.INTERACTION, blockType, null, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -47,10 +64,10 @@ public class PlayerInteractLogger {
int y = eventLocation.getBlockY();
int z = eventLocation.getBlockZ();
int data = 0;
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, data, null, null, 2, 0);
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, data, null, blockData, LookupActions.INTERACTION, 0);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -5,7 +5,7 @@ import java.util.Locale;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.entity.EntityType;
import net.coreprotect.CoreProtect;
import net.coreprotect.config.Config;
@@ -13,7 +13,9 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.BlockStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.model.action.LookupActions;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class PlayerKillLogger {
@@ -21,9 +23,9 @@ public class PlayerKillLogger {
throw new IllegalStateException("Database class");
}
public static void log(PreparedStatement preparedStmt, int batchCount, String user, BlockState block, String player) {
public static void log(PreparedStatement preparedStmt, int batchCount, String user, Location location, String player) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
@@ -31,8 +33,8 @@ public class PlayerKillLogger {
UserStatement.loadId(preparedStmt.getConnection(), player, null);
}
Location initialLocation = new Location(block.getWorld(), block.getX(), block.getY(), block.getZ());
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, initialLocation);
Location initialLocation = location.clone();
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, initialLocation, CoreProtectPreLogEvent.Action.PLAYER_KILL, LookupActions.ENTITY_KILL, null, EntityType.PLAYER, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -49,10 +51,10 @@ public class PlayerKillLogger {
int x = eventLocation.getBlockX();
int y = eventLocation.getBlockY();
int z = eventLocation.getBlockZ();
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, 0, playerId, null, null, 3, 0);
BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, 0, playerId, null, null, LookupActions.ENTITY_KILL, 0);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -8,6 +8,7 @@ import org.bukkit.Location;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.SessionStatement;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class PlayerSessionLogger {
@@ -17,7 +18,7 @@ public class PlayerSessionLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, String user, Location location, int time, int action) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
int x = location.getBlockX();
@@ -28,7 +29,7 @@ public class PlayerSessionLogger {
SessionStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, action);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -13,6 +13,7 @@ import net.coreprotect.database.statement.SignStatement;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.event.CoreProtectPreLogEvent;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class SignTextLogger {
@@ -22,11 +23,11 @@ public class SignTextLogger {
public static void log(PreparedStatement preparedStmt, int batchCount, String user, Location location, int action, int color, int colorSecondary, int data, boolean isWaxed, boolean isFront, String line1, String line2, String line3, String line4, String line5, String line6, String line7, String line8, int timeOffset) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location);
CoreProtectPreLogEvent event = new CoreProtectPreLogEvent(user, location, CoreProtectPreLogEvent.Action.SIGN_TEXT, action, null, null, null);
if (Config.getGlobal().API_ENABLED && !Bukkit.isPrimaryThread()) {
CoreProtect.getInstance().getServer().getPluginManager().callEvent(event);
}
@@ -59,7 +60,7 @@ public class SignTextLogger {
SignStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, action, color, colorSecondary, data, isWaxed ? 1 : 0, isFront ? 0 : 1, line1, line2, line3, line4, line5, line6, line7, line8);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -2,7 +2,6 @@ package net.coreprotect.database.logger;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Locale;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
@@ -12,6 +11,7 @@ import net.coreprotect.database.Database;
import net.coreprotect.database.statement.SkullStatement;
import net.coreprotect.paper.PaperAdapter;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.ErrorReporter;
public class SkullBreakLogger {
@@ -21,7 +21,7 @@ public class SkullBreakLogger {
public static void log(PreparedStatement preparedStmt, PreparedStatement preparedStmt2, int batchCount, String user, BlockState block) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null || block == null) {
if (ConfigHandler.isBlacklisted(user) || block == null) {
return;
}
int time = (int) (System.currentTimeMillis() / 1000L);
@@ -30,9 +30,9 @@ public class SkullBreakLogger {
String skullOwner = "";
String skullSkin = null;
int skullKey = 0;
if (skull.hasOwner()) {
skullOwner = PaperAdapter.ADAPTER.getSkullOwner(skull);
skullSkin = PaperAdapter.ADAPTER.getSkullSkin(skull);
skullOwner = PaperAdapter.ADAPTER.getSkullOwner(skull);
skullSkin = PaperAdapter.ADAPTER.getSkullSkin(skull);
if ((skullOwner != null && skullOwner.length() > 0) || (skullSkin != null && skullSkin.length() > 0)) {
ResultSet resultSet = SkullStatement.insert(preparedStmt2, time, skullOwner, skullSkin);
if (Database.hasReturningKeys()) {
resultSet.next();
@@ -50,7 +50,7 @@ public class SkullBreakLogger {
BlockBreakLogger.log(preparedStmt, batchCount, user, block.getLocation(), type, skullKey, null, block.getBlockData().getAsString(), null);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -2,7 +2,6 @@ package net.coreprotect.database.logger;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Locale;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
@@ -12,6 +11,7 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.SkullStatement;
import net.coreprotect.paper.PaperAdapter;
import net.coreprotect.utility.ErrorReporter;
public class SkullPlaceLogger {
@@ -21,7 +21,7 @@ public class SkullPlaceLogger {
public static void log(PreparedStatement preparedStmt, PreparedStatement preparedStmt2, int batchCount, String user, BlockState block, int replaceType, int replaceData) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null || block == null) {
if (ConfigHandler.isBlacklisted(user) || block == null) {
return;
}
int time = (int) (System.currentTimeMillis() / 1000L);
@@ -32,9 +32,9 @@ public class SkullPlaceLogger {
Skull skull = (Skull) block;
String skullOwner = "";
String skullSkin = null;
if (skull.hasOwner()) {
skullOwner = PaperAdapter.ADAPTER.getSkullOwner(skull);
skullSkin = PaperAdapter.ADAPTER.getSkullSkin(skull);
skullOwner = PaperAdapter.ADAPTER.getSkullOwner(skull);
skullSkin = PaperAdapter.ADAPTER.getSkullSkin(skull);
if ((skullOwner != null && skullOwner.length() > 0) || (skullSkin != null && skullSkin.length() > 0)) {
ResultSet resultSet = SkullStatement.insert(preparedStmt2, time, skullOwner, skullSkin);
if (Database.hasReturningKeys()) {
resultSet.next();
@@ -53,7 +53,7 @@ public class SkullPlaceLogger {
BlockPlaceLogger.log(preparedStmt, batchCount, user, block, replaceType, replaceData, type, skullKey, true, null, null, null);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -6,6 +6,7 @@ import java.sql.ResultSet;
import java.util.Locale;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.utility.ErrorReporter;
public class UsernameLogger {
@@ -15,7 +16,7 @@ public class UsernameLogger {
public static void log(Connection connection, String user, String uuid, int configUsernames, int time) {
try {
if (ConfigHandler.blacklist.get(user.toLowerCase(Locale.ROOT)) != null) {
if (ConfigHandler.isBlacklisted(user)) {
return;
}
@@ -92,7 +93,7 @@ public class UsernameLogger {
ConfigHandler.uuidCacheReversed.put(uuid, user);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
}
@@ -6,6 +6,7 @@ import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.*;
import net.coreprotect.utility.ErrorReporter;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.command.CommandSender;
@@ -112,12 +113,10 @@ public class BlockLookup {
target = EntityUtils.getEntityType(resultType).name();
}
else {
Material resultMaterial = MaterialUtils.getType(resultType);
if (resultMaterial == null) {
resultMaterial = Material.AIR;
target = MaterialUtils.getBlockDisplayName(resultType, resultData);
if (target.length() > 0 && !target.contains(":")) {
target = "minecraft:" + target.toLowerCase(Locale.ROOT);
}
target = StringUtils.nameFilter(resultMaterial.name().toLowerCase(Locale.ROOT), resultData);
target = "minecraft:" + target.toLowerCase(Locale.ROOT);
}
if (target.length() > 0) {
target = "" + target + "";
@@ -160,7 +159,7 @@ public class BlockLookup {
ConfigHandler.lookupCommand.put(commandSender.getName(), x + "." + y + "." + z + "." + worldId + ".0." + limit);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return resultText;
}
@@ -21,6 +21,7 @@ import net.coreprotect.utility.ItemUtils;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class ChestTransactionLookup {
@@ -108,13 +109,8 @@ public class ChestTransactionLookup {
rbFormat = Color.STRIKETHROUGH;
}
Material resultMaterial = MaterialUtils.getType(resultType);
if (resultMaterial == null) {
resultMaterial = Material.AIR;
}
String target = resultMaterial.name().toLowerCase(Locale.ROOT);
target = StringUtils.nameFilter(target, resultData);
if (target.length() > 0) {
String target = MaterialUtils.getBlockDisplayName(resultType, resultData);
if (target.length() > 0 && !target.contains(":")) {
target = "minecraft:" + target.toLowerCase(Locale.ROOT) + "";
}
@@ -148,7 +144,7 @@ public class ChestTransactionLookup {
ConfigHandler.lookupCommand.put(commandSender.getName(), x + "." + y + "." + z + "." + worldId + "." + x2 + "." + y2 + "." + z2 + "." + limit);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
@@ -4,7 +4,6 @@ import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Locale;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
@@ -16,8 +15,8 @@ import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.ChatUtils;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils;
import net.coreprotect.utility.ErrorReporter;
public class InteractionLookup {
@@ -96,13 +95,8 @@ public class InteractionLookup {
rbFormat = Color.STRIKETHROUGH;
}
Material resultMaterial = MaterialUtils.getType(resultType);
if (resultMaterial == null) {
resultMaterial = Material.AIR;
}
String target = resultMaterial.name().toLowerCase(Locale.ROOT);
target = StringUtils.nameFilter(target, resultData);
if (target.length() > 0) {
String target = MaterialUtils.getBlockDisplayName(resultType, resultData);
if (target.length() > 0 && !target.contains(":")) {
target = "minecraft:" + target.toLowerCase(Locale.ROOT) + "";
}
@@ -138,7 +132,7 @@ public class InteractionLookup {
ConfigHandler.lookupCommand.put(commandSender.getName(), x + "." + y + "." + z + "." + worldId + ".2." + limit);
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return result;
@@ -7,6 +7,7 @@ import java.util.Locale;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.utility.ErrorReporter;
public class PlayerLookup {
@@ -49,7 +50,7 @@ public class PlayerLookup {
}
}
catch (Exception e) {
e.printStackTrace();
ErrorReporter.report(e);
}
return false;
Loaded 100 of 235 files, more files were not shown because too many files have changed in this diff. Show more