49 Commits
Author SHA1 Message Date
NotAlexNoyle 6441a46542 Exclude CODEOWNERS from language statistics 2026-10-26 12:28:35 -04:00
NotAlexNoyle fa9ea0bbc4 Add CODEOWNERS (one staff approval) 2026-10-26 05:47:04 -04:00
Pheotis 193e4a5d24 Corrected some poorly worded sections of readme. 2021-04-03 23:57:26 -04:00
Thorinwasher e3fc64536e Merge branch 'main' of https://github.com/the-lockedcraft-legacy-organization/ParamnesticCure into main 2021-03-28 12:48:36 +02:00
Thorinwasher 16ca190ee5 fixed something with event priority
also Changed some classnames for clarity
2021-03-28 12:48:20 +02:00
Pheotis ac2a237ea0 Update README.md 2021-03-24 01:49:06 -04:00
Pheotis 06b463f90c Update README.md 2021-03-24 01:09:03 -04:00
Pheotis 6541e7dacf Update README.md 2021-03-24 01:01:23 -04:00
Thorinwasher 885b649dcc Update pom.xml 2021-03-12 20:43:01 +01:00
Thorinwasher e67199137d Unnecessary fancy stuff
Why am I doing this? who knows
2021-03-10 14:15:58 +01:00
Thorinwasher 15b2a12cd1 Update ParamnesticLocation.java 2021-03-08 16:29:19 +01:00
Thorinwasher 2b26b6b569 Update ParamnesticCure.java 2021-03-08 10:18:50 +01:00
Thorinwasher f981a202d0 Update LoggerManager.java 2021-03-07 14:51:51 +01:00
Thorinwasher f1e63c34a2 Language interpretation
Boring
2021-03-07 14:42:14 +01:00
Thorinwasher e244c4a60a Update README.md 2021-03-06 16:47:08 +01:00
Thorinwasher 33aa4a6b4a It's 1.0.0
I should have done this earlier
2021-03-06 16:38:20 +01:00
Thorinwasher c4a8d0cddc Update pom.xml 2021-03-06 16:33:37 +01:00
Thorinwasher a824e1efe0 minor argument interpret improvement
Accidentally wrote wrong once, so I might as well
2021-03-06 16:32:44 +01:00
Thorinwasher 0cf794322f Loads of tweaks
- Added debug method
- Refined rollbacks and restores
-Multiple connections are now used
-Made the code more rigid, which should  ease attempts of expansion
-Fixed a issue where the config.old got deleted to late
2021-03-06 16:23:37 +01:00
Thorinwasher db6fdf2808 Update README.md 2021-03-04 11:37:36 +01:00
Thorinwasher 4fecf0b59c One more setting in config and cleanup
Removed some unnecessary block tracking: Survival blocks should not need to be tracked  in any circumstance.  Removing those functions should result in better performance

Added the wait_time option in the config, as coreprotect was not as consistant as previously thought
2021-03-04 11:28:32 +01:00
Thorinwasher 317cec3f9d Added some comments 2021-02-26 20:07:30 +01:00
Thorinwasher e19f7131f4 Added some clearer information 2021-02-26 16:20:33 +01:00
Thorinwasher c117abbed6 Changed hikari config initialisation
Now loads from a properties file
2021-02-26 15:39:24 +01:00
Thorinwasher 6a031e3ddd Just wrote some descriptions
Also replaced a unnecessary for loop and added a try / catch statement to avoid error messages

This commit is so minor i wont document it
2021-02-25 22:14:58 +01:00
Thorinwasher 32fb98588d Merge branch 'main' of https://github.com/the-lockedcraft-legacy-organization/ParamnesticCure into main 2021-02-25 21:48:39 +01:00
Thorinwasher 98bd6dcc9d A minor refactor
This is kinda irrelevant, but i just moved some classes out of the main folder, as I noticed it was taking to long time to look for classes

Also removed two unused classes
2021-02-25 21:48:11 +01:00
Thorinwasher 5b15d5f484 Update README.md 2021-02-25 21:27:27 +01:00
Thorinwasher f7c6ba06e8 Merge branch 'main' of https://github.com/the-lockedcraft-legacy-organization/ParamnesticCure into main 2021-02-25 21:23:47 +01:00
Thorinwasher 099a82436d Made error/informative messages better 2021-02-25 21:23:45 +01:00
Thorinwasher 7e872d7cbc Update README.md 2021-02-25 11:41:50 +01:00
Thorinwasher 58ab1de049 Improved the partial fix of #10 2021-02-25 11:32:21 +01:00
Thorinwasher 6940173a9a Made rollbacks semiwork for entities
This will look for non block related arguments. And if found make the rollback trigger through paramnestic first, and then the logger (coreprotect)
Should be a semifix for #10
2021-02-24 22:08:00 +01:00
Thorinwasher d20ea07d9e Update README.md 2021-02-24 17:09:15 +01:00
Thorinwasher d28f61d476 Update README.md 2021-02-24 16:53:47 +01:00
Thorinwasher c9256f8da9 Update README.md 2021-02-24 16:52:31 +01:00
Thorinwasher 1ec2962487 Made the intercept event more cancellable 2021-02-24 16:45:03 +01:00
Thorinwasher ceb7dd75ed I think this should 100% solve #15
I apparently ignored restores for any block that had not been rollbacked. As coreprotect does not, Paramnestic should not either

Fixed some logic so that the creative status for blockbreak/ blockplace events get tracked properly
2021-02-24 15:53:00 +01:00
Thorinwasher 96cc2d2fbc Update pom.xml 2021-02-24 15:19:33 +01:00
Thorinwasher acd491a3b3 Nothing here 2021-02-24 15:18:35 +01:00
Thorinwasher 5eb48b19aa Another refactor
Changed the name of commandListener to commandTracker

Moved some methods from LoggerManager to CommandTracker. I think they fit better there
2021-02-24 15:17:26 +01:00
Thorinwasher 326bd81f9a A refactor and a fix?
Changed some names
Delocalised all listeners and split them into 3 different classes

Did something that might help with fixing #15
2021-02-24 15:08:38 +01:00
Thorinwasher 4ad3eead9b Made the plugin smaller
Also fixed an annoying, but harmless bug
2021-02-24 12:46:23 +01:00
Thorinwasher aa5276c816 Update pom.xml 2021-02-24 12:21:34 +01:00
Thorinwasher 03a9a6085d looks better 2021-02-24 12:00:23 +01:00
Thorinwasher 1b83a908ef Added bstats 2021-02-24 11:53:56 +01:00
Thorinwasher 08841ad481 A Refactor and some fixes
Changed config
Removed Cachedata / Databases class
renamed DatabaseCheck to SqlManager

Refactored all code to coincide with the renamed class

Fixed an issue where isMySql Didn't get assigned properly
2021-02-24 11:48:22 +01:00
Pheotis 4953bddbbd Update README.md 2021-02-24 03:19:25 -05:00
Pheotis 5945e0edb9 Merge pull request #14 from the-lockedcraft-legacy-organization/thorin
Merging thorin changes to main.
2021-02-24 03:16:48 -05:00
24 changed files with 1239 additions and 1261 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.gitea/CODEOWNERS linguist-detectable=false
+3
View File
@@ -0,0 +1,3 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
+98 -55
View File
@@ -1,66 +1,73 @@
## ***[PULL REQUESTS](https://github.com/the-lockedcraft-legacy-organization/ParamnesticCure/pulls) WELCOME!***
# Description
A spigot patch to prevent rollbacks from stripping creative block data.
Block Logging Plugins allow admins to restore/revert the blocks of any area to the way they were any point in time.<br />
Unfortunately, when doing this, Loggers do not consider the data Creative Limiter Plugins store.<br />
### Supported Loggers
- https://www.spigotmc.org/resources/coreprotect.8631/
For that reason, **Block Logger Plugins are NOT compatible with Creative Limiter Plugins**!<br />
Specifically, **they can UNPROTECT CREATIVE BLOCKS and MARK SURVIVAL BLOCKS AS CREATIVE**!<br />
### Supported Creative Limiters
- https://www.spigotmc.org/resources/restrictedcreative.42790/
For a technical explanation of the problem, see [this logic chain](https://i.imgur.com/KsChAdh.png).<br />
Note that it can be rather complex as that chain can occur recursively, in any order, and/or at any time.
<br /><br />
**PARAMNESTIC SOLVES THIS INCOMPATIBILITY**!<br />
PC stores the location and status of potential block conflicts in a third database.<br />
PC will then correct detected conflicts using the Logger's and the Limiter's APIs
## Scope
This project is currently a bare-bones patchwork which may or may not be fully featured in future.
### Features
- Blocks removed by a rollback are stripped of their creative data to ensure survival blocks later placed in that spot are not declared as creative.
- Creative data is restored to blocks modified by a rollback.
### Paramnestic Has Support For:
##### Block Loggers:
- [CoreProtect by Intelli](https://www.spigotmc.org/resources/coreprotect.8631/)
##### Creative Limiters
- [RestrictedCreative by Prunt](https://www.spigotmc.org/resources/restrictedcreative.42790/)
> Click [here](https://github.com/the-lockedcraft-legacy-organization/ParamnesticCure/issues/17) for a the list of loggers/limiters that may be supported in the future.
## Background
- This plugin was developed for a temporary collaborative public SMP project
- It was possible to obtain creative mode, which would be used within the context of a survival world.
- Griefing was prohibited by the rules; a block-logger was needed for enforcement.
- RB operations from any and all block loggers interfered with creative block protection, and as such, a temporary solution was needed.
- This is that temporary solution.
- The LCLO was a small (temporary) non-profit that hosted a temporary collaborative SMP event.
1. Players could obtain creative mode within the context of a survival world.
2. As griefing was prohibited by the rules, a block-logger was needed for enforcement.
- RestrictedCreative was used to accomplish `i` and CoreProtect was used to accomplish `ii`
- RC is a limiter plugin and CO is a logger plugin; the two were not compatible.
- This plugin was created to fix that incompatibility.
# Permissions
> This version of the plugin has no permissions, although some may be added in future!
```
pc.* -- Description of a parent node
pc.subnode -- Description of a node
```
## Default Permissions
```
NO PERMISSIONS YET -- Everyone
```
**NOTE: AS THIS WAS MADE FOR A TEMPORARY PROJECT, SUPPORT BEYOND 1.17 IS NOT GUARANTEED**
# Instructions
## Installing:
This plugin is a drag-and-drop; simply put it in the plugins folder of whatever instance is running your creative limiter.
Note that, if your creative logger and/or block logger uses a database, you will need to supply that information in the config.
Also note that Paramnestic requires its own database (to track creative info for risk-prone blocks).
PC is drag-and-drop; drop the jar into the plugins folder of whatever instance is running your logger and limiter.
Note that PC requires a database; by default, it uses SQLite.<br />
If you would like to use a different engine, please specify it in the configuration.<br />
## Usage:
Once PC is installed, simply forget it is there.
Commands sent to the block logger will be intercepted and executed with corrections for incompatibilities.
# Configuration
```
configVersion - Last update of PC that substantially changed the config. Do not change.
creativeManager - The plugin being used to manage creative block states.
blockLogger - The plugin being used to log, and roll back, player block placement.
blockLoggerRollbackCommands - All aliases of any command that can be used to trigger a rollback.
defaultconnection - The database information to be used if nothing is provided under Database_Names
driver - Type of database (options Sqlite, MySQL, or MariaDB)
address - Location of that database
port - Port database can be reached on
user - Username used to connect to database
password - Password used to connect to database
Database_Names - Specific database specifications.
creative - Database being used by your creativeManager
database - Database's name.
{See fields under defaultconnection}
logger - Database being used by your blockLogger
database - Database's name.
{See fields under defaultconnection}
paramestic - Database to be used by this plugin.
database - Database's name.
{See fields under defaultconnection}
On its first installation, Paramnestic will default to a config designed for RestrictedCreative and CoreProtect.<br />
Viewing that default configuration can be very helpful; it can be found [here](https://github.com/the-lockedcraft-legacy-organization/ParamnesticCure/blob/main/src/main/resources/config.yml).
```yaml
configVersion: Last update of PC that substantially changed the config. Please do not change this.
creativeManager: The plugin being used to manage creative block states.
blockLogger: The plugin being used to log, and roll back, player block placement.
blockLoggerRollbackCommands:
alias: All aliases of the rollback logger's primary command
rollback: The prefix before any subcommand which triggers a rollback.
restore: The prefix before any subcommand which triggers a reverse rollback.
undo: The prefix before any subcommand which reverts a rollback or restore function.
purge: The prefix before any subcommand that deletes past server blockdata.
help: The prefix of any subcommand which prints the plugin's command list.
blockLoggerPermissions:
rollback: The permission a mod needs to trigger a rollback.
purge: The permission an admin needs to purge block logger data.
restore: The permission a mod needs to trigger a reverse rollback.
help: The permission a player needs to see a logger's help files.
Database:
driver: The engine being used to run PC's database (valid options Sqlite & Mysql)
address: The IP of paramnestic's database
port: The port of paramnestic's database
databasename: The name of Paramnestic's database
Plugin_settings:
wait_time: The time to between the action and when paramnestic corrects it... higher numbers minimize issues.
debug: Whether or not to spam console with debug info
```
# Changelog
```
@@ -69,10 +76,46 @@ Version 0.0.0
| |_ Feature Release (Adds a new feature)
|_ Milestone Release (Adds a major feature from /ParamnesticCure/milestones )
```
#### [Version 0.4.0] (CURRENT TARGET)
- Fix all readily apparent runtime bugs with PC
- Preliminary testing of PC logic.
#### [Version 0.3.0] (CURRENT RELEASE)
#### [Version 1.0.1]
- Improved language interpretation
- Improved UI messages
- Bumped dependencies
- Rewrote ReadME for release.
- Added metrics.
#### [Version 1.0.0]
- Fixed a stupid sql structure
- Made the logic for rollbacks / restores more rigid
- Improved command interpretation
- Added a debug option
- Code cleanup
#### [Version 0.12.10]
- Uses hikari.properties file as config
- Added the wait_time setting
- Removed unnecessary blocktrackig
#### [Version 0.12.8]
- More formal and clear informational messages
#### [Version 0.12.7]
- Now cancells command intercept if the rollback/restore was for entities
- Better error messages
#### [Version 0.12.6]
- A huge refactor
- Fixed a issue which made sqlite unusable
- Made blocktracking more rigid
- Fixed an issue with restores
- removed the trigger of an annoying errormessage
- Removed unnecessary files
#### [Version 0.12.0]
- Implement SQLite
- Complete and functional logic implementation.
- Fixed alot of issues
- Implements MySQL
- Added undo
- Added purge
- Added Restores
- Added Rollbacks
- Added console commands
- Added command interpretation
#### [Version 0.3.0]
- Implemented the plugin's logic.
#### [Version 0.2.0]
- Outlined the logic needed to accomplish PC's goals.
+19 -7
View File
@@ -3,12 +3,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.mcsmp</groupId>
<artifactId>ParamnesticCure</artifactId>
<version>0.12.0</version>
<version>1.0.1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spigot-version>1.16</spigot-version>
<config-version>8</config-version>
<config-version>12</config-version>
</properties>
<repositories>
<repository>
@@ -31,7 +31,7 @@
<dependency>
<groupId>me.prunt.restrictedcreative</groupId>
<artifactId>RestrictedCreativeAPI</artifactId>
<version>2.4.6</version>
<version>2.4.8</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -49,8 +49,14 @@
<dependency>
<groupId>net.coreprotect</groupId>
<artifactId>CoreProtectAPI</artifactId>
<version>19.4</version>
<version>19.5</version>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>2.2.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>ParamnesticCure-${project.version}</finalName>
@@ -61,6 +67,12 @@
<version>3.2.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<artifactSet>
<includes>
<include>org.bstats:*</include>
<include>com.zaxxer:*</include>
</includes>
</artifactSet>
</configuration>
<executions>
<execution>
@@ -71,9 +83,9 @@
<configuration>
<relocations>
<relocation>
<pattern>org.xerial</pattern>
<shadedPattern>com.mcsmp.xerial</shadedPattern>
</relocation>
<pattern>org.bstats</pattern>
<shadedPattern>com.mcsmp.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
-60
View File
@@ -1,60 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
import com.mcsmp.database.DataBases;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Frostalf
*/
public class CacheData {
private ConcurrentHashMap<String, DataBases> databaseMap = new ConcurrentHashMap<>();
private final ParamnesticCure plugin = ParamnesticCure.getInstance();
private String address = plugin.getConfig().getString("defaultconnection.address");
private int port = plugin.getConfig().getInt("defaultconnection.port");
private String user = plugin.getConfig().getString("user");
private String password = plugin.getConfig().getString("defaultconnection.password");
private String driver = plugin.getConfig().getString("defaultconnection.driver");
private String location = "";
/**
* Method to cache database connections.
*/
public CacheData() {
//TODO simplify this
for (String databases : plugin.getConfig().getConfigurationSection("Database_Names").getKeys(false)) {
if ( !(plugin.getConfig().getString("Database_Names." + databases + ".address").chars().allMatch(Character::isWhitespace))) {
address = plugin.getConfig().getString("Database_Names." + databases + ".address");
}
if ( !(plugin.getConfig().getString("Database_Names." + databases + ".port").chars().allMatch(Character::isWhitespace)) ) {
port = plugin.getConfig().getInt("Database_Names." + databases + ".port");
}
if ( !(plugin.getConfig().getString("Database_Names." + databases + ".user").chars().allMatch(Character::isWhitespace))) {
user = plugin.getConfig().getString("Database_Names." + databases + ".user");
}
if ( !(plugin.getConfig().getString("Database_Names." + databases + ".password").chars().allMatch(Character::isWhitespace))) {
password = plugin.getConfig().getString("Database_Names." + databases + ".password");
}
if ( !(plugin.getConfig().getString("Database_Names." + databases + ".driver").chars().allMatch(Character::isWhitespace))) {
driver = plugin.getConfig().getString("Database_Names." + databases + ".driver");
}
location = plugin.getConfig().getString("Database_Names." + databases + ".location");
DataBases bases = new DataBases(databases.toLowerCase(), plugin.getConfig().getString("Database_Names." + databases + ".database").toLowerCase(), address, port, user, password, driver, location);
databaseMap.put(databases.toLowerCase(), bases);
}
}
/**
* Method to return hashmap of databases.
* @return Hashmap listing databases.
*/
public ConcurrentHashMap<String, DataBases> getDatabaseMap() {
return this.databaseMap;
}
}
+11 -7
View File
@@ -14,7 +14,7 @@ import org.bukkit.entity.Player;
*/
public class MessageManager {
private Player target;
private String prefix = ChatColor.DARK_GRAY + "[" +ChatColor.GRAY + "" + ChatColor.ITALIC + " Paramnestic " + ChatColor.RESET + "" + ChatColor.DARK_GRAY + "] ";
private String prefix = ChatColor.DARK_GRAY + "<" +ChatColor.GRAY + "" + ChatColor.ITALIC + " Paramnestic " + ChatColor.RESET + "" + ChatColor.DARK_GRAY + "> ";
private ChatColor errorColor = ChatColor.RED;
private ChatColor normalColor = ChatColor.WHITE;
@@ -23,18 +23,18 @@ public class MessageManager {
/**
*
* @param player The player that should get the messages
* @param target The player that should get the messages
* @param ini_type What type of process that the message manager is for
*/
MessageManager(Player target,String ini_type){
public MessageManager(Player target,String ini_type){
this(target);
sendMessage("Intercepted a " + ini_type + " command",false) ;
}
/**
*
* @param player The player that should get the messages
* @param target The player that should get the messages
*/
MessageManager(Player target){
public MessageManager(Player target){
if(target != null)
this.target = target;
else
@@ -46,8 +46,12 @@ public class MessageManager {
* @param isError
*/
public void sendMessage(String message, boolean isError) {
if(isConsole)
ParamnesticCure.getInstance().getLogger().info( message );
if(isConsole) {
if(isError)
ParamnesticCure.getInstance().getLogger().warning( message );
else
ParamnesticCure.getInstance().getLogger().info( message );
}
else {
message = ( isError ? errorColor : normalColor) + message;
if (!hasShownLogo) {
+66 -42
View File
@@ -6,6 +6,8 @@
package com.mcsmp;
import java.io.File;
import java.io.IOException;
import static java.lang.Byte.valueOf;
import static java.util.logging.Level.SEVERE;
@@ -14,13 +16,21 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Logger;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.World;
import static org.bukkit.Bukkit.getPluginManager;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import com.mcsmp.block.BlockListener;
import com.mcsmp.commands.CommandListener;
import com.mcsmp.database.SqlManager;
import net.coreprotect.CoreProtect;
import net.coreprotect.CoreProtectAPI;
/**
@@ -34,29 +44,47 @@ import net.coreprotect.CoreProtectAPI;
public class ParamnesticCure extends JavaPlugin {
private static ParamnesticCure instance;
private static boolean isDebug;
private Logger log = Bukkit.getLogger();
private CacheData dataCache;
private Connection connection;
private SqlManager database;
private boolean isMySql;
@Override
public void onEnable() {
//sets instance.
instance = this;
//registers bstats metrics
int pluginId = 10452;
new Metrics(this, pluginId);
this.saveDefaultConfig();
this.getServer().getPluginManager().registerEvents(new ParamnesticCureListener(this), this);
log = getLogger();
PluginManager pluginManager = this.getServer().getPluginManager();
pluginManager.registerEvents(new CommandListener(this), this);
pluginManager.registerEvents(new BlockListener(),this);
pluginManager.registerEvents(new WorldListener(),this);
log = getLogger();
final byte givenVersion = valueOf(getConfig().getString("configVersion"));
//Temporary variable indicating desired config version.
//Should ideally be maven-based, but currently isn't due to a bug.
final byte currentVersion = 8;
final byte currentVersion = 12;
File configVar = new File(getDataFolder(), "config.yml");
//if outdated config, rename old config and install a new one.
// Manages plugins config.
if (givenVersion != currentVersion) {
if (configVar.exists()){
configVar.renameTo(new File(getDataFolder(), "config.old"));
new File(getDataFolder(),"config.old").delete();
configVar.renameTo(new File(getDataFolder(), "config.old"));
}
this.saveDefaultConfig();
log.warning("[Startup] Invalid config! This is either your first time running PC, or, the config has updated since you last used it.");
@@ -65,35 +93,29 @@ public class ParamnesticCure extends JavaPlugin {
} else {
log.info("[Startup] Loaded Config");
//Temporary Warning.
log.warning("[Dev] You have enabled an early development version of this plugin.");
log.warning("[Dev] It will probably be unstable");
}
//Creates new cache
final String driver = getConfig().getString("defaultconnection.driver");
isMySql = (driver.toLowerCase() != "sqlite");
log.info("[Debug] Set driver to " + driver);
//sets instance.
instance = this;
dataCache = new CacheData();
try {
this.connection = getCacheData().getDatabaseMap().get("paramnestic").getDatabase().getConnection();
}
catch(SQLException ex)
{
ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());
getPluginManager().disablePlugin(this);
log.warning("[Dev] You have enabled an development version of this plugin.");
}
//Creates new cache
final String driver = getConfig().getString("Database.driver");
isMySql = !driver.equalsIgnoreCase("sqlite");
log.config("[Startup] Set driver to " + driver);
database = new SqlManager(
getConfig().getString("Database.driver"),
getConfig().getString("Database.address"),
getConfig().getInt("Database.port"),
getConfig().getString("Database.databasename")
);
createDB();
isDebug = getConfig().getBoolean("Plugin_settings.debug");
}
@Override
public void onDisable() {
try {
connection.close();
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
}
/**
@@ -103,14 +125,6 @@ public class ParamnesticCure extends JavaPlugin {
public static ParamnesticCure getInstance() {
return instance;
}
/**
* Gets cached data
* @return Returns dataCache
*/
public CacheData getCacheData() {
return this.dataCache;
}
/**
* Creates all the databases for this plugin, also adds all the worlds to the worlds database (if not done already)
@@ -125,7 +139,9 @@ public class ParamnesticCure extends JavaPlugin {
+ " ,UNIQUE(time,world,x,y,z));"
);
statement.execute();
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
statement.close();
connection.close();
}catch(SQLException ex) {getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
try {
Connection connection = getConnection();
@@ -135,12 +151,14 @@ public class ParamnesticCure extends JavaPlugin {
+ ", world VARCHAR(255), UNIQUE(world) );"
);
statement.execute();
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
statement.close();
connection.close();
}catch(SQLException ex) {getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
List<World> worldlist = ParamnesticCure.getInstance().getServer().getWorlds();
List<World> worldlist = getServer().getWorlds();
for(World world : worldlist) {
WorldManager.addWorldToDB(world);
WorldListener.addWorldToDB(world);
}
}
/**
@@ -172,7 +190,13 @@ public class ParamnesticCure extends JavaPlugin {
* Whether this is a good solution or not, i don't know. But it gives no errors
* @return Return's this plugin's shared connection
*/
public Connection getConnection() {
return connection;
public Connection getConnection() throws SQLException{
return database.getConnection();
}
static public void debug(String location, String message) {
if(isDebug)
instance.getLogger().info(location+"::"+message);
else
instance.getLogger().fine(location+"::"+message);
}
}
@@ -1,151 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.Bisected;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import org.bukkit.event.world.WorldInitEvent;
import me.prunt.restrictedcreative.RestrictedCreativeAPI;
/**
* @author Frostalf
* @author Thorin
*/
/*
* Paramnestic's listener class.
*/
public class ParamnesticCureListener implements Listener {
private ConfigurationSection configSektion;
/*
* Constructor class
* @param plugin Instance of the plugin.
*/
public ParamnesticCureListener(ParamnesticCure plugin) {
//
configSektion = plugin.getConfig().getConfigurationSection("");
}
/**
* Only tracking block break events, as those are the only necessary event that needs to get tracked; All critical actions are blockbreak events (except on rollback rollback)
* @param event BlockBreakEvent
*/
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
//Tracked block checks if the block is creative/critical
boolean isCreative = RestrictedCreativeAPI.isCreative(event.getBlock());
Block block = event.getBlock();
BlockState blockState = block.getState();
ParamnesticCure.getInstance().getServer().getScheduler().runTaskLaterAsynchronously(ParamnesticCure.getInstance(), new Runnable() {
@Override
public void run() {
TrackedBlocks.updateCreativeID(block,isCreative);
/*
* Makes it so that both blocks for doors get updated
*/
if( blockState.getType().toString().contains("DOOR") ) {
Location loc = blockState.getLocation();
Bisected door = (Bisected) blockState.getBlockData();
if(door.getHalf() == Bisected.Half.BOTTOM)
loc = loc.add(0, 1, 0);
else
loc = loc.add(0,-1,0);
TrackedBlocks.updateCreativeID(loc.getBlock(),isCreative);
}
}
},TrackedBlocks.waitPeriod);
}
/**
* Currently not in use. It would be unnecessary to track blockplace event's as blocks can be creative even though no blockplace event occured (for example a piston moving a creative block)
* @param event BlockPlaceEvent
*/
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
}
/**
* Checks for commands that should be intercepted
* @param event Command being processed
*/
@EventHandler
public void commandRollBack(PlayerCommandPreprocessEvent event) {
String command = event.getMessage().toLowerCase();
command = command.replaceAll(": ", ":");
String[] commandListed = command.split(" ");
List<String> commandAlias = configSektion.getStringList("blockLoggerCommands.alias");
int i = 0;
while(i < commandAlias.size()){
//the first string from commandListed will have / in front, all commandAlias should as well:
commandAlias.set( i , "/" + commandAlias.get(i) );
i++;
}
//Unnecessary to process already faulty commands
if(!commandAlias.contains(commandListed[0])||commandListed.length < 2) return;
if(loggerManager.createLoggerManager(commandListed, event.getPlayer().getLocation(),event.getPlayer()))
event.setCancelled(true);
}
/**
* Checks for commands that should be intercepted
* @param event Command being processed
*/
@EventHandler
public void serverCommandRollBack(ServerCommandEvent event) {
//if someone types that alias cancel it.
String command = event.getCommand().toLowerCase();
command = command.replaceAll(": ", ":");
String[] commandListed = command.split(" ");
List<String> commandAlias = configSektion.getStringList("blockLoggerCommands.alias");
if(!commandAlias.contains(commandListed[0])||commandListed.length < 2) return;
if(loggerManager.createLoggerManager(commandListed, null, null));
event.setCancelled(true);
}
/**
* If a world get created, its name needs to get stored in the database. TODO I should also add something that tracks if the world was renamed
* @param event
*/
@EventHandler
public void worldInit(WorldInitEvent event) {
WorldManager.addWorldToDB(event.getWorld());
}
}
-166
View File
@@ -1,166 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import static java.util.logging.Level.SEVERE;
import org.bukkit.block.Block;
import net.coreprotect.CoreProtectAPI;
import net.coreprotect.CoreProtectAPI.ParseResult;
/**
* Consist of all the functions that track the location, the time, and the creative status of critical block actions
* @author Frostalf
* @author Thorin
*/
public class TrackedBlocks {
private static ParamnesticCure plugin = ParamnesticCure.getInstance();
private static CoreProtectAPI coreprotect = plugin.getCoreProtect();
public static long waitPeriod = 50L;
/**
* Checks through the coreprotect database for the most recent block place / remove action. It then calls a function that stores it (if the block fulfils the right criteria)
*
* @param block the block that is going to be inspected
* @param isCreative whether the block was a creative block before the action occurred
*/
public static void updateCreativeID(Block block,boolean isCreative) {
int time = 0;
List<String[]> actiondataMsg = coreprotect.blockLookup(block,0);
for(String[] actionMsg : actiondataMsg) {
ParseResult action = coreprotect.parseResult(actionMsg);
if ( action.getActionId() > 2 ) continue; //has to be block place/break action
time = action.getTime();
break;//The returned data from parseResult seems to be ordered highest time to lowest, this should therefore return the most recent block action
}
updateCreativeID(time,block,isCreative);
}
/**
* Stores the specified action if it was creative, or if there already has been a creative action already on it's location
* @param time The time the action occurred according to coreprotect.
* @param block
* @param isCreative Whether the action had anything to do with a creative block
*/
public static void updateCreativeID(int time, Block block, boolean isCreative)
{
/*
* Avoids duplicate entries, but also irrelevant blocks
*/
int IsInDB = isInDatabase(block,time);
if( !isCreative && ( IsInDB == 0) || IsInDB == 2 ) return;
if(time == 0) { //this should never trigger, but exists as a safety precaution
//ParamnesticCure relies on the loggers for block information, as it takes time for these to process, the thread will have to wait
ParamnesticCure.getInstance().getLogger().warning("A action didn't get tracked properly. Please contact plugin author");
try {Thread.sleep(waitPeriod);}catch(InterruptedException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
waitPeriod *= 2;
updateCreativeID(block,isCreative);
return;
}
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement addToDatabase = connection.prepareStatement(
"INSERT INTO blockAction (time,world,x,y,z,is_creative)"
+ " VALUES (?,?,?,?,?,?);"
);
addToDatabase.setInt( 1, time);
addToDatabase.setInt( 2, WorldManager.getWorldId( block.getWorld().getName() ));
addToDatabase.setInt( 3, block.getX());
addToDatabase.setInt( 4, block.getY());
addToDatabase.setInt( 5, block.getZ());
addToDatabase.setInt( 6, isCreative ? 1 : 0 );
addToDatabase.execute();
//plugin.getLogger().info("[Manual Debug] Added the block action into the database as " + (isCreative ? "creative" : "survival") );
}catch(SQLException ex) {}
}
/**
*
* @param block
* @param time the time of an action
*
* @return Is this block in the database?
* 0 => No.
* 1 => yes, but not this action.
* 2 => yes, this action is already stored.
*/
public static int isInDatabase(Block block, int time) {
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement getCreativeStatus = connection.prepareStatement(
"SELECT time FROM blockAction INNER JOIN worlds"
+ " ON blockAction.world = worlds.world_id"
+ " WHERE world = ? AND x = ? AND y = ? AND z = ?"
);
getCreativeStatus.setString( 1, block.getWorld().getName() );
getCreativeStatus.setInt( 2, block.getX() );
getCreativeStatus.setInt( 3, block.getY() );
getCreativeStatus.setInt( 4, block.getZ() );
ResultSet set = getCreativeStatus.executeQuery();
if(set.next()) {
do{
if( set.getInt(1) == time ) // An action at the same timeperiod exist
return 2;
}while ( set.next() );
return 1; // No replica action was found
}
}
catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
return 0;
}
/**
* Purges all data from the database older than specified time
* @param time
*/
public static void purgeDatabase(int time) {
int oldestDataPoint = Math.round(System.currentTimeMillis()/1000) - time;//seconds
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement addToDatabase = connection.prepareStatement(
"DELETE FROM blockAction"
+ " WHERE time < ?"
);
addToDatabase.setInt( 1, oldestDataPoint);
addToDatabase.execute();
plugin.getLogger().info("[Purge] Purged the ParamnesticCure database");
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
}
}
@@ -11,13 +11,24 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
/**
* Keeps track of every world and changes the paramnestic database accordingly
* @author Thorin
*
*/
public class WorldManager {
public class WorldListener implements Listener {
/**
* If a world get created, its name needs to get stored in the database. TODO I should also add something that tracks if the world was renamed
* @param event
*/
@EventHandler
public void worldInit(WorldInitEvent event) {
WorldListener.addWorldToDB(event.getWorld());
}
/**
* Adds the world to the worlds table, which will assign it an id
* @param world
@@ -31,6 +42,8 @@ public class WorldManager {
);
statement.setString(1, world.getName());
statement.execute();
statement.close();
connection.close();
}catch(SQLException ex) {}
}
/**
@@ -50,7 +63,8 @@ public class WorldManager {
ResultSet set = statement.executeQuery();
if(set.next())
output = set.getInt(1);
statement.close();
connection.close();
}catch(SQLException ex) {}
return output;
}
@@ -0,0 +1,192 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.block;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import static java.util.logging.Level.SEVERE;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.Bisected;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import com.mcsmp.ParamnesticCure;
import com.mcsmp.WorldListener;
import me.prunt.restrictedcreative.RestrictedCreativeAPI;
import net.coreprotect.CoreProtectAPI;
import net.coreprotect.CoreProtectAPI.ParseResult;
/**
* Consist of all the functions that track the location, the time, and the creative status of critical block actions
* @author Frostalf
* @author Thorin
*/
public class BlockListener implements Listener {
private static ParamnesticCure plugin = ParamnesticCure.getInstance();
private static CoreProtectAPI coreprotect = plugin.getCoreProtect();
public static long waitPeriod = plugin.getConfig().getLong("Plugin_settings.wait_time");
/**
* @param event BlockBreakEvent
*/
@EventHandler(ignoreCancelled = true,priority = EventPriority.MONITOR)
public void onBlockBreak(BlockBreakEvent event) {
generalBlockEventTrigger(event.getBlock(),true);
}
/**
* @param event BlockPlaceEvent
*/
@EventHandler(ignoreCancelled = true,priority = EventPriority.MONITOR)
public void onBlockPlace(BlockPlaceEvent event) {
generalBlockEventTrigger(event.getBlock(),false);
}
/**
* Fetches the creative id of the block, also takes care of a door bug
* @param block the block affected
* @param isBlockBreak
*/
private void generalBlockEventTrigger(Block block, boolean isBlockBreak) {
final BlockState blockState = block.getState();
//due to async thread limitations i have to define a variable like this
final boolean extIsCreative = RestrictedCreativeAPI.isCreative(block);
ParamnesticCure.getInstance().getServer().getScheduler().runTaskLaterAsynchronously(ParamnesticCure.getInstance(), new Runnable() {
@Override
public void run() {
boolean isCreative = extIsCreative;
/*
* On blockplace events, it is important to wait a while so that the creative logger has time to register the block
* whilst for blockbreak events, the status before the database updates is sought after.
*/
if(!isBlockBreak)
isCreative = RestrictedCreativeAPI.isCreative(block);
if(!isCreative) return;
BlockListener.updateCreativeID(block,isCreative);
/*
* Makes it so that both blocks for doors get updated
*/
if( blockState.getType().toString().contains("DOOR") ) {
Location loc = blockState.getLocation();
Bisected door = (Bisected) blockState.getBlockData();
if(door.getHalf() == Bisected.Half.BOTTOM)
loc = loc.add(0, 1, 0);
else
loc = loc.add(0,-1,0);
BlockListener.updateCreativeID(loc.getBlock(),isCreative);
}
}
},waitPeriod);
}
/**
* Checks through the coreprotect database for the most recent block place / remove action. It then calls a function that stores it (if the block fulfils the right criteria)
*
* @param block the block that is going to be inspected
* @param isCreative whether the block was a creative block before the action occurred
*/
public static void updateCreativeID(Block block,boolean isCreative) {
int time = 0;
List<String[]> actiondataMsg = coreprotect.blockLookup(block,0);
for(String[] actionMsg : actiondataMsg) {
ParseResult action = coreprotect.parseResult(actionMsg);
plugin.getLogger().finer("[BlockTracker.updateCreativeID] Actionid = " + action.getActionId());
if ( action.getActionId() > 2 ) continue; //has to be block place/break action
time = action.getTime();
break;//The returned data from parseResult seems to be ordered highest time to lowest, this should therefore return the most recent block action
}
updateCreativeID(time,block,isCreative);
}
/**
* Stores the specified action if it was creative, or if there already has been a creative action already on it's location
* @param time The time the action occurred according to coreprotect.
* @param block
* @param isCreative Whether the action had anything to do with a creative block
*/
public static void updateCreativeID(int time, Block block, boolean isCreative)
{
if(time == 0) {
//this should never trigger, but exists as a safety precaution
//ParamnesticCure relies on the loggers for block information, as it takes time for these to process, the thread will have to wait
plugin.getLogger().warning("An action did not get tracked properly, please increase the wait time in Plugin_settings");
plugin.getLogger().info("The wait time will temporarily be doubled, to avoid any further issues in this session");
try {Thread.sleep(waitPeriod);}catch(InterruptedException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
waitPeriod *= 2;
updateCreativeID(block,isCreative);
return;
}
ParamnesticCure.debug("BlockTracker.updateCreativeID"," storing a action at " + block.getWorld().getName() + "," + block.getX() +" "+ block.getY() +" "+ block.getZ() + " time = " + time + (isCreative? "creative":"survival"));
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement statement = connection.prepareStatement(
"INSERT INTO blockAction (time,world,x,y,z,is_creative)"
+ " VALUES (?,?,?,?,?,?);"
);
statement.setInt( 1, time);
statement.setInt( 2, WorldListener.getWorldId( block.getWorld().getName()) );
statement.setInt( 3, block.getX());
statement.setInt( 4, block.getY());
statement.setInt( 5, block.getZ());
statement.setInt( 6, isCreative ? 1 : 0 );
statement.execute();
statement.close();
connection.close();
}catch(SQLException ex) {
ParamnesticCure.debug("BlockTracker.updateCreativeID"," Action has already been stored" );
}
}
/**
* Purges all data from the database older than specified time
* @param time
*/
public static void purgeDatabase(int time) {
int oldestDataPoint = Math.round(System.currentTimeMillis()/1000) - time;//seconds
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement statement = connection.prepareStatement(
"DELETE FROM blockAction"
+ " WHERE time < ?"
);
statement.setInt( 1, oldestDataPoint);
statement.execute();
statement.close();
connection.close();
plugin.getLogger().info("[Purge] Succesfully purged the ParamnesticCure database");
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
}
}
@@ -0,0 +1,393 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.block;
import static java.util.logging.Level.SEVERE;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import com.mcsmp.MessageManager;
import com.mcsmp.ParamnesticCure;
import net.coreprotect.CoreProtectAPI;
/**
* An abstract class with methods that are shared between all loggerManagers, It also consist of some
* methods that are used to create those loggerManagers.
* @author Thorin
*/
public abstract class LoggerManager {
protected CoreProtectAPI coreprotect;
protected int time;
protected List<String> restrict_users;
protected List<String> exclude_users;
protected List<Object> restrict_blocks;
protected List<Object> exclude_blocks;
protected List<Integer> action_list;
protected int radius;
protected Location location;
protected MessageManager msgManager;
protected boolean isCancelled = false;
protected boolean isIntercept = true;
private static ConfigurationSection configSektion = ParamnesticCure.getInstance().getConfig().getConfigurationSection("");
/**
* This function checks if any of the actions has been stored as creative and updates the creative status on that location
* @param actions
*/
protected int changeCreativeStatus(HashMap<ParamnesticLocation,Integer> actions){
int creativeBlockCounter = 0;
for(ParamnesticLocation actionKey: actions.keySet()) {
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement statement = connection.prepareStatement(
"SELECT is_creative FROM blockAction INNER JOIN worlds"
+ " ON blockAction.world = worlds.world_id"
+ " WHERE time = ? AND worlds.world = ? AND x = ? AND y = ? AND z = ?"
+ " ORDER BY time DESC"
);
statement.setInt(1, actions.get(actionKey));
statement.setString(2, actionKey.getWorld().getName());
statement.setInt(3, actionKey.getBlockX());
statement.setInt(4, actionKey.getBlockY());
statement.setInt(5, actionKey.getBlockZ());
ResultSet set = statement.executeQuery();
boolean isCreative = false;
if(set.next())
if(set.getInt(1) == 1) // is_creative == 1 -> action was creative
isCreative = true;
ParamnesticCure.debug("LoggerManager.ChangeCreativeStatus", "Selected location " + actionKey.getWorld().getName() + "," + actionKey.getBlockX() + "," + actionKey.getBlockY() + "," + actionKey.getBlockZ() + ",time=" + actions.get(actionKey));
creativeBlockCounter += actionKey.setCreativeStatus(isCreative);
statement.close();
connection.close();
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
}
return creativeBlockCounter;
}
/**
* Interprets the argument, and assigns values to the proper blocks
* @param arguments : The arguments of the command
* @param location : location where command was thrown
*/
protected void interpretArguments(String[] arguments, Location location) {
boolean checkForWeirdUserInput = false;
for(String argument :arguments) {
argument.replace(" ", "");
if(isCancelled)
break;
if(timeInterpreter(argument))
continue;
if(userInterpreter(argument))
continue;
if(excludeInterpreter(argument))
continue;
if(radiusInterpreter(argument,location))
continue;
if(blockInterpreter(argument))
continue;
if(actionInterpreter(argument))
continue;
if(argument != ""){
if(checkForWeirdUserInput) {
msgManager.sendMessage("Invalid argument, redirecting to logger",true);
isCancelled = true;
isIntercept = false;
return;
}
checkForWeirdUserInput = true;
this.restrict_users = new ArrayList<String>();
this.restrict_users.add(argument);
}
}
}
// ARGUMENT INTERPRETERS
/**
* Checks if it's a time argument, if so assigns a time
* @param argument
* @return true if there was a match
*/
private boolean timeInterpreter(String argument) {
List<String> timeAlias = configSektion.getStringList("blockLoggerCommands.arguments.time");
argument = checkAndTrimArgument(argument,timeAlias);
if(argument != "") {
long time = 0;//s
//might as well, right?
argument.replaceAll("seconds|second|sec", "s").replaceAll("minute|min","m").replaceAll("hours|hour", "h").replaceAll("days|day", "d").replaceAll("weeks|week", "w");
String[] splitedArgument = argument.split("(?<=[w*d*h*m*s])");
//convert to seconds
try {
for(String part : splitedArgument) {
if(part.contains("w")){
time += 604800 * Double.parseDouble(part.substring( 0 , part.indexOf('w') ));
continue;
}
if(part.contains("d")){
time += 86400 * Double.parseDouble(part.substring( 0 , part.indexOf('d') ));
continue;
}
if(part.contains("h")){
time += 3600 * Double.parseDouble(part.substring( 0 , part.indexOf('h') ));
continue;
}
if(part.contains("m")){
time += 60 * Double.parseDouble(part.substring( 0 , part.indexOf('m') ));
continue;
}
if(part.contains("s")){
time += Double.parseDouble(part.substring( 0 , part.indexOf('s') ));
continue;
}
//this is another way to specify seconds in Coreprotect
time += Double.parseDouble(part);
}
}catch(NumberFormatException e) {
msgManager.sendMessage("Invalid timeargument", true);
isCancelled = true;
}
this.time = Math.round(time);
return true;
}
return false;
}
/**
* Checks if it's a user argument, if so assigns a list of all the users
* @param argument
* @return true if there was a match
*/
private boolean userInterpreter(String argument) {
List<String> userAlias = configSektion.getStringList("blockLoggerCommands.arguments.user");
argument = checkAndTrimArgument(argument,userAlias);
if(argument != "") {
this.restrict_users = new ArrayList<String>();
String[] argumentSplited = argument.split(",");
for(String part : argumentSplited) {
this.restrict_users.add(part);
}
return true;
}
return false;
}
/**
* Checks if it's a exclude blocks argument, if so assigns a list of all the blocks that should be excluded
* @param argument
* @return true if there was a match
*/
private boolean excludeInterpreter(String argument) {
List<String> excludeAlias = configSektion.getStringList("blockLoggerCommands.arguments.exclude");
argument = checkAndTrimArgument(argument,excludeAlias);
if(argument != "") {
exclude_blocks = blockStringListToBlockList(argument);
return true;
}
return false;
}
/**
* Checks if it's a block argument, if so assigns a list of all the blocks that should be selected
* @return true if there was a match
*/
private boolean blockInterpreter(String argument) {
List<String> blockAlias = configSektion.getStringList("blockLoggerCommands.arguments.block");
argument = checkAndTrimArgument(argument,blockAlias);
if(argument != "") {
restrict_blocks = blockStringListToBlockList(argument);
return true;
}
return false;
}
/**
* This should (ehm ehm) be able to convert argument into a list of blockdata
* @param argument
* @return A list with blockdatatypes
*/
private List<Object> blockStringListToBlockList(String argument){
List<Object> tempBlockList = new ArrayList<Object>();
if(argument.chars().allMatch(Character::isWhitespace))
return tempBlockList;
String[] argumentSplited = argument.split(",");
for(String part : argumentSplited) {
try {
tempBlockList.add( Bukkit.createBlockData(part) );
}catch(Exception e) {
isIntercept = false;
}
}
if(tempBlockList.size() == 0) {
if(isIntercept)
msgManager.sendMessage("No block specified", true);
else{
msgManager.sendMessage("Entity selection has not yet been implemented",true);
msgManager.sendMessage("Cancelling intercept...",false);
}
isCancelled = true;
}
else if(!isIntercept){
msgManager.sendMessage("Entity selection has not yet been implemented",true);
msgManager.sendMessage("Cancelling intercept, paramnestic will still trigger...",false);
}
return tempBlockList;
}
/**
* Checks if it's a radius argument, if so assigns radius and location of command
* @param argument
* @param radius_location the location where the command was issued, null => console
* @return true if there was a match
*/
private boolean radiusInterpreter(String argument,Location location) {
List<String> radiusAlias = configSektion.getStringList("blockLoggerCommands.arguments.radius");
argument = checkAndTrimArgument(argument,radiusAlias);
if(argument != "") {
if(location == null) {
msgManager.sendMessage("You can't use the radius argument from console",true);
isCancelled = true;
}
else {
try {
this.radius = Integer.parseInt(argument);
this.location = location;
}catch(Exception e) {
msgManager.sendMessage("Invalid radius", true);
isCancelled = true;
}
}
return true;
}
return false;
}
/**
* Checks if its a action argument, translates the actions into integer and puts them into a list of actions
* @param argument
* @return true if there was a match
*/
private boolean actionInterpreter(String argument) {
List<String> actionAlias = configSektion.getStringList("blockLoggerCommands.arguments.action");
argument = checkAndTrimArgument(argument,actionAlias);
if(argument != "") {
this.action_list = new ArrayList<Integer>();
String[] argumentSplited = argument.split(",");
for(String actionArgument : argumentSplited) {
if(actionArgument.chars().allMatch(Character::isWhitespace))
break;
action_list.addAll(actionToInt(actionArgument));
}
if(isCancelled) {
if(isIntercept)
msgManager.sendMessage("No action specified", true);
else {
msgManager.sendMessage("Entity action selection not implemented yet",true);
msgManager.sendMessage("Cancelling intercept...",false);
}
}
return true;
}
return false;
}
/**
* As of now, the only known action integers are block remove, block place and block interaction (0,1,2).
* This just looks if its a block action, and with some hefty logic (if I say so myself) assigns the corresponding integers:
* block (0,1), +block(1), -block(0). Default value is 2
* @param action
* @return a list off all the actions that this part of the argument implied
*/
private List<Integer> actionToInt(String action) {
//TODO make this fit better with coreprotect logic
List<Integer> output = new ArrayList<Integer>();
if(action.contains("block"))
{
if(!action.contains("-"))
output.add(1);//place action
if(!action.contains("+"))
output.add(0);//remove action
}
else if(action.chars().allMatch(Character::isWhitespace)) {
isCancelled = true;
}
else {
isIntercept = false;
isCancelled = true;
}
return output;
}
/**
* A function used in command processing, checks if the argument contains any alias and return the argument without its alias
* @param argument
* @param aliases
* @return The argument without alias, or "" if there was no match
*/
private String checkAndTrimArgument(String argument,List<String> aliases) {
Matcher matcher;
Pattern pattern = null;
for(String alias : aliases) {
pattern = Pattern.compile("^" + alias + ":");
matcher = pattern.matcher(argument);
if(matcher.find()) {
return matcher.replaceAll("");
}
}
return "";
}
/**
* This function is shared between restores and rollbacks
*/
abstract boolean executeTask();
/**
* @return the interpreted time
*/
public int getTime() {
return time;
}
}
@@ -0,0 +1,77 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.block;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import com.mcsmp.ParamnesticCure;
import me.prunt.restrictedcreative.RestrictedCreativeAPI;
/**
* This is mainly a class of convenience, just adds a creative status to a location (which can later be used handily in a hashmap)
* @author Thorin
*/
public class ParamnesticLocation extends Location{
//This is needed for the current rollback / restore algorithm to work properly:
// - When a block place action gets rollbacked it is always going to rollback to a survival block (air)
// - When a block break action gets restored it is always going to restore to a survival block (air)
private boolean canBeCreative = false;
/**
*
* @param worldname
* @param x
* @param y
* @param z
* @param canBeCreative If this location can have a creative status
*/
public ParamnesticLocation(String worldname, int x, int y, int z,boolean canBeCreative) {
super(Bukkit.getWorld(worldname),x,y,z);
this.canBeCreative = canBeCreative;
}
/**
* As i don't care if the canBeCreative status is the same for the to objects in an equals statement, I will redefine it
*/
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if (!(obj instanceof ParamnesticLocation)) {
return false;
} else {
ParamnesticLocation that = (ParamnesticLocation)obj;
return super.equals(that.clone());
}
}
/**
* As I redefined the equals method, I have to change this function. The equals and hashCode method are closely interlinked.
*/
@Override
public int hashCode() {
return super.hashCode();
}
/**
* Changes the creative status in restrictedcreative, but also internally
* @param isCreative
*/
public int setCreativeStatus(boolean isCreative) {
isCreative = canBeCreative && isCreative;
ParamnesticCure.debug("ParamnesticLocation.setCreativeStatus","Setting creative status as " + (isCreative?"creative":"survival"));
Block block = getBlock();
if(isCreative) {
RestrictedCreativeAPI.add(block);
}
else {
RestrictedCreativeAPI.remove(block);
}
return isCreative?1:0;
}
}
@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
package com.mcsmp.block;
import java.util.HashMap;
@@ -11,6 +11,9 @@ import java.util.List;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import com.mcsmp.MessageManager;
import com.mcsmp.ParamnesticCure;
import net.coreprotect.CoreProtectAPI.ParseResult;
/**
* Does a series of logical operations to minimise opportunities for restores to mess with creative block data.
@@ -18,18 +21,18 @@ import net.coreprotect.CoreProtectAPI.ParseResult;
*
* @author Thorin
*/
public class RestoreManager extends loggerManager {
public class RestoreManager extends LoggerManager {
/**
* Constructor for RestoreManager
* @param arguments : The arguments of the command
* @param radius_location : location where command was thrown
* @param location : location where command was thrown
*/
public RestoreManager(String[] arguments, Location radius_location,Player player) {
public RestoreManager(String[] arguments, Location location,Player player) {
this.msgManager = new MessageManager(player,"Restore");
this.coreprotect = ParamnesticCure.getInstance().getCoreProtect();
interpretArguments(arguments,radius_location);
interpretArguments(arguments,location);
}
/**
@@ -39,23 +42,23 @@ public class RestoreManager extends loggerManager {
*
* It then checks through all the returned values, and selects the most recent action on every location,
* To then call the changeCreativeStatus function on that action
*
* @return true if this should cancel the event
*/
@Override
public void executeTask() {
public boolean executeTask() {
if(isCancelled)
return isIntercept;
ParamnesticCure.getInstance().getServer().getScheduler().runTaskLaterAsynchronously(ParamnesticCure.getInstance(), new Runnable() {
@Override
public void run() {
long startTime = System.nanoTime();
long startTime = System.currentTimeMillis();
//perform a restore and get a list of the actions specified
List<String[]> blockActionListMSG = coreprotect.performRestore(
time,restrict_users, exclude_users, restrict_blocks, exclude_blocks,action_list, radius, radius_location
time,restrict_users, exclude_users, restrict_blocks, exclude_blocks,action_list, radius, location
);
long endTime = System.nanoTime();
msgManager.sendMessage( "Operationall time: " + String.valueOf( (endTime-startTime)*Math.pow(10, -9) ) , false);
if(blockActionListMSG.size() == 0) {
@@ -65,43 +68,36 @@ public class RestoreManager extends loggerManager {
HashMap<String,Integer> blocks_to_be_changed = new HashMap<String,Integer>();
Integer creativeBlockCounter = 0;
HashMap<ParamnesticLocation,Integer> blocks_to_be_changed = new HashMap<ParamnesticLocation,Integer>();
//Go through every action
for(String[] parseMSG : blockActionListMSG) {
ParseResult blockAction = coreprotect.parseResult(parseMSG);
int newestTime = blockAction.getTime();
if(!blockAction.isRolledBack()) continue;
int x = blockAction.getX(); int y = blockAction.getY(); int z = blockAction.getZ();
int newestTime = blockAction.getTime(); String worldname = blockAction.worldName();
String compareKey = String.valueOf(x) + "," + String.valueOf(y) + "," + String.valueOf(z) + worldname;
if(blocks_to_be_changed.containsKey(compareKey))
//Block can only be creative if blockAction.getActionId == 1 (block place)
ParamnesticLocation compareKey = new ParamnesticLocation( blockAction.worldName() , blockAction.getX() , blockAction.getY() ,blockAction.getZ() , blockAction.getActionId() == 1);
//Only the most recent action on every location should be selected
if(blocks_to_be_changed.containsKey(compareKey))
if(blocks_to_be_changed.get(compareKey) > newestTime)
continue;
blocks_to_be_changed.put( compareKey , newestTime );
boolean isCreative = fetchDBIsCreative(newestTime,worldname,x,y,z);
if(blockAction.getActionId() == 0) //Any blockbreak action will result in a survival block (air block)
isCreative = false;
creativeBlockCounter += isCreative? 1 : 0;
changeCreativeStatus(x,y,z,worldname,isCreative);
blocks_to_be_changed.put( compareKey , newestTime );
}
msgManager.sendMessage( String.valueOf(blockActionListMSG.size()) + " block actions were found, " + String.valueOf( blocks_to_be_changed.size() ) + " Blocks were set", false);
msgManager.sendMessage(creativeBlockCounter.toString() + " blocks were set to creative", false);
Integer creativeBlockCounter = changeCreativeStatus(blocks_to_be_changed);
long endTime = System.currentTimeMillis();
msgManager.sendMessage( "Operational time: " + String.valueOf( endTime-startTime ) + "ms" , false);
msgManager.sendMessage( String.valueOf(blockActionListMSG.size()) + " block "+ "action"+ (blockActionListMSG.size() == 1?"":"s") +" were found, " + String.valueOf( blocks_to_be_changed.size() ) + " Block"+ (blocks_to_be_changed.size() == 1?"":"s") + " were set"
, false);
msgManager.sendMessage(creativeBlockCounter.toString() + " Block"+ (creativeBlockCounter == 1?"":"s") +" were set to creative", false);
}
},60L);
return isIntercept;
}
}
@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
package com.mcsmp.block;
@@ -11,9 +11,13 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import net.coreprotect.CoreProtectAPI.ParseResult;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import com.mcsmp.MessageManager;
import com.mcsmp.ParamnesticCure;
/**
* Does a series of logical operations to minimise opportunities for rollblacks to mess with creative block data.
* Note that this does not include rollback interference with inventories!
@@ -21,7 +25,7 @@ import org.bukkit.entity.Player;
* @author InteriorCamping
* @author Thorin
*/
public class RollbackManager extends loggerManager{
public class RollbackManager extends LoggerManager{
/**
* Constructor for RollbackManager
@@ -44,65 +48,68 @@ public class RollbackManager extends loggerManager{
*
* It then checks through all the returned values, and selects the oldest action on every location,
* To then call the changeCreativeStatus function on that action
* @return true if this should cancel the event
*/
@Override
public void executeTask() {
ParamnesticCure.getInstance().getServer().getScheduler().runTaskLaterAsynchronously(ParamnesticCure.getInstance(), new Runnable() {
public boolean executeTask() {
if(isCancelled)
return isIntercept;
ParamnesticCure.getInstance().getServer().getScheduler().runTaskAsynchronously(ParamnesticCure.getInstance(), new Runnable() {
@Override
public void run() {
long startTime = System.nanoTime(); //nano Seconds
long startTime = System.currentTimeMillis(); //nano Seconds
List<String[]> blockActionListMSG = new ArrayList<String[]>();
//perform a rollback and get a list of the actions specified
blockActionListMSG = coreprotect.performRollback(
time,restrict_users, exclude_users, restrict_blocks, exclude_blocks,action_list, radius, radius_location
time,restrict_users, exclude_users, restrict_blocks, exclude_blocks,action_list, radius, location
);
long endTime = System.nanoTime();
msgManager.sendMessage( "Operationall time: " + String.valueOf( (endTime-startTime)*Math.pow(10, -9) ) , false);
if(blockActionListMSG.size() == 0) {
msgManager.sendMessage("No actions were found",true);
return;
}
HashMap<String,Integer> blocks_to_be_changed = new HashMap<String,Integer>();
Integer creativeBlockCounter = 0;
HashMap<ParamnesticLocation,Integer> blocks_to_be_changed = new HashMap<ParamnesticLocation,Integer>();
//Go through every action
for(int i = blockActionListMSG.size()-1; i >= 0; i--){//cycles through the list backwards (should be slightly less costly)
ParseResult blockAction = coreprotect.parseResult(blockActionListMSG.get(i));
String worldname = blockAction.worldName();
int oldestTime = blockAction.getTime();
int x = blockAction.getX(); int y = blockAction.getY(); int z = blockAction.getZ();
String compareKey = String.valueOf(x) + "," + String.valueOf(y) + "," + String.valueOf(z) + worldname;
//Block can only be creative if blockAction.getActionId == 0 (block break)
ParamnesticLocation compareKey = new ParamnesticLocation( blockAction.worldName() , blockAction.getX() , blockAction.getY() ,blockAction.getZ() , blockAction.getActionId() == 0);
//Only the oldest action on every location should be selected
if(blocks_to_be_changed.containsKey(compareKey))
if(blocks_to_be_changed.get(compareKey) < oldestTime)
continue;
blocks_to_be_changed.put( compareKey , oldestTime );
boolean isCreative = fetchDBIsCreative(oldestTime,worldname,x,y,z);
if (blockAction.getActionId() == 1)
isCreative = false; //When a creative block place action is rollbacked, it will get removed. An airblock must have been before this action, which is survival
creativeBlockCounter += isCreative ? 1 : 0;
changeCreativeStatus(x,y,z,worldname,isCreative);
blocks_to_be_changed.put( compareKey , oldestTime );
}
msgManager.sendMessage( String.valueOf(blockActionListMSG.size()) + " block actions were found, " + String.valueOf( blocks_to_be_changed.size() ) + " Blocks were set", false);
msgManager.sendMessage(creativeBlockCounter.toString() + " blocks were set to creative", false);
Integer creativeBlockCounter = changeCreativeStatus(blocks_to_be_changed);
long endTime = System.currentTimeMillis();
msgManager.sendMessage( "Operational time: " + String.valueOf( endTime-startTime ) + "ms", false);
msgManager.sendMessage(
String.valueOf(blockActionListMSG.size()) + " block "+ "action"+ (blockActionListMSG.size() == 1?"":"s") +" were found, " + String.valueOf( blocks_to_be_changed.size() ) + " Block"+ (blocks_to_be_changed.size() == 1?"":"s") + " were set"
, false);
msgManager.sendMessage(creativeBlockCounter.toString() + " Block"+ (creativeBlockCounter == 1?"":"s")+" were set to creative", false);
}
},60L);
});
return isIntercept;
}
}
@@ -0,0 +1,230 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.commands;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import com.mcsmp.MessageManager;
import com.mcsmp.ParamnesticCure;
import com.mcsmp.block.BlockListener;
import com.mcsmp.block.RestoreManager;
import com.mcsmp.block.RollbackManager;
/**
* Tracks commands, and checks whether they should be intercepted
* @author Frostalf
* @author Thorin
*/
public class CommandListener implements Listener {
private static HashMap<String,String[]> storedCommands = new HashMap<String,String[]>();
private ConfigurationSection configSektion;
/*
* Constructor class
* @param plugin Instance of the plugin.
*/
public CommandListener(ParamnesticCure plugin) {
//
configSektion = plugin.getConfig().getConfigurationSection("");
}
//EVENT HANDLERS
/**
* Checks for commands that should be intercepted
* @param event Command being processed
*/
@EventHandler
public void playerCommand(PlayerCommandPreprocessEvent event) {
String command = event.getMessage().toLowerCase();
command = command.replaceAll(": ", ":");
String[] commandListed = command.split(" ");
List<String> commandAlias = configSektion.getStringList("blockLoggerCommands.alias");
int i = 0;
while(i < commandAlias.size()){
//the first string from commandListed will have / in front, all commandAlias should as well:
commandAlias.set( i , "/" + commandAlias.get(i) );
i++;
}
//Unnecessary to process already faulty commands
if(!commandAlias.contains(commandListed[0])||commandListed.length < 2) return;
if(createLoggerManager(commandListed, event.getPlayer().getLocation(),event.getPlayer()))
event.setCancelled(true);
else
ParamnesticCure.getInstance().getLogger().fine("[CommandTracker.playerComand] intercept cancelled");
}
/**
* Checks for commands that should be intercepted
* @param event Command being processed
*/
@EventHandler
public void serverCommand(ServerCommandEvent event) {
//if someone types that alias cancel it.
String command = event.getCommand().toLowerCase();
command = command.replaceAll(": ", ":");
String[] commandListed = command.split(" ");
List<String> commandAlias = configSektion.getStringList("blockLoggerCommands.alias");
if(!commandAlias.contains(commandListed[0])||commandListed.length < 2) return;
if(createLoggerManager(commandListed, null, null));
event.setCancelled(true);
}
//INTERNAL FUNCTIONS
/**
* Interprets a part of the command to see if a rollback,restore,undo, or purge should be created
* also does some relevant setup for those commands
* @param command The arguments after the logger alias
* @param location Location of the player (can be null)
* @param playerOperator the player who initiated the command
* @return true if command event should be cancelled
*/
private boolean createLoggerManager(String[] command, Location location, Player playerOperator) {
String operator = (playerOperator == null) ? null : playerOperator.getName();
List<String> rollbackAlias = configSektion.getStringList("blockLoggerCommands.rollback");
String[] arguments = Arrays.copyOfRange(command, 2, command.length);
if(rollbackAlias.contains(command[1])) {
if(!PermissionManager.hasRollback(playerOperator)) return false;
RollbackManager rollback = new RollbackManager( arguments , location , playerOperator);
if(!rollback.executeTask()) {
ParamnesticCure.getInstance().getLogger().finest("[CommandTracker.createLoggerManager] this function is going to return false");
return false;
}
storeCommand(operator,command);
return true;
}
List<String> restoreAlias = configSektion.getStringList("blockLoggerCommands.restore");
if(restoreAlias.contains(command[1])) {
if(!PermissionManager.hasRestore(playerOperator)) return false;
RestoreManager restore = new RestoreManager( arguments, location , playerOperator );
if(!restore.executeTask())
return false;
storeCommand(operator,command);
return true;
}
List<String> undoAlias = configSektion.getStringList("blockLoggerCommands.undo");
if(undoAlias.contains(command[1])) {
if(!(PermissionManager.hasRollback(playerOperator)&&PermissionManager.hasRestore(playerOperator))) return false;
//TODO make better undo's, that store location and takes time into consideration
String player = operator;
if(command.length == 3)
player = command[2];
else if(command.length > 3) {
return false;
}
if (undoCommand(player, operator, location))
return true;
}
List<String> purgeAlias = configSektion.getStringList("blockLoggerCommands.purge");
if(purgeAlias.contains(command[1])) {
if(!PermissionManager.hasPurge(playerOperator)) return false;
if(command.length > 3) {
new MessageManager(playerOperator).sendMessage("Invalid argument " + command[1], true);
return true;
}
//don't look here, this is stupid
String[] temp = {command[2]};
int time = (new RollbackManager(temp,null,null)).getTime();
BlockListener.purgeDatabase(time);
}
List<String> helpAlias = configSektion.getStringList("blockLoggerCommands.help");
if(helpAlias.contains(command[1]) && PermissionManager.hasHelp(playerOperator)) {
//don't know if this is necessary
}
return false;
}
/**
* This stores commands for the undo command
* @param operator the player who initiated the command
* @param command the type of logger command that was used
* @param arguments the arguments of that command
*/
private void storeCommand(String operator, String[] commandListed) {
String command = "";
for(String argument:commandListed) command = command+" " + argument;
storedCommands.put(operator, commandListed);
}
/**
* This is the main logic done to convert a command to it's opposite, to then call the
* createLoggerManager with the newly created command.
*
* This approximately undoes the previous command.
* @param player the player which command should be undone
* @param operator the player that initiated the command
* @return true if successful
*/
private boolean undoCommand(String player,String operator,Location location) {
ConfigurationSection configSektion = ParamnesticCure.getInstance().getConfig().getConfigurationSection("");
if(storedCommands.containsKey(player)) {
String[] commandListed = storedCommands.get(player);
List<String> rbAlias = configSektion.getStringList("blockLoggerCommands.rollback");
List<String> reAlias = configSektion.getStringList("blockLoggerCommands.restore");
if(rbAlias.contains(commandListed[1]))
commandListed[1] = reAlias.get(0);
else
commandListed[1] = rbAlias.get(0);
String command = "";
for(String argument:commandListed) command = command+" " + argument;
Player playerPlayer = Bukkit.getServer().getPlayer(player);
//if the createLoggerManager does take the command as intercept
if(!createLoggerManager(commandListed, location, playerPlayer))
return false;
storeCommand(operator,commandListed);
return true;
}
Player playerOperator = (operator == null)? null : Bukkit.getServer().getPlayer(operator);
new MessageManager(playerOperator).sendMessage("Could not find the user " + player,true);
return false;
}
}
@@ -1,15 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.commands;
/**
* @author Frostalf
*/
public class CommandManager {
}
@@ -3,10 +3,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
package com.mcsmp.commands;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import com.mcsmp.ParamnesticCure;
/**
* We all know what this does
* @author Thorin
@@ -1,15 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.commands;
/**
* @author Frostalf
*/
public class reloadCommand {
}
@@ -1,133 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp.database;
import java.net.InetAddress;
import static java.net.InetAddress.getByName;
import java.net.UnknownHostException;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Frostalf
*/
public class DataBases {
private String name;
private String databaseName;
private String address;
private int port;
private String user;
private String password;
private String driver;
private DatabaseCheck databaseConnection;
private String location;
/**
* Connects to a certain database.
* @param name Name of the plugin this database pertains to.
* @param databaseName Name of the database being checked.
* @param address Address of the database being checked.
* @param port Port on which to communicate with the database being checked.
* @param user User to use when communicating with the database.
* @param password Password to be used when communicating with the database as provided user.
* @param driver Driver to use for this database communication.
* @param location db file location.
*/
public DataBases(String name, String databaseName, String address, int port, String user, String password, String driver, String location) {
this.name = name;
this.databaseName = databaseName;
this.address = address;
this.port = port;
this.user = user;
this.password = password;
this.driver = driver.toLowerCase();
this.location = location;
this.databaseConnection = new DatabaseCheck(name, databaseName, address, port, user, password, driver, location);
}
/**
*
* @return Config name of database.
*/
public String getConfigName() {
return this.name;
}
/**
* Checks status of database being interacted with.
* @return Name of database in question.
*/
public String getDatabaseName() {
return this.databaseName;
}
/**
* Checks status of database being interacted with.
* @return Address of database in question.
* @throws java.net.UnknownHostException if the host being connected to is unknown.
*/
public InetAddress getAddress() throws UnknownHostException {
return getByName(this.address);
}
/**
* Checks status of database being interacted with.
* @return Port of database in question.
*/
public Integer getPort() {
return this.port;
}
/**
* Checks status of database being interacted with.
* @return User of database in question.
*/
public String getUser() {
return this.user;
}
/**
* Checks status of database being interacted with.
* @return Password of database in question.
*/
public String getPassword() {
return this.password;
}
/**
* Checks status of database being interacted with.
* @return Driver being used for connection.
*/
public String getDriver() {
return driver;
}
/**
* Check database connection.
* @return Current database connection.
*/
//public Connection getConnection() throws SQLException {
// return this.databaseConnection.getConnection();
//}
public DatabaseCheck getDatabase() {
return this.databaseConnection;
}
/**
* Queries the current database.
* @param query SQL query expression.
* @return returns the results of the SQL query.
* @throws java.sql.SQLException any error with the sql query
*/
public ResultSet getResults(String query) throws SQLException {
return this.databaseConnection.getConnection().createStatement().executeQuery(query);
}
}
@@ -11,6 +11,8 @@ import com.mcsmp.ParamnesticCure;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import static org.bukkit.Bukkit.getPluginManager;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -18,62 +20,51 @@ import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Frostalf
* @author Thorin
*/
public class DatabaseCheck {
public class SqlManager {
private HikariDataSource boneCP;
private Connection connection;
private HikariConfig config = null;
private ParamnesticCure plugin = ParamnesticCure.getInstance();
private String database;
private String address;
private int port;
private String user;
private String password;
private String driver;
private final String database;
private final String address;
private final int port;
private final String driver;
private String url;
private boolean mysql = false;
private String location;
private final boolean mysql;
/**
* Caches and checks the status of a certain database..
* @param name Name of the plugin this database pertains to.
* @param database Name of the database being checked.
* @param driver Driver to use for this database communication.
* @param address Address of the database being checked.
* @param port Port on which to communicate with the database being checked.
* @param user User to use when communicating with the database.
* @param password Password to be used when communicating with the database as provided user.
* @param driver Driver to use for this database communication.
* @param location location of db file.
* @param database Name of the database being checked.
*/
public DatabaseCheck(String name, String database, String address, int port, String user, String password, String driver, String location) {
this.location = location;
public SqlManager(String driver, String address, int port, String database) {
this.database = database;
this.address = address;
this.port = port;
if(user == null || user.chars().allMatch(Character::isWhitespace)) {
this.user = "default";
} else {
this.user = user;
}
this.password = password;
this.driver = setDriver(driver).toString();
this.port = port;
this.address = address;
if(getDriver() == DriverEnum.SQLITE) {
try {
setupSQLITE(location);
setupSQLITE();
} catch (SQLException ex) {
Logger.getLogger(DatabaseCheck.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(SqlManager.class.getName()).log(Level.SEVERE, null, ex);
}
mysql = false;
} else {
mysql = true;
try {
setupMySQL();
} catch (SQLException ex) {
Logger.getLogger(DatabaseCheck.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(SqlManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
@@ -91,7 +82,7 @@ public class DatabaseCheck {
if (mysql) {
return connection = this.boneCP.getConnection();
}
plugin.getLogger().log(Level.INFO, "{0} {1} {2}", new Object[]{this.url, this.user, this.database, this.connection.toString()});
plugin.getLogger().log(Level.INFO, "{0} {1} {2}", new Object[]{this.url, this.database, this.connection.toString()});
return this.connection;
}
@@ -112,17 +103,24 @@ public class DatabaseCheck {
}
private void setupMySQL() throws SQLException {
final int MAXCONNECT = 20;
this.config = new HikariConfig();
this.config.setMaximumPoolSize(MAXCONNECT);
this.config.setUsername(this.user);
this.config.setPassword(this.password);
ParamnesticCure.getInstance().getLogger().info("[DatabaseCheck.setupMySQL] Values: " + this.driver + "," + this.address + "," + this.port + "," + this.database);
//Creates a properties file if it doesn't exist
if ( !new File(plugin.getDataFolder(), "hikari.properties").exists() ) {
plugin.getLogger().warning("[Startup] hikari.properties file is missing.");
plugin.getLogger().info("Providing you with a new properties file");
plugin.getDataFolder().mkdirs();
plugin.saveResource("hikari.properties", true);
getPluginManager().disablePlugin(plugin);
}
//creates a config based on the properties file
this.config = new HikariConfig(plugin.getDataFolder()+"/hikari.properties");
config.setJdbcUrl("jdbc:"+ this.driver +"://" + this.address + ":" + this.port + "/" + this.database);
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException ex) {
Logger.getLogger(DatabaseCheck.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(SqlManager.class.getName()).log(Level.SEVERE, null, ex);
}
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
@@ -131,18 +129,14 @@ public class DatabaseCheck {
private File dbFile;
private void setupSQLITE(String location) throws SQLException {
if (location.chars().allMatch(Character::isWhitespace)) {
dbFile = new File(plugin.getDataFolder().getAbsoluteFile(), this.database + ".db");
} else {
dbFile = new File(location, this.database + ".db");
}
private void setupSQLITE() throws SQLException {
dbFile = new File(plugin.getDataFolder().getAbsoluteFile(), this.database + ".db");
this.url = ("jdbc:sqlite:" + dbFile.getAbsoluteFile());
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException ex) {
Logger.getLogger(DatabaseCheck.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(SqlManager.class.getName()).log(Level.SEVERE, null, ex);
}
DriverManager.registerDriver(new org.sqlite.JDBC());
}
-474
View File
@@ -1,474 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.mcsmp;
import static java.util.logging.Level.SEVERE;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import me.prunt.restrictedcreative.RestrictedCreativeAPI;
import net.coreprotect.CoreProtectAPI;
/**
* An abstract class with methods that are shared between all loggerManagers, It also consist of some
* methods that are used to create those loggerManagers.
* @author Thorin
*/
public abstract class loggerManager {
protected CoreProtectAPI coreprotect;
protected int time;
protected List<String> restrict_users;
protected List<String> exclude_users;
protected List<Object> restrict_blocks;
protected List<Object> exclude_blocks;
protected List<Integer> action_list;
protected int radius;
protected Location radius_location;
protected MessageManager msgManager;
private static HashMap<String,String[]> storedCommands = new HashMap<String,String[]>();
private static ConfigurationSection configSektion = ParamnesticCure.getInstance().getConfig().getConfigurationSection("");
/**
* Checks the database if this action has been stored as creative
* @param time The time of action
* @param worldName
* @param x
* @param y
* @param z
* @return true if a creative action at this time and location was stored in the database
*/
protected boolean fetchDBIsCreative(int time, String worldName, int x, int y, int z) {
try {
Connection connection = ParamnesticCure.getInstance().getConnection();
PreparedStatement getCreativeStatus = connection.prepareStatement(
"SELECT is_creative FROM blockAction INNER JOIN worlds"
+ " ON blockAction.world = worlds.world_id"
+ " WHERE time = ? AND worlds.world = ? AND x = ? AND y = ? AND z = ?"
+ " ORDER BY time DESC"
);
getCreativeStatus.setInt(1, time);
getCreativeStatus.setString(2, worldName );
getCreativeStatus.setInt(3, x);
getCreativeStatus.setInt(4, y);
getCreativeStatus.setInt(5, z);
ResultSet set = getCreativeStatus.executeQuery();
if(set.next()) return (set.getInt(1) == 1); // is_creative = 1 -> action was creative
}catch(SQLException ex) {ParamnesticCure.getInstance().getLogger().log(SEVERE, ex.getMessage(), ex.getCause());}
return false;
}
/**
* Takes an action as input, then calls a function which adds the block into the
* database (an important function if you want restores to work properly).
*
* It also updates the creative status on the location
*
* @param x
* @param y
* @param z
* @param worldname
* @param DBCreativeStatus true if this location should be set to creative
*/
protected void changeCreativeStatus(Integer x, Integer y, Integer z, String worldname, boolean DBCreativeStatus) {
List<World> worldlist = ParamnesticCure.getInstance().getServer().getWorlds();
World world = null;
for (World worldTest : worldlist) {
if(worldTest.getName().equals(worldname)) { world = worldTest; break; }
}
Block block = world.getBlockAt(x, y, z);
//to prevent issues on restores as some actions would not have been tracked otherways
if(RestrictedCreativeAPI.isCreative(block)) {
TrackedBlocks.updateCreativeID(block, true);
}
if(DBCreativeStatus) {
RestrictedCreativeAPI.add(block);
}
else {
RestrictedCreativeAPI.remove(block);
}
}
/**
* Interprets a part of the command to see if a rollback,restore,undo, or purge should be created
* Whether this method fits better in the listener class is unclear
* @param command The arguments after the logger alias
* @param location Location of the player (can be null)
* @param playerOperator the player who initiated the command
* @return true if command event should be cancelled
*/
static public boolean createLoggerManager(String[] command, Location location, Player playerOperator) {
String operator = (playerOperator == null) ? null : playerOperator.getName();
List<String> rollbackAlias = configSektion.getStringList("blockLoggerCommands.rollback");
String[] arguments = Arrays.copyOfRange(command, 2, command.length);
if(rollbackAlias.contains(command[1])) {
if(!PermissionManager.hasRollback(playerOperator)) return false;
RollbackManager rollback = new RollbackManager( arguments , location , playerOperator);
rollback.executeTask();
storeCommand(operator,command);
return true;
}
List<String> restoreAlias = configSektion.getStringList("blockLoggerCommands.restore");
if(restoreAlias.contains(command[1])) {
if(!PermissionManager.hasRestore(playerOperator)) return false;
RestoreManager restore = new RestoreManager( arguments, location , playerOperator );
restore.executeTask();
storeCommand(operator,command);
return true;
}
List<String> undoAlias = configSektion.getStringList("blockLoggerCommands.undo");
if(undoAlias.contains(command[1])) {
if(!(PermissionManager.hasRollback(playerOperator)&&PermissionManager.hasRestore(playerOperator))) return false;
//TODO make better undo's, that store location and takes time into consideration
String player = operator;
if(command.length == 3)
player = command[2];
else if(command.length > 3) {
return false;
}
if (undoCommand(player, operator, location))
return true;
}
List<String> purgeAlias = configSektion.getStringList("blockLoggerCommands.purge");
if(purgeAlias.contains(command[1])) {
if(!PermissionManager.hasPurge(playerOperator)) return false;
if(command.length > 3) {
new MessageManager(playerOperator).sendMessage("Invalid argument " + command[1], true);
return true;
}
//don't look here, this is stupid
String[] temp = {command[2]};
int time = (new RollbackManager(temp,null,null)).time;
TrackedBlocks.purgeDatabase(time);
}
List<String> helpAlias = configSektion.getStringList("blockLoggerCommands.help");
if(helpAlias.contains(command[1]) && PermissionManager.hasHelp(playerOperator)) {
//don't know if this is necessary
}
return false;
}
/**
* This stores commands for the undo command
* @param operator the player who initiated the command
* @param command the type of logger command that was used
* @param arguments the arguments of that command
*/
static private void storeCommand(String operator, String[] commandListed) {
String command = "";
for(String argument:commandListed) command = command+" " + argument;
storedCommands.put(operator, commandListed);
}
/**
* This is the main logic done to convert a command to it's opposite, to then call the
* createLoggerManager with the newly created command.
*
* This approximately undoes the previous command.
* @param player the player which command should be undone
* @param operator the player that initiated the command
* @return true if successful
*/
static private boolean undoCommand(String player,String operator,Location location) {
ConfigurationSection configSektion = ParamnesticCure.getInstance().getConfig().getConfigurationSection("");
if(storedCommands.containsKey(player)) {
String[] commandListed = storedCommands.get(player);
List<String> rbAlias = configSektion.getStringList("blockLoggerCommands.rollback");
List<String> reAlias = configSektion.getStringList("blockLoggerCommands.restore");
if(rbAlias.contains(commandListed[1]))
commandListed[1] = reAlias.get(0);
else
commandListed[1] = rbAlias.get(0);
String command = "";
for(String argument:commandListed) command = command+" " + argument;
Player playerPlayer = Bukkit.getServer().getPlayer(player);
createLoggerManager(commandListed, location, playerPlayer);
storeCommand(operator,commandListed);
return true;
}
Player playerOperator = (operator == null)? null : Bukkit.getServer().getPlayer(operator);
new MessageManager(playerOperator).sendMessage("Could not find the user " + player,true);
return false;
}
/**
* Interprets the argument, and assigns values to the proper blocks
* @param arguments : The arguments of the command
* @param radius_location : location where command was thrown
*/
protected void interpretArguments(String[] arguments, Location radius_location) {
boolean checkForWeirdUserInput = false;
for(String argument :arguments) {
argument.replace(" ", "");
if(timeInterpreter(argument))
continue;
if(userInterpreter(argument))
continue;
if(excludeInterpreter(argument))
continue;
if(radiusInterpreter(argument,radius_location))
continue;
if(blockInterpreter(argument))
continue;
if(actionInterpreter(argument))
continue;
if(argument != ""){
if(checkForWeirdUserInput) {
msgManager.sendMessage("Invalid argument ''" + argument+"''",true);
return;
}
checkForWeirdUserInput = true;
this.restrict_users = new ArrayList<String>();
this.restrict_users.add(argument);
}
}
}
// ARGUMENT INTERPRETERS
/**
*
* @param argument
* @return true if there was a match
*/
private boolean timeInterpreter(String argument) {
List<String> timeAlias = configSektion.getStringList("blockLoggerCommands.arguments.time");
argument = checkAndTrimArgument(argument,timeAlias);
if(argument != "") {
long time = 0;//s
String[] splitedArgument = argument.split("(?<=[w*d*h*m*s])");
//convert to seconds
for(String part : splitedArgument) {
if(part.contains("w")){
time += 604800 * Double.parseDouble(part.substring( 0 , part.indexOf('w') ));
}
if(part.contains("d")){
time += 86400 * Double.parseDouble(part.substring( 0 , part.indexOf('d') ));
}
if(part.contains("h")){
time += 3600 * Double.parseDouble(part.substring( 0 , part.indexOf('h') ));
}
if(part.contains("m")){
time += 60 * Double.parseDouble(part.substring( 0 , part.indexOf('m') ));
}
if(part.contains("s")){
time += Double.parseDouble(part.substring( 0 , part.indexOf('s') ));
}
}
this.time = Math.round(time);
return true;
}
return false;
}
/**
*
* @param argument
* @return true if there was a match
*/
private boolean userInterpreter(String argument) {
List<String> userAlias = configSektion.getStringList("blockLoggerCommands.arguments.user");
argument = checkAndTrimArgument(argument,userAlias);
if(argument != "") {
this.restrict_users = new ArrayList<String>();
String[] argumentSplited = argument.split(",");
for(String part : argumentSplited) {
this.restrict_users.add(part);
}
return true;
}
return false;
}
/**
*
* @param argument
* @return true if there was a match
*/
private boolean excludeInterpreter(String argument) {
List<String> excludeAlias = configSektion.getStringList("blockLoggerCommands.arguments.exclude");
argument = checkAndTrimArgument(argument,excludeAlias);
if(argument != "") {
this.exclude_blocks = new ArrayList<Object>();
String[] argumentSplited = argument.split(",");
for(String part : argumentSplited) { this.exclude_blocks.add( Bukkit.createBlockData(part) ); }
return true;
}
return false;
}
/**
*
* @param argument
* @param radius_location the location where the command was issued, null => console
* @return true if there was a match
*/
private boolean radiusInterpreter(String argument,Location radius_location) {
List<String> radiusAlias = configSektion.getStringList("blockLoggerCommands.arguments.radius");
argument = checkAndTrimArgument(argument,radiusAlias);
if(argument != "") {
if(radius_location == null)
msgManager.sendMessage(" You can't use the radius argument from the console",true);
this.radius = Integer.parseInt(argument);
this.radius_location = radius_location;
return true;
}
return false;
}
/**
*
* @param argument
* @return true if there was a match
*/
private boolean blockInterpreter(String argument) {
List<String> blockAlias = configSektion.getStringList("blockLoggerCommands.arguments.block");
argument = checkAndTrimArgument(argument,blockAlias);
if(argument != "") {
this.restrict_blocks = new ArrayList<Object>();
String[] argumentSplited = argument.split(",");
for(String material : argumentSplited) {
this.restrict_blocks.add( Material.getMaterial("material:" + material) );
}
return true;
}
return false;
}
/**
*
* @param argument
* @return true if there was a match
*/
private boolean actionInterpreter(String argument) {
List<String> actionAlias = configSektion.getStringList("blockLoggerCommands.arguments.action");
argument = checkAndTrimArgument(argument,actionAlias);
if(argument != "") {
this.action_list = new ArrayList<Integer>();
String[] argumentSplited = argument.split(",");
for(String actionArgument : argumentSplited) {
for(Integer action:actionToInt(actionArgument))
action_list.add(action);
}
return true;
}
return false;
}
/**
* As of now, the only known action integers are block remove, block place and block interaction (0,1,2).
* This just looks if its a block action, and with some hefty logic (if I say so myself) assigns the corresponding integers:
* block (0,1), +block(1), -block(0). Default value is 2
* @param action
* @return a list off all the actions that this part of the argument implied
*/
private List<Integer> actionToInt(String action) {
//TODO add numbers for all the other alternatives
List<Integer> output = null;
if(action.contains("block"))
{
output = new ArrayList<Integer>();
if(!action.contains("-"))
output.add(1);//place action
if(!action.contains("+"))
output.add(0);//remove action
}
else {
output = new ArrayList<Integer>();
output.add(2);
}
return output;
}
/**
* A function used in command processing, checks if the argument contains any alias and return the argument without its alias
* @param argument
* @param aliases
* @return The argument without alias, or "" if there was no match
*/
private String checkAndTrimArgument(String argument,List<String> aliases) {
Matcher matcher;
Pattern pattern = null;
for(String alias : aliases) {
pattern = Pattern.compile("^" + alias + ":");
matcher = pattern.matcher(argument);
if(matcher.find()) {
return matcher.replaceAll("");
}
}
return "";
}
/**
* This function is shared between restores and rollbacks
*/
abstract void executeTask();
}
+14 -20
View File
@@ -56,34 +56,28 @@ blockLoggerCommands:
block:
- b
- block
# The permessions for the blocklogger
blockLoggerPermissions:
rollback: coreprotect.rollback
purge: coreprotect.purge
restore: coreprotect.restore
help: coreprotect.help
# Default information used when a value in Database_Names is blank ("")
# Please ensure that all three of the databases you intend to use have already been configured by your logger and creative manager.
defaultconnection:
# All database config for the database of paramnestic
Database:
# Database type
driver: Sqlite
# Database location
address: localhost
# Port used by your db.
port: 3306
# Username with which to connect to the db.
user: 'root'
# Password for that username.
password: 'pass'
# Databases for us to send specific requests to.
# Paramnestic requires all three databases to be running, set up, and seperate to function.
Database_Names:
# The database for Paramnestic to store its own data.
# (ParamnesticCure)
paramnestic:
database: "paramnestic"
location: ""
driver: ""
address: ""
port: ""
user: ""
password: ""
# The name for the database
databasename: "paramnestic"
Plugin_settings:
# The time between the ocurence of the action and when it's going to be logged
# Keep it high if you dont want any issues to arise
wait_time: 100
# For development
debug: false
+6
View File
@@ -0,0 +1,6 @@
#Paramnestic Hikari Datasource Properties for advanced database Configuration
dataSource.user=default
dataSource.password=pas
dataSource.cachePrepStmts=true
dataSource.prepStmtCacheSize=250
dataSource.prepStmtCacheSqlLimit=2048