forked from LogBlock/LogBlock
Compare commits
259 Commits
v1.13-SNAP
...
inventory-
Author | SHA1 | Date | |
---|---|---|---|
1482b2c4fe | |||
cb1231eab5 | |||
1df380741b | |||
2049a7a7a4 | |||
8148386e3e | |||
87074da8a1 | |||
0fd3266c7b | |||
c20b677507 | |||
fe7e244898 | |||
4f7c02b285 | |||
8a8471c3e6 | |||
fe98370acd | |||
76df1a4913 | |||
841ce89f21 | |||
033a53e338 | |||
f42649adc3 | |||
81e0135046 | |||
e181c85647 | |||
dde8dc8289 | |||
ac462261dc | |||
42715de265 | |||
d548206c3a | |||
24b5455f08 | |||
35f921a9a0 | |||
0d7a8016a1 | |||
6a398a67ab | |||
6dcca54637 | |||
650f7e20f1 | |||
5c22beb2e5 | |||
a63c97bd70 | |||
1562bbacea | |||
aba6e4d9c8 | |||
1ef7c78c0d | |||
788d8fd4d5 | |||
3bfb19cdfa | |||
04b5d9e7ed | |||
a96f82efae | |||
39f58a6bd4 | |||
e1064dd0b1 | |||
fc1cd5ef2c | |||
1dba9f20f1 | |||
8eb93411ec | |||
068ac89819 | |||
6b71a3c30d | |||
6dec1b6c37 | |||
b9513df20e | |||
8b34e39797 | |||
1cda6506c7 | |||
5b0e2d9adb | |||
cdf6c1df04 | |||
cdee5b3609 | |||
8e948e857f | |||
793df218e5 | |||
31428d60e4 | |||
169328e159 | |||
60a771224b | |||
3135fe8696 | |||
59d0794c3d | |||
8214e7d177 | |||
e77e95cae0 | |||
241a7adc48 | |||
27cc59f922 | |||
8192aa4fb8 | |||
078fe7f423 | |||
76a81c124a | |||
d98d46d0c9 | |||
1e1dce99c0 | |||
921df872d1 | |||
cd38ac9866 | |||
a7967e9b1e | |||
af895aa21d | |||
2f92fd3426 | |||
f298a5f70f | |||
091bdca142 | |||
07bf9421dd | |||
06f24bf632 | |||
3f7ace7f70 | |||
6f4ce7e6d0 | |||
d03bbe68ba | |||
e9d78bffb1 | |||
d829005c7e | |||
a6e4d79e0c | |||
e8aaadf37b | |||
1525d7682f | |||
76f7f8701d | |||
9b5e0c9025 | |||
e6b0108bc5 | |||
3efd92d9df | |||
05d7652bcc | |||
72fc78b3c0 | |||
9eef03aa90 | |||
da692ed01a | |||
424ef3b02b | |||
4fda020dfc | |||
8f429afbeb | |||
f6522b73f4 | |||
ac233a3920 | |||
7a946fc23d | |||
1602fdb03a | |||
33c18a9e62 | |||
e66b5a8f9d | |||
bd23c93071 | |||
503541ad4e | |||
82d61d5ee7 | |||
254c856b2f | |||
d4b127244e | |||
87c09766d3 | |||
8b1ee254b4 | |||
34eeb52c8d | |||
399cbc901f | |||
7dce1776e7 | |||
92de737e4e | |||
025950a8c4 | |||
dc62524d0d | |||
947163477b | |||
2e81e2be9d | |||
58223b7612 | |||
51f84251dc | |||
31ef2d942b | |||
9f8fd3e1ca | |||
71527530f2 | |||
d5ee15ebba | |||
ab464e1dd5 | |||
d847908d3c | |||
7e47a0c375 | |||
ab7c8ffbb2 | |||
0e8bb2599c | |||
7f3bb300ef | |||
83157ad64f | |||
cd798e86de | |||
c3b0fda017 | |||
27c72b43c1 | |||
8a1897e102 | |||
9ea7a47b4e | |||
76aeb5f602 | |||
1eace44cce | |||
a5ffa3b709 | |||
4e1a79ca0f | |||
ea16656fcb | |||
9d1baee2e2 | |||
3a2c1d8d6f | |||
868c56ef6a | |||
f9d246dd63 | |||
707e0a1eed | |||
5ad0f06d16 | |||
4ce7ad0f7d | |||
4af5b3f1ea | |||
8c6ee4cf0c | |||
737afcd1fa | |||
f2dc3daad0 | |||
35e62e03e9 | |||
40531988b0 | |||
fde6927aeb | |||
3e836c2f50 | |||
396b79ab68 | |||
be5ee9f792 | |||
497e844486 | |||
90dbc8d8df | |||
91a08e7ea0 | |||
eec8c91a42 | |||
a4368ea77f | |||
7a8551d94f | |||
96c9b694b8 | |||
b1e0f91bd7 | |||
91315b10c8 | |||
210d6cec37 | |||
eb99b6d278 | |||
a55cbabbdd | |||
421f16784f | |||
faaab7c4f6 | |||
0bdeb7dc86 | |||
2bb9e09959 | |||
d214b646db | |||
3ef6e48ca4 | |||
1b316dc11f | |||
3c64376dd1 | |||
c390504b70 | |||
df8c8bcdda | |||
544385f2ad | |||
9c2a93dafb | |||
404c9b91c0 | |||
1cbc192b31 | |||
76fce15305 | |||
8045ab1ecd | |||
2faa9cbd6d | |||
f65509408e | |||
2afa3c88cd | |||
282090459f | |||
681c4a2033 | |||
56404533db | |||
710de5b35a | |||
eb0b969477 | |||
c997fb9db9 | |||
572df51d28 | |||
ce1a1c3bd2 | |||
51b72bafa6 | |||
dc4d7e0319 | |||
466775631b | |||
83506e6cd9 | |||
89d9da02e3 | |||
c623525847 | |||
cfea33e1fd | |||
8b71a8a62b | |||
e6310e6174 | |||
8d11ea3f53 | |||
d04501baf4 | |||
47f7ddec01 | |||
cbf0011cd3 | |||
66070e2b38 | |||
6168ef1713 | |||
d0f64070ae | |||
2c06c90c6d | |||
60a049ed49 | |||
a37dd9cff1 | |||
1878b94781 | |||
a853230c8d | |||
3d1f57cc79 | |||
f85dbdbbdf | |||
e98910615f | |||
39a0fbeafa | |||
ecae2abaf0 | |||
cc939ab413 | |||
680db124a9 | |||
d8e53173e0 | |||
33d97ed971 | |||
3dbb7a6c43 | |||
0eb2b0dbc8 | |||
37ce2303dc | |||
95b7be57fc | |||
92b1a2f394 | |||
5a7ba77095 | |||
7a5e46b65f | |||
8084b3e4c0 | |||
dd58019be1 | |||
c30aba4f90 | |||
6d13c6436c | |||
4baa989e60 | |||
1b0a575945 | |||
cd2dbc0813 | |||
fd450aee80 | |||
e5097a1577 | |||
c541847225 | |||
2fe886205b | |||
28aabd09c7 | |||
b80777a9a0 | |||
c73b29e43b | |||
354c9078b1 | |||
759cd230a1 | |||
19762691d0 | |||
1e8779cb9a | |||
a1d622ebbd | |||
76500f2e51 | |||
d403af42d9 | |||
f83fc7cee2 | |||
6680e9e3eb | |||
58e5cdf890 | |||
fca9c90032 | |||
f6e440c1df | |||
afb81f850d |
@ -1,5 +1,5 @@
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk7
|
||||
- openjdk8
|
||||
notifications:
|
||||
email: false
|
||||
|
Binary file not shown.
@ -4,4 +4,4 @@ LogBlock
|
||||
This plugin logs block changes such as breaking, placing, modifying, or burning to a MySQL Database. It can be used as an anti-griefing tool to find out who made a particular edit, or even roll back changes by certain players.
|
||||
Originally written by bootswithdefer, for hMod, ported to Bukkit by me, because of the inability to identfy griefers. BigBrother also did't work, so I was forced to do it myself. The honor belongs to bootswithdefer for the sourcecode, I only spent about 8 hours to transcribe. All functions except sign text logging shold work as in hMod. The use of permissions plugin is possible, but not necessary.
|
||||
|
||||
Questioner: http://git.io/u2MxKQ
|
||||
You can download development builds [from our Jenkins server](https://www.iani.de/jenkins/job/LogBlock/).
|
||||
|
55
pom.xml
55
pom.xml
@ -1,10 +1,10 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.diddiz</groupId>
|
||||
<artifactId>logblock</artifactId>
|
||||
<version>1.13-SNAPSHOT</version>
|
||||
<version>1.16.5.2-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>LogBlock</name>
|
||||
@ -42,26 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>questioner</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/LogBlockQuestioner.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q.worldedit</groupId>
|
||||
<artifactId>worldedit-core</artifactId>
|
||||
<version>7.0.0-SNAPSHOT</version>
|
||||
<version>1.16.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sk89q.worldedit</groupId>
|
||||
<artifactId>worldedit-bukkit</artifactId>
|
||||
<version>7.0.0-SNAPSHOT</version>
|
||||
<version>7.1.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -73,24 +60,28 @@
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.4.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.10</version>
|
||||
<version>1.7.25</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sk89q-repo</id>
|
||||
<url>https://maven.sk89q.com/repo/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
<id>brokkonaut-repo</id>
|
||||
<url>https://www.iani.de/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<profiles>
|
||||
@ -171,17 +162,17 @@
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>de.diddiz.lib.com.zaxxer.hikari</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.slf4j</pattern>
|
||||
<shadedPattern>de.diddiz.lib.org.slf4j</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>de.diddiz.lib.com.zaxxer.hikari</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.slf4j</pattern>
|
||||
<shadedPattern>de.diddiz.lib.org.slf4j</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
@ -3,6 +3,7 @@ package de.diddiz.LogBlock;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.projectiles.BlockProjectileSource;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
|
||||
@ -12,47 +13,61 @@ import java.util.Collection;
|
||||
|
||||
import static de.diddiz.util.BukkitUtils.entityName;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class Actor {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 79 * hash + (this.UUID != null ? this.UUID.hashCode() : 0);
|
||||
return hash;
|
||||
return this.UUID != null ? this.UUID.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Actor other = (Actor) obj;
|
||||
return ((this.UUID == null && other.UUID == null) || this.UUID.equals(other.UUID));
|
||||
return (this.UUID == null) ? (other.UUID == null) : this.UUID.equals(other.UUID);
|
||||
}
|
||||
|
||||
final String name;
|
||||
final String UUID;
|
||||
final Location blockLocation;
|
||||
|
||||
public Actor(String name, String UUID) {
|
||||
this.name = name;
|
||||
this.UUID = UUID;
|
||||
this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID);
|
||||
this.blockLocation = null;
|
||||
}
|
||||
|
||||
public Actor(String name, String UUID, Block block) {
|
||||
this.name = name;
|
||||
this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID);
|
||||
this.blockLocation = block == null ? null : block.getLocation();
|
||||
}
|
||||
|
||||
public Actor(String name, java.util.UUID UUID) {
|
||||
this.name = name;
|
||||
this.UUID = UUID.toString();
|
||||
this.blockLocation = null;
|
||||
}
|
||||
|
||||
public Actor(String name, java.util.UUID UUID, Block block) {
|
||||
this.name = name;
|
||||
this.UUID = UUID.toString();
|
||||
this.blockLocation = block == null ? null : block.getLocation();
|
||||
}
|
||||
|
||||
public Actor(String name) {
|
||||
this(name, generateUUID(name));
|
||||
}
|
||||
|
||||
public Actor(String name, Block block) {
|
||||
this(name, generateUUID(name), block);
|
||||
}
|
||||
|
||||
public Actor(ResultSet rs) throws SQLException {
|
||||
this(rs.getString("playername"), rs.getString("UUID"));
|
||||
}
|
||||
@ -65,12 +80,21 @@ public class Actor {
|
||||
return UUID;
|
||||
}
|
||||
|
||||
public Location getBlockLocation() {
|
||||
return blockLocation;
|
||||
}
|
||||
|
||||
public static Actor actorFromEntity(Entity entity) {
|
||||
if (entity instanceof Player) {
|
||||
return new Actor(entityName(entity), entity.getUniqueId());
|
||||
} else {
|
||||
return new Actor(entityName(entity));
|
||||
}
|
||||
if (entity instanceof Projectile) {
|
||||
ProjectileSource shooter = ((Projectile) entity).getShooter();
|
||||
if (shooter != null) {
|
||||
return actorFromProjectileSource(shooter);
|
||||
}
|
||||
}
|
||||
return new Actor(entityName(entity));
|
||||
}
|
||||
|
||||
public static Actor actorFromEntity(EntityType entity) {
|
||||
@ -88,20 +112,24 @@ public class Actor {
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Generate an Actor object from a String name, trying to guess if it's an online player
|
||||
* and if so, setting the UUID accordingly. This only checks against currently online
|
||||
* players and is a "best effort" attempt for use with the pre-UUID API
|
||||
* <p>
|
||||
* If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) }
|
||||
* or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods
|
||||
* <p>
|
||||
* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)}
|
||||
* @deprecated Only use this if you have a String of unknown origin
|
||||
*
|
||||
* @param actorName String of unknown origin
|
||||
* @return
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate an Actor object from a String name, trying to guess if it's an online player
|
||||
* and if so, setting the UUID accordingly. This only checks against currently online
|
||||
* players and is a "best effort" attempt for use with the pre-UUID API
|
||||
* <p>
|
||||
* If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) }
|
||||
* or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods
|
||||
* <p>
|
||||
* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)}
|
||||
*
|
||||
* @deprecated Only use this if you have a String of unknown origin
|
||||
*
|
||||
* @param actorName
|
||||
* String of unknown origin
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static Actor actorFromString(String actorName) {
|
||||
Collection<? extends Player> players = Bukkit.getServer().getOnlinePlayers();
|
||||
for (Player p : players) {
|
||||
@ -109,8 +137,8 @@ public class Actor {
|
||||
return actorFromEntity(p);
|
||||
}
|
||||
}
|
||||
// No player found online with that name, assuming non-player entity/effect
|
||||
return new Actor(actorName);
|
||||
// No player found online with that name, assuming non-player entity/effect
|
||||
return new Actor(actorName);
|
||||
}
|
||||
|
||||
public static boolean isValidUUID(String uuid) {
|
||||
|
@ -19,6 +19,7 @@ public class AutoClearLog implements Runnable {
|
||||
for (final String paramStr : autoClearLog) {
|
||||
try {
|
||||
final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" ")));
|
||||
params.noForcedLimit = true;
|
||||
handler.new CommandClearLog(getServer().getConsoleSender(), params, false);
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.SEVERE, "Failed to schedule auto ClearLog: ", ex);
|
||||
|
@ -1,42 +1,60 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import static de.diddiz.util.ActionColor.CREATE;
|
||||
import static de.diddiz.util.ActionColor.DESTROY;
|
||||
import static de.diddiz.util.ActionColor.INTERACT;
|
||||
import static de.diddiz.util.TypeColor.DEFAULT;
|
||||
import static de.diddiz.util.MessagingUtil.createTextComponentWithColor;
|
||||
import static de.diddiz.util.MessagingUtil.prettyDate;
|
||||
import static de.diddiz.util.MessagingUtil.prettyLocation;
|
||||
import static de.diddiz.util.MessagingUtil.prettyMaterial;
|
||||
import static de.diddiz.util.MessagingUtil.prettyState;
|
||||
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.util.Utils;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Level;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Note;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Openable;
|
||||
import org.bukkit.block.data.Powerable;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.block.data.type.Comparator;
|
||||
import org.bukkit.block.data.type.DaylightDetector;
|
||||
import org.bukkit.block.data.type.Lectern;
|
||||
import org.bukkit.block.data.type.NoteBlock;
|
||||
import org.bukkit.block.data.type.Repeater;
|
||||
import org.bukkit.block.data.type.Sign;
|
||||
import org.bukkit.block.data.type.Switch;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static de.diddiz.util.LoggingUtil.checkText;
|
||||
|
||||
public class BlockChange implements LookupCacheElement {
|
||||
public final long id, date;
|
||||
public final Location loc;
|
||||
public final Actor actor;
|
||||
public final String playerName;
|
||||
// public final BlockData replaced, type;
|
||||
public final int replacedMaterial, replacedData, typeMaterial, typeData;
|
||||
public final String signtext;
|
||||
public final byte[] replacedState, typeState;
|
||||
public final ChestAccess ca;
|
||||
|
||||
public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
|
||||
id = 0;
|
||||
this.date = date;
|
||||
this.loc = loc;
|
||||
this.actor = actor;
|
||||
this.replacedMaterial = replaced;
|
||||
this.replacedData = replacedData;
|
||||
this.replacedState = replacedState;
|
||||
this.typeMaterial = type;
|
||||
this.typeData = typeData;
|
||||
this.signtext = checkText(signtext);
|
||||
this.typeState = typeState;
|
||||
this.ca = ca;
|
||||
this.playerName = actor == null ? null : actor.getName();
|
||||
}
|
||||
@ -51,84 +69,185 @@ public class BlockChange implements LookupCacheElement {
|
||||
replacedData = p.needType ? rs.getInt("replacedData") : -1;
|
||||
typeMaterial = p.needType ? rs.getInt("type") : 0;
|
||||
typeData = p.needType ? rs.getInt("typeData") : -1;
|
||||
signtext = p.needSignText ? rs.getString("signtext") : null;
|
||||
replacedState = p.needType ? rs.getBytes("replacedState") : null;
|
||||
typeState = p.needType ? rs.getBytes("typeState") : null;
|
||||
ChestAccess catemp = null;
|
||||
if (p.needChestAccess) {
|
||||
ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
|
||||
if (stack != null) {
|
||||
catemp = new ChestAccess(stack, rs.getBoolean("itemremove"));
|
||||
catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype"));
|
||||
}
|
||||
}
|
||||
ca = catemp;
|
||||
}
|
||||
|
||||
private String getTypeDetails(BlockData type, byte[] typeState) {
|
||||
String typeDetails = null;
|
||||
|
||||
if (BlockStateCodecs.hasCodec(type.getMaterial())) {
|
||||
try {
|
||||
typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState));
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeDetails == null) {
|
||||
return "";
|
||||
} else {
|
||||
return " " + typeDetails;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
BlockData type = MaterialConverter.getBlockData(typeMaterial, typeData);
|
||||
BlockData replaced = MaterialConverter.getBlockData(replacedMaterial, replacedData);
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
return BaseComponent.toPlainText(getLogMessage(-1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
TextComponent msg = new TextComponent();
|
||||
if (date > 0) {
|
||||
msg.append(Config.formatter.format(date)).append(" ");
|
||||
msg.addExtra(prettyDate(date));
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
if (actor != null) {
|
||||
msg.append(actor.getName()).append(" ");
|
||||
msg.addExtra(actor.getName());
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
if (signtext != null) {
|
||||
final String action = BukkitUtils.isEmpty(type.getMaterial()) ? "destroyed " : "created ";
|
||||
if (!signtext.contains("\0")) {
|
||||
msg.append(action).append(signtext);
|
||||
} else {
|
||||
msg.append(action).append((!BukkitUtils.isEmpty(type.getMaterial()) ? type : replaced).getMaterial().name()).append(" [").append(signtext.replace("\0", "] [")).append("]");
|
||||
}
|
||||
} else if (type.equals(replaced)) {
|
||||
BlockData type = getBlockSet();
|
||||
BlockData replaced = getBlockReplaced();
|
||||
if (type == null || replaced == null) {
|
||||
msg.addExtra("did an unknown block modification");
|
||||
return new BaseComponent[] { msg };
|
||||
}
|
||||
|
||||
// Process type details once for later use.
|
||||
String typeDetails = getTypeDetails(type, typeState);
|
||||
String replacedDetails = getTypeDetails(replaced, replacedState);
|
||||
|
||||
if (type.getMaterial().equals(replaced.getMaterial())) {
|
||||
if (BukkitUtils.isEmpty(type.getMaterial())) {
|
||||
msg.append("did an unspecified action");
|
||||
msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor()));
|
||||
} else if (ca != null) {
|
||||
if (ca.itemStack == null) {
|
||||
msg.append("looked inside ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (ca.remove) {
|
||||
msg.append("took ").append(ca.itemStack.getAmount()).append("x ").append(ca.itemStack.getType().name()).append(" from ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor()));
|
||||
msg.addExtra(BukkitUtils.toString(ca.itemStack));
|
||||
msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else {
|
||||
msg.append("put ").append(ca.itemStack.getAmount()).append("x ").append(ca.itemStack.getType().name()).append(" into ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor()));
|
||||
msg.addExtra(BukkitUtils.toString(ca.itemStack));
|
||||
msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
}
|
||||
} else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) {
|
||||
if (((Waterlogged) type).isWaterlogged()) {
|
||||
msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else {
|
||||
msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
}
|
||||
} else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) {
|
||||
msg.append("opened ").append(type.getMaterial().name());
|
||||
} else if (type instanceof Openable) {
|
||||
msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) {
|
||||
// Door, Trapdoor, Fence gate
|
||||
msg.append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name());
|
||||
} else if (type.getMaterial() == Material.LEVER) {
|
||||
msg.append("switched ").append(type.getMaterial().name());
|
||||
} else if (type instanceof Switch) {
|
||||
msg.append("pressed ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) {
|
||||
msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off"));
|
||||
} else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) {
|
||||
msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (type.getMaterial() == Material.CAKE) {
|
||||
msg.append("ate a piece of ").append(type.getMaterial().name());
|
||||
} else if (type.getMaterial() == Material.NOTE_BLOCK || type.getMaterial() == Material.REPEATER || type.getMaterial() == Material.COMPARATOR || type.getMaterial() == Material.DAYLIGHT_DETECTOR) {
|
||||
msg.append("changed ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (type.getMaterial() == Material.NOTE_BLOCK) {
|
||||
Note note = ((NoteBlock) type).getNote();
|
||||
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(" to ");
|
||||
msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : "")));
|
||||
} else if (type.getMaterial() == Material.REPEATER) {
|
||||
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(" to ");
|
||||
msg.addExtra(prettyState(((Repeater) type).getDelay()));
|
||||
msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor()));
|
||||
} else if (type.getMaterial() == Material.COMPARATOR) {
|
||||
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(" to ");
|
||||
msg.addExtra(prettyState(((Comparator) type).getMode()));
|
||||
} else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) {
|
||||
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(" to ");
|
||||
msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal"));
|
||||
} else if (type instanceof Lectern) {
|
||||
msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(" to");
|
||||
msg.addExtra(prettyState(typeDetails.length() == 0 ? " empty" : typeDetails));
|
||||
} else if (type instanceof Powerable) {
|
||||
msg.append("stepped on ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (type.getMaterial() == Material.TRIPWIRE) {
|
||||
msg.append("ran into ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
} else if (type instanceof Sign || type instanceof WallSign) {
|
||||
msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(createTextComponentWithColor(" to ", CREATE.getColor()));
|
||||
msg.addExtra(prettyState(typeDetails));
|
||||
} else {
|
||||
msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(replaced));
|
||||
msg.addExtra(prettyState(replacedDetails));
|
||||
msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(prettyState(typeDetails));
|
||||
}
|
||||
} else if (BukkitUtils.isEmpty(type.getMaterial())) {
|
||||
msg.append("destroyed ").append(replaced.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor()));
|
||||
msg.addExtra(prettyMaterial(replaced));
|
||||
msg.addExtra(prettyState(replacedDetails));
|
||||
} else if (BukkitUtils.isEmpty(replaced.getMaterial())) {
|
||||
msg.append("created ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(prettyState(typeDetails));
|
||||
} else {
|
||||
msg.append("replaced ").append(replaced.getMaterial().name()).append(" with ").append(type.getMaterial().name());
|
||||
msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(replaced));
|
||||
msg.addExtra(prettyState(replacedDetails));
|
||||
msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(type));
|
||||
msg.addExtra(prettyState(typeDetails));
|
||||
}
|
||||
if (loc != null) {
|
||||
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
|
||||
msg.addExtra(" at ");
|
||||
msg.addExtra(prettyLocation(loc, entry));
|
||||
}
|
||||
return msg.toString();
|
||||
return new BaseComponent[] { msg };
|
||||
}
|
||||
|
||||
public BlockData getBlockReplaced() {
|
||||
return MaterialConverter.getBlockData(replacedMaterial, replacedData);
|
||||
}
|
||||
|
||||
public BlockData getBlockSet() {
|
||||
return MaterialConverter.getBlockData(typeMaterial, typeData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import static de.diddiz.util.LoggingUtil.checkText;
|
||||
import static de.diddiz.util.MessagingUtil.brackets;
|
||||
import static de.diddiz.util.MessagingUtil.prettyDate;
|
||||
|
||||
import de.diddiz.util.MessagingUtil;
|
||||
import de.diddiz.util.MessagingUtil.BracketType;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static de.diddiz.util.LoggingUtil.checkText;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class ChatMessage implements LookupCacheElement {
|
||||
final long id, date;
|
||||
@ -34,7 +39,21 @@ public class ChatMessage implements LookupCacheElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return (player != null ? "<" + player.getName() + "> " : "") + (message != null ? message : "");
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
TextComponent msg = new TextComponent();
|
||||
if (date > 0) {
|
||||
msg.addExtra(prettyDate(date));
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
if (playerName != null) {
|
||||
msg.addExtra(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, net.md_5.bungee.api.ChatColor.WHITE)));
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
if (message != null) {
|
||||
for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) {
|
||||
msg.addExtra(messageComponent);
|
||||
}
|
||||
}
|
||||
return new BaseComponent[] { msg };
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ package de.diddiz.LogBlock;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ChestAccess {
|
||||
final ItemStack itemStack;
|
||||
final boolean remove;
|
||||
public final ItemStack itemStack;
|
||||
public final boolean remove;
|
||||
public final int itemType;
|
||||
|
||||
public ChestAccess(ItemStack itemStack, boolean remove) {
|
||||
public ChestAccess(ItemStack itemStack, boolean remove, int itemType) {
|
||||
this.itemStack = itemStack;
|
||||
this.remove = remove;
|
||||
this.itemType = itemType;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6,10 +6,12 @@ import java.io.*;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static de.diddiz.util.Utils.newline;
|
||||
import static org.bukkit.Bukkit.getLogger;
|
||||
|
||||
public class DumpedLogImporter implements Runnable {
|
||||
private final LogBlock logblock;
|
||||
@ -20,9 +22,10 @@ public class DumpedLogImporter implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final File[] imports = new File("plugins/LogBlock/import/").listFiles(new ExtensionFilenameFilter("sql"));
|
||||
final File[] imports = new File(logblock.getDataFolder(), "import").listFiles(new ExtensionFilenameFilter("sql"));
|
||||
if (imports != null && imports.length > 0) {
|
||||
getLogger().info("Found " + imports.length + " imports.");
|
||||
logblock.getLogger().info("Found " + imports.length + " imports.");
|
||||
Arrays.sort(imports, new ImportsComparator());
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = logblock.getConnection();
|
||||
@ -33,30 +36,65 @@ public class DumpedLogImporter implements Runnable {
|
||||
final Statement st = conn.createStatement();
|
||||
final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt")));
|
||||
int successes = 0, errors = 0;
|
||||
for (final File sqlFile : imports) {
|
||||
getLogger().info("Trying to import " + sqlFile.getName() + " ...");
|
||||
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
try {
|
||||
for (final File sqlFile : imports) {
|
||||
String line = null;
|
||||
try {
|
||||
st.execute(line);
|
||||
successes++;
|
||||
} catch (final Exception ex) {
|
||||
getLogger().warning("Error while importing: '" + line + "': " + ex.getMessage());
|
||||
writer.write(line + newline);
|
||||
errors++;
|
||||
logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ...");
|
||||
// first try batch import the whole file
|
||||
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
|
||||
int statements = 0;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.endsWith(";")) {
|
||||
line = line.substring(0, line.length() - 1);
|
||||
}
|
||||
if (!line.isEmpty()) {
|
||||
statements++;
|
||||
st.addBatch(line);
|
||||
}
|
||||
}
|
||||
st.executeBatch();
|
||||
conn.commit();
|
||||
reader.close();
|
||||
sqlFile.delete();
|
||||
successes += statements;
|
||||
logblock.getLogger().info("Successfully imported " + sqlFile.getName() + ".");
|
||||
} catch (final Exception ignored) {
|
||||
// if the batch import did not work, retry line by line
|
||||
try {
|
||||
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.endsWith(";")) {
|
||||
line = line.substring(0, line.length() - 1);
|
||||
}
|
||||
if (!line.isEmpty()) {
|
||||
try {
|
||||
st.execute(line);
|
||||
successes++;
|
||||
} catch (final SQLException ex) {
|
||||
logblock.getLogger().severe("Error while importing: '" + line + "': " + ex.getMessage());
|
||||
writer.write(line + newline);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
conn.commit();
|
||||
reader.close();
|
||||
sqlFile.delete();
|
||||
logblock.getLogger().info("Successfully imported " + sqlFile.getName() + ".");
|
||||
} catch (final Exception ex) {
|
||||
logblock.getLogger().severe("Error while importing " + sqlFile.getName() + ": " + ex.getMessage());
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
conn.commit();
|
||||
reader.close();
|
||||
sqlFile.delete();
|
||||
getLogger().info("Successfully imported " + sqlFile.getName() + ".");
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
writer.close();
|
||||
st.close();
|
||||
getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)");
|
||||
logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)");
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.WARNING, "Error while importing: ", ex);
|
||||
logblock.getLogger().log(Level.WARNING, "Error while importing: ", ex);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
try {
|
||||
@ -67,4 +105,44 @@ public class DumpedLogImporter implements Runnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ImportsComparator implements Comparator<File> {
|
||||
private final Pattern splitPattern = Pattern.compile("[\\-\\.]");
|
||||
|
||||
@Override
|
||||
public int compare(File o1, File o2) {
|
||||
String[] name1 = splitPattern.split(o1.getName());
|
||||
String[] name2 = splitPattern.split(o2.getName());
|
||||
if (name1.length > name2.length) {
|
||||
return 1;
|
||||
} else if (name1.length < name2.length) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < name1.length; i++) {
|
||||
String part1 = name1[i];
|
||||
String part2 = name2[i];
|
||||
if (part1.length() > 0 && part2.length() > 0) {
|
||||
char first1 = part1.charAt(0);
|
||||
char first2 = part2.charAt(0);
|
||||
if (first1 >= '0' && first1 <= '9' && first2 >= '0' && first2 <= '9') {
|
||||
try {
|
||||
long long1 = Long.parseLong(part1);
|
||||
long long2 = Long.parseLong(part2);
|
||||
if (long1 == long2) {
|
||||
continue;
|
||||
}
|
||||
return long1 > long2 ? 1 : -1;
|
||||
} catch (NumberFormatException e) {
|
||||
// fallthrough to string compare
|
||||
}
|
||||
}
|
||||
}
|
||||
int compareString = part1.compareTo(part2);
|
||||
if (compareString != 0) {
|
||||
return compareString;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
138
src/main/java/de/diddiz/LogBlock/EntityChange.java
Normal file
138
src/main/java/de/diddiz/LogBlock/EntityChange.java
Normal file
@ -0,0 +1,138 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import static de.diddiz.util.ActionColor.CREATE;
|
||||
import static de.diddiz.util.ActionColor.DESTROY;
|
||||
import static de.diddiz.util.ActionColor.INTERACT;
|
||||
import static de.diddiz.util.MessagingUtil.createTextComponentWithColor;
|
||||
import static de.diddiz.util.MessagingUtil.prettyDate;
|
||||
import static de.diddiz.util.MessagingUtil.prettyEntityType;
|
||||
import static de.diddiz.util.MessagingUtil.prettyLocation;
|
||||
import static de.diddiz.util.MessagingUtil.prettyMaterial;
|
||||
|
||||
import de.diddiz.util.Utils;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class EntityChange implements LookupCacheElement {
|
||||
public static enum EntityChangeType {
|
||||
CREATE,
|
||||
KILL,
|
||||
MODIFY,
|
||||
ADDEQUIP,
|
||||
REMOVEEQUIP,
|
||||
GET_STUNG;
|
||||
|
||||
private static EntityChangeType[] values = values();
|
||||
|
||||
public static EntityChangeType valueOf(int ordinal) {
|
||||
return values[ordinal];
|
||||
}
|
||||
}
|
||||
|
||||
public final long id, date;
|
||||
public final Location loc;
|
||||
public final Actor actor;
|
||||
public final EntityType type;
|
||||
public final int entityId;
|
||||
public final UUID entityUUID;
|
||||
public final EntityChangeType changeType;
|
||||
public final byte[] data;
|
||||
|
||||
public EntityChange(long date, Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) {
|
||||
id = 0;
|
||||
this.date = date;
|
||||
this.loc = loc;
|
||||
this.actor = actor;
|
||||
this.type = type;
|
||||
this.entityId = -1;
|
||||
this.entityUUID = entityid;
|
||||
this.changeType = changeType;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public EntityChange(ResultSet rs, QueryParams p) throws SQLException {
|
||||
id = p.needId ? rs.getInt("id") : 0;
|
||||
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
|
||||
loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null;
|
||||
actor = p.needPlayer ? new Actor(rs) : null;
|
||||
type = p.needType ? EntityTypeConverter.getEntityType(rs.getInt("entitytypeid")) : null;
|
||||
entityId = p.needData ? rs.getInt("entityid") : 0;
|
||||
entityUUID = p.needData ? UUID.fromString(rs.getString("entityuuid")) : null;
|
||||
changeType = p.needType ? EntityChangeType.valueOf(rs.getInt("action")) : null;
|
||||
data = p.needData ? rs.getBytes("data") : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return BaseComponent.toPlainText(getLogMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
TextComponent msg = new TextComponent();
|
||||
if (date > 0) {
|
||||
msg.addExtra(prettyDate(date));
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
if (actor != null) {
|
||||
msg.addExtra(actor.getName());
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
if (changeType == EntityChangeType.CREATE) {
|
||||
msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor()));
|
||||
} else if (changeType == EntityChangeType.KILL) {
|
||||
boolean living = type != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass());
|
||||
msg.addExtra(createTextComponentWithColor(living ? "killed " : "destroyed ", DESTROY.getColor()));
|
||||
} else if (changeType == EntityChangeType.ADDEQUIP) {
|
||||
YamlConfiguration conf = Utils.deserializeYamlConfiguration(data);
|
||||
ItemStack stack = conf == null ? null : conf.getItemStack("item");
|
||||
if (stack == null) {
|
||||
msg.addExtra(createTextComponentWithColor("added an item to ", CREATE.getColor()));
|
||||
} else {
|
||||
msg.addExtra(createTextComponentWithColor("added ", CREATE.getColor()));
|
||||
msg.addExtra(prettyMaterial(stack.getType()));
|
||||
msg.addExtra(" to ");
|
||||
}
|
||||
} else if (changeType == EntityChangeType.REMOVEEQUIP) {
|
||||
YamlConfiguration conf = Utils.deserializeYamlConfiguration(data);
|
||||
ItemStack stack = conf == null ? null : conf.getItemStack("item");
|
||||
if (stack == null) {
|
||||
msg.addExtra(createTextComponentWithColor("removed an item from ", DESTROY.getColor()));
|
||||
} else {
|
||||
msg.addExtra(createTextComponentWithColor("removed ", DESTROY.getColor()));
|
||||
msg.addExtra(prettyMaterial(stack.getType()));
|
||||
msg.addExtra(" from ");
|
||||
}
|
||||
} else if (changeType == EntityChangeType.MODIFY) {
|
||||
msg.addExtra(createTextComponentWithColor("modified ", INTERACT.getColor()));
|
||||
} else if (changeType == EntityChangeType.GET_STUNG) {
|
||||
msg.addExtra(createTextComponentWithColor("got stung by ", DESTROY.getColor()));
|
||||
} else {
|
||||
msg.addExtra(createTextComponentWithColor("did an unknown action to ", INTERACT.getColor()));
|
||||
}
|
||||
if (type != null) {
|
||||
msg.addExtra(prettyEntityType(type));
|
||||
} else {
|
||||
msg.addExtra(prettyMaterial("an unknown entity"));
|
||||
}
|
||||
if (loc != null) {
|
||||
msg.addExtra(" at ");
|
||||
msg.addExtra(prettyLocation(loc, entry));
|
||||
}
|
||||
return new BaseComponent[] { msg };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
}
|
114
src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java
Normal file
114
src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java
Normal file
@ -0,0 +1,114 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public class EntityTypeConverter {
|
||||
private static EntityType[] idToEntityType = new EntityType[10];
|
||||
private static HashMap<EntityType, Integer> entityTypeToId = new HashMap<>();
|
||||
private static int nextEntityTypeId;
|
||||
|
||||
public synchronized static Integer getExistingEntityTypeId(EntityType entityType) {
|
||||
return entityType == null ? null : entityTypeToId.get(entityType);
|
||||
}
|
||||
|
||||
public synchronized static int getOrAddEntityTypeId(EntityType entityType) {
|
||||
Integer key = entityTypeToId.get(entityType);
|
||||
int tries = 0;
|
||||
while (key == null && tries < 10) {
|
||||
tries++;
|
||||
key = nextEntityTypeId;
|
||||
Connection conn = LogBlock.getInstance().getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-entitytypes` (id, name) VALUES (?, ?)");
|
||||
smt.setInt(1, key);
|
||||
smt.setString(2, entityType.name());
|
||||
boolean couldAdd = smt.executeUpdate() > 0;
|
||||
conn.commit();
|
||||
smt.close();
|
||||
if (couldAdd) {
|
||||
internalAddEntityType(key, entityType);
|
||||
} else {
|
||||
initializeEntityTypes(conn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-entitytypes", e);
|
||||
reinitializeEntityTypesCatchException();
|
||||
if (tries == 10) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
key = entityTypeToId.get(entityType);
|
||||
}
|
||||
return key.intValue();
|
||||
}
|
||||
|
||||
public synchronized static EntityType getEntityType(int entityTypeId) {
|
||||
return entityTypeId >= 0 && entityTypeId < idToEntityType.length ? idToEntityType[entityTypeId] : null;
|
||||
}
|
||||
|
||||
private static void reinitializeEntityTypesCatchException() {
|
||||
Connection conn = LogBlock.getInstance().getConnection();
|
||||
try {
|
||||
initializeEntityTypes(conn);
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not reinitialize lb-entitytypes", e);
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (Exception e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized static void initializeEntityTypes(Connection connection) throws SQLException {
|
||||
Statement smt = connection.createStatement();
|
||||
ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`");
|
||||
while (rs.next()) {
|
||||
int key = rs.getInt(1);
|
||||
try {
|
||||
EntityType entityType = EntityType.valueOf(rs.getString(2));
|
||||
internalAddEntityType(key, entityType);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// the key is used, but not available in this version
|
||||
if (nextEntityTypeId <= key) {
|
||||
nextEntityTypeId = key + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
rs.close();
|
||||
smt.close();
|
||||
connection.close();
|
||||
}
|
||||
|
||||
private static void internalAddEntityType(int key, EntityType entityType) {
|
||||
entityTypeToId.put(entityType, key);
|
||||
int length = idToEntityType.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
}
|
||||
if (length > idToEntityType.length) {
|
||||
idToEntityType = Arrays.copyOf(idToEntityType, length);
|
||||
}
|
||||
idToEntityType[key] = entityType;
|
||||
if (nextEntityTypeId <= key) {
|
||||
nextEntityTypeId = key + 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,17 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import static de.diddiz.util.ActionColor.DESTROY;
|
||||
import static de.diddiz.util.MessagingUtil.prettyDate;
|
||||
import static de.diddiz.util.MessagingUtil.prettyLocation;
|
||||
import static de.diddiz.util.MessagingUtil.prettyMaterial;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import de.diddiz.util.MessagingUtil;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public class Kill implements LookupCacheElement {
|
||||
final long id, date;
|
||||
@ -35,17 +39,7 @@ public class Kill implements LookupCacheElement {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
if (date > 0) {
|
||||
msg.append(Config.formatter.format(date)).append(" ");
|
||||
}
|
||||
msg.append(killerName).append(" killed ").append(victimName);
|
||||
if (loc != null) {
|
||||
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
|
||||
}
|
||||
String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon));
|
||||
msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " )
|
||||
return msg.toString();
|
||||
return BaseComponent.toPlainText(getLogMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,14 +48,29 @@ public class Kill implements LookupCacheElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return toString();
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
TextComponent msg = new TextComponent();
|
||||
if (date > 0) {
|
||||
msg.addExtra(prettyDate(date));
|
||||
msg.addExtra(" ");
|
||||
}
|
||||
msg.addExtra(MessagingUtil.createTextComponentWithColor(killerName + " killed ", DESTROY.getColor()));
|
||||
msg.addExtra(new TextComponent(victimName));
|
||||
if (loc != null) {
|
||||
msg.addExtra(" at ");
|
||||
msg.addExtra(prettyLocation(loc, entry));
|
||||
}
|
||||
if (weapon != 0) {
|
||||
msg.addExtra(" with ");
|
||||
msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon)));
|
||||
}
|
||||
return new BaseComponent[] { msg };
|
||||
}
|
||||
|
||||
public String prettyItemName(Material t) {
|
||||
public TextComponent prettyItemName(Material t) {
|
||||
if (t == null || BukkitUtils.isEmpty(t)) {
|
||||
return "fist";
|
||||
return prettyMaterial("fist");
|
||||
}
|
||||
return t.toString().replace('_', ' ').toLowerCase();
|
||||
return prettyMaterial(t.toString().replace('_', ' '));
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.listeners.*;
|
||||
import de.diddiz.LogBlock.questioner.Questioner;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.util.MySQLConnectionPool;
|
||||
import de.diddiz.worldedit.WorldEditHelper;
|
||||
import de.diddiz.worldedit.WorldEditLoggingHook;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
@ -16,14 +18,12 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.*;
|
||||
@ -34,14 +34,20 @@ public class LogBlock extends JavaPlugin {
|
||||
private MySQLConnectionPool pool;
|
||||
private Consumer consumer = null;
|
||||
private CommandsHandler commandsHandler;
|
||||
private Updater updater = null;
|
||||
private Timer timer = null;
|
||||
private boolean errorAtLoading = false, noDb = false, connected = true;
|
||||
private boolean noDb = false, connected = true;
|
||||
private PlayerInfoLogging playerInfoLogging;
|
||||
private ScaffoldingLogging scaffoldingLogging;
|
||||
private Questioner questioner;
|
||||
private volatile boolean isCompletelyEnabled;
|
||||
|
||||
public static LogBlock getInstance() {
|
||||
return logblock;
|
||||
}
|
||||
|
||||
public boolean isCompletelyEnabled() {
|
||||
return isCompletelyEnabled;
|
||||
}
|
||||
|
||||
public Consumer getConsumer() {
|
||||
return consumer;
|
||||
}
|
||||
@ -50,20 +56,30 @@ public class LogBlock extends JavaPlugin {
|
||||
return commandsHandler;
|
||||
}
|
||||
|
||||
Updater getUpdater() {
|
||||
return updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
public void onEnable() {
|
||||
logblock = this;
|
||||
|
||||
BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run
|
||||
final PluginManager pm = getPluginManager();
|
||||
|
||||
consumer = new Consumer(this);
|
||||
try {
|
||||
updater = new Updater(this);
|
||||
Config.load(this);
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage());
|
||||
pm.disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
getLogger().info("Connecting to " + user + "@" + url + "...");
|
||||
pool = new MySQLConnectionPool(url, user, password);
|
||||
final Connection conn = getConnection();
|
||||
try {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
}
|
||||
pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL);
|
||||
final Connection conn = getConnection(true);
|
||||
if (conn == null) {
|
||||
noDb = true;
|
||||
return;
|
||||
@ -76,9 +92,11 @@ public class LogBlock extends JavaPlugin {
|
||||
st.executeQuery("SET NAMES utf8mb4;");
|
||||
}
|
||||
conn.close();
|
||||
Updater updater = new Updater(this);
|
||||
updater.checkTables();
|
||||
MaterialConverter.initializeMaterials(getConnection());
|
||||
MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry
|
||||
MaterialConverter.getOrAddMaterialId(Material.AIR); // AIR must be the first entry
|
||||
EntityTypeConverter.initializeEntityTypes(getConnection());
|
||||
if (updater.update()) {
|
||||
load(this);
|
||||
}
|
||||
@ -86,75 +104,43 @@ public class LogBlock extends JavaPlugin {
|
||||
getLogger().log(Level.SEVERE, "Error while loading: ", ex);
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex);
|
||||
errorAtLoading = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run
|
||||
final PluginManager pm = getPluginManager();
|
||||
if (errorAtLoading) {
|
||||
pm.disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
if (noDb) {
|
||||
return;
|
||||
}
|
||||
if (pm.getPlugin("WorldEdit") != null) {
|
||||
if (Integer.parseInt(pm.getPlugin("WorldEdit").getDescription().getVersion().substring(0, 1)) > 5) {
|
||||
new WorldEditLoggingHook(this).hook();
|
||||
} else {
|
||||
getLogger().warning("Failed to hook into WorldEdit. Your WorldEdit version seems to be outdated, please make sure WorldEdit is at least version 6.");
|
||||
}
|
||||
|
||||
if (WorldEditHelper.hasWorldEdit()) {
|
||||
new WorldEditLoggingHook(this).hook();
|
||||
}
|
||||
commandsHandler = new CommandsHandler(this);
|
||||
getCommand("lb").setExecutor(commandsHandler);
|
||||
if (enableAutoClearLog && autoClearLogDelay > 0) {
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20);
|
||||
}
|
||||
getServer().getScheduler().runTaskAsynchronously(this, new DumpedLogImporter(this));
|
||||
new DumpedLogImporter(this).run();
|
||||
registerEvents();
|
||||
if (useBukkitScheduler) {
|
||||
if (getServer().getScheduler().runTaskTimerAsynchronously(this, consumer, delayBetweenRuns < 20 ? 20 : delayBetweenRuns, delayBetweenRuns).getTaskId() > 0) {
|
||||
getLogger().info("Scheduled consumer with bukkit scheduler.");
|
||||
} else {
|
||||
getLogger().warning("Failed to schedule consumer with bukkit scheduler. Now trying schedule with timer.");
|
||||
timer = new Timer();
|
||||
timer.schedule(consumer, delayBetweenRuns < 20 ? 1000 : delayBetweenRuns * 50, delayBetweenRuns * 50);
|
||||
}
|
||||
} else {
|
||||
timer = new Timer();
|
||||
timer.schedule(consumer, delayBetweenRuns < 20 ? 1000 : delayBetweenRuns * 50, delayBetweenRuns * 50);
|
||||
getLogger().info("Scheduled consumer with timer.");
|
||||
}
|
||||
getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this));
|
||||
consumer.start();
|
||||
for (final Tool tool : toolsByType.values()) {
|
||||
if (pm.getPermission("logblock.tools." + tool.name) == null) {
|
||||
final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault);
|
||||
pm.addPermission(perm);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Metrics metrics = new Metrics(this);
|
||||
metrics.start();
|
||||
} catch (IOException ex) {
|
||||
getLogger().info("Could not start metrics: " + ex.getMessage());
|
||||
}
|
||||
questioner = new Questioner(this);
|
||||
isCompletelyEnabled = true;
|
||||
getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this));
|
||||
}
|
||||
|
||||
private void registerEvents() {
|
||||
final PluginManager pm = getPluginManager();
|
||||
pm.registerEvents(new ToolListener(this), this);
|
||||
pm.registerEvents(new PlayerInfoLogging(this), this);
|
||||
pm.registerEvents(playerInfoLogging = new PlayerInfoLogging(this), this);
|
||||
if (askRollbackAfterBan) {
|
||||
pm.registerEvents(new BanListener(this), this);
|
||||
}
|
||||
if (isLogging(Logging.BLOCKPLACE)) {
|
||||
pm.registerEvents(new BlockPlaceLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.BLOCKPLACE) || isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) {
|
||||
if (isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) {
|
||||
pm.registerEvents(new FluidFlowLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.BLOCKBREAK)) {
|
||||
@ -172,6 +158,9 @@ public class LogBlock extends JavaPlugin {
|
||||
if (isLogging(Logging.SNOWFADE)) {
|
||||
pm.registerEvents(new SnowFadeLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.SCAFFOLDING)) {
|
||||
pm.registerEvents(scaffoldingLogging = new ScaffoldingLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) {
|
||||
pm.registerEvents(new ExplosionLogging(this), this);
|
||||
}
|
||||
@ -181,7 +170,8 @@ public class LogBlock extends JavaPlugin {
|
||||
if (isLogging(Logging.CHESTACCESS)) {
|
||||
pm.registerEvents(new ChestAccessLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT) || isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) {
|
||||
if (isLogging(Logging.BLOCKBREAK) || isLogging(Logging.BLOCKPLACE) || isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT)
|
||||
|| isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) {
|
||||
pm.registerEvents(new InteractLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.CREATURECROPTRAMPLE)) {
|
||||
@ -190,7 +180,7 @@ public class LogBlock extends JavaPlugin {
|
||||
if (isLogging(Logging.KILL)) {
|
||||
pm.registerEvents(new KillLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.CHAT)) {
|
||||
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
pm.registerEvents(new ChatLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.ENDERMEN)) {
|
||||
@ -205,40 +195,41 @@ public class LogBlock extends JavaPlugin {
|
||||
if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD)) {
|
||||
pm.registerEvents(new BlockSpreadLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.DRAGONEGGTELEPORT)) {
|
||||
pm.registerEvents(new DragonEggLogging(this), this);
|
||||
}
|
||||
if (isLogging(Logging.LECTERNBOOKCHANGE)) {
|
||||
pm.registerEvents(new LecternLogging(this), this);
|
||||
}
|
||||
if (Config.isLoggingAnyEntities()) {
|
||||
if (!WorldEditHelper.hasFullWorldEdit()) {
|
||||
getLogger().severe("No compatible WorldEdit found, entity logging will not work!");
|
||||
} else {
|
||||
pm.registerEvents(new AdvancedEntityLogging(this), this);
|
||||
getLogger().info("Entity logging enabled!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
}
|
||||
isCompletelyEnabled = false;
|
||||
getServer().getScheduler().cancelTasks(this);
|
||||
if (consumer != null) {
|
||||
if (logPlayerInfo && getServer().getOnlinePlayers() != null) {
|
||||
if (logPlayerInfo && playerInfoLogging != null) {
|
||||
for (final Player player : getServer().getOnlinePlayers()) {
|
||||
consumer.queueLeave(player);
|
||||
playerInfoLogging.onPlayerQuit(player);
|
||||
}
|
||||
}
|
||||
getLogger().info("Waiting for consumer ...");
|
||||
consumer.run();
|
||||
consumer.shutdown();
|
||||
if (consumer.getQueueSize() > 0) {
|
||||
int tries = 9;
|
||||
while (consumer.getQueueSize() > 0) {
|
||||
getLogger().info("Remaining queue size: " + consumer.getQueueSize());
|
||||
if (tries > 0) {
|
||||
getLogger().info("Remaining tries: " + tries);
|
||||
} else {
|
||||
getLogger().info("Unable to save queue to database. Trying to write to a local file.");
|
||||
try {
|
||||
consumer.writeToFile();
|
||||
getLogger().info("Successfully dumped queue.");
|
||||
} catch (final FileNotFoundException ex) {
|
||||
getLogger().info("Failed to write. Given up.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
consumer.run();
|
||||
tries--;
|
||||
getLogger().info("Remaining queue size: " + consumer.getQueueSize() + ". Trying to write to a local file.");
|
||||
try {
|
||||
consumer.writeToFile();
|
||||
getLogger().info("Successfully dumped queue.");
|
||||
} catch (final FileNotFoundException ex) {
|
||||
getLogger().info("Failed to write. Given up.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,6 +251,10 @@ public class LogBlock extends JavaPlugin {
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return getConnection(false);
|
||||
}
|
||||
|
||||
public Connection getConnection(boolean testConnection) {
|
||||
try {
|
||||
final Connection conn = pool.getConnection();
|
||||
if (!connected) {
|
||||
@ -268,7 +263,9 @@ public class LogBlock extends JavaPlugin {
|
||||
}
|
||||
return conn;
|
||||
} catch (final Exception ex) {
|
||||
if (connected) {
|
||||
if (testConnection) {
|
||||
getLogger().log(Level.SEVERE, "Could not connect to the Database! Please check your config! " + ex.getMessage());
|
||||
} else if (connected) {
|
||||
getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex);
|
||||
connected = false;
|
||||
} else {
|
||||
@ -299,7 +296,7 @@ public class LogBlock extends JavaPlugin {
|
||||
try {
|
||||
state = conn.createStatement();
|
||||
final ResultSet rs = state.executeQuery(params.getQuery());
|
||||
final List<BlockChange> blockchanges = new ArrayList<BlockChange>();
|
||||
final List<BlockChange> blockchanges = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
blockchanges.add(new BlockChange(rs, params));
|
||||
}
|
||||
@ -313,6 +310,9 @@ public class LogBlock extends JavaPlugin {
|
||||
}
|
||||
|
||||
public int getCount(QueryParams params) throws SQLException {
|
||||
if (params == null || params.world == null || !Config.isLogged(params.world)) {
|
||||
throw new IllegalArgumentException("World is not logged: " + ((params == null || params.world == null) ? "null" : params.world.getName()));
|
||||
}
|
||||
final Connection conn = getConnection();
|
||||
Statement state = null;
|
||||
if (conn == null) {
|
||||
@ -334,9 +334,17 @@ public class LogBlock extends JavaPlugin {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public File getFile() {
|
||||
return super.getFile();
|
||||
}
|
||||
|
||||
public Questioner getQuestioner() {
|
||||
return questioner;
|
||||
}
|
||||
|
||||
public ScaffoldingLogging getScaffoldingLogging() {
|
||||
return scaffoldingLogging;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,55 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
public enum Logging {
|
||||
BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true),
|
||||
GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY,
|
||||
LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT,
|
||||
SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT,
|
||||
PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE,
|
||||
NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD,
|
||||
WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW,
|
||||
WORLDEDIT, TNTMINECARTEXPLOSION(true), ENDERCRYSTALEXPLOSION(true);
|
||||
BLOCKPLACE(true),
|
||||
BLOCKBREAK(true),
|
||||
SIGNTEXT(true),
|
||||
TNTEXPLOSION(true),
|
||||
CREEPEREXPLOSION(true),
|
||||
GHASTFIREBALLEXPLOSION(true),
|
||||
ENDERDRAGON(true),
|
||||
MISCEXPLOSION(true),
|
||||
FIRE(true),
|
||||
LEAVESDECAY,
|
||||
LAVAFLOW,
|
||||
WATERFLOW,
|
||||
CHESTACCESS,
|
||||
KILL,
|
||||
CHAT,
|
||||
SNOWFORM,
|
||||
SNOWFADE,
|
||||
DOORINTERACT,
|
||||
SWITCHINTERACT,
|
||||
CAKEEAT,
|
||||
ENDERMEN,
|
||||
NOTEBLOCKINTERACT,
|
||||
DIODEINTERACT,
|
||||
COMPARATORINTERACT,
|
||||
PRESUREPLATEINTERACT,
|
||||
TRIPWIREINTERACT,
|
||||
CREATURECROPTRAMPLE,
|
||||
CROPTRAMPLE,
|
||||
NATURALSTRUCTUREGROW,
|
||||
GRASSGROWTH,
|
||||
MYCELIUMSPREAD,
|
||||
VINEGROWTH,
|
||||
MUSHROOMSPREAD,
|
||||
BAMBOOGROWTH,
|
||||
WITHER(true),
|
||||
WITHER_SKULL(true),
|
||||
BONEMEALSTRUCTUREGROW,
|
||||
WORLDEDIT,
|
||||
TNTMINECARTEXPLOSION(true),
|
||||
ENDERCRYSTALEXPLOSION(true),
|
||||
BEDEXPLOSION(true),
|
||||
DRAGONEGGTELEPORT(true),
|
||||
DAYLIGHTDETECTORINTERACT,
|
||||
LECTERNBOOKCHANGE(true),
|
||||
SCAFFOLDING(true),
|
||||
SHULKER_BOX_CONTENT,
|
||||
PLAYER_COMMANDS,
|
||||
COMMANDBLOCK_COMMANDS,
|
||||
CONSOLE_COMMANDS;
|
||||
|
||||
public static final int length = Logging.values().length;
|
||||
private final boolean defaultEnabled;
|
||||
|
@ -1,9 +1,18 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public interface LookupCacheElement {
|
||||
public Location getLocation();
|
||||
|
||||
public String getMessage();
|
||||
public default BaseComponent[] getLogMessage() {
|
||||
return getLogMessage(-1);
|
||||
}
|
||||
|
||||
public BaseComponent[] getLogMessage(int entry);
|
||||
|
||||
public default int getNumChanges() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,12 @@ public class LookupCacheElementFactory {
|
||||
return new SummedKills(rs, params, spaceFactor);
|
||||
}
|
||||
}
|
||||
if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) {
|
||||
if (params.sum == SummarizationMode.NONE) {
|
||||
return new EntityChange(rs, params);
|
||||
}
|
||||
return new SummedEntityChanges(rs, params, spaceFactor);
|
||||
}
|
||||
if (params.sum == SummarizationMode.NONE) {
|
||||
return new BlockChange(rs, params);
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
public class MaterialConverter {
|
||||
@ -20,7 +21,7 @@ public class MaterialConverter {
|
||||
private static String[] idToBlockState = new String[10];
|
||||
private static HashMap<String, Integer> blockStateToID = new HashMap<>();
|
||||
private static int nextBlockStateId;
|
||||
|
||||
|
||||
private static HashMap<String, Material> materialKeyToMaterial = new HashMap<>();
|
||||
|
||||
static {
|
||||
@ -29,109 +30,227 @@ public class MaterialConverter {
|
||||
}
|
||||
}
|
||||
|
||||
public static int getOrAddMaterialId(NamespacedKey nameSpaceKey) {
|
||||
return getOrAddMaterialId(nameSpaceKey.toString());
|
||||
public synchronized static Integer getExistingMaterialId(BlockData blockData) {
|
||||
return blockData == null ? null : getExistingMaterialId(blockData.getMaterial());
|
||||
}
|
||||
|
||||
public static int getOrAddMaterialId(String blockDataString) {
|
||||
String materialString = blockDataString;
|
||||
int dataPart = blockDataString.indexOf("[");
|
||||
if (dataPart >= 0) {
|
||||
materialString = blockDataString.substring(0, dataPart);
|
||||
public synchronized static Integer getExistingMaterialId(Material material) {
|
||||
if (material == null) {
|
||||
return null;
|
||||
}
|
||||
String materialString = material.getKey().toString();
|
||||
return materialToID.get(materialString);
|
||||
}
|
||||
|
||||
public synchronized static int getOrAddMaterialId(BlockData blockData) {
|
||||
return getOrAddMaterialId(blockData == null ? Material.AIR : blockData.getMaterial());
|
||||
}
|
||||
|
||||
public synchronized static int getOrAddMaterialId(Material material) {
|
||||
if (material == null) {
|
||||
material = Material.AIR;
|
||||
}
|
||||
String materialString = material.getKey().toString();
|
||||
Integer key = materialToID.get(materialString);
|
||||
if (key == null) {
|
||||
key = nextMaterialId++;
|
||||
materialToID.put(materialString, key);
|
||||
int length = idToMaterial.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
int tries = 0;
|
||||
while (key == null && tries < 10) {
|
||||
tries++;
|
||||
key = nextMaterialId;
|
||||
Connection conn = LogBlock.getInstance().getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-materials` (id, name) VALUES (?, ?)");
|
||||
smt.setInt(1, key);
|
||||
smt.setString(2, materialString);
|
||||
boolean couldAdd = smt.executeUpdate() > 0;
|
||||
conn.commit();
|
||||
smt.close();
|
||||
if (couldAdd) {
|
||||
internalAddMaterial(key, materialString);
|
||||
} else {
|
||||
initializeMaterials(conn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-materials", e);
|
||||
reinitializeMaterialsCatchException();
|
||||
if (tries == 10) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
if (length > idToMaterial.length) {
|
||||
idToMaterial = Arrays.copyOf(idToMaterial, length);
|
||||
}
|
||||
idToMaterial[key] = materialString;
|
||||
LogBlock.getInstance().getConsumer().queueAddMaterialMapping(key, materialString);
|
||||
key = materialToID.get(materialString);
|
||||
}
|
||||
return key.intValue();
|
||||
}
|
||||
|
||||
public static int getOrAddBlockStateId(String blockDataString) {
|
||||
public synchronized static Integer getExistingBlockStateId(BlockData blockData) {
|
||||
if (blockData == null) {
|
||||
return -1;
|
||||
}
|
||||
String blockDataString = blockData.getAsString();
|
||||
int dataPart = blockDataString.indexOf("[");
|
||||
if (dataPart < 0) {
|
||||
return -1;
|
||||
}
|
||||
String materialString = blockDataString.substring(dataPart);
|
||||
return blockStateToID.get(materialString);
|
||||
}
|
||||
|
||||
public synchronized static int getOrAddBlockStateId(BlockData blockData) {
|
||||
if (blockData == null) {
|
||||
return -1;
|
||||
}
|
||||
String blockDataString = blockData.getAsString();
|
||||
int dataPart = blockDataString.indexOf("[");
|
||||
if (dataPart < 0) {
|
||||
return -1;
|
||||
}
|
||||
String materialString = blockDataString.substring(dataPart);
|
||||
Integer key = blockStateToID.get(materialString);
|
||||
if (key == null) {
|
||||
key = nextBlockStateId++;
|
||||
blockStateToID.put(materialString, key);
|
||||
int length = idToBlockState.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
int tries = 0;
|
||||
while (key == null && tries < 10) {
|
||||
tries++;
|
||||
key = nextBlockStateId;
|
||||
Connection conn = LogBlock.getInstance().getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-blockstates` (id, name) VALUES (?, ?)");
|
||||
smt.setInt(1, key);
|
||||
smt.setString(2, materialString);
|
||||
boolean couldAdd = smt.executeUpdate() > 0;
|
||||
conn.commit();
|
||||
smt.close();
|
||||
if (couldAdd) {
|
||||
internalAddBlockState(key, materialString);
|
||||
} else {
|
||||
initializeMaterials(conn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-blockstates", e);
|
||||
reinitializeMaterialsCatchException();
|
||||
if (tries == 10) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
if (length > idToBlockState.length) {
|
||||
idToBlockState = Arrays.copyOf(idToBlockState, length);
|
||||
}
|
||||
idToBlockState[key] = materialString;
|
||||
LogBlock.getInstance().getConsumer().queueAddBlockStateMapping(key, materialString);
|
||||
key = blockStateToID.get(materialString);
|
||||
}
|
||||
return key.intValue();
|
||||
}
|
||||
|
||||
public static BlockData getBlockData(int materialId, int blockStateId) {
|
||||
String material = idToMaterial[materialId];
|
||||
if (blockStateId >= 0) {
|
||||
material = material + idToBlockState[blockStateId];
|
||||
public synchronized static BlockData getBlockData(int materialId, int blockStateId) {
|
||||
String material = materialId >= 0 && materialId < idToMaterial.length ? idToMaterial[materialId] : null;
|
||||
if (material == null) {
|
||||
return null;
|
||||
}
|
||||
if (blockStateId >= 0 && blockStateId < idToBlockState.length && idToBlockState[blockStateId] != null) {
|
||||
material = material + updateBlockState(material, idToBlockState[blockStateId]);
|
||||
}
|
||||
try {
|
||||
return Bukkit.createBlockData(material);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// fall back to create the default block data for the material
|
||||
try {
|
||||
return Bukkit.createBlockData(idToMaterial[materialId]);
|
||||
} catch (IllegalArgumentException ignored2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return Bukkit.createBlockData(material);
|
||||
}
|
||||
|
||||
public static Material getMaterial(int materialId) {
|
||||
return materialKeyToMaterial.get(idToMaterial[materialId]);
|
||||
public synchronized static Material getMaterial(int materialId) {
|
||||
return materialId >= 0 && materialId < idToMaterial.length ? materialKeyToMaterial.get(idToMaterial[materialId]) : null;
|
||||
}
|
||||
|
||||
public static void initializeMaterials(Connection connection) throws SQLException {
|
||||
private static void reinitializeMaterialsCatchException() {
|
||||
Connection conn = LogBlock.getInstance().getConnection();
|
||||
try {
|
||||
initializeMaterials(conn);
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not reinitialize lb-materials", e);
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (Exception e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized static void initializeMaterials(Connection connection) throws SQLException {
|
||||
Statement smt = connection.createStatement();
|
||||
ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-materials`");
|
||||
while (rs.next()) {
|
||||
int key = rs.getInt(1);
|
||||
String materialString = rs.getString(2);
|
||||
|
||||
materialToID.put(materialString, key);
|
||||
int length = idToMaterial.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
}
|
||||
if (length > idToMaterial.length) {
|
||||
idToMaterial = Arrays.copyOf(idToMaterial, length);
|
||||
}
|
||||
idToMaterial[key] = materialString;
|
||||
if (nextMaterialId <= key) {
|
||||
nextMaterialId = key + 1;
|
||||
}
|
||||
internalAddMaterial(key, materialString);
|
||||
}
|
||||
rs.close();
|
||||
rs = smt.executeQuery("SELECT id, name FROM `lb-blockstates`");
|
||||
while (rs.next()) {
|
||||
int key = rs.getInt(1);
|
||||
String materialString = rs.getString(2);
|
||||
|
||||
blockStateToID.put(materialString, key);
|
||||
int length = idToBlockState.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
}
|
||||
if (length > idToBlockState.length) {
|
||||
idToBlockState = Arrays.copyOf(idToBlockState, length);
|
||||
}
|
||||
idToBlockState[key] = materialString;
|
||||
if (nextBlockStateId <= key) {
|
||||
nextBlockStateId = key + 1;
|
||||
}
|
||||
internalAddBlockState(key, materialString);
|
||||
}
|
||||
rs.close();
|
||||
smt.close();
|
||||
connection.close();
|
||||
}
|
||||
|
||||
private static void internalAddMaterial(int key, String materialString) {
|
||||
materialToID.put(materialString, key);
|
||||
int length = idToMaterial.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
}
|
||||
if (length > idToMaterial.length) {
|
||||
idToMaterial = Arrays.copyOf(idToMaterial, length);
|
||||
}
|
||||
idToMaterial[key] = materialString;
|
||||
if (nextMaterialId <= key) {
|
||||
nextMaterialId = key + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void internalAddBlockState(int key, String materialString) {
|
||||
blockStateToID.put(materialString, key);
|
||||
int length = idToBlockState.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
}
|
||||
if (length > idToBlockState.length) {
|
||||
idToBlockState = Arrays.copyOf(idToBlockState, length);
|
||||
}
|
||||
idToBlockState[key] = materialString;
|
||||
if (nextBlockStateId <= key) {
|
||||
nextBlockStateId = key + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static String updateBlockState(String material, String blockState) {
|
||||
// since 1.16
|
||||
if (material.endsWith("_wall")) {
|
||||
if (blockState.contains("east=false") || blockState.contains("east=true")) {
|
||||
blockState = blockState.replace("east=false", "east=none");
|
||||
blockState = blockState.replace("west=false", "west=none");
|
||||
blockState = blockState.replace("north=false", "north=none");
|
||||
blockState = blockState.replace("south=false", "south=none");
|
||||
blockState = blockState.replace("east=true", "east=low");
|
||||
blockState = blockState.replace("west=true", "west=low");
|
||||
blockState = blockState.replace("north=true", "north=low");
|
||||
blockState = blockState.replace("south=true", "south=low");
|
||||
}
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
}
|
||||
|
@ -1,750 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Tyler Blair. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and contributors and should not be interpreted as representing official policies,
|
||||
* either expressed or implied, of anybody else.
|
||||
*/
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class Metrics {
|
||||
|
||||
/**
|
||||
* The current revision number
|
||||
*/
|
||||
private final static int REVISION = 7;
|
||||
|
||||
/**
|
||||
* The base url of the metrics domain
|
||||
*/
|
||||
private static final String BASE_URL = "http://report.mcstats.org";
|
||||
|
||||
/**
|
||||
* The url used to report a server's status
|
||||
*/
|
||||
private static final String REPORT_URL = "/plugin/%s";
|
||||
|
||||
/**
|
||||
* Interval of time to ping (in minutes)
|
||||
*/
|
||||
private static final int PING_INTERVAL = 15;
|
||||
|
||||
/**
|
||||
* The plugin this metrics submits for
|
||||
*/
|
||||
private final Plugin plugin;
|
||||
|
||||
/**
|
||||
* All of the custom graphs to submit to metrics
|
||||
*/
|
||||
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
|
||||
|
||||
/**
|
||||
* The plugin configuration file
|
||||
*/
|
||||
private final YamlConfiguration configuration;
|
||||
|
||||
/**
|
||||
* The plugin configuration file
|
||||
*/
|
||||
private final File configurationFile;
|
||||
|
||||
/**
|
||||
* Unique server id
|
||||
*/
|
||||
private final String guid;
|
||||
|
||||
/**
|
||||
* Debug mode
|
||||
*/
|
||||
private final boolean debug;
|
||||
|
||||
/**
|
||||
* Lock for synchronization
|
||||
*/
|
||||
private final Object optOutLock = new Object();
|
||||
|
||||
/**
|
||||
* The scheduled task
|
||||
*/
|
||||
private volatile BukkitTask task = null;
|
||||
|
||||
public Metrics(final Plugin plugin) throws IOException {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null");
|
||||
}
|
||||
|
||||
this.plugin = plugin;
|
||||
|
||||
// load the config
|
||||
configurationFile = getConfigFile();
|
||||
configuration = YamlConfiguration.loadConfiguration(configurationFile);
|
||||
|
||||
// add some defaults
|
||||
configuration.addDefault("opt-out", false);
|
||||
configuration.addDefault("guid", UUID.randomUUID().toString());
|
||||
configuration.addDefault("debug", false);
|
||||
|
||||
// Do we need to create the file?
|
||||
if (configuration.get("guid", null) == null) {
|
||||
configuration.options().header("http://mcstats.org").copyDefaults(true);
|
||||
configuration.save(configurationFile);
|
||||
}
|
||||
|
||||
// Load the guid then
|
||||
guid = configuration.getString("guid");
|
||||
debug = configuration.getBoolean("debug", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
|
||||
* website. Plotters can be added to the graph object returned.
|
||||
*
|
||||
* @param name The name of the graph
|
||||
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
|
||||
*/
|
||||
public Graph createGraph(final String name) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("Graph name cannot be null");
|
||||
}
|
||||
|
||||
// Construct the graph object
|
||||
final Graph graph = new Graph(name);
|
||||
|
||||
// Now we can add our graph
|
||||
graphs.add(graph);
|
||||
|
||||
// and return back
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
|
||||
*
|
||||
* @param graph The name of the graph
|
||||
*/
|
||||
public void addGraph(final Graph graph) {
|
||||
if (graph == null) {
|
||||
throw new IllegalArgumentException("Graph cannot be null");
|
||||
}
|
||||
|
||||
graphs.add(graph);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
|
||||
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
|
||||
* ticks.
|
||||
*
|
||||
* @return True if statistics measuring is running, otherwise false.
|
||||
*/
|
||||
public boolean start() {
|
||||
synchronized (optOutLock) {
|
||||
// Did we opt out?
|
||||
if (isOptOut()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is metrics already running?
|
||||
if (task != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Begin hitting the server with glorious data
|
||||
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
|
||||
|
||||
private boolean firstPost = true;
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
// This has to be synchronized or it can collide with the disable method.
|
||||
synchronized (optOutLock) {
|
||||
// Disable Task, if it is running and the server owner decided to opt-out
|
||||
if (isOptOut() && task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
// Tell all plotters to stop gathering information.
|
||||
for (Graph graph : graphs) {
|
||||
graph.onOptOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We use the inverse of firstPost because if it is the first time we are posting,
|
||||
// it is not a interval ping, so it evaluates to FALSE
|
||||
// Each time thereafter it will evaluate to TRUE, i.e PING!
|
||||
postPlugin(!firstPost);
|
||||
|
||||
// After the first post we set firstPost to false
|
||||
// Each post thereafter will be a ping
|
||||
firstPost = false;
|
||||
} catch (IOException e) {
|
||||
if (debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, PING_INTERVAL * 1200);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the server owner denied plugin metrics?
|
||||
*
|
||||
* @return true if metrics should be opted out of it
|
||||
*/
|
||||
public boolean isOptOut() {
|
||||
synchronized (optOutLock) {
|
||||
try {
|
||||
// Reload the metrics file
|
||||
configuration.load(getConfigFile());
|
||||
} catch (IOException ex) {
|
||||
if (debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
return true;
|
||||
} catch (InvalidConfigurationException ex) {
|
||||
if (debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return configuration.getBoolean("opt-out", false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void enable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the task.
|
||||
synchronized (optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set it.
|
||||
if (isOptOut()) {
|
||||
configuration.set("opt-out", false);
|
||||
configuration.save(configurationFile);
|
||||
}
|
||||
|
||||
// Enable Task, if it is not running
|
||||
if (task == null) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void disable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the task.
|
||||
synchronized (optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set it.
|
||||
if (!isOptOut()) {
|
||||
configuration.set("opt-out", true);
|
||||
configuration.save(configurationFile);
|
||||
}
|
||||
|
||||
// Disable Task, if it is running
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
|
||||
*
|
||||
* @return the File object for the config file
|
||||
*/
|
||||
public File getConfigFile() {
|
||||
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
|
||||
// is to abuse the plugin object we already have
|
||||
// plugin.getDataFolder() => base/plugins/PluginA/
|
||||
// pluginsFolder => base/plugins/
|
||||
// The base is not necessarily relative to the startup directory.
|
||||
File pluginsFolder = plugin.getDataFolder().getParentFile();
|
||||
|
||||
// return => base/plugins/PluginMetrics/config.yml
|
||||
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method that posts a plugin to the metrics website
|
||||
*/
|
||||
private void postPlugin(final boolean isPing) throws IOException {
|
||||
// Server software specific section
|
||||
PluginDescriptionFile description = plugin.getDescription();
|
||||
String pluginName = description.getName();
|
||||
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
|
||||
String pluginVersion = description.getVersion();
|
||||
String serverVersion = Bukkit.getVersion();
|
||||
int playersOnline = Bukkit.getServer().getOnlinePlayers().size();
|
||||
|
||||
// END server software specific section -- all code below does not use any code outside of this class / Java
|
||||
|
||||
// Construct the post data
|
||||
StringBuilder json = new StringBuilder(1024);
|
||||
json.append('{');
|
||||
|
||||
// The plugin's description file containg all of the plugin data such as name, version, author, etc
|
||||
appendJSONPair(json, "guid", guid);
|
||||
appendJSONPair(json, "plugin_version", pluginVersion);
|
||||
appendJSONPair(json, "server_version", serverVersion);
|
||||
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
|
||||
|
||||
// New data as of R6
|
||||
String osname = System.getProperty("os.name");
|
||||
String osarch = System.getProperty("os.arch");
|
||||
String osversion = System.getProperty("os.version");
|
||||
String java_version = System.getProperty("java.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
// normalize os arch .. amd64 -> x86_64
|
||||
if (osarch.equals("amd64")) {
|
||||
osarch = "x86_64";
|
||||
}
|
||||
|
||||
appendJSONPair(json, "osname", osname);
|
||||
appendJSONPair(json, "osarch", osarch);
|
||||
appendJSONPair(json, "osversion", osversion);
|
||||
appendJSONPair(json, "cores", Integer.toString(coreCount));
|
||||
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
|
||||
appendJSONPair(json, "java_version", java_version);
|
||||
|
||||
// If we're pinging, append it
|
||||
if (isPing) {
|
||||
appendJSONPair(json, "ping", "1");
|
||||
}
|
||||
|
||||
if (graphs.size() > 0) {
|
||||
synchronized (graphs) {
|
||||
json.append(',');
|
||||
json.append('"');
|
||||
json.append("graphs");
|
||||
json.append('"');
|
||||
json.append(':');
|
||||
json.append('{');
|
||||
|
||||
boolean firstGraph = true;
|
||||
|
||||
final Iterator<Graph> iter = graphs.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Graph graph = iter.next();
|
||||
|
||||
StringBuilder graphJson = new StringBuilder();
|
||||
graphJson.append('{');
|
||||
|
||||
for (Plotter plotter : graph.getPlotters()) {
|
||||
appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue()));
|
||||
}
|
||||
|
||||
graphJson.append('}');
|
||||
|
||||
if (!firstGraph) {
|
||||
json.append(',');
|
||||
}
|
||||
|
||||
json.append(escapeJSON(graph.getName()));
|
||||
json.append(':');
|
||||
json.append(graphJson);
|
||||
|
||||
firstGraph = false;
|
||||
}
|
||||
|
||||
json.append('}');
|
||||
}
|
||||
}
|
||||
|
||||
// close json
|
||||
json.append('}');
|
||||
|
||||
// Create the url
|
||||
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
|
||||
|
||||
// Connect to the website
|
||||
URLConnection connection;
|
||||
|
||||
// Mineshafter creates a socks proxy, so we can safely bypass it
|
||||
// It does not reroute POST requests so we need to go around it
|
||||
if (isMineshafterPresent()) {
|
||||
connection = url.openConnection(Proxy.NO_PROXY);
|
||||
} else {
|
||||
connection = url.openConnection();
|
||||
}
|
||||
|
||||
|
||||
byte[] uncompressed = json.toString().getBytes();
|
||||
byte[] compressed = gzip(json.toString());
|
||||
|
||||
// Headers
|
||||
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
|
||||
connection.addRequestProperty("Content-Type", "application/json");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
|
||||
connection.setDoOutput(true);
|
||||
|
||||
if (debug) {
|
||||
System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
|
||||
}
|
||||
|
||||
// Write the data
|
||||
OutputStream os = connection.getOutputStream();
|
||||
os.write(compressed);
|
||||
os.flush();
|
||||
|
||||
// Now read the response
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String response = reader.readLine();
|
||||
|
||||
// close resources
|
||||
os.close();
|
||||
reader.close();
|
||||
|
||||
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
|
||||
if (response == null) {
|
||||
response = "null";
|
||||
} else if (response.startsWith("7")) {
|
||||
response = response.substring(response.startsWith("7,") ? 2 : 1);
|
||||
}
|
||||
|
||||
throw new IOException(response);
|
||||
} else {
|
||||
// Is this the first update this hour?
|
||||
if (response.equals("1") || response.contains("This is your first update this hour")) {
|
||||
synchronized (graphs) {
|
||||
final Iterator<Graph> iter = graphs.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final Graph graph = iter.next();
|
||||
|
||||
for (Plotter plotter : graph.getPlotters()) {
|
||||
plotter.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GZip compress a string of bytes
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static byte[] gzip(String input) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzos = null;
|
||||
|
||||
try {
|
||||
gzos = new GZIPOutputStream(baos);
|
||||
gzos.write(input.getBytes("UTF-8"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (gzos != null) {
|
||||
try {
|
||||
gzos.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
|
||||
*
|
||||
* @return true if mineshafter is installed on the server
|
||||
*/
|
||||
private boolean isMineshafterPresent() {
|
||||
try {
|
||||
Class.forName("mineshafter.MineServer");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a json encoded key/value pair to the given string builder.
|
||||
*
|
||||
* @param json
|
||||
* @param key
|
||||
* @param value
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
|
||||
boolean isValueNumeric = false;
|
||||
|
||||
try {
|
||||
if (value.equals("0") || !value.endsWith("0")) {
|
||||
Double.parseDouble(value);
|
||||
isValueNumeric = true;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
isValueNumeric = false;
|
||||
}
|
||||
|
||||
if (json.charAt(json.length() - 1) != '{') {
|
||||
json.append(',');
|
||||
}
|
||||
|
||||
json.append(escapeJSON(key));
|
||||
json.append(':');
|
||||
|
||||
if (isValueNumeric) {
|
||||
json.append(value);
|
||||
} else {
|
||||
json.append(escapeJSON(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string to create a valid JSON string
|
||||
*
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
private static String escapeJSON(String text) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append('"');
|
||||
for (int index = 0; index < text.length(); index++) {
|
||||
char chr = text.charAt(index);
|
||||
|
||||
switch (chr) {
|
||||
case '"':
|
||||
case '\\':
|
||||
builder.append('\\');
|
||||
builder.append(chr);
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
default:
|
||||
if (chr < ' ') {
|
||||
String t = "000" + Integer.toHexString(chr);
|
||||
builder.append("\\u" + t.substring(t.length() - 4));
|
||||
} else {
|
||||
builder.append(chr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
builder.append('"');
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode text as UTF-8
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the encoded text, as UTF-8
|
||||
*/
|
||||
private static String urlEncode(final String text) throws UnsupportedEncodingException {
|
||||
return URLEncoder.encode(text, "UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom graph on the website
|
||||
*/
|
||||
public static class Graph {
|
||||
|
||||
/**
|
||||
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
|
||||
* rejected
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The set of plotters that are contained within this graph
|
||||
*/
|
||||
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
|
||||
|
||||
private Graph(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the graph's name
|
||||
*
|
||||
* @return the Graph's name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plotter to the graph, which will be used to plot entries
|
||||
*
|
||||
* @param plotter the plotter to add to the graph
|
||||
*/
|
||||
public void addPlotter(final Plotter plotter) {
|
||||
plotters.add(plotter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a plotter from the graph
|
||||
*
|
||||
* @param plotter the plotter to remove from the graph
|
||||
*/
|
||||
public void removePlotter(final Plotter plotter) {
|
||||
plotters.remove(plotter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
|
||||
*
|
||||
* @return an unmodifiable {@link java.util.Set} of the plotter objects
|
||||
*/
|
||||
public Set<Plotter> getPlotters() {
|
||||
return Collections.unmodifiableSet(plotters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (!(object instanceof Graph)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Graph graph = (Graph) object;
|
||||
return graph.name.equals(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
|
||||
*/
|
||||
protected void onOptOut() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to collect custom data for a plugin
|
||||
*/
|
||||
public static abstract class Plotter {
|
||||
|
||||
/**
|
||||
* The plot's name
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Construct a plotter with the default plot name
|
||||
*/
|
||||
public Plotter() {
|
||||
this("Default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a plotter with a specific plot name
|
||||
*
|
||||
* @param name the name of the plotter to use, which will show up on the website
|
||||
*/
|
||||
public Plotter(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current value for the plotted point. Since this function defers to an external function it may or may
|
||||
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
|
||||
* from any thread so care should be taken when accessing resources that need to be synchronized.
|
||||
*
|
||||
* @return the current value for the point to be plotted.
|
||||
*/
|
||||
public abstract int getValue();
|
||||
|
||||
/**
|
||||
* Get the column name for the plotted point
|
||||
*
|
||||
* @return the plotted point's column name
|
||||
*/
|
||||
public String getColumnName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the website graphs have been updated
|
||||
*/
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getColumnName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (!(object instanceof Plotter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Plotter plotter = (Plotter) object;
|
||||
return plotter.name.equals(name) && plotter.getValue() == getValue();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -10,14 +10,14 @@ import static de.diddiz.LogBlock.config.Config.toolsByType;
|
||||
import static org.bukkit.Bukkit.getServer;
|
||||
|
||||
public class Session {
|
||||
private static final Map<String, Session> sessions = new HashMap<String, Session>();
|
||||
private static final Map<String, Session> sessions = new HashMap<>();
|
||||
public QueryParams lastQuery = null;
|
||||
public LookupCacheElement[] lookupCache = null;
|
||||
public int page = 1;
|
||||
public Map<Tool, ToolData> toolData;
|
||||
|
||||
private Session(Player player) {
|
||||
toolData = new HashMap<Tool, ToolData>();
|
||||
toolData = new HashMap<>();
|
||||
final LogBlock logblock = LogBlock.getInstance();
|
||||
if (player != null) {
|
||||
for (final Tool tool : toolsByType.values()) {
|
||||
|
@ -1,12 +1,14 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import static de.diddiz.util.MessagingUtil.prettyMaterial;
|
||||
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import de.diddiz.util.MessagingUtil;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static de.diddiz.util.Utils.spaces;
|
||||
import java.util.Objects;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class SummedBlockChanges implements LookupCacheElement {
|
||||
private final int type;
|
||||
@ -29,7 +31,12 @@ public class SummedBlockChanges implements LookupCacheElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : MaterialConverter.getMaterial(type).toString());
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type))), 10, 10, spaceFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumChanges() {
|
||||
return created + destroyed;
|
||||
}
|
||||
}
|
||||
|
44
src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java
Normal file
44
src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java
Normal file
@ -0,0 +1,44 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
|
||||
import de.diddiz.util.MessagingUtil;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
|
||||
import static de.diddiz.util.MessagingUtil.prettyMaterial;
|
||||
|
||||
public class SummedEntityChanges implements LookupCacheElement {
|
||||
private final int type;
|
||||
private final int created, destroyed;
|
||||
private final float spaceFactor;
|
||||
private final Actor actor;
|
||||
|
||||
public SummedEntityChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException {
|
||||
// Actor currently useless here as we don't yet output UUID in results anywhere
|
||||
actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null;
|
||||
type = p.sum == SummarizationMode.TYPES ? rs.getInt("entitytypeid") : 0;
|
||||
created = rs.getInt("created");
|
||||
destroyed = rs.getInt("destroyed");
|
||||
this.spaceFactor = spaceFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(EntityTypeConverter.getEntityType(type))), 10, 10, spaceFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumChanges() {
|
||||
return created + destroyed;
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import de.diddiz.util.MessagingUtil;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static de.diddiz.util.Utils.spaces;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class SummedKills implements LookupCacheElement {
|
||||
private final Actor player;
|
||||
@ -25,7 +25,12 @@ public class SummedKills implements LookupCacheElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return kills + spaces((int) ((6 - String.valueOf(kills).length()) / spaceFactor)) + killed + spaces((int) ((7 - String.valueOf(killed).length()) / spaceFactor)) + player.getName();
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumChanges() {
|
||||
return kills + killed;
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,10 @@ public class Tool {
|
||||
public final QueryParams params;
|
||||
public final ToolMode mode;
|
||||
public final PermissionDefault permissionDefault;
|
||||
public final boolean removeOnDisable;
|
||||
public final boolean dropToDisable;
|
||||
|
||||
public Tool(String name, List<String> aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault) {
|
||||
public Tool(String name, List<String> aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable, boolean dropToDisable) {
|
||||
this.name = name;
|
||||
this.aliases = aliases;
|
||||
this.leftClickBehavior = leftClickBehavior;
|
||||
@ -27,5 +29,7 @@ public class Tool {
|
||||
this.params = params;
|
||||
this.mode = mode;
|
||||
this.permissionDefault = permissionDefault;
|
||||
this.removeOnDisable = removeOnDisable;
|
||||
this.dropToDisable = dropToDisable;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
public enum ToolBehavior {
|
||||
TOOL, BLOCK, NONE
|
||||
TOOL,
|
||||
BLOCK,
|
||||
NONE
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
public enum ToolMode {
|
||||
CLEARLOG("logblock.clearlog"), LOOKUP("logblock.lookup"), REDO("logblock.rollback"), ROLLBACK("logblock.rollback"), WRITELOGFILE("logblock.rollback");
|
||||
CLEARLOG("logblock.clearlog"),
|
||||
LOOKUP("logblock.lookup"),
|
||||
REDO("logblock.rollback"),
|
||||
ROLLBACK("logblock.rollback"),
|
||||
WRITELOGFILE("logblock.rollback");
|
||||
private final String permission;
|
||||
|
||||
private ToolMode(String permission) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecSign;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.UUIDFetcher;
|
||||
@ -26,13 +27,12 @@ import static de.diddiz.LogBlock.config.Config.getLoggedWorlds;
|
||||
import static de.diddiz.LogBlock.config.Config.isLogging;
|
||||
import static de.diddiz.util.BukkitUtils.friendlyWorldname;
|
||||
import de.diddiz.util.ComparableVersion;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.bukkit.Bukkit.getLogger;
|
||||
|
||||
class Updater {
|
||||
private final LogBlock logblock;
|
||||
final int UUID_CONVERT_BATCH_SIZE = 100;
|
||||
final int BLOCKS_CONVERT_BATCH_SIZE = 100000;
|
||||
final int OTHER_CONVERT_BATCH_SIZE = 20000;
|
||||
|
||||
Updater(LogBlock logblock) {
|
||||
this.logblock = logblock;
|
||||
@ -41,34 +41,29 @@ class Updater {
|
||||
boolean update() {
|
||||
final ConfigurationSection config = logblock.getConfig();
|
||||
String versionString = config.getString("version");
|
||||
if (Pattern.matches("1\\.\\d{2}",versionString)) {
|
||||
versionString = "1." + versionString.charAt(2) + "." + versionString.charAt(3);
|
||||
config.set("version",versionString);
|
||||
logblock.saveConfig();
|
||||
}
|
||||
ComparableVersion configVersion = new ComparableVersion(versionString);
|
||||
if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion())) >= 0) {
|
||||
return false;
|
||||
}
|
||||
// if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) {
|
||||
// return false;
|
||||
// }
|
||||
if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) {
|
||||
getLogger().info("Updating tables to 1.2.7 ...");
|
||||
if (isLogging(Logging.CHAT)) {
|
||||
logblock.getLogger().info("Updating tables to 1.2.7 ...");
|
||||
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
final Statement st = conn.createStatement();
|
||||
st.execute("ALTER TABLE `lb-chat` ENGINE = MyISAM, ADD FULLTEXT message (message)");
|
||||
st.execute("ALTER TABLE `lb-chat` ADD FULLTEXT message (message)");
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
config.set("version", "1.2.7");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.3")) < 0) {
|
||||
getLogger().info("Updating config to 1.3.0 ...");
|
||||
logblock.getLogger().info("Updating config to 1.3.0 ...");
|
||||
for (final String tool : config.getConfigurationSection("tools").getKeys(false)) {
|
||||
if (config.get("tools." + tool + ".permissionDefault") == null) {
|
||||
config.set("tools." + tool + ".permissionDefault", "OP");
|
||||
@ -77,7 +72,7 @@ class Updater {
|
||||
config.set("version", "1.3.0");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.3.1")) < 0) {
|
||||
getLogger().info("Updating tables to 1.3.1 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.3.1 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -86,13 +81,13 @@ class Updater {
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.3.1");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.3.2")) < 0) {
|
||||
getLogger().info("Updating tables to 1.3.2 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.3.2 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -101,18 +96,18 @@ class Updater {
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.3.2");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.4")) < 0) {
|
||||
getLogger().info("Updating config to 1.4.0 ...");
|
||||
logblock.getLogger().info("Updating config to 1.4.0 ...");
|
||||
config.set("clearlog.keepLogDays", null);
|
||||
config.set("version", "1.4.0");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.4.2")) < 0) {
|
||||
getLogger().info("Updating config to 1.4.2 ...");
|
||||
logblock.getLogger().info("Updating config to 1.4.2 ...");
|
||||
for (final String world : config.getStringList("loggedWorlds")) {
|
||||
final File file = new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml");
|
||||
final YamlConfiguration wcfg = YamlConfiguration.loadConfiguration(file);
|
||||
@ -191,14 +186,14 @@ class Updater {
|
||||
try {
|
||||
wcfg.save(file);
|
||||
} catch (final IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
}
|
||||
}
|
||||
config.set("clearlog.keepLogDays", null);
|
||||
config.set("version", "1.4.2");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.5.1")) < 0) {
|
||||
getLogger().info("Updating tables to 1.5.1 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.5.1 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -211,13 +206,13 @@ class Updater {
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.5.1");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.5.2")) < 0) {
|
||||
getLogger().info("Updating tables to 1.5.2 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.5.2 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -229,18 +224,18 @@ class Updater {
|
||||
st.execute("ALTER TABLE `lb-players` DROP onlinetime");
|
||||
st.execute("ALTER TABLE `lb-players` CHANGE onlinetime2 onlinetime INT UNSIGNED NOT NULL");
|
||||
} else {
|
||||
getLogger().info("Column lb-players was already modified, skipping it.");
|
||||
logblock.getLogger().info("Column lb-players was already modified, skipping it.");
|
||||
}
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.5.2");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.8.1")) < 0) {
|
||||
getLogger().info("Updating tables to 1.8.1 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.8.1 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -248,21 +243,21 @@ class Updater {
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
if (wcfg.isLogging(Logging.CHESTACCESS)) {
|
||||
st.execute("ALTER TABLE `" + wcfg.table + "-chest` CHANGE itemdata itemdata SMALLINT NOT NULL");
|
||||
getLogger().info("Table " + wcfg.table + "-chest modified");
|
||||
logblock.getLogger().info("Table " + wcfg.table + "-chest modified");
|
||||
}
|
||||
}
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.8.1");
|
||||
}
|
||||
|
||||
if (configVersion.compareTo(new ComparableVersion("1.9")) < 0) {
|
||||
getLogger().info("Updating tables to 1.9.0 ...");
|
||||
getLogger().info("Importing UUIDs for large databases may take some time");
|
||||
logblock.getLogger().info("Updating tables to 1.9.0 ...");
|
||||
logblock.getLogger().info("Importing UUIDs for large databases may take some time");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -271,7 +266,7 @@ class Updater {
|
||||
} catch (final SQLException ex) {
|
||||
// Error 1060 is MySQL error "column already exists". We want to continue with import if we get that error
|
||||
if (ex.getErrorCode() != 1060) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -291,12 +286,12 @@ class Updater {
|
||||
rs = st.executeQuery("SELECT COUNT(playername) FROM `lb-players` WHERE LENGTH(UUID)=0");
|
||||
rs.next();
|
||||
String total = Integer.toString(rs.getInt(1));
|
||||
getLogger().info(total + " players to convert");
|
||||
logblock.getLogger().info(total + " players to convert");
|
||||
int done = 0;
|
||||
|
||||
conn.setAutoCommit(false);
|
||||
Map<String, Integer> players = new HashMap<String, Integer>();
|
||||
List<String> names = new ArrayList<String>(UUID_CONVERT_BATCH_SIZE);
|
||||
Map<String, Integer> players = new HashMap<>();
|
||||
List<String> names = new ArrayList<>(UUID_CONVERT_BATCH_SIZE);
|
||||
Map<String, UUID> response;
|
||||
rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE));
|
||||
while (rs.next()) {
|
||||
@ -310,7 +305,7 @@ class Updater {
|
||||
for (Map.Entry<String, Integer> entry : players.entrySet()) {
|
||||
if (response.get(entry.getKey()) == null) {
|
||||
theUUID = unimportedPrefix + entry.getKey();
|
||||
getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID);
|
||||
logblock.getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID);
|
||||
} else {
|
||||
theUUID = response.get(entry.getKey()).toString();
|
||||
}
|
||||
@ -321,7 +316,7 @@ class Updater {
|
||||
conn.commit();
|
||||
players.clear();
|
||||
names.clear();
|
||||
getLogger().info("Processed " + Integer.toString(done) + " out of " + total);
|
||||
logblock.getLogger().info("Processed " + Integer.toString(done) + " out of " + total);
|
||||
rs.close();
|
||||
rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE));
|
||||
}
|
||||
@ -331,16 +326,16 @@ class Updater {
|
||||
conn.close();
|
||||
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[UUID importer]", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[UUID importer]", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.9.0");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.9.4")) < 0) {
|
||||
getLogger().info("Updating tables to 1.9.4 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.9.4 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -350,7 +345,7 @@ class Updater {
|
||||
st.execute("DROP INDEX UUID ON `lb-players`");
|
||||
} catch (final SQLException ex) {
|
||||
if (ex.getErrorCode() != 1091) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -358,7 +353,7 @@ class Updater {
|
||||
st.execute("DROP INDEX playername ON `lb-players`");
|
||||
} catch (final SQLException ex) {
|
||||
if (ex.getErrorCode() != 1091) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -367,7 +362,7 @@ class Updater {
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.9.4");
|
||||
@ -375,32 +370,32 @@ class Updater {
|
||||
// Ensure charset for free-text fields is UTF-8, or UTF8-mb4 if possible
|
||||
// As this may be an expensive operation and the database default may already be this, check on a table-by-table basis before converting
|
||||
if (configVersion.compareTo(new ComparableVersion("1.10.0")) < 0) {
|
||||
getLogger().info("Updating tables to 1.10.0 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.10.0 ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
final Statement st = conn.createStatement();
|
||||
checkCharset("lb-players","name",st);
|
||||
if (isLogging(Logging.CHAT)) {
|
||||
checkCharset("lb-chat","message", st);
|
||||
checkCharset("lb-players", "name", st, false);
|
||||
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
checkCharset("lb-chat", "message", st, false);
|
||||
}
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT)) {
|
||||
checkCharset(wcfg.table + "-sign","signtext",st);
|
||||
// checkCharset(wcfg.table + "-sign","signtext",st);
|
||||
}
|
||||
}
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.10.0");
|
||||
}
|
||||
|
||||
if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) {
|
||||
getLogger().info("Updating tables to 1.12.0 ...");
|
||||
if (isLogging(Logging.CHAT)) {
|
||||
logblock.getLogger().info("Updating tables to 1.12.0 ...");
|
||||
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(true);
|
||||
@ -409,40 +404,40 @@ class Updater {
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
config.set("version", "1.12.0");
|
||||
}
|
||||
if (configVersion.compareTo(new ComparableVersion("1.13.0")) < 0) {
|
||||
getLogger().info("Updating tables to 1.13.0 ...");
|
||||
logblock.getLogger().info("Updating tables to 1.13.0 ...");
|
||||
try {
|
||||
MaterialUpdater1_13 materialUpdater = new MaterialUpdater1_13(logblock);
|
||||
getLogger().info("Convertig BlockId to BlockData. This can take a while ...");
|
||||
logblock.getLogger().info("Convertig BlockId to BlockData. This can take a while ...");
|
||||
final Connection conn = logblock.getConnection();
|
||||
conn.setAutoCommit(false);
|
||||
final Statement st = conn.createStatement();
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
getLogger().info("Processing world " + wcfg.world + "...");
|
||||
getLogger().info("Processing block changes...");
|
||||
logblock.getLogger().info("Processing world " + wcfg.world + "...");
|
||||
logblock.getLogger().info("Processing block changes...");
|
||||
boolean hadRow = true;
|
||||
int rowsToConvert = 0;
|
||||
int done = 0;
|
||||
long rowsToConvert = 0;
|
||||
long done = 0;
|
||||
try {
|
||||
ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "`");
|
||||
if (rs.next()) {
|
||||
rowsToConvert = rs.getInt(1);
|
||||
getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table);
|
||||
rowsToConvert = rs.getLong(1);
|
||||
logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table);
|
||||
}
|
||||
rs.close();
|
||||
|
||||
|
||||
PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?");
|
||||
PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
|
||||
|
||||
while (hadRow) {
|
||||
hadRow = false;
|
||||
ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT 10000");
|
||||
ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE);
|
||||
while (entries.next()) {
|
||||
hadRow = true;
|
||||
int id = entries.getInt("id");
|
||||
@ -459,8 +454,8 @@ class Updater {
|
||||
}
|
||||
|
||||
try {
|
||||
String replacedBlockData = materialUpdater.getBlockData(replaced, data).getAsString();
|
||||
String setBlockData = materialUpdater.getBlockData(type, data).getAsString();
|
||||
BlockData replacedBlockData = materialUpdater.getBlockData(replaced, data);
|
||||
BlockData setBlockData = materialUpdater.getBlockData(type, data);
|
||||
|
||||
int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData);
|
||||
int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData);
|
||||
@ -480,7 +475,7 @@ class Updater {
|
||||
insertStatement.setInt(10, z);
|
||||
insertStatement.addBatch();
|
||||
} catch (Exception e) {
|
||||
getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage());
|
||||
logblock.getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage());
|
||||
}
|
||||
deleteStatement.setInt(1, id);
|
||||
deleteStatement.addBatch();
|
||||
@ -488,35 +483,43 @@ class Updater {
|
||||
done++;
|
||||
}
|
||||
entries.close();
|
||||
int failedRows = 0;
|
||||
if (hadRow) {
|
||||
insertStatement.executeBatch();
|
||||
try {
|
||||
insertStatement.executeBatch();
|
||||
} catch (BatchUpdateException e) {
|
||||
for (int result : e.getUpdateCounts()) {
|
||||
if (result == Statement.EXECUTE_FAILED) {
|
||||
failedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteStatement.executeBatch();
|
||||
}
|
||||
conn.commit();
|
||||
logblock.getConsumer().run(); // force a consumer run to save new material mappings
|
||||
getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
}
|
||||
insertStatement.close();
|
||||
deleteStatement.close();
|
||||
} catch (SQLException e) {
|
||||
getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage());
|
||||
logblock.getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
getLogger().info("Processing chests...");
|
||||
logblock.getLogger().info("Processing chests...");
|
||||
rowsToConvert = 0;
|
||||
done = 0;
|
||||
try {
|
||||
ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-chest`");
|
||||
if (rs.next()) {
|
||||
rowsToConvert = rs.getInt(1);
|
||||
getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest");
|
||||
rowsToConvert = rs.getLong(1);
|
||||
logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove) VALUES (?, ?, ?)");
|
||||
|
||||
PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)");
|
||||
PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?");
|
||||
while (true) {
|
||||
rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT 10000");
|
||||
rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE);
|
||||
boolean anyRow = false;
|
||||
while (rs.next()) {
|
||||
anyRow = true;
|
||||
@ -528,12 +531,14 @@ class Updater {
|
||||
if (weaponMaterial == null) {
|
||||
weaponMaterial = Material.AIR;
|
||||
}
|
||||
ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short)itemdata) : new ItemStack(weaponMaterial, Math.abs(amount));
|
||||
@SuppressWarnings("deprecation")
|
||||
ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short) itemdata) : new ItemStack(weaponMaterial, Math.abs(amount));
|
||||
insertChestData.setInt(1, id);
|
||||
insertChestData.setBytes(2, Utils.saveItemStack(stack));
|
||||
insertChestData.setInt(3, amount >= 0 ? 0 : 1);
|
||||
insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial));
|
||||
insertChestData.addBatch();
|
||||
|
||||
|
||||
deleteChest.setInt(1, id);
|
||||
deleteChest.addBatch();
|
||||
done++;
|
||||
@ -542,32 +547,41 @@ class Updater {
|
||||
if (!anyRow) {
|
||||
break;
|
||||
}
|
||||
insertChestData.executeBatch();
|
||||
int failedRows = 0;
|
||||
try {
|
||||
insertChestData.executeBatch();
|
||||
} catch (BatchUpdateException e) {
|
||||
for (int result : e.getUpdateCounts()) {
|
||||
if (result == Statement.EXECUTE_FAILED) {
|
||||
failedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteChest.executeBatch();
|
||||
conn.commit();
|
||||
getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
}
|
||||
insertChestData.close();
|
||||
deleteChest.close();
|
||||
} catch (SQLException e) {
|
||||
getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage());
|
||||
logblock.getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage());
|
||||
}
|
||||
|
||||
if (wcfg.isLogging(Logging.KILL)) {
|
||||
getLogger().info("Processing kills...");
|
||||
logblock.getLogger().info("Processing kills...");
|
||||
rowsToConvert = 0;
|
||||
done = 0;
|
||||
try {
|
||||
ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-kills`");
|
||||
if (rs.next()) {
|
||||
rowsToConvert = rs.getInt(1);
|
||||
getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills");
|
||||
rowsToConvert = rs.getLong(1);
|
||||
logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "`-kills SET weapon = ? WHERE id = ?");
|
||||
for (int start = 0;; start += 10000) {
|
||||
rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + ",10000");
|
||||
|
||||
PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?");
|
||||
for (int start = 0;; start += OTHER_CONVERT_BATCH_SIZE) {
|
||||
rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + OTHER_CONVERT_BATCH_SIZE);
|
||||
boolean anyUpdate = false;
|
||||
boolean anyRow = false;
|
||||
while (rs.next()) {
|
||||
@ -578,7 +592,7 @@ class Updater {
|
||||
if (weaponMaterial == null) {
|
||||
weaponMaterial = Material.AIR;
|
||||
}
|
||||
int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial.getKey());
|
||||
int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial);
|
||||
if (newWeapon != weapon) {
|
||||
anyUpdate = true;
|
||||
updateWeaponStatement.setInt(1, newWeapon);
|
||||
@ -591,23 +605,22 @@ class Updater {
|
||||
if (anyUpdate) {
|
||||
updateWeaponStatement.executeBatch();
|
||||
conn.commit();
|
||||
logblock.getConsumer().run(); // force a consumer run to save new material mappings
|
||||
}
|
||||
getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
if (!anyRow) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateWeaponStatement.close();
|
||||
} catch (SQLException e) {
|
||||
getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage());
|
||||
logblock.getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
st.close();
|
||||
conn.close();
|
||||
|
||||
getLogger().info("Updating config to 1.13.0 ...");
|
||||
logblock.getLogger().info("Updating config to 1.13.0 ...");
|
||||
config.set("logging.hiddenBlocks", materialUpdater.convertMaterials(config.getStringList("logging.hiddenBlocks")));
|
||||
config.set("rollback.dontRollback", materialUpdater.convertMaterials(config.getStringList("rollback.dontRollback")));
|
||||
config.set("rollback.replaceAnyway", materialUpdater.convertMaterials(config.getStringList("rollback.replaceAnyway")));
|
||||
@ -617,17 +630,160 @@ class Updater {
|
||||
tSec.set("item", materialUpdater.convertMaterial(tSec.getString("item", "OAK_LOG")));
|
||||
}
|
||||
} catch (final SQLException | IOException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
config.set("version", "1.13.0");
|
||||
}
|
||||
|
||||
if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) {
|
||||
logblock.getLogger().info("Updating tables to 1.13.1 ...");
|
||||
try {
|
||||
final Connection conn = logblock.getConnection();
|
||||
conn.setAutoCommit(false);
|
||||
final Statement st = conn.createStatement();
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
logblock.getLogger().info("Processing world " + wcfg.world + "...");
|
||||
ResultSet rsCol = st.executeQuery("SHOW COLUMNS FROM `" + wcfg.table + "-chestdata` LIKE 'itemtype'");
|
||||
if (!rsCol.next()) {
|
||||
st.execute("ALTER TABLE `" + wcfg.table + "-chestdata` ADD COLUMN `itemtype` SMALLINT NOT NULL DEFAULT '0'");
|
||||
}
|
||||
rsCol.close();
|
||||
conn.commit();
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT)) {
|
||||
long rowsToConvert = 0;
|
||||
long done = 0;
|
||||
try {
|
||||
ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`");
|
||||
if (rs.next()) {
|
||||
rowsToConvert = rs.getLong(1);
|
||||
logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)");
|
||||
PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?");
|
||||
while (true) {
|
||||
rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE);
|
||||
boolean anyRow = false;
|
||||
while (rs.next()) {
|
||||
anyRow = true;
|
||||
int id = rs.getInt("id");
|
||||
String signText = rs.getString("signtext");
|
||||
int replaced = rs.getInt("replaced");
|
||||
boolean nullBlock = rs.wasNull();
|
||||
int type = rs.getInt("type");
|
||||
|
||||
if (!nullBlock && signText != null) {
|
||||
String[] lines = signText.split("\0", 4);
|
||||
byte[] bytes = Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines));
|
||||
|
||||
Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial();
|
||||
Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial();
|
||||
boolean wasSign = replacedMaterial == Material.OAK_SIGN || replacedMaterial == Material.OAK_WALL_SIGN;
|
||||
boolean isSign = typeMaterial == Material.OAK_SIGN || typeMaterial == Material.OAK_WALL_SIGN;
|
||||
|
||||
insertSignState.setInt(1, id);
|
||||
insertSignState.setBytes(2, wasSign ? bytes : null);
|
||||
insertSignState.setBytes(3, isSign ? bytes : null);
|
||||
insertSignState.addBatch();
|
||||
}
|
||||
|
||||
deleteSign.setInt(1, id);
|
||||
deleteSign.addBatch();
|
||||
done++;
|
||||
}
|
||||
rs.close();
|
||||
if (!anyRow) {
|
||||
break;
|
||||
}
|
||||
int failedRows = 0;
|
||||
try {
|
||||
insertSignState.executeBatch();
|
||||
} catch (BatchUpdateException e) {
|
||||
for (int result : e.getUpdateCounts()) {
|
||||
if (result == Statement.EXECUTE_FAILED) {
|
||||
failedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteSign.executeBatch();
|
||||
conn.commit();
|
||||
logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
}
|
||||
insertSignState.close();
|
||||
deleteSign.close();
|
||||
} catch (SQLException e) {
|
||||
logblock.getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
config.set("version", "1.13.1");
|
||||
}
|
||||
|
||||
if (configVersion.compareTo(new ComparableVersion("1.16.0")) < 0) {
|
||||
try (Connection conn = logblock.getConnection()) {
|
||||
conn.setAutoCommit(true);
|
||||
final Statement st = conn.createStatement();
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
createIndexIfDoesNotExist(wcfg.table + "-entities", "entityid", "KEY `entityid` (entityid)", st, false);
|
||||
}
|
||||
st.close();
|
||||
} catch (final SQLException ex) {
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not add index", ex);
|
||||
}
|
||||
config.set("version", "1.16.0");
|
||||
}
|
||||
|
||||
if (configVersion.compareTo(new ComparableVersion(Config.CURRENT_CONFIG_VERSION)) < 0) {
|
||||
config.set("version", Config.CURRENT_CONFIG_VERSION);
|
||||
}
|
||||
|
||||
// this can always be checked
|
||||
try {
|
||||
final Connection conn = logblock.getConnection();
|
||||
conn.setAutoCommit(true);
|
||||
final Statement st = conn.createStatement();
|
||||
checkCharset("lb-players", "name", st, true);
|
||||
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
checkCharset("lb-chat", "message", st, true);
|
||||
}
|
||||
createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(150))", st, true);
|
||||
createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(150))", st, true);
|
||||
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
updateMaterialsPost1_13();
|
||||
|
||||
logblock.saveConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
void checkCharset(String table, String column, Statement st) throws SQLException {
|
||||
void createIndexIfDoesNotExist(String table, String indexName, String definition, Statement st, boolean silent) throws SQLException {
|
||||
final ResultSet rs = st.executeQuery("SHOW INDEX FROM `" + table + "` WHERE Key_name = '" + indexName + "'");
|
||||
if (!rs.next()) {
|
||||
st.execute("ALTER TABLE `" + table + "` ADD " + definition);
|
||||
logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Table modified");
|
||||
} else if (!silent) {
|
||||
logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Already fine, skipping it");
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
|
||||
void checkCharset(String table, String column, Statement st, boolean silent) throws SQLException {
|
||||
final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `" + table + "` WHERE field = '" + column + "'");
|
||||
String charset = "utf8";
|
||||
if (Config.mb4) {
|
||||
@ -635,10 +791,11 @@ class Updater {
|
||||
}
|
||||
if (rs.next() && !rs.getString("Collation").substring(0, charset.length()).equalsIgnoreCase(charset)) {
|
||||
st.execute("ALTER TABLE `" + table + "` CONVERT TO CHARSET " + charset);
|
||||
getLogger().info("Table " + table + " modified");
|
||||
} else {
|
||||
getLogger().info("Table " + table + " already fine, skipping it");
|
||||
logblock.getLogger().info("Table " + table + " modified");
|
||||
} else if (!silent) {
|
||||
logblock.getLogger().info("Table " + table + " already fine, skipping it");
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
|
||||
void checkTables() throws SQLException {
|
||||
@ -651,42 +808,122 @@ class Updater {
|
||||
throw new SQLException("No connection");
|
||||
}
|
||||
final Statement state = conn.createStatement();
|
||||
final DatabaseMetaData dbm = conn.getMetaData();
|
||||
conn.setAutoCommit(true);
|
||||
createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, UUID varchar(36) NOT NULL, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), INDEX (UUID), INDEX (playername)) DEFAULT CHARSET " + charset);
|
||||
createTable(state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, UUID varchar(36) NOT NULL, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), INDEX (UUID), INDEX (playername)) DEFAULT CHARSET " + charset);
|
||||
// Players table must not be empty or inserts won't work - bug #492
|
||||
final ResultSet rs = state.executeQuery("SELECT NULL FROM `lb-players` LIMIT 1;");
|
||||
if (!rs.next()) {
|
||||
state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')");
|
||||
}
|
||||
if (isLogging(Logging.CHAT)) {
|
||||
createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(256) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM DEFAULT CHARSET " + charset);
|
||||
}
|
||||
createTable(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM DEFAULT CHARSET " + charset);
|
||||
createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM DEFAULT CHARSET " + charset);
|
||||
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
createTable(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))");
|
||||
createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, PRIMARY KEY (id))");
|
||||
if (wcfg.isLogging(Logging.KILL)) {
|
||||
createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))");
|
||||
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
try {
|
||||
createTable(state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(256) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) DEFAULT CHARSET " + charset);
|
||||
} catch (SQLException e) {
|
||||
createTable(state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(256) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid)) DEFAULT CHARSET " + charset);
|
||||
}
|
||||
}
|
||||
createTable(state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
createTable(state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
createTable(state, "lb-entitytypes", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
createTable(state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))");
|
||||
createTable(state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, itemtype SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id))");
|
||||
createTable(state, wcfg.table + "-state", "(id INT UNSIGNED NOT NULL, replacedState MEDIUMBLOB NULL, typeState MEDIUMBLOB NULL, PRIMARY KEY (id))");
|
||||
if (wcfg.isLogging(Logging.KILL)) {
|
||||
createTable(state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))");
|
||||
}
|
||||
createTable(state, wcfg.table + "-entityids", "(entityid INT UNSIGNED NOT NULL AUTO_INCREMENT, entityuuid VARCHAR(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (entityid), UNIQUE KEY (entityuuid))");
|
||||
createTable(state, wcfg.table + "-entities", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, entityid INT UNSIGNED NOT NULL, entitytypeid INT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, action TINYINT UNSIGNED NOT NULL, data MEDIUMBLOB NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid), KEY entityid (entityid))");
|
||||
}
|
||||
state.close();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
private static void createTable(DatabaseMetaData dbm, Statement state, String table, String query) throws SQLException {
|
||||
if (!dbm.getTables(null, null, table, null).next()) {
|
||||
getLogger().log(Level.INFO, "Creating table " + table + ".");
|
||||
state.execute("CREATE TABLE `" + table + "` " + query);
|
||||
if (!dbm.getTables(null, null, table, null).next()) {
|
||||
throw new SQLException("Table " + table + " not found and failed to create");
|
||||
private void createTable(Statement state, String table, String query) throws SQLException {
|
||||
try (ResultSet tableResult = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) {
|
||||
if (!tableResult.next()) {
|
||||
logblock.getLogger().log(Level.INFO, "Creating table " + table + ".");
|
||||
state.execute("CREATE TABLE `" + table + "` " + query);
|
||||
try (ResultSet tableResultNew = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) {
|
||||
if (!tableResultNew.next()) {
|
||||
throw new SQLException("Table " + table + " not found and failed to create");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update materials that were renamed
|
||||
*/
|
||||
private void updateMaterialsPost1_13() {
|
||||
final ConfigurationSection config = logblock.getConfig();
|
||||
String previousMinecraftVersion = config.getString("previousMinecraftVersion");
|
||||
if (previousMinecraftVersion == null) {
|
||||
previousMinecraftVersion = "1.13";
|
||||
}
|
||||
ComparableVersion comparablePreviousMinecraftVersion = new ComparableVersion(previousMinecraftVersion);
|
||||
String currentMinecraftVersion = logblock.getServer().getVersion();
|
||||
currentMinecraftVersion = currentMinecraftVersion.substring(currentMinecraftVersion.indexOf("(MC: ") + 5);
|
||||
int currentVersionEnd = currentMinecraftVersion.indexOf(" ");
|
||||
int currentVersionEnd2 = currentMinecraftVersion.indexOf(")");
|
||||
if (currentVersionEnd2 >= 0 && (currentVersionEnd < 0 || currentVersionEnd2 < currentVersionEnd)) {
|
||||
currentVersionEnd = currentVersionEnd2;
|
||||
}
|
||||
currentMinecraftVersion = currentMinecraftVersion.substring(0, currentVersionEnd);
|
||||
logblock.getLogger().info("[Updater] Current Minecraft Version: '" + currentMinecraftVersion + "'");
|
||||
ComparableVersion comparableCurrentMinecraftVersion = new ComparableVersion(currentMinecraftVersion);
|
||||
|
||||
if (comparablePreviousMinecraftVersion.compareTo("1.14") < 0 && comparableCurrentMinecraftVersion.compareTo("1.14") >= 0) {
|
||||
logblock.getLogger().info("[Updater] Upgrading Materials to 1.14");
|
||||
renameMaterial("minecraft:sign", Material.OAK_SIGN);
|
||||
renameMaterial("minecraft:wall_sign", Material.OAK_WALL_SIGN);
|
||||
renameMaterial("minecraft:stone_slab", Material.SMOOTH_STONE_SLAB);
|
||||
renameMaterial("minecraft:rose_red", Material.RED_DYE);
|
||||
renameMaterial("minecraft:dandelion_yellow", Material.YELLOW_DYE);
|
||||
renameMaterial("minecraft:cactus_green", Material.GREEN_DYE);
|
||||
}
|
||||
|
||||
config.set("previousMinecraftVersion", currentMinecraftVersion);
|
||||
logblock.saveConfig();
|
||||
}
|
||||
|
||||
private void renameMaterial(String oldName, Material newName) {
|
||||
final Connection conn = logblock.getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
PreparedStatement stSelectMaterial = conn.prepareStatement("SELECT id FROM `lb-materials` WHERE name = ?");
|
||||
stSelectMaterial.setString(1, oldName);
|
||||
ResultSet rs = stSelectMaterial.executeQuery();
|
||||
if (rs.next()) {
|
||||
logblock.getLogger().info("[Updater] Updating " + oldName + " to " + newName);
|
||||
int oldId = rs.getInt(1);
|
||||
int newId = MaterialConverter.getOrAddMaterialId(newName);
|
||||
|
||||
Statement st = conn.createStatement();
|
||||
int rows = 0;
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET replaced = " + newId + " WHERE replaced = " + oldId);
|
||||
rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET type = " + newId + " WHERE type = " + oldId);
|
||||
rows += st.executeUpdate("UPDATE `" + wcfg.table + "-chestdata` SET itemtype = " + newId + " WHERE itemtype = " + oldId);
|
||||
if (wcfg.isLogging(Logging.KILL)) {
|
||||
rows += st.executeUpdate("UPDATE `" + wcfg.table + "-kills` SET weapon = " + newId + " WHERE weapon = " + oldId);
|
||||
}
|
||||
}
|
||||
st.close();
|
||||
if (rows > 0) {
|
||||
logblock.getLogger().info("[Updater] Successfully updated " + rows + " entries..");
|
||||
}
|
||||
}
|
||||
stSelectMaterial.close();
|
||||
conn.commit();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerCountChecker implements Runnable {
|
||||
|
||||
private LogBlock logblock;
|
||||
@ -710,7 +947,9 @@ class Updater {
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
if (logblock.isCompletelyEnabled()) {
|
||||
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -718,6 +957,7 @@ class Updater {
|
||||
public static class MaterialUpdater1_13 {
|
||||
BlockData[][] blockDataMapping;
|
||||
Material[][] itemMapping = new Material[10][];
|
||||
|
||||
public MaterialUpdater1_13(LogBlock plugin) throws IOException {
|
||||
blockDataMapping = new BlockData[256][16];
|
||||
try (JarFile file = new JarFile(plugin.getFile())) {
|
||||
|
@ -7,38 +7,53 @@ import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.block.data.Bisected.Half;
|
||||
import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
import org.bukkit.block.data.type.Chest;
|
||||
import org.bukkit.block.data.type.Bed.Part;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.block.data.type.Piston;
|
||||
import org.bukkit.block.data.type.PistonHead;
|
||||
import org.bukkit.block.data.type.TechnicalPiston.Type;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Bee;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.diddiz.LogBlock.QueryParams.Order;
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.util.Utils;
|
||||
import de.diddiz.worldedit.WorldEditHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.dontRollback;
|
||||
import static de.diddiz.LogBlock.config.Config.replaceAnyway;
|
||||
import static de.diddiz.util.BukkitUtils.*;
|
||||
import static org.bukkit.Bukkit.getLogger;
|
||||
|
||||
public class WorldEditor implements Runnable {
|
||||
private final LogBlock logblock;
|
||||
private final Queue<Edit> edits = new LinkedBlockingQueue<Edit>();
|
||||
private final ArrayList<Edit> edits = new ArrayList<>();
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
@ -49,10 +64,18 @@ public class WorldEditor implements Runnable {
|
||||
private int successes = 0, blacklistCollisions = 0;
|
||||
private long elapsedTime = 0;
|
||||
public LookupCacheElement[] errors;
|
||||
private boolean forceReplace;
|
||||
private HashMap<Integer, UUID> uuidReplacements = new HashMap<>();
|
||||
private boolean started = false;
|
||||
|
||||
public WorldEditor(LogBlock logblock, World world) {
|
||||
this(logblock, world, false);
|
||||
}
|
||||
|
||||
public WorldEditor(LogBlock logblock, World world, boolean forceReplace) {
|
||||
this.logblock = logblock;
|
||||
this.world = world;
|
||||
this.forceReplace = forceReplace;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
@ -71,13 +94,36 @@ public class WorldEditor implements Runnable {
|
||||
return blacklistCollisions;
|
||||
}
|
||||
|
||||
|
||||
public void setSender(CommandSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) {
|
||||
edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item));
|
||||
public void queueBlockEdit(long time, int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) {
|
||||
if (started) {
|
||||
throw new IllegalStateException("Already started");
|
||||
}
|
||||
edits.add(new BlockEdit(time, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item));
|
||||
}
|
||||
|
||||
public void queueEntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLException {
|
||||
if (started) {
|
||||
throw new IllegalStateException("Already started");
|
||||
}
|
||||
edits.add(new EntityEdit(rs, p, rollback));
|
||||
}
|
||||
|
||||
public void reverseRowOrder() {
|
||||
if (started) {
|
||||
throw new IllegalStateException("Already started");
|
||||
}
|
||||
Collections.reverse(edits);
|
||||
}
|
||||
|
||||
public void sortRows(QueryParams.Order order) {
|
||||
if (started) {
|
||||
throw new IllegalStateException("Already started");
|
||||
}
|
||||
edits.sort(new EditComparator(order));
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
@ -85,6 +131,10 @@ public class WorldEditor implements Runnable {
|
||||
}
|
||||
|
||||
synchronized public void start() throws Exception {
|
||||
if (started) {
|
||||
throw new IllegalStateException("Already started");
|
||||
}
|
||||
started = true;
|
||||
final long start = System.currentTimeMillis();
|
||||
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
|
||||
if (taskID == -1) {
|
||||
@ -100,12 +150,12 @@ public class WorldEditor implements Runnable {
|
||||
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
final List<WorldEditorException> errorList = new ArrayList<WorldEditorException>();
|
||||
final List<WorldEditorException> errorList = new ArrayList<>();
|
||||
int counter = 0;
|
||||
float size = edits.size();
|
||||
while (!edits.isEmpty() && counter < 100) {
|
||||
try {
|
||||
switch (edits.poll().perform()) {
|
||||
switch (edits.remove(edits.size() - 1).perform()) {
|
||||
case SUCCESS:
|
||||
successes++;
|
||||
break;
|
||||
@ -118,7 +168,7 @@ public class WorldEditor implements Runnable {
|
||||
} catch (final WorldEditorException ex) {
|
||||
errorList.add(ex);
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex);
|
||||
logblock.getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex);
|
||||
}
|
||||
counter++;
|
||||
if (sender != null) {
|
||||
@ -137,7 +187,7 @@ public class WorldEditor implements Runnable {
|
||||
file.getParentFile().mkdirs();
|
||||
final PrintWriter writer = new PrintWriter(file);
|
||||
for (final LookupCacheElement err : errorList) {
|
||||
writer.println(err.getMessage());
|
||||
writer.println(BaseComponent.toPlainText(err.getLogMessage()));
|
||||
}
|
||||
writer.close();
|
||||
} catch (final Exception ex) {
|
||||
@ -148,18 +198,158 @@ public class WorldEditor implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private static enum PerformResult {
|
||||
SUCCESS, BLACKLISTED, NO_ACTION
|
||||
protected UUID getReplacedUUID(int entityid, UUID unreplaced) {
|
||||
UUID replaced = uuidReplacements.get(entityid);
|
||||
return replaced != null ? replaced : unreplaced;
|
||||
}
|
||||
|
||||
private class Edit extends BlockChange {
|
||||
public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca);
|
||||
public static enum PerformResult {
|
||||
SUCCESS,
|
||||
BLACKLISTED,
|
||||
NO_ACTION
|
||||
}
|
||||
|
||||
public interface Edit {
|
||||
PerformResult perform() throws WorldEditorException;
|
||||
|
||||
public long getTime();
|
||||
}
|
||||
|
||||
public class EntityEdit extends EntityChange implements Edit {
|
||||
private boolean rollback;
|
||||
|
||||
public EntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLException {
|
||||
super(rs, p);
|
||||
this.rollback = rollback;
|
||||
}
|
||||
|
||||
PerformResult perform() throws WorldEditorException {
|
||||
BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData);
|
||||
BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData);
|
||||
@Override
|
||||
public long getTime() {
|
||||
return date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PerformResult perform() throws WorldEditorException {
|
||||
if (type == null) {
|
||||
throw new WorldEditorException("Unkown entity type for entity " + entityUUID, loc);
|
||||
}
|
||||
if (changeType == (rollback ? EntityChangeType.KILL : EntityChangeType.CREATE)) {
|
||||
// spawn entity
|
||||
UUID uuid = getReplacedUUID(entityId, entityUUID);
|
||||
Entity result = null;
|
||||
YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data);
|
||||
double x = deserialized.getDouble("x");
|
||||
double y = deserialized.getDouble("y");
|
||||
double z = deserialized.getDouble("z");
|
||||
float yaw = (float) deserialized.getDouble("yaw");
|
||||
float pitch = (float) deserialized.getDouble("pitch");
|
||||
Location location = new Location(world, x, y, z, yaw, pitch);
|
||||
Entity existing = BukkitUtils.loadEntityAround(location.getChunk(), uuid);
|
||||
if (existing != null) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
byte[] serializedWorldEditEntity = (byte[]) deserialized.get("worldedit");
|
||||
if (serializedWorldEditEntity != null) {
|
||||
result = WorldEditHelper.restoreEntity(location, type, serializedWorldEditEntity);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new WorldEditorException("Could not restore " + type, location);
|
||||
} else {
|
||||
if (!result.getUniqueId().equals(uuid)) {
|
||||
logblock.getConsumer().queueEntityUUIDChange(world, entityId, result.getUniqueId());
|
||||
uuidReplacements.put(entityId, result.getUniqueId());
|
||||
}
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
} else if (changeType == (rollback ? EntityChangeType.CREATE : EntityChangeType.KILL)) {
|
||||
// kill entity
|
||||
UUID uuid = getReplacedUUID(entityId, entityUUID);
|
||||
YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data);
|
||||
double x = deserialized.getDouble("x");
|
||||
double y = deserialized.getDouble("y");
|
||||
double z = deserialized.getDouble("z");
|
||||
float yaw = (float) deserialized.getDouble("yaw");
|
||||
float pitch = (float) deserialized.getDouble("pitch");
|
||||
Location location = new Location(world, x, y, z, yaw, pitch);
|
||||
Entity existing = BukkitUtils.loadEntityAround(location.getChunk(), uuid);
|
||||
if (existing != null) {
|
||||
existing.remove();
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
return PerformResult.NO_ACTION; // the entity is not there, so we cannot do anything
|
||||
} else if (changeType == (rollback ? EntityChangeType.REMOVEEQUIP : EntityChangeType.ADDEQUIP)) {
|
||||
// set equip
|
||||
UUID uuid = getReplacedUUID(entityId, entityUUID);
|
||||
Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid);
|
||||
if (existing != null) {
|
||||
YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data);
|
||||
ItemStack item = deserialized.getItemStack("item");
|
||||
if (item != null && existing instanceof ItemFrame) {
|
||||
ItemStack old = ((ItemFrame) existing).getItem();
|
||||
if (old == null || old.getType() == Material.AIR) {
|
||||
((ItemFrame) existing).setItem(item);
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
} else if (item != null && existing instanceof ArmorStand) {
|
||||
EquipmentSlot slot = EquipmentSlot.valueOf(deserialized.getString("slot"));
|
||||
ArmorStand stand = (ArmorStand) existing;
|
||||
ItemStack old = BukkitUtils.getItemInSlot(stand, slot);
|
||||
if (old == null || old.getType() == Material.AIR) {
|
||||
BukkitUtils.setItemInSlot(stand, slot, item);
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PerformResult.NO_ACTION; // the entity is not there, or equip does not match
|
||||
} else if (changeType == (rollback ? EntityChangeType.ADDEQUIP : EntityChangeType.REMOVEEQUIP)) {
|
||||
// remove equip
|
||||
UUID uuid = getReplacedUUID(entityId, entityUUID);
|
||||
Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid);
|
||||
if (existing != null) {
|
||||
YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data);
|
||||
ItemStack item = deserialized.getItemStack("item");
|
||||
if (item != null && existing instanceof ItemFrame) {
|
||||
ItemStack old = ((ItemFrame) existing).getItem();
|
||||
if (old != null && old.isSimilar(item)) {
|
||||
((ItemFrame) existing).setItem(null);
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
} else if (item != null && existing instanceof ArmorStand) {
|
||||
EquipmentSlot slot = EquipmentSlot.valueOf(deserialized.getString("slot"));
|
||||
ArmorStand stand = (ArmorStand) existing;
|
||||
ItemStack old = BukkitUtils.getItemInSlot(stand, slot);
|
||||
if (old != null && old.isSimilar(item)) {
|
||||
BukkitUtils.setItemInSlot(stand, slot, null);
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PerformResult.NO_ACTION; // the entity is not there, or equip does not match
|
||||
} else if (changeType == EntityChangeType.GET_STUNG) {
|
||||
UUID uuid = getReplacedUUID(entityId, entityUUID);
|
||||
Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid);
|
||||
if (existing != null && existing instanceof Bee) {
|
||||
((Bee) existing).setHasStung(!rollback);
|
||||
}
|
||||
}
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
public class BlockEdit extends BlockChange implements Edit {
|
||||
public BlockEdit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
|
||||
super(time, loc, actor, replaced, replaceData, replacedState, type, typeData, typeState, ca);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTime() {
|
||||
return date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PerformResult perform() throws WorldEditorException {
|
||||
BlockData replacedBlock = getBlockReplaced();
|
||||
BlockData setBlock = getBlockSet();
|
||||
if (replacedBlock == null || setBlock == null) {
|
||||
throw new WorldEditorException("Could not parse the material", loc.clone());
|
||||
}
|
||||
@ -172,66 +362,45 @@ public class WorldEditor implements Runnable {
|
||||
if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
final BlockState state = block.getState();
|
||||
if (!world.isChunkLoaded(block.getChunk())) {
|
||||
world.loadChunk(block.getChunk());
|
||||
}
|
||||
BlockState state = block.getState();
|
||||
if (setBlock.equals(replacedBlock)) {
|
||||
if (BukkitUtils.isEmpty(setBlock.getMaterial())) {
|
||||
block.setType(Material.AIR);
|
||||
} else if (ca != null) {
|
||||
if (state instanceof InventoryHolder) {
|
||||
if (ca != null) {
|
||||
if (state instanceof Container && state.getType() == replacedBlock.getMaterial()) {
|
||||
int leftover;
|
||||
try {
|
||||
leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove);
|
||||
// Special-case blocks which might be double chests
|
||||
if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) {
|
||||
for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||
if (block.getRelative(face).getType() == setBlock.getMaterial()) {
|
||||
ItemStack remaining = new ItemStack(ca.itemStack);
|
||||
remaining.setAmount(leftover);
|
||||
leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
throw new WorldEditorException(ex.getMessage(), block.getLocation());
|
||||
}
|
||||
if (leftover > 0 && ca.remove) {
|
||||
throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation());
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
} else if (!block.getBlockData().equals(replacedBlock)) {
|
||||
block.setBlockData(replacedBlock);
|
||||
} else {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) {
|
||||
if (!forceReplace && !BukkitUtils.isSimilarForRollback(setBlock.getMaterial(), block.getType()) && !block.isEmpty() && !replaceAnyway.contains(block.getType())) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
if (state instanceof InventoryHolder) {
|
||||
((InventoryHolder) state).getInventory().clear();
|
||||
if (state instanceof Container && replacedBlock.getMaterial() != block.getType()) {
|
||||
((Container) state).getSnapshotInventory().clear();
|
||||
state.update();
|
||||
}
|
||||
block.setBlockData(replacedBlock);
|
||||
BlockData newData = block.getBlockData();
|
||||
if (BlockStateCodecs.hasCodec(replacedBlock.getMaterial())) {
|
||||
state = block.getState();
|
||||
try {
|
||||
BlockStateCodecs.deserialize(state, Utils.deserializeYamlConfiguration(replacedState));
|
||||
state.update();
|
||||
} catch (Exception e) {
|
||||
throw new WorldEditorException("Failed to restore blockstate of " + block.getType() + ": " + e, block.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
final Material curtype = block.getType();
|
||||
if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) {
|
||||
final Sign sign = (Sign) block.getState();
|
||||
final String[] lines = signtext.split("\0", 4);
|
||||
if (lines.length < 4) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sign.setLine(i, lines[i]);
|
||||
}
|
||||
if (!sign.update()) {
|
||||
throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation());
|
||||
}
|
||||
} else if (newData instanceof Bed) {
|
||||
if (newData instanceof Bed) {
|
||||
final Bed bed = (Bed) newData;
|
||||
final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing());
|
||||
if (secBlock.isEmpty()) {
|
||||
@ -239,13 +408,13 @@ public class WorldEditor implements Runnable {
|
||||
bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD);
|
||||
secBlock.setBlockData(bed2);
|
||||
}
|
||||
} else if (newData instanceof Door) {
|
||||
final Door door = (Door) newData;
|
||||
final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP);
|
||||
} else if (curtype == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(curtype) || BukkitUtils.isDoublePlant(curtype)) {
|
||||
final Bisected firstPart = (Bisected) newData;
|
||||
final Block secBlock = block.getRelative(firstPart.getHalf() == Half.TOP ? BlockFace.DOWN : BlockFace.UP);
|
||||
if (secBlock.isEmpty()) {
|
||||
Door door2 = (Door) door.clone();
|
||||
door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP);
|
||||
secBlock.setBlockData(door2);
|
||||
Bisected secondPart = (Bisected) firstPart.clone();
|
||||
secondPart.setHalf(firstPart.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP);
|
||||
secBlock.setBlockData(secondPart);
|
||||
}
|
||||
} else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) {
|
||||
Piston piston = (Piston) newData;
|
||||
@ -267,11 +436,34 @@ public class WorldEditor implements Runnable {
|
||||
piston.setExtended(true);
|
||||
secBlock.setBlockData(piston);
|
||||
}
|
||||
} else if (newData instanceof Chest) {
|
||||
Chest chest = (Chest) newData;
|
||||
if (chest.getType() != org.bukkit.block.data.type.Chest.Type.SINGLE) {
|
||||
if (getConnectedChest(block) == null) {
|
||||
chest.setType(org.bukkit.block.data.type.Chest.Type.SINGLE);
|
||||
block.setBlockData(chest);
|
||||
}
|
||||
}
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EditComparator implements Comparator<Edit> {
|
||||
private final int mult;
|
||||
|
||||
public EditComparator(QueryParams.Order order) {
|
||||
mult = order == Order.DESC ? 1 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Edit edit1, Edit edit2) {
|
||||
long time1 = edit1.getTime();
|
||||
long time2 = edit2.getTime();
|
||||
return time1 > time2 ? mult : time1 < time2 ? -mult : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class WorldEditorException extends Exception implements LookupCacheElement {
|
||||
private final Location loc;
|
||||
@ -289,5 +481,10 @@ public class WorldEditor implements Runnable {
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent[] getLogMessage(int entry) {
|
||||
return TextComponent.fromLegacyText(getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
38
src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java
Normal file
38
src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java
Normal file
@ -0,0 +1,38 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.diddiz.LogBlock.QueryParams.BlockChangeType;
|
||||
import de.diddiz.util.Utils;
|
||||
|
||||
public class WorldEditorEditFactory {
|
||||
private final WorldEditor editor;
|
||||
private final boolean rollback;
|
||||
private final QueryParams params;
|
||||
|
||||
public WorldEditorEditFactory(WorldEditor editor, QueryParams params, boolean rollback) {
|
||||
this.editor = editor;
|
||||
this.params = params;
|
||||
this.rollback = rollback;
|
||||
}
|
||||
|
||||
public void processRow(ResultSet rs) throws SQLException {
|
||||
if (params.bct == BlockChangeType.ENTITIES) {
|
||||
editor.queueEntityEdit(rs, params, rollback);
|
||||
return;
|
||||
}
|
||||
ChestAccess chestaccess = null;
|
||||
ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
|
||||
if (stack != null) {
|
||||
chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove") == rollback, rs.getInt("itemtype"));
|
||||
}
|
||||
if (rollback) {
|
||||
editor.queueBlockEdit(rs.getTimestamp("date").getTime(), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess);
|
||||
} else {
|
||||
editor.queueBlockEdit(rs.getTimestamp("date").getTime(), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public interface BlockStateCodec {
|
||||
Material[] getApplicableMaterials();
|
||||
|
||||
YamlConfiguration serialize(BlockState state);
|
||||
|
||||
void deserialize(BlockState state, YamlConfiguration conf);
|
||||
|
||||
String toString(YamlConfiguration conf);
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Banner;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.banner.Pattern;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecBanner implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.WHITE_BANNER, Material.ORANGE_BANNER, Material.MAGENTA_BANNER, Material.LIGHT_BLUE_BANNER, Material.YELLOW_BANNER, Material.LIME_BANNER, Material.PINK_BANNER, Material.GRAY_BANNER, Material.LIGHT_GRAY_BANNER, Material.CYAN_BANNER, Material.PURPLE_BANNER,
|
||||
Material.BLUE_BANNER, Material.BROWN_BANNER, Material.GREEN_BANNER, Material.RED_BANNER, Material.BLACK_BANNER, Material.WHITE_WALL_BANNER, Material.ORANGE_WALL_BANNER, Material.MAGENTA_WALL_BANNER, Material.LIGHT_BLUE_WALL_BANNER, Material.YELLOW_WALL_BANNER,
|
||||
Material.LIME_WALL_BANNER, Material.PINK_WALL_BANNER, Material.GRAY_WALL_BANNER, Material.LIGHT_GRAY_WALL_BANNER, Material.CYAN_WALL_BANNER, Material.PURPLE_WALL_BANNER, Material.BLUE_WALL_BANNER, Material.BROWN_WALL_BANNER, Material.GREEN_WALL_BANNER, Material.RED_WALL_BANNER,
|
||||
Material.BLACK_WALL_BANNER };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Banner) {
|
||||
Banner banner = (Banner) state;
|
||||
int nr = 0;
|
||||
List<Pattern> patterns = banner.getPatterns();
|
||||
if (!patterns.isEmpty()) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
ConfigurationSection patternsSection = conf.createSection("patterns");
|
||||
for (Pattern pattern : patterns) {
|
||||
ConfigurationSection section = patternsSection.createSection(Integer.toString(nr));
|
||||
section.set("color", pattern.getColor().name());
|
||||
section.set("pattern", pattern.getPattern().name());
|
||||
nr++;
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Banner) {
|
||||
Banner banner = (Banner) state;
|
||||
int oldPatterns = banner.getPatterns().size();
|
||||
for (int i = 0; i < oldPatterns; i++) {
|
||||
banner.removePattern(0);
|
||||
}
|
||||
ConfigurationSection patternsSection = conf == null ? null : conf.getConfigurationSection("patterns");
|
||||
if (patternsSection != null) {
|
||||
for (String key : patternsSection.getKeys(false)) {
|
||||
ConfigurationSection section = patternsSection.getConfigurationSection(key);
|
||||
if (section != null) {
|
||||
DyeColor color = DyeColor.valueOf(section.getString("color"));
|
||||
PatternType type = PatternType.valueOf(section.getString("pattern"));
|
||||
banner.addPattern(new Pattern(color, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Lectern;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class BlockStateCodecLectern implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.LECTERN };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Lectern) {
|
||||
Lectern lectern = (Lectern) state;
|
||||
ItemStack book = lectern.getSnapshotInventory().getItem(0);
|
||||
if (book != null && book.getType() != Material.AIR) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("book", book);
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Lectern) {
|
||||
Lectern lectern = (Lectern) state;
|
||||
ItemStack book = null;
|
||||
if (conf != null) {
|
||||
book = conf.getItemStack("book");
|
||||
}
|
||||
try {
|
||||
lectern.getSnapshotInventory().setItem(0, book);
|
||||
} catch (NullPointerException e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
if (conf != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[").append("book").append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.ShulkerBox;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class BlockStateCodecShulkerBox implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return BukkitUtils.getShulkerBoxBlocks().toArray(new Material[BukkitUtils.getShulkerBoxBlocks().size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
WorldConfig wcfg = getWorldConfig(state.getWorld());
|
||||
if (wcfg == null || !wcfg.isLogging(Logging.SHULKER_BOX_CONTENT)) {
|
||||
return null;
|
||||
}
|
||||
if (state instanceof ShulkerBox) {
|
||||
ShulkerBox shulkerBox = (ShulkerBox) state;
|
||||
ItemStack[] content = shulkerBox.getSnapshotInventory().getStorageContents();
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
boolean anySlot = false;
|
||||
for (int i = 0; i < content.length; i++) {
|
||||
ItemStack stack = content[i];
|
||||
if (stack != null && stack.getType() != Material.AIR) {
|
||||
conf.set("slot" + i, stack);
|
||||
anySlot = true;
|
||||
}
|
||||
}
|
||||
if (anySlot) {
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof ShulkerBox) {
|
||||
ShulkerBox shulkerBox = (ShulkerBox) state;
|
||||
if (conf != null) {
|
||||
ItemStack[] content = shulkerBox.getSnapshotInventory().getStorageContents();
|
||||
for (int i = 0; i < content.length; i++) {
|
||||
ItemStack stack = conf.getItemStack("slot" + i);
|
||||
if (stack != null && stack.getType() != Material.AIR) {
|
||||
content[i] = stack;
|
||||
}
|
||||
}
|
||||
shulkerBox.getSnapshotInventory().setContents(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
if (conf != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
boolean anySlot = false;
|
||||
for (String key : conf.getKeys(false)) {
|
||||
if (key.startsWith("slot")) {
|
||||
ItemStack stack = conf.getItemStack(key);
|
||||
if (stack != null && stack.getType() != Material.AIR) {
|
||||
if (anySlot) {
|
||||
sb.append(",");
|
||||
}
|
||||
anySlot = true;
|
||||
sb.append(stack.getAmount()).append("x").append(stack.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append("]");
|
||||
return anySlot ? sb.toString() : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecSign implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return BukkitUtils.getAllSignsArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Sign) {
|
||||
Sign sign = (Sign) state;
|
||||
String[] lines = sign.getLines();
|
||||
boolean hasText = false;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
if (lines[i] != null && lines[i].length() > 0) {
|
||||
hasText = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DyeColor signColor = sign.getColor();
|
||||
if (signColor == null) {
|
||||
signColor = DyeColor.BLACK;
|
||||
}
|
||||
if (hasText || signColor != DyeColor.BLACK) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
if (hasText) {
|
||||
conf.set("lines", Arrays.asList(lines));
|
||||
}
|
||||
if (signColor != DyeColor.BLACK) {
|
||||
conf.set("color", signColor.name());
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is required for the SignChangeEvent, because we have no BlockState there.
|
||||
*/
|
||||
public static YamlConfiguration serialize(String[] lines) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("lines", Arrays.asList(lines));
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Sign) {
|
||||
Sign sign = (Sign) state;
|
||||
DyeColor signColor = DyeColor.BLACK;
|
||||
List<String> lines = Collections.emptyList();
|
||||
if (conf != null) {
|
||||
if (conf.contains("lines")) {
|
||||
lines = conf.getStringList("lines");
|
||||
}
|
||||
if (conf.contains("color")) {
|
||||
try {
|
||||
signColor = DyeColor.valueOf(conf.getString("color"));
|
||||
} catch (IllegalArgumentException | NullPointerException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : "";
|
||||
sign.setLine(i, line);
|
||||
}
|
||||
sign.setColor(signColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
if (conf != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line : conf.getStringList("lines")) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append("[").append(line).append("]");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecSkull implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.PLAYER_WALL_HEAD, Material.PLAYER_HEAD };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Skull) {
|
||||
Skull skull = (Skull) state;
|
||||
OfflinePlayer owner = skull.hasOwner() ? skull.getOwningPlayer() : null;
|
||||
if (owner != null) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("owner", owner.getUniqueId().toString());
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Skull) {
|
||||
Skull skull = (Skull) state;
|
||||
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
|
||||
if (ownerId == null) {
|
||||
skull.setOwningPlayer(null);
|
||||
} else {
|
||||
skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
|
||||
if (ownerId != null) {
|
||||
OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId);
|
||||
return "[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public class BlockStateCodecSpawner implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.SPAWNER };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof CreatureSpawner) {
|
||||
CreatureSpawner spawner = (CreatureSpawner) state;
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("delay", spawner.getDelay());
|
||||
conf.set("maxNearbyEntities", spawner.getMaxNearbyEntities());
|
||||
conf.set("maxSpawnDelay", spawner.getMaxSpawnDelay());
|
||||
conf.set("minSpawnDelay", spawner.getMinSpawnDelay());
|
||||
conf.set("requiredPlayerRange", spawner.getRequiredPlayerRange());
|
||||
conf.set("spawnCount", spawner.getSpawnCount());
|
||||
conf.set("spawnedType", spawner.getSpawnedType().name());
|
||||
conf.set("spawnRange", spawner.getSpawnRange());
|
||||
return conf;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof CreatureSpawner) {
|
||||
CreatureSpawner spawner = (CreatureSpawner) state;
|
||||
if (conf != null) {
|
||||
spawner.setDelay(conf.getInt("delay"));
|
||||
spawner.setMaxNearbyEntities(conf.getInt("maxNearbyEntities"));
|
||||
spawner.setMaxSpawnDelay(conf.getInt("maxSpawnDelay"));
|
||||
spawner.setMinSpawnDelay(conf.getInt("minSpawnDelay"));
|
||||
spawner.setRequiredPlayerRange(conf.getInt("requiredPlayerRange"));
|
||||
spawner.setSpawnCount(conf.getInt("spawnCount"));
|
||||
spawner.setSpawnedType(EntityType.valueOf(conf.getString("spawnedType")));
|
||||
spawner.setSpawnRange(conf.getInt("spawnRange"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
if (conf != null) {
|
||||
EntityType entity = EntityType.valueOf(conf.getString("spawnedType"));
|
||||
if (entity != null) {
|
||||
return "[" + entity + "]";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecs {
|
||||
private static Map<Material, BlockStateCodec> codecs = new EnumMap<>(Material.class);
|
||||
|
||||
public static void registerCodec(BlockStateCodec codec) {
|
||||
Material[] materials = codec.getApplicableMaterials();
|
||||
for (Material material : materials) {
|
||||
if (codecs.containsKey(material)) {
|
||||
throw new IllegalArgumentException("BlockStateCodec for " + material + " already registered!");
|
||||
}
|
||||
codecs.put(material, codec);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
registerCodec(new BlockStateCodecSign());
|
||||
registerCodec(new BlockStateCodecSkull());
|
||||
registerCodec(new BlockStateCodecBanner());
|
||||
registerCodec(new BlockStateCodecSpawner());
|
||||
registerCodec(new BlockStateCodecLectern());
|
||||
registerCodec(new BlockStateCodecShulkerBox());
|
||||
}
|
||||
|
||||
public static boolean hasCodec(Material material) {
|
||||
return codecs.containsKey(material);
|
||||
}
|
||||
|
||||
public static YamlConfiguration serialize(BlockState state) {
|
||||
BlockStateCodec codec = codecs.get(state.getType());
|
||||
if (codec != null) {
|
||||
YamlConfiguration serialized = codec.serialize(state);
|
||||
if (serialized != null && !serialized.getKeys(false).isEmpty()) {
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void deserialize(BlockState block, YamlConfiguration state) {
|
||||
BlockStateCodec codec = codecs.get(block.getType());
|
||||
if (codec != null) {
|
||||
codec.deserialize(block, state);
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString(Material material, YamlConfiguration state) {
|
||||
BlockStateCodec codec = codecs.get(material);
|
||||
if (codec != null) {
|
||||
return codec.toString(state);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import de.diddiz.util.ComparableVersion;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
|
||||
import java.io.File;
|
||||
@ -24,6 +25,9 @@ public class Config {
|
||||
private static LoggingEnabledMapping superWorldConfig;
|
||||
private static Map<String, WorldConfig> worldConfigs;
|
||||
public static String url, user, password;
|
||||
public static String mysqlDatabase;
|
||||
public static boolean mysqlUseSSL;
|
||||
public static boolean mysqlRequireSSL;
|
||||
public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun;
|
||||
public static boolean fireCustomEvents;
|
||||
public static boolean useBukkitScheduler;
|
||||
@ -32,35 +36,43 @@ public class Config {
|
||||
public static List<String> autoClearLog;
|
||||
public static int autoClearLogDelay;
|
||||
public static boolean dumpDeletedLog;
|
||||
public static boolean logBedExplosionsAsPlayerWhoTriggeredThese;
|
||||
public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo;
|
||||
public static boolean logFireSpreadAsPlayerWhoCreatedIt;
|
||||
public static boolean logFluidFlowAsPlayerWhoTriggeredIt;
|
||||
public static LogKillsLevel logKillsLevel;
|
||||
public static Set<Material> dontRollback, replaceAnyway;
|
||||
public static int rollbackMaxTime, rollbackMaxArea;
|
||||
public static Map<String, Tool> toolsByName;
|
||||
public static Map<Material, Tool> toolsByType;
|
||||
public static int defaultDist, defaultTime;
|
||||
public static int linesPerPage, linesLimit;
|
||||
public static int linesPerPage, linesLimit, hardLinesLimit;
|
||||
public static boolean askRollbacks, askRedos, askClearLogs, askClearLogAfterRollback, askRollbackAfterBan;
|
||||
public static String banPermission;
|
||||
public static Set<Material> hiddenBlocks;
|
||||
public static Set<String> hiddenPlayers;
|
||||
public static Set<String> ignoredChat;
|
||||
public static List<String> ignoredChat;
|
||||
public static SimpleDateFormat formatter;
|
||||
public static SimpleDateFormat formatterShort;
|
||||
public static boolean safetyIdCheck;
|
||||
public static boolean debug;
|
||||
public static boolean logEnvironmentalKills;
|
||||
// Not loaded from config - checked at runtime
|
||||
public static boolean mb4 = false;
|
||||
|
||||
public static final String CURRENT_CONFIG_VERSION = "1.16.0";
|
||||
|
||||
public static enum LogKillsLevel {
|
||||
PLAYERS, MONSTERS, ANIMALS;
|
||||
PLAYERS,
|
||||
MONSTERS,
|
||||
ANIMALS;
|
||||
}
|
||||
|
||||
public static void load(LogBlock logblock) throws DataFormatException, IOException {
|
||||
final ConfigurationSection config = logblock.getConfig();
|
||||
final Map<String, Object> def = new HashMap<String, Object>();
|
||||
def.put("version", logblock.getDescription().getVersion());
|
||||
final List<String> worldNames = new ArrayList<String>();
|
||||
final Map<String, Object> def = new HashMap<>();
|
||||
def.put("version", CURRENT_CONFIG_VERSION);
|
||||
final List<String> worldNames = new ArrayList<>();
|
||||
for (final World world : getWorlds()) {
|
||||
worldNames.add(world.getName());
|
||||
}
|
||||
@ -75,6 +87,8 @@ public class Config {
|
||||
def.put("mysql.database", "minecraft");
|
||||
def.put("mysql.user", "username");
|
||||
def.put("mysql.password", "pass");
|
||||
def.put("mysql.useSSL", true);
|
||||
def.put("mysql.requireSSL", false);
|
||||
def.put("consumer.delayBetweenRuns", 2);
|
||||
def.put("consumer.forceToProcessAtLeast", 200);
|
||||
def.put("consumer.timePerRun", 1000);
|
||||
@ -83,9 +97,18 @@ public class Config {
|
||||
def.put("consumer.queueWarningSize", 1000);
|
||||
def.put("clearlog.dumpDeletedLog", false);
|
||||
def.put("clearlog.enableAutoClearLog", false);
|
||||
def.put("clearlog.auto", Arrays.asList("world \"world\" before 365 days all", "world \"world\" player lavaflow waterflow leavesdecay before 7 days all", "world world_nether before 365 days all", "world world_nether player lavaflow before 7 days all"));
|
||||
final List<String> autoClearlog = new ArrayList<>();
|
||||
for (final String world : worldNames) {
|
||||
autoClearlog.add("world \"" + world + "\" before 365 days all");
|
||||
autoClearlog.add("world \"" + world + "\" player lavaflow waterflow leavesdecay before 7 days all");
|
||||
autoClearlog.add("world \"" + world + "\" entities before 365 days");
|
||||
}
|
||||
def.put("clearlog.auto", autoClearlog);
|
||||
def.put("clearlog.autoClearLogDelay", "6h");
|
||||
def.put("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true);
|
||||
def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false);
|
||||
def.put("logging.logFireSpreadAsPlayerWhoCreatedIt", true);
|
||||
def.put("logging.logFluidFlowAsPlayerWhoTriggeredIt", false);
|
||||
def.put("logging.logKillsLevel", "PLAYERS");
|
||||
def.put("logging.logEnvironmentalKills", false);
|
||||
def.put("logging.logPlayerInfo", false);
|
||||
@ -93,19 +116,26 @@ public class Config {
|
||||
def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name(), Material.CAVE_AIR.name(), Material.VOID_AIR.name()));
|
||||
def.put("logging.ignoredChat", Arrays.asList("/register", "/login"));
|
||||
def.put("rollback.dontRollback", Arrays.asList(Material.LAVA.name(), Material.TNT.name(), Material.FIRE.name()));
|
||||
def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name()));
|
||||
def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name(), Material.GRASS_BLOCK.name()));
|
||||
def.put("rollback.maxTime", "2 days");
|
||||
def.put("rollback.maxArea", 50);
|
||||
def.put("lookup.defaultDist", 20);
|
||||
def.put("lookup.defaultTime", "30 minutes");
|
||||
def.put("lookup.linesPerPage", 15);
|
||||
def.put("lookup.linesLimit", 1500);
|
||||
def.put("lookup.hardLinesLimit", 100000);
|
||||
try {
|
||||
formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "MM-dd HH:mm:ss"));
|
||||
formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "yyyy-MM-dd HH:mm:ss"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage());
|
||||
}
|
||||
def.put("lookup.dateFormat", "MM-dd HH:mm:ss");
|
||||
def.put("lookup.dateFormat", "yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
formatterShort = new SimpleDateFormat(config.getString("lookup.dateFormatShort", "MM-dd HH:mm"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage());
|
||||
}
|
||||
def.put("lookup.dateFormatShort", "MM-dd HH:mm");
|
||||
def.put("questioner.askRollbacks", true);
|
||||
def.put("questioner.askRedos", true);
|
||||
def.put("questioner.askClearLogs", true);
|
||||
@ -118,7 +148,9 @@ public class Config {
|
||||
def.put("tools.tool.defaultEnabled", true);
|
||||
def.put("tools.tool.item", Material.WOODEN_PICKAXE.name());
|
||||
def.put("tools.tool.canDrop", true);
|
||||
def.put("tools.tool.params", "area 0 all sum none limit 15 desc silent");
|
||||
def.put("tools.tool.removeOnDisable", true);
|
||||
def.put("tools.tool.dropToDisable", false);
|
||||
def.put("tools.tool.params", "area 0 all sum none limit 15 desc since 60d silent");
|
||||
def.put("tools.tool.mode", "LOOKUP");
|
||||
def.put("tools.tool.permissionDefault", "OP");
|
||||
def.put("tools.toolblock.aliases", Arrays.asList("tb"));
|
||||
@ -127,7 +159,9 @@ public class Config {
|
||||
def.put("tools.toolblock.defaultEnabled", true);
|
||||
def.put("tools.toolblock.item", Material.BEDROCK.name());
|
||||
def.put("tools.toolblock.canDrop", false);
|
||||
def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc silent");
|
||||
def.put("tools.toolblock.removeOnDisable", true);
|
||||
def.put("tools.toolblock.dropToDisable", false);
|
||||
def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc since 60d silent");
|
||||
def.put("tools.toolblock.mode", "LOOKUP");
|
||||
def.put("tools.toolblock.permissionDefault", "OP");
|
||||
def.put("safety.id.check", true);
|
||||
@ -138,13 +172,16 @@ public class Config {
|
||||
}
|
||||
}
|
||||
logblock.saveConfig();
|
||||
|
||||
|
||||
ComparableVersion configVersion = new ComparableVersion(config.getString("version"));
|
||||
boolean oldConfig = configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) < 0;
|
||||
|
||||
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database");
|
||||
boolean oldConfig = configVersion.compareTo(new ComparableVersion(CURRENT_CONFIG_VERSION)) < 0;
|
||||
|
||||
mysqlDatabase = getStringIncludingInts(config, "mysql.database");
|
||||
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + mysqlDatabase;
|
||||
user = getStringIncludingInts(config, "mysql.user");
|
||||
password = getStringIncludingInts(config, "mysql.password");
|
||||
mysqlUseSSL = config.getBoolean("mysql.useSSL", true);
|
||||
mysqlRequireSSL = config.getBoolean("mysql.requireSSL", false);
|
||||
delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2);
|
||||
forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0);
|
||||
timePerRun = config.getInt("consumer.timePerRun", 1000);
|
||||
@ -155,7 +192,10 @@ public class Config {
|
||||
autoClearLog = config.getStringList("clearlog.auto");
|
||||
dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", false);
|
||||
autoClearLogDelay = parseTimeSpec(config.getString("clearlog.autoClearLogDelay").split(" "));
|
||||
logBedExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true);
|
||||
logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false);
|
||||
logFireSpreadAsPlayerWhoCreatedIt = config.getBoolean("logging.logFireSpreadAsPlayerWhoCreatedIt", true);
|
||||
logFluidFlowAsPlayerWhoTriggeredIt = config.getBoolean("logging.logFluidFlowAsPlayerWhoTriggeredIt", false);
|
||||
logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true);
|
||||
try {
|
||||
logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase());
|
||||
@ -163,11 +203,11 @@ public class Config {
|
||||
throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'");
|
||||
}
|
||||
logEnvironmentalKills = config.getBoolean("logging.logEnvironmentalKills", false);
|
||||
hiddenPlayers = new HashSet<String>();
|
||||
hiddenPlayers = new HashSet<>();
|
||||
for (final String playerName : config.getStringList("logging.hiddenPlayers")) {
|
||||
hiddenPlayers.add(playerName.toLowerCase().trim());
|
||||
}
|
||||
hiddenBlocks = new HashSet<Material>();
|
||||
hiddenBlocks = new HashSet<>();
|
||||
for (final String blocktype : config.getStringList("logging.hiddenBlocks")) {
|
||||
final Material mat = Material.matchMaterial(blocktype);
|
||||
if (mat != null) {
|
||||
@ -176,11 +216,11 @@ public class Config {
|
||||
throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'");
|
||||
}
|
||||
}
|
||||
ignoredChat = new HashSet<String>();
|
||||
ignoredChat = new ArrayList<>();
|
||||
for (String chatCommand : config.getStringList("logging.ignoredChat")) {
|
||||
ignoredChat.add(chatCommand);
|
||||
ignoredChat.add(chatCommand.toLowerCase());
|
||||
}
|
||||
dontRollback = new HashSet<Material>();
|
||||
dontRollback = new HashSet<>();
|
||||
for (String e : config.getStringList("rollback.dontRollback")) {
|
||||
Material mat = Material.matchMaterial(e);
|
||||
if (mat != null) {
|
||||
@ -189,7 +229,7 @@ public class Config {
|
||||
throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'");
|
||||
}
|
||||
}
|
||||
replaceAnyway = new HashSet<Material>();
|
||||
replaceAnyway = new HashSet<>();
|
||||
for (String e : config.getStringList("rollback.replaceAnyway")) {
|
||||
Material mat = Material.matchMaterial(e);
|
||||
if (mat != null) {
|
||||
@ -204,6 +244,7 @@ public class Config {
|
||||
defaultTime = parseTimeSpec(config.getString("lookup.defaultTime").split(" "));
|
||||
linesPerPage = config.getInt("lookup.linesPerPage", 15);
|
||||
linesLimit = config.getInt("lookup.linesLimit", 1500);
|
||||
hardLinesLimit = config.getInt("lookup.hardLinesLimit", 100000);
|
||||
askRollbacks = config.getBoolean("questioner.askRollbacks", true);
|
||||
askRedos = config.getBoolean("questioner.askRedos", true);
|
||||
askClearLogs = config.getBoolean("questioner.askClearLogs", true);
|
||||
@ -212,7 +253,7 @@ public class Config {
|
||||
safetyIdCheck = config.getBoolean("safety.id.check", true);
|
||||
debug = config.getBoolean("debug", false);
|
||||
banPermission = config.getString("questioner.banPermission");
|
||||
final List<Tool> tools = new ArrayList<Tool>();
|
||||
final List<Tool> tools = new ArrayList<>();
|
||||
final ConfigurationSection toolsSec = config.getConfigurationSection("tools");
|
||||
for (final String toolName : toolsSec.getKeys(false)) {
|
||||
try {
|
||||
@ -221,20 +262,22 @@ public class Config {
|
||||
final ToolBehavior leftClickBehavior = ToolBehavior.valueOf(tSec.getString("leftClickBehavior").toUpperCase());
|
||||
final ToolBehavior rightClickBehavior = ToolBehavior.valueOf(tSec.getString("rightClickBehavior").toUpperCase());
|
||||
final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false);
|
||||
final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG"));
|
||||
final Material item = Material.matchMaterial(tSec.getString("item", "OAK_LOG"));
|
||||
final boolean canDrop = tSec.getBoolean("canDrop", false);
|
||||
final boolean removeOnDisable = tSec.getBoolean("removeOnDisable", true);
|
||||
final boolean dropToDisable = tSec.getBoolean("dropToDisable", false);
|
||||
final QueryParams params = new QueryParams(logblock);
|
||||
params.prepareToolQuery = true;
|
||||
params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" ")));
|
||||
params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" ")), false);
|
||||
final ToolMode mode = ToolMode.valueOf(tSec.getString("mode").toUpperCase());
|
||||
final PermissionDefault pdef = PermissionDefault.valueOf(tSec.getString("permissionDefault").toUpperCase());
|
||||
tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef));
|
||||
tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef, removeOnDisable, dropToDisable));
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex);
|
||||
}
|
||||
}
|
||||
toolsByName = new HashMap<String, Tool>();
|
||||
toolsByType = new HashMap<Material, Tool>();
|
||||
toolsByName = new HashMap<>();
|
||||
toolsByType = new HashMap<>();
|
||||
for (final Tool tool : tools) {
|
||||
toolsByType.put(tool.item, tool);
|
||||
toolsByName.put(tool.name.toLowerCase(), tool);
|
||||
@ -243,7 +286,7 @@ public class Config {
|
||||
}
|
||||
}
|
||||
final List<String> loggedWorlds = config.getStringList("loggedWorlds");
|
||||
worldConfigs = new HashMap<String, WorldConfig>();
|
||||
worldConfigs = new HashMap<>();
|
||||
if (loggedWorlds.isEmpty()) {
|
||||
throw new DataFormatException("No worlds configured");
|
||||
}
|
||||
@ -300,16 +343,34 @@ public class Config {
|
||||
public static Collection<WorldConfig> getLoggedWorlds() {
|
||||
return worldConfigs.values();
|
||||
}
|
||||
|
||||
public static boolean isLogging(World world, EntityLogging logging, Entity entity) {
|
||||
final WorldConfig wcfg = worldConfigs.get(world.getName());
|
||||
return wcfg != null && wcfg.isLogging(logging, entity);
|
||||
}
|
||||
|
||||
public static boolean isLoggingAnyEntities() {
|
||||
for (WorldConfig worldConfig : worldConfigs.values()) {
|
||||
if (worldConfig.isLoggingAnyEntities()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingEnabledMapping {
|
||||
private final boolean[] logging = new boolean[Logging.length];
|
||||
private final EnumSet<Logging> logging = EnumSet.noneOf(Logging.class);
|
||||
|
||||
public void setLogging(Logging l, boolean enabled) {
|
||||
logging[l.ordinal()] = enabled;
|
||||
if (enabled) {
|
||||
logging.add(l);
|
||||
} else {
|
||||
logging.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLogging(Logging l) {
|
||||
return logging[l.ordinal()];
|
||||
return logging.contains(l);
|
||||
}
|
||||
}
|
||||
|
28
src/main/java/de/diddiz/LogBlock/config/EntityLogging.java
Normal file
28
src/main/java/de/diddiz/LogBlock/config/EntityLogging.java
Normal file
@ -0,0 +1,28 @@
|
||||
package de.diddiz.LogBlock.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public enum EntityLogging {
|
||||
SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name() }),
|
||||
DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name(), "ANIMAL" }),
|
||||
MODIFY(new String[] { "ALL" });
|
||||
|
||||
public static final int length = EntityLogging.values().length;
|
||||
private final List<String> defaultEnabled;
|
||||
|
||||
private EntityLogging() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private EntityLogging(String[] defaultEnabled) {
|
||||
this.defaultEnabled = defaultEnabled == null ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(defaultEnabled));
|
||||
}
|
||||
|
||||
public List<String> getDefaultEnabled() {
|
||||
return defaultEnabled;
|
||||
}
|
||||
}
|
@ -1,21 +1,44 @@
|
||||
package de.diddiz.LogBlock.config;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Monster;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.WaterMob;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class WorldConfig extends LoggingEnabledMapping {
|
||||
public final String world;
|
||||
public final String table;
|
||||
public final String insertBlockStatementString;
|
||||
public final String selectBlockActorIdStatementString;
|
||||
public final String insertBlockStateStatementString;
|
||||
public final String insertBlockChestDataStatementString;
|
||||
public final String insertEntityStatementString;
|
||||
public final String updateEntityUUIDString;
|
||||
|
||||
private final EnumMap<EntityLogging, EntityLoggingList> entityLogging = new EnumMap<>(EntityLogging.class);
|
||||
|
||||
public WorldConfig(String world, File file) throws IOException {
|
||||
this.world = world;
|
||||
final Map<String, Object> def = new HashMap<String, Object>();
|
||||
final Map<String, Object> def = new HashMap<>();
|
||||
// "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual
|
||||
// They _can_ contain spaces, but replace them as well
|
||||
def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_"));
|
||||
@ -28,10 +51,97 @@ public class WorldConfig extends LoggingEnabledMapping {
|
||||
config.set(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
for (EntityLogging el : EntityLogging.values()) {
|
||||
if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) {
|
||||
config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled());
|
||||
}
|
||||
entityLogging.put(el, new EntityLoggingList(config.getStringList("entity." + el.name().toLowerCase())));
|
||||
}
|
||||
config.save(file);
|
||||
table = config.getString("table");
|
||||
for (final Logging l : Logging.values()) {
|
||||
setLogging(l, config.getBoolean("logging." + l.toString()));
|
||||
}
|
||||
|
||||
insertBlockStatementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1";
|
||||
insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)";
|
||||
insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)";
|
||||
insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?";
|
||||
}
|
||||
|
||||
public boolean isLogging(EntityLogging logging, Entity entity) {
|
||||
return entityLogging.get(logging).isLogging(entity);
|
||||
}
|
||||
|
||||
public boolean isLoggingAnyEntities() {
|
||||
for (EntityLoggingList list : entityLogging.values()) {
|
||||
if (list.isLoggingAnyEntities()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class EntityLoggingList {
|
||||
private final EnumSet<EntityType> logged = EnumSet.noneOf(EntityType.class);
|
||||
private final boolean logAll;
|
||||
private final boolean logAnimals;
|
||||
private final boolean logMonsters;
|
||||
private final boolean logLiving;
|
||||
|
||||
public EntityLoggingList(List<String> types) {
|
||||
boolean all = false;
|
||||
boolean animals = false;
|
||||
boolean monsters = false;
|
||||
boolean living = false;
|
||||
for (String type : types) {
|
||||
EntityType et = BukkitUtils.matchEntityType(type);
|
||||
if (et != null) {
|
||||
logged.add(et);
|
||||
} else {
|
||||
if (type.equalsIgnoreCase("all")) {
|
||||
all = true;
|
||||
} else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) {
|
||||
animals = true;
|
||||
} else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) {
|
||||
monsters = true;
|
||||
} else if (type.equalsIgnoreCase("living")) {
|
||||
living = true;
|
||||
} else {
|
||||
LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
logAll = all;
|
||||
logAnimals = animals;
|
||||
logMonsters = monsters;
|
||||
logLiving = living;
|
||||
}
|
||||
|
||||
public boolean isLogging(Entity entity) {
|
||||
if (entity == null || (entity instanceof Player)) {
|
||||
return false;
|
||||
}
|
||||
EntityType type = entity.getType();
|
||||
if (logAll || logged.contains(type)) {
|
||||
return true;
|
||||
}
|
||||
if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) {
|
||||
return true;
|
||||
}
|
||||
if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()))) {
|
||||
return true;
|
||||
}
|
||||
if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isLoggingAnyEntities() {
|
||||
return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,12 @@ package de.diddiz.LogBlock.events;
|
||||
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.ChestAccess;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public class BlockChangePreLogEvent extends PreLogEvent {
|
||||
@ -16,32 +15,29 @@ public class BlockChangePreLogEvent extends PreLogEvent {
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private Location location;
|
||||
private BlockData typeBefore, typeAfter;
|
||||
private String signText;
|
||||
private ChestAccess chestAccess;
|
||||
private YamlConfiguration stateBefore;
|
||||
private YamlConfiguration stateAfter;
|
||||
|
||||
public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter,
|
||||
String signText, ChestAccess chestAccess) {
|
||||
|
||||
public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess chestAccess) {
|
||||
super(owner);
|
||||
this.location = location;
|
||||
this.typeBefore = typeBefore;
|
||||
this.typeAfter = typeAfter;
|
||||
this.signText = signText;
|
||||
this.stateBefore = stateBefore;
|
||||
this.stateAfter = stateAfter;
|
||||
this.chestAccess = chestAccess;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(Location location) {
|
||||
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public BlockData getTypeBefore() {
|
||||
|
||||
return typeBefore;
|
||||
}
|
||||
|
||||
@ -53,7 +49,6 @@ public class BlockChangePreLogEvent extends PreLogEvent {
|
||||
}
|
||||
|
||||
public BlockData getTypeAfter() {
|
||||
|
||||
return typeAfter;
|
||||
}
|
||||
|
||||
@ -64,58 +59,36 @@ public class BlockChangePreLogEvent extends PreLogEvent {
|
||||
this.typeAfter = typeAfter;
|
||||
}
|
||||
|
||||
public String getSignText() {
|
||||
|
||||
return signText;
|
||||
public YamlConfiguration getStateBefore() {
|
||||
return stateBefore;
|
||||
}
|
||||
|
||||
public void setSignText(String[] signText) {
|
||||
|
||||
if (signText != null) {
|
||||
// Check for block
|
||||
Validate.isTrue(isValidSign(), "Must be valid sign block");
|
||||
|
||||
// Check for problems
|
||||
Validate.noNullElements(signText, "No null lines");
|
||||
Validate.isTrue(signText.length == 4, "Sign text must be 4 strings");
|
||||
|
||||
this.signText = signText[0] + "\0" + signText[1] + "\0" + signText[2] + "\0" + signText[3];
|
||||
} else {
|
||||
this.signText = null;
|
||||
}
|
||||
public YamlConfiguration getStateAfter() {
|
||||
return stateAfter;
|
||||
}
|
||||
|
||||
private boolean isValidSign() {
|
||||
public void setStateBefore(YamlConfiguration stateBefore) {
|
||||
this.stateBefore = stateBefore;
|
||||
}
|
||||
|
||||
if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && BukkitUtils.isEmpty(typeBefore.getMaterial())) {
|
||||
return true;
|
||||
}
|
||||
if ((typeBefore.getMaterial() == Material.SIGN || typeBefore.getMaterial() == Material.WALL_SIGN) && BukkitUtils.isEmpty(typeAfter.getMaterial())) {
|
||||
return true;
|
||||
}
|
||||
if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && typeBefore.equals(typeAfter)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public void setStateAfter(YamlConfiguration stateAfter) {
|
||||
this.stateAfter = stateAfter;
|
||||
}
|
||||
|
||||
public ChestAccess getChestAccess() {
|
||||
|
||||
return chestAccess;
|
||||
}
|
||||
|
||||
public void setChestAccess(ChestAccess chestAccess) {
|
||||
|
||||
this.chestAccess = chestAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ public abstract class PreLogEvent extends Event implements Cancellable {
|
||||
protected Actor owner;
|
||||
|
||||
public PreLogEvent(Actor owner) {
|
||||
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@ -21,8 +20,8 @@ public abstract class PreLogEvent extends Event implements Cancellable {
|
||||
* @deprecated {@link #getOwnerActor() } returns an object encapsulating
|
||||
* name and uuid. Names are not guaranteed to be unique.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getOwner() {
|
||||
|
||||
return owner.getName();
|
||||
}
|
||||
|
||||
@ -41,17 +40,16 @@ public abstract class PreLogEvent extends Event implements Cancellable {
|
||||
* @param owner The player/monster/cause who is involved in this event
|
||||
*/
|
||||
public void setOwner(Actor owner) {
|
||||
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancelled) {
|
||||
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
}
|
||||
|
59
src/main/java/de/diddiz/LogBlock/events/ToolUseEvent.java
Normal file
59
src/main/java/de/diddiz/LogBlock/events/ToolUseEvent.java
Normal file
@ -0,0 +1,59 @@
|
||||
package de.diddiz.LogBlock.events;
|
||||
|
||||
import de.diddiz.LogBlock.QueryParams;
|
||||
import de.diddiz.LogBlock.Tool;
|
||||
import de.diddiz.LogBlock.ToolBehavior;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
|
||||
/**
|
||||
* Fired whether a tool is about to be used by a player.
|
||||
*/
|
||||
public class ToolUseEvent extends PlayerEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private boolean cancel;
|
||||
private final Tool tool;
|
||||
private final ToolBehavior behavior;
|
||||
private final QueryParams params;
|
||||
|
||||
public ToolUseEvent(Player who, Tool tool, ToolBehavior behavior, QueryParams params) {
|
||||
super(who);
|
||||
this.tool = tool;
|
||||
this.behavior = behavior;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancel = cancel;
|
||||
}
|
||||
|
||||
public Tool getTool() {
|
||||
return tool;
|
||||
}
|
||||
|
||||
public ToolBehavior getBehavior() {
|
||||
return behavior;
|
||||
}
|
||||
|
||||
public QueryParams getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
package de.diddiz.LogBlock.listeners;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Bee;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Hanging;
|
||||
import org.bukkit.entity.IronGolem;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Snowman;
|
||||
import org.bukkit.entity.Wither;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
|
||||
import org.bukkit.event.hanging.HangingBreakEvent;
|
||||
import org.bukkit.event.hanging.HangingPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerArmorStandManipulateEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.EntityChange;
|
||||
import de.diddiz.LogBlock.EntityChange.EntityChangeType;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.config.EntityLogging;
|
||||
import de.diddiz.util.LoggingUtil;
|
||||
import de.diddiz.worldedit.WorldEditHelper;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdvancedEntityLogging extends LoggingListener {
|
||||
|
||||
private Player lastSpawner;
|
||||
private Class<? extends Entity> lastSpawning;
|
||||
private boolean lastSpawnerEgg;
|
||||
|
||||
// serialize them before the death event
|
||||
private UUID lastEntityDamagedForDeathUUID;
|
||||
private byte[] lastEntityDamagedForDeathSerialized;
|
||||
|
||||
public AdvancedEntityLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resetOnTick();
|
||||
}
|
||||
}.runTaskTimer(lb, 1, 1);
|
||||
}
|
||||
|
||||
private void resetOnTick() {
|
||||
lastSpawner = null;
|
||||
lastSpawning = null;
|
||||
lastSpawnerEgg = false;
|
||||
lastEntityDamagedForDeathUUID = null;
|
||||
lastEntityDamagedForDeathSerialized = null;
|
||||
}
|
||||
|
||||
private void setLastSpawner(Player player, Class<? extends Entity> spawning, boolean spawnEgg) {
|
||||
lastSpawner = player;
|
||||
lastSpawning = spawning;
|
||||
lastSpawnerEgg = spawnEgg;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerBlockPlace(BlockPlaceEvent event) {
|
||||
Material placed = event.getBlock().getType();
|
||||
if (placed == Material.WITHER_SKELETON_SKULL) {
|
||||
setLastSpawner(event.getPlayer(), Wither.class, false);
|
||||
} else if (placed == Material.CARVED_PUMPKIN) {
|
||||
Material below = event.getBlock().getRelative(BlockFace.DOWN).getType();
|
||||
if (below == Material.SNOW_BLOCK) {
|
||||
setLastSpawner(event.getPlayer(), Snowman.class, false);
|
||||
} else if (below == Material.IRON_BLOCK) {
|
||||
setLastSpawner(event.getPlayer(), IronGolem.class, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
ItemStack inHand = event.getItem();
|
||||
if (inHand != null) {
|
||||
Material mat = inHand.getType();
|
||||
if (mat == Material.ARMOR_STAND) {
|
||||
setLastSpawner(event.getPlayer(), ArmorStand.class, false);
|
||||
} else if (mat.name().endsWith("_SPAWN_EGG")) {
|
||||
setLastSpawner(event.getPlayer(), null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||
ItemStack inHand = event.getHand() == EquipmentSlot.HAND ? event.getPlayer().getInventory().getItemInMainHand() : event.getPlayer().getInventory().getItemInOffHand();
|
||||
if (inHand != null && inHand.getType() != Material.AIR) {
|
||||
Material mat = inHand.getType();
|
||||
if (mat.name().endsWith("_SPAWN_EGG")) {
|
||||
setLastSpawner(event.getPlayer(), null, true);
|
||||
}
|
||||
|
||||
Entity entity = event.getRightClicked();
|
||||
if (entity instanceof ItemFrame) {
|
||||
ItemStack oldItem = ((ItemFrame) entity).getItem();
|
||||
if (oldItem == null || oldItem.getType() == Material.AIR) {
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) {
|
||||
Actor actor = Actor.actorFromEntity(event.getPlayer());
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
inHand = inHand.clone();
|
||||
inHand.setAmount(1);
|
||||
data.set("item", inHand);
|
||||
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onEntitySpawn(CreatureSpawnEvent event) {
|
||||
if (!event.isCancelled()) {
|
||||
if (event.getSpawnReason() == SpawnReason.CUSTOM || event.getSpawnReason() == SpawnReason.BEEHIVE) {
|
||||
return;
|
||||
}
|
||||
LivingEntity entity = event.getEntity();
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) {
|
||||
Actor actor = null;
|
||||
if (lastSpawner != null && lastSpawner.getWorld() == entity.getWorld() && lastSpawner.getLocation().distance(entity.getLocation()) < 10) {
|
||||
if (lastSpawnerEgg && event.getSpawnReason() == SpawnReason.SPAWNER_EGG) {
|
||||
actor = Actor.actorFromEntity(lastSpawner);
|
||||
} else if (lastSpawning != null && lastSpawning.isAssignableFrom(entity.getClass())) {
|
||||
actor = Actor.actorFromEntity(lastSpawner);
|
||||
}
|
||||
}
|
||||
if (actor == null) {
|
||||
actor = new Actor(event.getSpawnReason().toString());
|
||||
}
|
||||
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE);
|
||||
}
|
||||
}
|
||||
resetOnTick();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
LivingEntity entity = event.getEntity();
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
|
||||
Actor actor = null;
|
||||
EntityDamageEvent lastDamage = entity.getLastDamageCause();
|
||||
if (lastDamage instanceof EntityDamageByEntityEvent) {
|
||||
Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) lastDamage).getDamager());
|
||||
if (damager != null) {
|
||||
actor = Actor.actorFromEntity(damager);
|
||||
}
|
||||
}
|
||||
if (actor == null) {
|
||||
actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString());
|
||||
}
|
||||
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onHangingPlace(HangingPlaceEvent event) {
|
||||
Hanging entity = event.getEntity();
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) {
|
||||
Actor actor = Actor.actorFromEntity(event.getPlayer());
|
||||
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onHangingBreak(HangingBreakEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
|
||||
Actor actor;
|
||||
if (event instanceof HangingBreakByEntityEvent) {
|
||||
Entity damager = LoggingUtil.getRealDamager(((HangingBreakByEntityEvent) event).getRemover());
|
||||
actor = Actor.actorFromEntity(damager);
|
||||
} else {
|
||||
actor = new Actor(event.getCause().toString());
|
||||
}
|
||||
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
if (entity instanceof ItemFrame) {
|
||||
ItemStack oldItem = ((ItemFrame) entity).getItem();
|
||||
if (oldItem != null && oldItem.getType() != Material.AIR) {
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) {
|
||||
Actor actor;
|
||||
if (event instanceof EntityDamageByEntityEvent) {
|
||||
Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) event).getDamager());
|
||||
actor = Actor.actorFromEntity(damager);
|
||||
} else {
|
||||
actor = new Actor(event.getCause().toString());
|
||||
}
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.set("item", oldItem);
|
||||
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
|
||||
lastEntityDamagedForDeathUUID = entity.getUniqueId();
|
||||
lastEntityDamagedForDeathSerialized = WorldEditHelper.serializeEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
|
||||
Entity damager = event.getDamager();
|
||||
if (damager instanceof Bee && !((Bee) damager).hasStung()) {
|
||||
if (Config.isLogging(damager.getWorld(), EntityLogging.MODIFY, damager)) {
|
||||
Actor actor = Actor.actorFromEntity(event.getEntity());
|
||||
consumer.queueEntityModification(actor, damager.getUniqueId(), damager.getType(), damager.getLocation(), EntityChange.EntityChangeType.GET_STUNG, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerArmorStandManipulate(PlayerArmorStandManipulateEvent event) {
|
||||
ArmorStand entity = event.getRightClicked();
|
||||
ItemStack oldItem = event.getArmorStandItem();
|
||||
ItemStack newItem = event.getPlayerItem();
|
||||
boolean oldEmpty = oldItem == null || oldItem.getType() == Material.AIR;
|
||||
boolean newEmpty = newItem == null || newItem.getType() == Material.AIR;
|
||||
if ((!oldEmpty || !newEmpty) && Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) {
|
||||
Actor actor = Actor.actorFromEntity(event.getPlayer());
|
||||
if (!oldEmpty && !newEmpty && newItem.getAmount() > 1) {
|
||||
return;
|
||||
}
|
||||
if (!oldEmpty) {
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.set("item", oldItem);
|
||||
data.set("slot", event.getSlot().name());
|
||||
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data);
|
||||
}
|
||||
if (!newEmpty) {
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.set("item", newItem);
|
||||
data.set("slot", event.getSlot().name());
|
||||
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.EntityChangeType changeType) {
|
||||
Location location = entity.getLocation();
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.set("x", location.getX());
|
||||
data.set("y", location.getY());
|
||||
data.set("z", location.getZ());
|
||||
data.set("yaw", location.getYaw());
|
||||
data.set("pitch", location.getPitch());
|
||||
if (changeType == EntityChangeType.KILL && entity.getUniqueId().equals(lastEntityDamagedForDeathUUID)) {
|
||||
data.set("worldedit", lastEntityDamagedForDeathSerialized);
|
||||
} else {
|
||||
data.set("worldedit", WorldEditHelper.serializeEntity(entity));
|
||||
}
|
||||
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, changeType, data);
|
||||
}
|
||||
}
|
@ -10,7 +10,8 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
@ -19,6 +20,7 @@ import org.bukkit.event.player.PlayerBucketFillEvent;
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
import static de.diddiz.LogBlock.config.Config.isLogging;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogBlockBreak;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogBlockReplace;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogFallables;
|
||||
|
||||
public class BlockBreakLogging extends LoggingListener {
|
||||
@ -38,16 +40,14 @@ public class BlockBreakLogging extends LoggingListener {
|
||||
final Block origin = event.getBlock();
|
||||
final Material type = origin.getType();
|
||||
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) {
|
||||
consumer.queueSignBreak(actor, (Sign) origin.getState());
|
||||
} else if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) {
|
||||
if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) {
|
||||
consumer.queueContainerBreak(actor, origin.getState());
|
||||
} else if (type == Material.ICE) {
|
||||
// When in creative mode ice doesn't form water
|
||||
if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) {
|
||||
consumer.queueBlockBreak(actor, origin.getState());
|
||||
smartLogBlockBreak(consumer, actor, origin);
|
||||
} else {
|
||||
consumer.queueBlockReplace(actor, origin.getState(), Bukkit.createBlockData(Material.WATER));
|
||||
smartLogBlockReplace(consumer, actor, origin, Bukkit.createBlockData(Material.WATER));
|
||||
}
|
||||
} else {
|
||||
smartLogBlockBreak(consumer, actor, origin);
|
||||
@ -59,7 +59,17 @@ public class BlockBreakLogging extends LoggingListener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerBucketFill(PlayerBucketFillEvent event) {
|
||||
if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) {
|
||||
consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState());
|
||||
BlockData clickedBlockData = event.getBlockClicked().getBlockData();
|
||||
if (clickedBlockData instanceof Waterlogged) {
|
||||
Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData;
|
||||
if (clickedWaterlogged.isWaterlogged()) {
|
||||
Waterlogged clickedWaterloggedWithoutWater = (Waterlogged) clickedWaterlogged.clone();
|
||||
clickedWaterloggedWithoutWater.setWaterlogged(false);
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithoutWater);
|
||||
}
|
||||
} else {
|
||||
consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package de.diddiz.LogBlock.listeners;
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -10,10 +12,13 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockBurnEvent;
|
||||
import org.bukkit.event.block.BlockIgniteEvent;
|
||||
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.isLogging;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogBlockBreak;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogBlockReplace;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogFallables;
|
||||
|
||||
public class BlockBurnLogging extends LoggingListener {
|
||||
@ -24,8 +29,31 @@ public class BlockBurnLogging extends LoggingListener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockBurn(BlockBurnEvent event) {
|
||||
if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) {
|
||||
smartLogBlockBreak(consumer, new Actor("Fire"), event.getBlock());
|
||||
smartLogFallables(consumer, new Actor("Fire"), event.getBlock());
|
||||
smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData());
|
||||
smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockIgnite(BlockIgniteEvent event) {
|
||||
Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null);
|
||||
if (event.getCause() == IgniteCause.FLINT_AND_STEEL) {
|
||||
if (event.getIgnitingEntity() != null) {
|
||||
return; // handled in block place
|
||||
} else {
|
||||
actor = new Actor("Dispenser");
|
||||
}
|
||||
} else if (event.getCause() == IgniteCause.LIGHTNING) {
|
||||
actor = new Actor("Lightning");
|
||||
} else if (event.getCause() == IgniteCause.EXPLOSION) {
|
||||
actor = new Actor("Explosion");
|
||||
} else if (event.getCause() == IgniteCause.LAVA) {
|
||||
actor = new Actor("Lava");
|
||||
} else if (event.getCause() == IgniteCause.ENDER_CRYSTAL) {
|
||||
actor = new Actor("EnderCrystal");
|
||||
}
|
||||
if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) {
|
||||
consumer.queueBlockPlace(actor, event.getBlock().getLocation(), Material.FIRE.createBlockData());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,20 +3,19 @@ package de.diddiz.LogBlock.listeners;
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.util.LoggingUtil;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
import static de.diddiz.LogBlock.config.Config.isLogging;
|
||||
|
||||
public class BlockPlaceLogging extends LoggingListener {
|
||||
@ -26,69 +25,44 @@ public class BlockPlaceLogging extends LoggingListener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
|
||||
if (wcfg != null && wcfg.isLogging(Logging.BLOCKPLACE)) {
|
||||
final Material type = event.getBlock().getType();
|
||||
if (Config.isLogging(event.getBlock().getWorld(), Logging.BLOCKPLACE)) {
|
||||
final BlockState before = event.getBlockReplacedState();
|
||||
final BlockState after = event.getBlockPlaced().getState();
|
||||
final Actor actor = Actor.actorFromEntity(event.getPlayer());
|
||||
|
||||
//Handle falling blocks
|
||||
if (type.hasGravity()) {
|
||||
|
||||
// Catch placed blocks overwriting something
|
||||
if (!BukkitUtils.isEmpty(before.getType())) {
|
||||
consumer.queueBlockBreak(actor, before);
|
||||
}
|
||||
|
||||
Location loc = event.getBlock().getLocation();
|
||||
int x = loc.getBlockX();
|
||||
int y = loc.getBlockY();
|
||||
int z = loc.getBlockZ();
|
||||
// Blocks only fall if they have a chance to start a velocity
|
||||
if (BukkitUtils.isEmpty(event.getBlock().getRelative(BlockFace.DOWN).getType())) {
|
||||
while (y > 0 && BukkitUtils.canFall(loc.getWorld(), x, (y - 1), z)) {
|
||||
y--;
|
||||
}
|
||||
}
|
||||
// If y is 0 then the sand block fell out of the world :(
|
||||
if (y != 0) {
|
||||
Location finalLoc = new Location(loc.getWorld(), x, y, z);
|
||||
// Run this check to avoid false positives
|
||||
if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) {
|
||||
if (BukkitUtils.isEmpty(finalLoc.getBlock().getType()) || finalLoc.equals(event.getBlock().getLocation())) {
|
||||
consumer.queueBlockPlace(actor, finalLoc, event.getBlock().getBlockData());
|
||||
} else {
|
||||
consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), event.getBlock().getBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Sign logging is handled elsewhere
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Delay queuing by one tick to allow data to be updated
|
||||
LogBlock.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(LogBlock.getInstance(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (BukkitUtils.isEmpty(before.getType())) {
|
||||
consumer.queueBlockPlace(actor, after);
|
||||
} else {
|
||||
consumer.queueBlockReplace(actor, before, after);
|
||||
}
|
||||
}
|
||||
}, 1L);
|
||||
LoggingUtil.smartLogBlockPlace(consumer, actor, before, after);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
|
||||
if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) {
|
||||
consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), Bukkit.createBlockData(event.getBucket() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA));
|
||||
Material placedMaterial = event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER;
|
||||
BlockData clickedBlockData = event.getBlockClicked().getBlockData();
|
||||
if (placedMaterial == Material.WATER && clickedBlockData instanceof Waterlogged) {
|
||||
Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData;
|
||||
if (!clickedWaterlogged.isWaterlogged()) {
|
||||
Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone();
|
||||
clickedWaterloggedWithWater.setWaterlogged(true);
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace());
|
||||
if (placedAt.isEmpty()) {
|
||||
consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData());
|
||||
} else {
|
||||
BlockData placedAtBlock = placedAt.getBlockData();
|
||||
if (placedAtBlock instanceof Waterlogged && !(((Waterlogged) placedAtBlock).isWaterlogged())) {
|
||||
Waterlogged clickedWaterloggedWithWater = (Waterlogged) placedAtBlock.clone();
|
||||
clickedWaterloggedWithWater.setWaterlogged(true);
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, clickedWaterloggedWithWater);
|
||||
} else {
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, placedMaterial.createBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,18 @@ public class BlockSpreadLogging extends LoggingListener {
|
||||
}
|
||||
name = "MushroomSpread";
|
||||
break;
|
||||
case BAMBOO:
|
||||
case BAMBOO_SAPLING: {
|
||||
if (!isLogging(world, Logging.BAMBOOGROWTH)) {
|
||||
return;
|
||||
}
|
||||
name = "BambooGrowth";
|
||||
if (type == Material.BAMBOO_SAPLING) {
|
||||
// bamboo sapling gets replaced by bamboo
|
||||
consumer.queueBlockReplace(new Actor(name), event.getSource().getState(), Material.BAMBOO.createBlockData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ package de.diddiz.LogBlock.listeners;
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.minecart.CommandMinecart;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
@ -18,7 +21,7 @@ public class ChatLogging extends LoggingListener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
||||
if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) {
|
||||
if (isLogging(event.getPlayer().getWorld(), Logging.PLAYER_COMMANDS)) {
|
||||
consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage());
|
||||
}
|
||||
}
|
||||
@ -32,6 +35,24 @@ public class ChatLogging extends LoggingListener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onServerCommand(ServerCommandEvent event) {
|
||||
consumer.queueChat(new Actor("Console"), "/" + event.getCommand());
|
||||
CommandSender sender = event.getSender();
|
||||
Actor actor;
|
||||
if (sender instanceof BlockCommandSender) {
|
||||
if (!isLogging(((BlockCommandSender) sender).getBlock().getWorld(), Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
return;
|
||||
}
|
||||
actor = new Actor("CommandBlock");
|
||||
} else if (sender instanceof CommandMinecart) {
|
||||
if (!isLogging(((CommandMinecart) sender).getWorld(), Logging.COMMANDBLOCK_COMMANDS)) {
|
||||
return;
|
||||
}
|
||||
actor = new Actor("CommandMinecart");
|
||||
} else {
|
||||
if (!isLogging(Logging.CONSOLE_COMMANDS)) {
|
||||
return;
|
||||
}
|
||||
actor = new Actor("Console");
|
||||
}
|
||||
consumer.queueChat(actor, "/" + event.getCommand());
|
||||
}
|
||||
}
|
||||
|
@ -10,19 +10,84 @@ import org.bukkit.block.DoubleChest;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.isLogging;
|
||||
import static de.diddiz.util.BukkitUtils.*;
|
||||
|
||||
public class ChestAccessLogging extends LoggingListener {
|
||||
private final Map<HumanEntity, ItemStack[]> containers = new HashMap<HumanEntity, ItemStack[]>();
|
||||
private class PlayerActiveInventoryModifications {
|
||||
private final HumanEntity actor;
|
||||
private final Location location;
|
||||
private final HashMap<ItemStack, Integer> modifications;
|
||||
|
||||
public PlayerActiveInventoryModifications(HumanEntity actor, Location location) {
|
||||
this.actor = actor;
|
||||
this.location = location;
|
||||
this.modifications = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addModification(ItemStack stack, int amount) {
|
||||
if (amount == 0) {
|
||||
return;
|
||||
}
|
||||
// if we have other viewers, we have to flush their changes
|
||||
ArrayList<PlayerActiveInventoryModifications> allViewers = containersByLocation.get(location);
|
||||
if (allViewers.size() > 1) {
|
||||
for (PlayerActiveInventoryModifications other : allViewers) {
|
||||
if (other != this) {
|
||||
other.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount);
|
||||
stack = new ItemStack(stack);
|
||||
stack.setAmount(1);
|
||||
Integer existing = modifications.get(stack);
|
||||
int newTotal = amount + (existing == null ? 0 : existing);
|
||||
if (newTotal == 0) {
|
||||
modifications.remove(stack);
|
||||
} else {
|
||||
modifications.put(stack, newTotal);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (!modifications.isEmpty()) {
|
||||
for (Entry<ItemStack, Integer> e : modifications.entrySet()) {
|
||||
ItemStack stack = e.getKey();
|
||||
int amount = e.getValue();
|
||||
stack.setAmount(Math.abs(amount));
|
||||
consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0));
|
||||
consumer.queueChestAccess(Actor.actorFromEntity(actor), location, location.getWorld().getBlockAt(location).getBlockData(), stack, amount < 0);
|
||||
}
|
||||
modifications.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public HumanEntity getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<HumanEntity, PlayerActiveInventoryModifications> containersByOwner = new HashMap<>();
|
||||
private final Map<Location, ArrayList<PlayerActiveInventoryModifications>> containersByLocation = new HashMap<>();
|
||||
|
||||
public ChestAccessLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
@ -30,39 +95,207 @@ public class ChestAccessLogging extends LoggingListener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
|
||||
if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) {
|
||||
final HumanEntity player = event.getPlayer();
|
||||
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
|
||||
return;
|
||||
}
|
||||
InventoryHolder holder = event.getInventory().getHolder();
|
||||
if (holder instanceof BlockState || holder instanceof DoubleChest) {
|
||||
final HumanEntity player = event.getPlayer();
|
||||
final ItemStack[] before = containers.get(player);
|
||||
if (before != null) {
|
||||
final ItemStack[] after = compressInventory(event.getInventory().getContents());
|
||||
final ItemStack[] diff = compareInventories(before, after);
|
||||
final Location loc = getInventoryHolderLocation(holder);
|
||||
for (final ItemStack item : diff) {
|
||||
ItemStack item2 = item.clone();
|
||||
item2.setAmount(Math.abs(item.getAmount()));
|
||||
consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), item2, item.getAmount() < 0);
|
||||
final PlayerActiveInventoryModifications modifications = containersByOwner.remove(player);
|
||||
if (modifications != null) {
|
||||
final Location loc = modifications.getLocation();
|
||||
ArrayList<PlayerActiveInventoryModifications> atLocation = containersByLocation.get(loc);
|
||||
atLocation.remove(modifications);
|
||||
if (atLocation.isEmpty()) {
|
||||
containersByLocation.remove(loc);
|
||||
}
|
||||
containers.remove(player);
|
||||
modifications.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onInventoryOpen(InventoryOpenEvent event) {
|
||||
|
||||
if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) {
|
||||
final HumanEntity player = event.getPlayer();
|
||||
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
|
||||
return;
|
||||
}
|
||||
if (event.getInventory() != null) {
|
||||
InventoryHolder holder = event.getInventory().getHolder();
|
||||
if (holder instanceof BlockState || holder instanceof DoubleChest) {
|
||||
if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) {
|
||||
containers.put(event.getPlayer(), compressInventory(event.getInventory().getContents()));
|
||||
PlayerActiveInventoryModifications modifications = new PlayerActiveInventoryModifications(event.getPlayer(), getInventoryHolderLocation(holder));
|
||||
containersByOwner.put(modifications.getActor(), modifications);
|
||||
containersByLocation.compute(modifications.getLocation(), (k, v) -> {
|
||||
if (v == null) {
|
||||
v = new ArrayList<>();
|
||||
}
|
||||
v.add(modifications);
|
||||
return v;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
final HumanEntity player = event.getWhoClicked();
|
||||
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
|
||||
return;
|
||||
}
|
||||
InventoryHolder holder = event.getInventory().getHolder();
|
||||
if (holder instanceof BlockState || holder instanceof DoubleChest) {
|
||||
final PlayerActiveInventoryModifications modifications = containersByOwner.get(player);
|
||||
if (modifications != null) {
|
||||
switch (event.getAction()) {
|
||||
case PICKUP_ONE:
|
||||
case DROP_ONE_SLOT:
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
modifications.addModification(event.getCurrentItem(), -1);
|
||||
}
|
||||
break;
|
||||
case PICKUP_HALF:
|
||||
// server behaviour: round up
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
modifications.addModification(event.getCurrentItem(), -(event.getCurrentItem().getAmount() + 1) / 2);
|
||||
}
|
||||
break;
|
||||
case PICKUP_SOME: // oversized stack - can not take all when clicking
|
||||
// server behaviour: leave a full stack in the slot, take everything else
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
int taken = event.getCurrentItem().getAmount() - event.getCurrentItem().getMaxStackSize();
|
||||
modifications.addModification(event.getCursor(), -taken);
|
||||
}
|
||||
break;
|
||||
case PICKUP_ALL:
|
||||
case DROP_ALL_SLOT:
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount());
|
||||
}
|
||||
break;
|
||||
case PLACE_ONE:
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
modifications.addModification(event.getCursor(), 1);
|
||||
}
|
||||
break;
|
||||
case PLACE_SOME: // not enough free place in target slot
|
||||
// server behaviour: place as much as possible
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
int placeable = event.getCurrentItem().getMaxStackSize() - event.getCurrentItem().getAmount();
|
||||
modifications.addModification(event.getCursor(), placeable);
|
||||
}
|
||||
break;
|
||||
case PLACE_ALL:
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
modifications.addModification(event.getCursor(), event.getCursor().getAmount());
|
||||
}
|
||||
break;
|
||||
case SWAP_WITH_CURSOR:
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
modifications.addModification(event.getCursor(), event.getCursor().getAmount());
|
||||
modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount());
|
||||
}
|
||||
break;
|
||||
case MOVE_TO_OTHER_INVENTORY: // shift + click
|
||||
boolean removed = event.getRawSlot() < event.getView().getTopInventory().getSize();
|
||||
modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1));
|
||||
break;
|
||||
case COLLECT_TO_CURSOR: // double click
|
||||
// server behaviour: first collect all with an amount != maxstacksize, then others, starting from slot 0 (container)
|
||||
ItemStack cursor = event.getCursor();
|
||||
if (cursor == null) {
|
||||
return;
|
||||
}
|
||||
int toPickUp = cursor.getMaxStackSize() - cursor.getAmount();
|
||||
int takenFromContainer = 0;
|
||||
boolean takeFromFullStacks = false;
|
||||
Inventory top = event.getView().getTopInventory();
|
||||
Inventory bottom = event.getView().getBottomInventory();
|
||||
while (toPickUp > 0) {
|
||||
for (ItemStack stack : top.getStorageContents()) {
|
||||
if (cursor.isSimilar(stack)) {
|
||||
if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) {
|
||||
int take = Math.min(toPickUp, stack.getAmount());
|
||||
toPickUp -= take;
|
||||
takenFromContainer += take;
|
||||
if (toPickUp <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toPickUp <= 0) {
|
||||
break;
|
||||
}
|
||||
for (ItemStack stack : bottom.getStorageContents()) {
|
||||
if (cursor.isSimilar(stack)) {
|
||||
if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) {
|
||||
int take = Math.min(toPickUp, stack.getAmount());
|
||||
toPickUp -= take;
|
||||
if (toPickUp <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (takeFromFullStacks) {
|
||||
break;
|
||||
} else {
|
||||
takeFromFullStacks = true;
|
||||
}
|
||||
}
|
||||
if (takenFromContainer > 0) {
|
||||
modifications.addModification(event.getCursor(), -takenFromContainer);
|
||||
}
|
||||
break;
|
||||
case HOTBAR_SWAP: // number key or offhand key
|
||||
case HOTBAR_MOVE_AND_READD: // something was in the other slot
|
||||
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
|
||||
ItemStack otherSlot = (event.getClick() == ClickType.SWAP_OFFHAND) ? event.getWhoClicked().getInventory().getItemInOffHand() : event.getWhoClicked().getInventory().getItem(event.getHotbarButton());
|
||||
if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) {
|
||||
modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount());
|
||||
}
|
||||
if (otherSlot != null && otherSlot.getType() != Material.AIR) {
|
||||
modifications.addModification(otherSlot, otherSlot.getAmount());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DROP_ALL_CURSOR:
|
||||
case DROP_ONE_CURSOR:
|
||||
case CLONE_STACK:
|
||||
case NOTHING:
|
||||
// only the cursor or nothing (but not the inventory) was modified
|
||||
break;
|
||||
case UNKNOWN:
|
||||
default:
|
||||
// unable to log something we don't know
|
||||
consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
final HumanEntity player = event.getWhoClicked();
|
||||
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
|
||||
return;
|
||||
}
|
||||
InventoryHolder holder = event.getInventory().getHolder();
|
||||
if (holder instanceof BlockState || holder instanceof DoubleChest) {
|
||||
final PlayerActiveInventoryModifications modifications = containersByOwner.get(player);
|
||||
if (modifications != null) {
|
||||
Inventory container = event.getView().getTopInventory();
|
||||
int containerSize = container.getSize();
|
||||
for (Entry<Integer, ItemStack> e : event.getNewItems().entrySet()) {
|
||||
int slot = e.getKey();
|
||||
if (slot < containerSize) {
|
||||
ItemStack old = container.getItem(slot);
|
||||
int oldAmount = (old == null || old.getType() == Material.AIR) ? 0 : old.getAmount();
|
||||
modifications.addModification(e.getValue(), e.getValue().getAmount() - oldAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.type.TurtleEgg;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -48,8 +49,19 @@ public class CreatureInteractLogging extends LoggingListener {
|
||||
consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState());
|
||||
}
|
||||
}
|
||||
} else if (type == Material.TURTLE_EGG) {
|
||||
if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) {
|
||||
TurtleEgg turtleEggData = (TurtleEgg) clicked.getBlockData();
|
||||
int eggs = turtleEggData.getEggs();
|
||||
if (eggs > 1) {
|
||||
TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone();
|
||||
turtleEggData2.setEggs(eggs - 1);
|
||||
consumer.queueBlock(new Actor("CreatureTrample"), loc, turtleEggData, turtleEggData2);
|
||||
} else {
|
||||
consumer.queueBlock(new Actor("CreatureTrample"), loc, turtleEggData, Material.AIR.createBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
package de.diddiz.LogBlock.listeners;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.util.LoggingUtil;
|
||||
|
||||
public class DragonEggLogging extends LoggingListener {
|
||||
|
||||
private UUID lastDragonEggInteractionPlayer;
|
||||
private Location lastDragonEggInteractionLocation;
|
||||
|
||||
public DragonEggLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock() && event.getClickedBlock().getType() == Material.DRAGON_EGG) {
|
||||
Block block = event.getClickedBlock();
|
||||
if (!Config.isLogging(block.getWorld(), Logging.DRAGONEGGTELEPORT)) {
|
||||
return;
|
||||
}
|
||||
lastDragonEggInteractionPlayer = event.getPlayer().getUniqueId();
|
||||
lastDragonEggInteractionLocation = block.getLocation();
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
lastDragonEggInteractionPlayer = null;
|
||||
lastDragonEggInteractionLocation = null;
|
||||
}
|
||||
}.runTask(LogBlock.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onDragonEggTeleport(BlockFromToEvent event) {
|
||||
Block block = event.getBlock();
|
||||
Player teleportCause = null;
|
||||
if (lastDragonEggInteractionPlayer != null && lastDragonEggInteractionLocation != null && lastDragonEggInteractionLocation.equals(block.getLocation())) {
|
||||
teleportCause = Bukkit.getPlayer(lastDragonEggInteractionPlayer);
|
||||
}
|
||||
|
||||
if (block.getType() == Material.DRAGON_EGG && Config.isLogging(block.getWorld(), Logging.DRAGONEGGTELEPORT)) {
|
||||
Actor actor = new Actor("DragonEgg");
|
||||
if (teleportCause != null) {
|
||||
actor = Actor.actorFromEntity(teleportCause);
|
||||
}
|
||||
BlockData data = block.getBlockData();
|
||||
consumer.queueBlockBreak(actor, block.getLocation(), data);
|
||||
BlockState finalState = event.getToBlock().getState();
|
||||
finalState.setBlockData(data);
|
||||
LoggingUtil.smartLogBlockPlace(consumer, actor, event.getToBlock().getState(), finalState);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,23 +3,36 @@ package de.diddiz.LogBlock.listeners;
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.entity.minecart.ExplosiveMinecart;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese;
|
||||
import static de.diddiz.util.BukkitUtils.getContainerBlocks;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ExplosionLogging extends LoggingListener {
|
||||
|
||||
private UUID lastBedInteractionPlayer;
|
||||
private Location lastBedInteractionLocation;
|
||||
|
||||
public ExplosionLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
}
|
||||
@ -87,7 +100,7 @@ public class ExplosionLogging extends LoggingListener {
|
||||
}
|
||||
actor = Actor.actorFromEntity(source);
|
||||
|
||||
} else if (source instanceof EnderCrystal){
|
||||
} else if (source instanceof EnderCrystal) {
|
||||
if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) {
|
||||
return;
|
||||
}
|
||||
@ -100,9 +113,7 @@ public class ExplosionLogging extends LoggingListener {
|
||||
}
|
||||
for (final Block block : event.blockList()) {
|
||||
final Material type = block.getType();
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) {
|
||||
consumer.queueSignBreak(actor, (Sign) block.getState());
|
||||
} else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) {
|
||||
if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) {
|
||||
consumer.queueContainerBreak(actor, block.getState());
|
||||
} else {
|
||||
consumer.queueBlockBreak(actor, block.getState());
|
||||
@ -111,21 +122,53 @@ public class ExplosionLogging extends LoggingListener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock() && BukkitUtils.isBed(event.getClickedBlock().getType())) {
|
||||
Block block = event.getClickedBlock();
|
||||
if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) {
|
||||
return;
|
||||
}
|
||||
lastBedInteractionPlayer = event.getPlayer().getUniqueId();
|
||||
lastBedInteractionLocation = block.getLocation();
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
lastBedInteractionPlayer = null;
|
||||
lastBedInteractionLocation = null;
|
||||
}
|
||||
}.runTask(LogBlock.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockExplode(BlockExplodeEvent event) {
|
||||
Player bedCause = null;
|
||||
if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) {
|
||||
Location block = event.getBlock().getLocation();
|
||||
if (lastBedInteractionLocation.getWorld() == block.getWorld() && block.distanceSquared(lastBedInteractionLocation) <= 1) {
|
||||
bedCause = Bukkit.getPlayer(lastBedInteractionPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
for (final Block block : event.blockList()) {
|
||||
final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld());
|
||||
|
||||
if (wcfg != null) {
|
||||
if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
|
||||
Actor actor = new Actor("Explosion");
|
||||
if (bedCause != null) {
|
||||
if (!wcfg.isLogging(Logging.BEDEXPLOSION)) {
|
||||
return;
|
||||
}
|
||||
if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) {
|
||||
actor = Actor.actorFromEntity(bedCause);
|
||||
}
|
||||
} else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
|
||||
return;
|
||||
}
|
||||
Actor actor = new Actor("Explosion");
|
||||
|
||||
final Material type = block.getType();
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) {
|
||||
consumer.queueSignBreak(actor, (Sign) block.getState());
|
||||
} else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) {
|
||||
if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) {
|
||||
consumer.queueContainerBreak(actor, block.getState());
|
||||
} else {
|
||||
consumer.queueBlockBreak(actor, block.getState());
|
||||
|
@ -3,6 +3,7 @@ package de.diddiz.LogBlock.listeners;
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
@ -11,8 +12,10 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Levelled;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockFormEvent;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
@ -26,59 +29,70 @@ public class FluidFlowLogging extends LoggingListener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockFromTo(BlockFromToEvent event) {
|
||||
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
|
||||
if (wcfg != null) {
|
||||
if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) {
|
||||
final BlockData blockDataFrom = event.getBlock().getBlockData();
|
||||
final Material typeFrom = blockDataFrom.getMaterial();
|
||||
|
||||
Material typeFrom = blockDataFrom.getMaterial();
|
||||
boolean fromWaterlogged = false;
|
||||
if (blockDataFrom instanceof Waterlogged) {
|
||||
typeFrom = Material.WATER;
|
||||
fromWaterlogged = true;
|
||||
}
|
||||
if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) {
|
||||
typeFrom = Material.WATER;
|
||||
fromWaterlogged = true;
|
||||
}
|
||||
|
||||
Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null;
|
||||
final Block to = event.getToBlock();
|
||||
final Material typeTo = to.getType();
|
||||
boolean down = event.getFace() == BlockFace.DOWN;
|
||||
final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo);
|
||||
if (typeFrom == Material.LAVA) {
|
||||
Levelled levelledFrom = (Levelled)blockDataFrom;
|
||||
if (canFlow && wcfg.isLogging(Logging.LAVAFLOW)) {
|
||||
if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) {
|
||||
Levelled levelledFrom = (Levelled) blockDataFrom;
|
||||
if (canFlow) {
|
||||
if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) {
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData());
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData());
|
||||
} else {
|
||||
Levelled newBlock = (Levelled) blockDataFrom.clone();
|
||||
newBlock.setLevel(levelledFrom.getLevel() + 1);
|
||||
newBlock.setLevel(down ? 1 : levelledFrom.getLevel() + 1);
|
||||
if (BukkitUtils.isEmpty(typeTo)) {
|
||||
consumer.queueBlockPlace(new Actor("LavaFlow"), to.getLocation(), newBlock);
|
||||
consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock);
|
||||
} else {
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), newBlock);
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), newBlock);
|
||||
}
|
||||
}
|
||||
} else if (typeTo == Material.WATER) {
|
||||
if (event.getFace() == BlockFace.DOWN) {
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.STONE.createBlockData());
|
||||
if (down) {
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData());
|
||||
} else {
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData());
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData());
|
||||
}
|
||||
}
|
||||
} else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) {
|
||||
Levelled levelledFrom = (Levelled)blockDataFrom;
|
||||
Levelled newBlock = (Levelled) blockDataFrom.clone();
|
||||
newBlock.setLevel(levelledFrom.getLevel() + 1);
|
||||
Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom;
|
||||
Levelled newBlock = (Levelled) Material.WATER.createBlockData();
|
||||
newBlock.setLevel(fromWaterlogged || down ? 1 : levelledFrom.getLevel() + 1);
|
||||
if (BukkitUtils.isEmpty(typeTo)) {
|
||||
consumer.queueBlockPlace(new Actor("WaterFlow"), to.getLocation(), newBlock);
|
||||
consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock);
|
||||
} else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), newBlock);
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock);
|
||||
} else if (typeTo == Material.LAVA) {
|
||||
int toLevel = ((Levelled)to.getBlockData()).getLevel();
|
||||
int toLevel = ((Levelled) to.getBlockData()).getLevel();
|
||||
if (toLevel == 0) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.OBSIDIAN.createBlockData());
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.OBSIDIAN.createBlockData());
|
||||
} else if (event.getFace() == BlockFace.DOWN) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.STONE.createBlockData());
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData());
|
||||
}
|
||||
}
|
||||
if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) {
|
||||
for (final BlockFace face : new BlockFace[]{BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) {
|
||||
for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) {
|
||||
final Block lower = to.getRelative(face);
|
||||
if (lower.getType() == Material.LAVA) {
|
||||
int toLevel = ((Levelled)lower.getBlockData()).getLevel();
|
||||
int toLevel = ((Levelled) lower.getBlockData()).getLevel();
|
||||
if (toLevel == 0) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), Material.OBSIDIAN.createBlockData());
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.OBSIDIAN.createBlockData());
|
||||
} else if (event.getFace() == BlockFace.DOWN) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), Material.STONE.createBlockData());
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.STONE.createBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,9 +101,25 @@ public class FluidFlowLogging extends LoggingListener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockForm(BlockFormEvent event) {
|
||||
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
|
||||
if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) {
|
||||
if (wcfg.isLogging(Logging.LAVAFLOW) && event.getBlock().getType() == Material.WATER && event.getNewState().getType() == Material.COBBLESTONE) {
|
||||
consumer.queueBlockReplace(new Actor("LavaFlow"), event.getBlock().getBlockData(), event.getNewState());
|
||||
}
|
||||
if (wcfg.isLogging(Logging.WATERFLOW) && event.getBlock().getType() == Material.LAVA) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState());
|
||||
}
|
||||
if (wcfg.isLogging(Logging.WATERFLOW) && BukkitUtils.isConcreteBlock(event.getNewState().getType())) {
|
||||
consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSurroundedByWater(Block block) {
|
||||
for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) {
|
||||
if(block.getRelative(face).getType() == Material.WATER) {
|
||||
for (final BlockFace face : new BlockFace[] { BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) {
|
||||
if (block.getRelative(face).getType() == Material.WATER) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,33 @@ import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.Note;
|
||||
import org.bukkit.Note.Tone;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Directional;
|
||||
import org.bukkit.block.data.Openable;
|
||||
import org.bukkit.block.data.type.Cake;
|
||||
import org.bukkit.block.data.type.Comparator;
|
||||
import org.bukkit.block.data.type.Comparator.Mode;
|
||||
import org.bukkit.block.data.type.DaylightDetector;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.block.data.type.NoteBlock;
|
||||
import org.bukkit.block.data.type.Repeater;
|
||||
import org.bukkit.block.data.type.Switch;
|
||||
import org.bukkit.block.data.type.TurtleEgg;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
|
||||
@ -44,34 +60,63 @@ public class InteractLogging extends LoggingListener {
|
||||
case JUNGLE_FENCE_GATE:
|
||||
case ACACIA_FENCE_GATE:
|
||||
case DARK_OAK_FENCE_GATE:
|
||||
case WARPED_FENCE_GATE:
|
||||
case CRIMSON_FENCE_GATE:
|
||||
case OAK_TRAPDOOR:
|
||||
case SPRUCE_TRAPDOOR:
|
||||
case BIRCH_TRAPDOOR:
|
||||
case JUNGLE_TRAPDOOR:
|
||||
case ACACIA_TRAPDOOR:
|
||||
case DARK_OAK_TRAPDOOR:
|
||||
case WARPED_TRAPDOOR:
|
||||
case CRIMSON_TRAPDOOR:
|
||||
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
Openable newBlockData = (Openable) blockData.clone();
|
||||
newBlockData.setOpen(!newBlockData.isOpen());
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case CAKE:
|
||||
if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
Cake newBlockData = (Cake) blockData.clone();
|
||||
if (newBlockData.getBites() < 6) {
|
||||
newBlockData.setBites(newBlockData.getBites() + 1);
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
} else {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NOTE_BLOCK:
|
||||
if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
NoteBlock newBlockData = (NoteBlock) blockData.clone();
|
||||
if (newBlockData.getNote().getOctave() == 2) {
|
||||
newBlockData.setNote(new Note(0, Tone.F, true));
|
||||
} else {
|
||||
newBlockData.setNote(newBlockData.getNote().sharped());
|
||||
}
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case REPEATER:
|
||||
if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
Repeater newBlockData = (Repeater) blockData.clone();
|
||||
newBlockData.setDelay((newBlockData.getDelay() % 4) + 1);
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case COMPARATOR:
|
||||
if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
Comparator newBlockData = (Comparator) blockData.clone();
|
||||
newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE);
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case DAYLIGHT_DETECTOR:
|
||||
if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
DaylightDetector newBlockData = (DaylightDetector) blockData.clone();
|
||||
newBlockData.setInverted(!newBlockData.isInverted());
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case OAK_PRESSURE_PLATE:
|
||||
@ -80,6 +125,8 @@ public class InteractLogging extends LoggingListener {
|
||||
case JUNGLE_PRESSURE_PLATE:
|
||||
case ACACIA_PRESSURE_PLATE:
|
||||
case DARK_OAK_PRESSURE_PLATE:
|
||||
case WARPED_PRESSURE_PLATE:
|
||||
case CRIMSON_PRESSURE_PLATE:
|
||||
case STONE_PRESSURE_PLATE:
|
||||
case HEAVY_WEIGHTED_PRESSURE_PLATE:
|
||||
case LIGHT_WEIGHTED_PRESSURE_PLATE:
|
||||
@ -103,17 +150,108 @@ public class InteractLogging extends LoggingListener {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TURTLE_EGG:
|
||||
if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) {
|
||||
TurtleEgg turtleEggData = (TurtleEgg) blockData;
|
||||
int eggs = turtleEggData.getEggs();
|
||||
if (eggs > 1) {
|
||||
TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone();
|
||||
turtleEggData2.setEggs(eggs - 1);
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2);
|
||||
} else {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PUMPKIN:
|
||||
if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
ItemStack inHand = event.getItem();
|
||||
if (inHand != null && inHand.getType() == Material.SHEARS) {
|
||||
BlockFace clickedFace = event.getBlockFace();
|
||||
Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData();
|
||||
if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) {
|
||||
newBlockData.setFacing(clickedFace);
|
||||
} else {
|
||||
// use player distance to calculate the facing
|
||||
Location playerLoc = player.getLocation();
|
||||
playerLoc.subtract(0.5, 0, 0.5);
|
||||
double dx = playerLoc.getX() - loc.getX();
|
||||
double dz = playerLoc.getZ() - loc.getZ();
|
||||
if (Math.abs(dx) > Math.abs(dz)) {
|
||||
newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST);
|
||||
} else {
|
||||
newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH);
|
||||
}
|
||||
}
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OAK_DOOR:
|
||||
case SPRUCE_DOOR:
|
||||
case BIRCH_DOOR:
|
||||
case JUNGLE_DOOR:
|
||||
case ACACIA_DOOR:
|
||||
case DARK_OAK_DOOR:
|
||||
case WARPED_DOOR:
|
||||
case CRIMSON_DOOR:
|
||||
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
Door newBlockData = (Door) blockData.clone();
|
||||
newBlockData.setOpen(!newBlockData.isOpen());
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case STONE_BUTTON:
|
||||
case OAK_BUTTON:
|
||||
case SPRUCE_BUTTON:
|
||||
case BIRCH_BUTTON:
|
||||
case JUNGLE_BUTTON:
|
||||
case ACACIA_BUTTON:
|
||||
case DARK_OAK_BUTTON:
|
||||
case WARPED_BUTTON:
|
||||
case CRIMSON_BUTTON:
|
||||
case LEVER:
|
||||
if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
Switch newBlockData = (Switch) blockData.clone();
|
||||
if (!newBlockData.isPowered() || type == Material.LEVER) {
|
||||
newBlockData.setPowered(!newBlockData.isPowered());
|
||||
}
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
|
||||
}
|
||||
break;
|
||||
case OAK_SIGN:
|
||||
case SPRUCE_SIGN:
|
||||
case BIRCH_SIGN:
|
||||
case JUNGLE_SIGN:
|
||||
case ACACIA_SIGN:
|
||||
case DARK_OAK_SIGN:
|
||||
case WARPED_SIGN:
|
||||
case CRIMSON_SIGN:
|
||||
case OAK_WALL_SIGN:
|
||||
case SPRUCE_WALL_SIGN:
|
||||
case BIRCH_WALL_SIGN:
|
||||
case JUNGLE_WALL_SIGN:
|
||||
case ACACIA_WALL_SIGN:
|
||||
case DARK_OAK_WALL_SIGN:
|
||||
case WARPED_WALL_SIGN:
|
||||
case CRIMSON_WALL_SIGN:
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
ItemStack stack = event.getItem();
|
||||
if (stack != null && BukkitUtils.isDye(stack.getType())) {
|
||||
final BlockState before = event.getClickedBlock().getState();
|
||||
if (before instanceof Sign) {
|
||||
DyeColor newColor = BukkitUtils.dyeToDyeColor(stack.getType());
|
||||
Sign signBefore = (Sign) before;
|
||||
if (newColor != null && signBefore.getColor() != newColor) {
|
||||
final Sign signAfter = (Sign) event.getClickedBlock().getState();
|
||||
signAfter.setColor(newColor);
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (Tag.BUTTONS.isTagged(type) || type == Material.LEVER) {
|
||||
if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
}
|
||||
}
|
||||
if (Tag.WOODEN_DOORS.isTagged(type)) {
|
||||
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import org.bukkit.event.entity.EntityDeathEvent;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.*;
|
||||
|
||||
|
||||
public class KillLogging extends LoggingListener {
|
||||
|
||||
public KillLogging(LogBlock lb) {
|
||||
|
@ -0,0 +1,67 @@
|
||||
package de.diddiz.LogBlock.listeners;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Lectern;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerTakeLecternBookEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class LecternLogging extends LoggingListener {
|
||||
public LecternLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
|
||||
if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) {
|
||||
final BlockState before = event.getBlockReplacedState();
|
||||
final BlockState after = event.getBlockPlaced().getState();
|
||||
if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) {
|
||||
Lectern lecternBefore = (Lectern) before.getBlock().getState();
|
||||
ItemStack book = lecternBefore.getSnapshotInventory().getItem(0);
|
||||
try {
|
||||
lecternBefore.getSnapshotInventory().setItem(0, null);
|
||||
} catch (NullPointerException e) {
|
||||
//ignored
|
||||
}
|
||||
lecternBefore.setBlockData(before.getBlockData());
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lecternBefore, after);
|
||||
try {
|
||||
lecternBefore.getSnapshotInventory().setItem(0, book);
|
||||
} catch (NullPointerException e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) {
|
||||
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
|
||||
if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) {
|
||||
Lectern oldState = event.getLectern();
|
||||
Lectern newState = (Lectern) oldState.getBlock().getState();
|
||||
try {
|
||||
newState.getSnapshotInventory().setItem(0, null);
|
||||
} catch (NullPointerException e) {
|
||||
//ignored
|
||||
}
|
||||
org.bukkit.block.data.type.Lectern oldBlockData = (org.bukkit.block.data.type.Lectern) oldState.getBlockData();
|
||||
org.bukkit.block.data.type.Lectern blockData = (org.bukkit.block.data.type.Lectern) Material.LECTERN.createBlockData();
|
||||
blockData.setFacing(oldBlockData.getFacing());
|
||||
blockData.setPowered(oldBlockData.isPowered());
|
||||
newState.setBlockData(blockData);
|
||||
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), oldState, newState);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,43 @@
|
||||
package de.diddiz.LogBlock.listeners;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class PlayerInfoLogging extends LoggingListener {
|
||||
|
||||
private final HashMap<UUID, Long> playerLogins = new HashMap<>();
|
||||
|
||||
public PlayerInfoLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
playerLogins.put(event.getPlayer().getUniqueId(), System.currentTimeMillis());
|
||||
consumer.queueJoin(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
consumer.queueLeave(event.getPlayer());
|
||||
onPlayerQuit(event.getPlayer());
|
||||
}
|
||||
|
||||
public void onPlayerQuit(Player player) {
|
||||
Long joinTime = playerLogins.remove(player.getUniqueId());
|
||||
if (Config.logPlayerInfo && joinTime != null) {
|
||||
long onlineTime = (System.currentTimeMillis() - joinTime) / 1000;
|
||||
if (onlineTime > 0) {
|
||||
consumer.queueLeave(player, onlineTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,171 @@
|
||||
package de.diddiz.LogBlock.listeners;
|
||||
|
||||
import de.diddiz.LogBlock.Actor;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockFadeEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.isLogging;
|
||||
import static de.diddiz.util.LoggingUtil.smartLogFallables;
|
||||
|
||||
public class ScaffoldingLogging extends LoggingListener {
|
||||
private final static long MAX_SCAFFOLDING_LOG_TIME_MS = 2000;
|
||||
private final static EnumSet<BlockFace> NEIGHBOURS_SIDES_AND_UP = EnumSet.of(BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
|
||||
private final static EnumSet<BlockFace> NEIGHBOURS_SIDES_AND_BELOW = EnumSet.of(BlockFace.DOWN, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
|
||||
|
||||
private final ArrayDeque<ScaffoldingBreaker> scaffoldingBreakersList = new ArrayDeque<>();
|
||||
private final HashMap<Location, ScaffoldingBreaker> scaffoldingBreakersByLocation = new HashMap<>();
|
||||
private final HashMap<Location, Actor> scaffoldingPlacersByLocation = new HashMap<>();
|
||||
|
||||
public ScaffoldingLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockFade(BlockFadeEvent event) {
|
||||
Block block = event.getBlock();
|
||||
if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) {
|
||||
final Material type = block.getType();
|
||||
if (type == Material.SCAFFOLDING) {
|
||||
Actor actor = scaffoldingPlacersByLocation.get(block.getLocation()); // get placer before cleanupScaffoldingBreakers
|
||||
cleanupScaffoldingBreakers();
|
||||
if (actor == null) {
|
||||
actor = getScaffoldingBreaker(block);
|
||||
if (actor != null) {
|
||||
for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) {
|
||||
Block otherBlock = block.getRelative(dir);
|
||||
if (otherBlock.getType() == Material.SCAFFOLDING) {
|
||||
addScaffoldingBreaker(actor, otherBlock);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
actor = new Actor("ScaffoldingFall");
|
||||
}
|
||||
}
|
||||
consumer.queueBlockReplace(actor, block.getState(), event.getNewState());
|
||||
smartLogFallables(consumer, actor, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
Block block = event.getBlock();
|
||||
if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) {
|
||||
cleanupScaffoldingBreakers();
|
||||
Block otherBlock;
|
||||
if (block.getType() == Material.SCAFFOLDING) {
|
||||
for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) {
|
||||
otherBlock = block.getRelative(dir);
|
||||
if (otherBlock.getType() == Material.SCAFFOLDING) {
|
||||
addScaffoldingBreaker(Actor.actorFromEntity(event.getPlayer()), otherBlock);
|
||||
}
|
||||
}
|
||||
} else if ((otherBlock = block.getRelative(BlockFace.UP)).getType() == Material.SCAFFOLDING) {
|
||||
addScaffoldingBreaker(Actor.actorFromEntity(event.getPlayer()), otherBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
Block block = event.getBlock();
|
||||
if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) {
|
||||
cleanupScaffoldingBreakers();
|
||||
if (block.getType() == Material.SCAFFOLDING) {
|
||||
scaffoldingPlacersByLocation.put(block.getLocation(), Actor.actorFromEntity(event.getPlayer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addScaffoldingBreaker(Actor actor, Block block) {
|
||||
ScaffoldingBreaker breaker = new ScaffoldingBreaker(actor, block.getLocation());
|
||||
scaffoldingBreakersList.addLast(breaker);
|
||||
scaffoldingBreakersByLocation.put(breaker.getLocation(), breaker);
|
||||
|
||||
}
|
||||
|
||||
private void cleanupScaffoldingBreakers() {
|
||||
if (!scaffoldingPlacersByLocation.isEmpty()) {
|
||||
scaffoldingPlacersByLocation.clear();
|
||||
}
|
||||
if (!scaffoldingBreakersList.isEmpty()) {
|
||||
long time = System.currentTimeMillis() - MAX_SCAFFOLDING_LOG_TIME_MS;
|
||||
while (!scaffoldingBreakersList.isEmpty() && scaffoldingBreakersList.getFirst().getTime() < time) {
|
||||
ScaffoldingBreaker breaker = scaffoldingBreakersList.removeFirst();
|
||||
scaffoldingBreakersByLocation.remove(breaker.getLocation(), breaker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Actor getScaffoldingBreaker(Block block) {
|
||||
if (scaffoldingBreakersList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ScaffoldingBreaker breaker = scaffoldingBreakersByLocation.get(block.getLocation());
|
||||
if (breaker != null) {
|
||||
return breaker.getActor();
|
||||
}
|
||||
|
||||
// Search all connected scaffoldings
|
||||
ArrayDeque<Block> front = new ArrayDeque<>();
|
||||
HashSet<Block> frontAndDone = new HashSet<>();
|
||||
front.addLast(block);
|
||||
frontAndDone.add(block);
|
||||
while (!front.isEmpty()) {
|
||||
Block current = front.removeFirst();
|
||||
Location loc = current.getLocation();
|
||||
|
||||
breaker = scaffoldingBreakersByLocation.get(loc);
|
||||
if (breaker != null) {
|
||||
return breaker.getActor();
|
||||
}
|
||||
|
||||
for (BlockFace dir : NEIGHBOURS_SIDES_AND_BELOW) {
|
||||
Block otherBlock = current.getRelative(dir);
|
||||
if (!frontAndDone.contains(otherBlock) && otherBlock.getType() == Material.SCAFFOLDING) {
|
||||
front.addLast(otherBlock);
|
||||
frontAndDone.add(otherBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class ScaffoldingBreaker {
|
||||
protected final Actor actor;
|
||||
protected final long time;
|
||||
protected final Location location;
|
||||
|
||||
public ScaffoldingBreaker(Actor actor, Location location) {
|
||||
this.actor = actor;
|
||||
this.location = location;
|
||||
this.time = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public Actor getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ public class SignChangeLogging extends LoggingListener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onSignChange(SignChangeEvent event) {
|
||||
if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) {
|
||||
consumer.queueSignPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines());
|
||||
consumer.queueSignChange(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,6 @@ public class SnowFormLogging extends LoggingListener {
|
||||
super(lb);
|
||||
}
|
||||
|
||||
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
// public void onLeavesDecay(LeavesDecayEvent event) {
|
||||
// if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM))
|
||||
// consumer.queueBlockBreak("LeavesDecay", event.getBlock().getState());
|
||||
// }
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockForm(BlockFormEvent event) {
|
||||
if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) {
|
||||
|
@ -1,11 +1,12 @@
|
||||
package de.diddiz.LogBlock.listeners;
|
||||
|
||||
import de.diddiz.LogBlock.*;
|
||||
import de.diddiz.worldedit.RegionContainer;
|
||||
import de.diddiz.LogBlock.events.ToolUseEvent;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.util.CuboidRegion;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -31,7 +32,7 @@ public class ToolListener implements Listener {
|
||||
handler = logblock.getCommandsHandler();
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (event.getMaterial() != null) {
|
||||
final Action action = event.getAction();
|
||||
@ -48,27 +49,26 @@ public class ToolListener implements Listener {
|
||||
return;
|
||||
}
|
||||
final Block block = event.getClickedBlock();
|
||||
final QueryParams params = toolData.params;
|
||||
final QueryParams params = toolData.params.clone();
|
||||
params.loc = null;
|
||||
params.sel = null;
|
||||
if (behavior == ToolBehavior.BLOCK) {
|
||||
params.setLocation(block.getRelative(event.getBlockFace()).getLocation());
|
||||
} else if ((block.getType() != Material.CHEST && block.getType() != Material.TRAPPED_CHEST) || tool.params.radius != 0) {
|
||||
} else if (tool.params.radius != 0) {
|
||||
params.setLocation(block.getLocation());
|
||||
} else {
|
||||
if (logblock.getServer().getPluginManager().isPluginEnabled("WorldEdit")) {
|
||||
for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||
if (block.getRelative(face).getType() == block.getType()) {
|
||||
params.setSelection(RegionContainer.fromCorners(event.getPlayer().getWorld(),
|
||||
block.getLocation(), block.getRelative(face).getLocation()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params.sel == null) {
|
||||
Block otherHalfChest = BukkitUtils.getConnectedChest(block);
|
||||
if (otherHalfChest == null) {
|
||||
params.setLocation(block.getLocation());
|
||||
} else {
|
||||
params.setSelection(CuboidRegion.fromCorners(block.getLocation().getWorld(), block.getLocation(), otherHalfChest.getLocation()));
|
||||
}
|
||||
}
|
||||
try {
|
||||
params.validate();
|
||||
if (this.callToolUseEvent(new ToolUseEvent(player, tool, behavior, params))) {
|
||||
return;
|
||||
}
|
||||
if (toolData.mode == ToolMode.ROLLBACK) {
|
||||
handler.new CommandRollback(player, params, true);
|
||||
} else if (toolData.mode == ToolMode.REDO) {
|
||||
@ -89,6 +89,11 @@ public class ToolListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean callToolUseEvent(ToolUseEvent event) {
|
||||
this.logblock.getServer().getPluginManager().callEvent(event);
|
||||
return event.isCancelled();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
@ -99,7 +104,9 @@ public class ToolListener implements Listener {
|
||||
final ToolData toolData = entry.getValue();
|
||||
if (toolData.enabled && !logblock.hasPermission(player, "logblock.tools." + tool.name)) {
|
||||
toolData.enabled = false;
|
||||
player.getInventory().removeItem(new ItemStack(tool.item, 1));
|
||||
if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) {
|
||||
player.getInventory().removeItem(new ItemStack(tool.item, 1));
|
||||
}
|
||||
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
|
||||
}
|
||||
}
|
||||
@ -115,9 +122,28 @@ public class ToolListener implements Listener {
|
||||
final Tool tool = entry.getKey();
|
||||
final ToolData toolData = entry.getValue();
|
||||
final Material item = event.getItemDrop().getItemStack().getType();
|
||||
if (item == tool.item && toolData.enabled && !tool.canDrop) {
|
||||
player.sendMessage(ChatColor.RED + "You cannot drop this tool.");
|
||||
event.setCancelled(true);
|
||||
if (item == tool.item && toolData.enabled) {
|
||||
if (tool.dropToDisable) {
|
||||
toolData.enabled = false;
|
||||
ItemStack stack = event.getItemDrop().getItemStack();
|
||||
if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) {
|
||||
if (stack.isSimilar(new ItemStack(item))) {
|
||||
if (stack.getAmount() > 1) {
|
||||
stack.setAmount(stack.getAmount() - 1);
|
||||
event.getItemDrop().setItemStack(stack);
|
||||
} else {
|
||||
event.getItemDrop().remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (BukkitUtils.hasInventoryStorageSpaceFor(player.getInventory(), stack)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
|
||||
} else if (!tool.canDrop) {
|
||||
player.sendMessage(ChatColor.RED + "You cannot drop this tool.");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
73
src/main/java/de/diddiz/LogBlock/questioner/Question.java
Normal file
73
src/main/java/de/diddiz/LogBlock/questioner/Question.java
Normal file
@ -0,0 +1,73 @@
|
||||
package de.diddiz.LogBlock.questioner;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class Question {
|
||||
private String answer;
|
||||
private final String[] answers;
|
||||
private final String questionMessage;
|
||||
private final Player respondent;
|
||||
private final long start;
|
||||
|
||||
public Question(Player respondent, String questionMessage, String[] answers) {
|
||||
this.start = System.currentTimeMillis();
|
||||
this.respondent = respondent;
|
||||
this.questionMessage = questionMessage;
|
||||
this.answers = answers;
|
||||
}
|
||||
|
||||
public synchronized String ask() {
|
||||
StringBuilder options = new StringBuilder();
|
||||
for (String ans : this.answers) {
|
||||
options.append("/" + ans + ", ");
|
||||
}
|
||||
options.delete(options.length() - 2, options.length());
|
||||
this.respondent.sendMessage(this.questionMessage);
|
||||
this.respondent.sendMessage("- " + options + "?");
|
||||
while (answer == null) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ex) {
|
||||
if (answer == null) {
|
||||
answer = "interrupted";
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.answer;
|
||||
}
|
||||
|
||||
public synchronized boolean isExpired(boolean forceExpire) {
|
||||
if (forceExpire || System.currentTimeMillis() - this.start > 120000L || this.answer != null) {
|
||||
if (answer == null) {
|
||||
answer = "timed out";
|
||||
}
|
||||
notifyAll();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean returnAnswer(String answer) {
|
||||
return returnAnswer(answer, false);
|
||||
}
|
||||
|
||||
public synchronized boolean returnAnswer(String answer, boolean forceReturn) {
|
||||
if (forceReturn) {
|
||||
if (this.answer == null) {
|
||||
this.answer = answer;
|
||||
}
|
||||
notifyAll();
|
||||
return true;
|
||||
}
|
||||
for (String s : answers) {
|
||||
if (s.equalsIgnoreCase(answer)) {
|
||||
if (this.answer == null) {
|
||||
this.answer = s;
|
||||
}
|
||||
notifyAll();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
76
src/main/java/de/diddiz/LogBlock/questioner/Questioner.java
Normal file
76
src/main/java/de/diddiz/LogBlock/questioner/Questioner.java
Normal file
@ -0,0 +1,76 @@
|
||||
package de.diddiz.LogBlock.questioner;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
|
||||
public class Questioner {
|
||||
private final LogBlock logBlock;
|
||||
private final ConcurrentHashMap<UUID, Question> questions = new ConcurrentHashMap<>();
|
||||
|
||||
public Questioner(LogBlock logBlock) {
|
||||
this.logBlock = logBlock;
|
||||
logBlock.getServer().getPluginManager().registerEvents(new QuestionerListener(), logBlock);
|
||||
logBlock.getServer().getScheduler().scheduleSyncRepeatingTask(logBlock, new QuestionsReaper(), 600, 600);
|
||||
}
|
||||
|
||||
public String ask(Player respondent, String questionMessage, String... answers) {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
throw new IllegalStateException("This method may not be called from the primary thread");
|
||||
}
|
||||
Question question = new Question(respondent, questionMessage, answers);
|
||||
Question oldQuestion = this.questions.put(respondent.getUniqueId(), question);
|
||||
if (oldQuestion != null) {
|
||||
oldQuestion.returnAnswer("no", true);
|
||||
// wait a little time to let the other thread continue
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
return question.ask();
|
||||
}
|
||||
|
||||
private class QuestionsReaper implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (questions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Iterator<Entry<UUID, Question>> it = questions.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<UUID, Question> e = it.next();
|
||||
Question question = e.getValue();
|
||||
if (question.isExpired(logBlock.getServer().getPlayer(e.getKey()) == null)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class QuestionerListener implements Listener {
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
||||
UUID player = event.getPlayer().getUniqueId();
|
||||
Question question;
|
||||
question = questions.get(player);
|
||||
if (question != null) {
|
||||
String answer = event.getMessage().substring(1).toLowerCase();
|
||||
if (question.returnAnswer(answer)) {
|
||||
questions.remove(player, question);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
src/main/java/de/diddiz/util/ActionColor.java
Normal file
24
src/main/java/de/diddiz/util/ActionColor.java
Normal file
@ -0,0 +1,24 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
public enum ActionColor {
|
||||
DESTROY(ChatColor.RED),
|
||||
CREATE(ChatColor.DARK_GREEN),
|
||||
INTERACT(ChatColor.GRAY);
|
||||
|
||||
private final ChatColor color;
|
||||
|
||||
ActionColor(ChatColor color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public ChatColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return color.toString();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
// Taken from maven-artifact at
|
||||
// Taken from maven-artifact at
|
||||
// http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source
|
||||
|
||||
/*
|
||||
@ -34,7 +34,7 @@ import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Generic implementation of version comparison.
|
||||
*
|
||||
*
|
||||
* <p>Features:
|
||||
* <ul>
|
||||
* <li>mixing of '<code>-</code>' (dash) and '<code>.</code>' (dot) separators,</li>
|
||||
@ -61,22 +61,19 @@ import java.util.Stack;
|
||||
* @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
|
||||
* @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
|
||||
*/
|
||||
public class ComparableVersion
|
||||
implements Comparable<ComparableVersion>
|
||||
{
|
||||
public class ComparableVersion implements Comparable<ComparableVersion> {
|
||||
private String value;
|
||||
|
||||
private String canonical;
|
||||
|
||||
private ListItem items;
|
||||
|
||||
private interface Item
|
||||
{
|
||||
private interface Item {
|
||||
int INTEGER_ITEM = 0;
|
||||
int STRING_ITEM = 1;
|
||||
int LIST_ITEM = 2;
|
||||
|
||||
int compareTo( Item item );
|
||||
int compareTo(Item item);
|
||||
|
||||
int getType();
|
||||
|
||||
@ -86,46 +83,40 @@ public class ComparableVersion
|
||||
/**
|
||||
* Represents a numeric item in the version item list.
|
||||
*/
|
||||
private static class IntegerItem
|
||||
implements Item
|
||||
{
|
||||
private static final BigInteger BIG_INTEGER_ZERO = new BigInteger( "0" );
|
||||
private static class IntegerItem implements Item {
|
||||
private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0");
|
||||
|
||||
private final BigInteger value;
|
||||
|
||||
public static final IntegerItem ZERO = new IntegerItem();
|
||||
|
||||
private IntegerItem()
|
||||
{
|
||||
private IntegerItem() {
|
||||
this.value = BIG_INTEGER_ZERO;
|
||||
}
|
||||
|
||||
public IntegerItem( String str )
|
||||
{
|
||||
this.value = new BigInteger( str );
|
||||
public IntegerItem(String str) {
|
||||
this.value = new BigInteger(str);
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
@Override
|
||||
public int getType() {
|
||||
return INTEGER_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return BIG_INTEGER_ZERO.equals( value );
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
return BIG_INTEGER_ZERO.equals(value);
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
return BIG_INTEGER_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
@Override
|
||||
public int compareTo(Item item) {
|
||||
if (item == null) {
|
||||
return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
}
|
||||
|
||||
switch ( item.getType() )
|
||||
{
|
||||
switch (item.getType()) {
|
||||
case INTEGER_ITEM:
|
||||
return value.compareTo( ( (IntegerItem) item ).value );
|
||||
return value.compareTo(((IntegerItem) item).value);
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1.1 > 1-sp
|
||||
@ -134,12 +125,12 @@ public class ComparableVersion
|
||||
return 1; // 1.1 > 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
throw new RuntimeException("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
@Override
|
||||
public String toString() {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
@ -147,36 +138,30 @@ public class ComparableVersion
|
||||
/**
|
||||
* Represents a string in the version item list, usually a qualifier.
|
||||
*/
|
||||
private static class StringItem
|
||||
implements Item
|
||||
{
|
||||
private static class StringItem implements Item {
|
||||
private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" };
|
||||
|
||||
private static final List<String> _QUALIFIERS = Arrays.asList( QUALIFIERS );
|
||||
private static final List<String> _QUALIFIERS = Arrays.asList(QUALIFIERS);
|
||||
|
||||
private static final Properties ALIASES = new Properties();
|
||||
static
|
||||
{
|
||||
ALIASES.put( "ga", "" );
|
||||
ALIASES.put( "final", "" );
|
||||
ALIASES.put( "cr", "rc" );
|
||||
static {
|
||||
ALIASES.put("ga", "");
|
||||
ALIASES.put("final", "");
|
||||
ALIASES.put("cr", "rc");
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
|
||||
* the version older than one without a qualifier, or more recent.
|
||||
*/
|
||||
private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) );
|
||||
private static final String RELEASE_VERSION_INDEX = String.valueOf(_QUALIFIERS.indexOf(""));
|
||||
|
||||
private String value;
|
||||
|
||||
public StringItem( String value, boolean followedByDigit )
|
||||
{
|
||||
if ( followedByDigit && value.length() == 1 )
|
||||
{
|
||||
public StringItem(String value, boolean followedByDigit) {
|
||||
if (followedByDigit && value.length() == 1) {
|
||||
// a1 = alpha-1, b1 = beta-1, m1 = milestone-1
|
||||
switch ( value.charAt( 0 ) )
|
||||
{
|
||||
switch (value.charAt(0)) {
|
||||
case 'a':
|
||||
value = "alpha";
|
||||
break;
|
||||
@ -188,17 +173,17 @@ public class ComparableVersion
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.value = ALIASES.getProperty( value , value );
|
||||
this.value = ALIASES.getProperty(value, value);
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
@Override
|
||||
public int getType() {
|
||||
return STRING_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 );
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,38 +198,35 @@ public class ComparableVersion
|
||||
* @param qualifier
|
||||
* @return an equivalent value that can be used with lexical comparison
|
||||
*/
|
||||
public static String comparableQualifier( String qualifier )
|
||||
{
|
||||
int i = _QUALIFIERS.indexOf( qualifier );
|
||||
public static String comparableQualifier(String qualifier) {
|
||||
int i = _QUALIFIERS.indexOf(qualifier);
|
||||
|
||||
return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i );
|
||||
return i == -1 ? (_QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i);
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
@Override
|
||||
public int compareTo(Item item) {
|
||||
if (item == null) {
|
||||
// 1-rc < 1, 1-ga > 1
|
||||
return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX );
|
||||
return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX);
|
||||
}
|
||||
switch ( item.getType() )
|
||||
{
|
||||
switch (item.getType()) {
|
||||
case INTEGER_ITEM:
|
||||
return -1; // 1.any < 1.1 ?
|
||||
|
||||
case STRING_ITEM:
|
||||
return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) );
|
||||
return comparableQualifier(value).compareTo(comparableQualifier(((StringItem) item).value));
|
||||
|
||||
case LIST_ITEM:
|
||||
return -1; // 1.any < 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
throw new RuntimeException("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@ -253,51 +235,40 @@ public class ComparableVersion
|
||||
* Represents a version list item. This class is used both for the global item list and for sub-lists (which start
|
||||
* with '-(number)' in the version specification).
|
||||
*/
|
||||
private static class ListItem
|
||||
extends ArrayList<Item>
|
||||
implements Item
|
||||
{
|
||||
private static class ListItem extends ArrayList<Item> implements Item {
|
||||
private static final long serialVersionUID = 5914575811857700009L;
|
||||
|
||||
public int getType()
|
||||
{
|
||||
@Override
|
||||
public int getType() {
|
||||
return LIST_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return ( size() == 0 );
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
return (size() == 0);
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
for ( ListIterator<Item> iterator = listIterator( size() ); iterator.hasPrevious(); )
|
||||
{
|
||||
void normalize() {
|
||||
for (ListIterator<Item> iterator = listIterator(size()); iterator.hasPrevious();) {
|
||||
Item item = iterator.previous();
|
||||
if ( item.isNull() )
|
||||
{
|
||||
if (item.isNull()) {
|
||||
iterator.remove(); // remove null trailing items: 0, "", empty list
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
if ( size() == 0 )
|
||||
{
|
||||
@Override
|
||||
public int compareTo(Item item) {
|
||||
if (item == null) {
|
||||
if (size() == 0) {
|
||||
return 0; // 1-0 = 1- (normalize) = 1
|
||||
}
|
||||
Item first = get( 0 );
|
||||
return first.compareTo( null );
|
||||
Item first = get(0);
|
||||
return first.compareTo(null);
|
||||
}
|
||||
switch ( item.getType() )
|
||||
{
|
||||
switch (item.getType()) {
|
||||
case INTEGER_ITEM:
|
||||
return -1; // 1-1 < 1.0.x
|
||||
|
||||
@ -306,18 +277,16 @@ public class ComparableVersion
|
||||
|
||||
case LIST_ITEM:
|
||||
Iterator<Item> left = iterator();
|
||||
Iterator<Item> right = ( (ListItem) item ).iterator();
|
||||
Iterator<Item> right = ((ListItem) item).iterator();
|
||||
|
||||
while ( left.hasNext() || right.hasNext() )
|
||||
{
|
||||
while (left.hasNext() || right.hasNext()) {
|
||||
Item l = left.hasNext() ? left.next() : null;
|
||||
Item r = right.hasNext() ? right.next() : null;
|
||||
|
||||
// if this is shorter, then invert the compare and mul with -1
|
||||
int result = l == null ? ( r == null ? 0 : -1 * r.compareTo( l ) ) : l.compareTo( r );
|
||||
int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r);
|
||||
|
||||
if ( result != 0 )
|
||||
{
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -325,105 +294,83 @@ public class ComparableVersion
|
||||
return 0;
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
throw new RuntimeException("invalid item: " + item.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder( "(" );
|
||||
for ( Iterator<Item> iter = iterator(); iter.hasNext(); )
|
||||
{
|
||||
buffer.append( iter.next() );
|
||||
if ( iter.hasNext() )
|
||||
{
|
||||
buffer.append( ',' );
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder("(");
|
||||
for (Iterator<Item> iter = iterator(); iter.hasNext();) {
|
||||
buffer.append(iter.next());
|
||||
if (iter.hasNext()) {
|
||||
buffer.append(',');
|
||||
}
|
||||
}
|
||||
buffer.append( ')' );
|
||||
buffer.append(')');
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public ComparableVersion( String version )
|
||||
{
|
||||
parseVersion( version );
|
||||
public ComparableVersion(String version) {
|
||||
parseVersion(version);
|
||||
}
|
||||
|
||||
public final void parseVersion( String version )
|
||||
{
|
||||
public final void parseVersion(String version) {
|
||||
this.value = version;
|
||||
|
||||
items = new ListItem();
|
||||
|
||||
version = version.toLowerCase( Locale.ENGLISH );
|
||||
version = version.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
ListItem list = items;
|
||||
|
||||
Stack<Item> stack = new Stack<Item>();
|
||||
stack.push( list );
|
||||
Stack<Item> stack = new Stack<>();
|
||||
stack.push(list);
|
||||
|
||||
boolean isDigit = false;
|
||||
|
||||
int startIndex = 0;
|
||||
|
||||
for ( int i = 0; i < version.length(); i++ )
|
||||
{
|
||||
char c = version.charAt( i );
|
||||
for (int i = 0; i < version.length(); i++) {
|
||||
char c = version.charAt(i);
|
||||
|
||||
if ( c == '.' )
|
||||
{
|
||||
if ( i == startIndex )
|
||||
{
|
||||
list.add( IntegerItem.ZERO );
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
|
||||
if (c == '.') {
|
||||
if (i == startIndex) {
|
||||
list.add(IntegerItem.ZERO);
|
||||
} else {
|
||||
list.add(parseItem(isDigit, version.substring(startIndex, i)));
|
||||
}
|
||||
startIndex = i + 1;
|
||||
}
|
||||
else if ( c == '-' )
|
||||
{
|
||||
if ( i == startIndex )
|
||||
{
|
||||
list.add( IntegerItem.ZERO );
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
|
||||
} else if (c == '-') {
|
||||
if (i == startIndex) {
|
||||
list.add(IntegerItem.ZERO);
|
||||
} else {
|
||||
list.add(parseItem(isDigit, version.substring(startIndex, i)));
|
||||
}
|
||||
startIndex = i + 1;
|
||||
|
||||
if ( isDigit )
|
||||
{
|
||||
if (isDigit) {
|
||||
list.normalize(); // 1.0-* = 1-*
|
||||
|
||||
if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) )
|
||||
{
|
||||
if ((i + 1 < version.length()) && Character.isDigit(version.charAt(i + 1))) {
|
||||
// new ListItem only if previous were digits and new char is a digit,
|
||||
// ie need to differentiate only 1.1 from 1-1
|
||||
list.add( list = new ListItem() );
|
||||
list.add(list = new ListItem());
|
||||
|
||||
stack.push( list );
|
||||
stack.push(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( Character.isDigit( c ) )
|
||||
{
|
||||
if ( !isDigit && i > startIndex )
|
||||
{
|
||||
list.add( new StringItem( version.substring( startIndex, i ), true ) );
|
||||
} else if (Character.isDigit(c)) {
|
||||
if (!isDigit && i > startIndex) {
|
||||
list.add(new StringItem(version.substring(startIndex, i), true));
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
isDigit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isDigit && i > startIndex )
|
||||
{
|
||||
list.add( parseItem( true, version.substring( startIndex, i ) ) );
|
||||
} else {
|
||||
if (isDigit && i > startIndex) {
|
||||
list.add(parseItem(true, version.substring(startIndex, i)));
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
@ -431,13 +378,11 @@ public class ComparableVersion
|
||||
}
|
||||
}
|
||||
|
||||
if ( version.length() > startIndex )
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex ) ) );
|
||||
if (version.length() > startIndex) {
|
||||
list.add(parseItem(isDigit, version.substring(startIndex)));
|
||||
}
|
||||
|
||||
while ( !stack.isEmpty() )
|
||||
{
|
||||
while (!stack.isEmpty()) {
|
||||
list = (ListItem) stack.pop();
|
||||
list.normalize();
|
||||
}
|
||||
@ -445,29 +390,35 @@ public class ComparableVersion
|
||||
canonical = items.toString();
|
||||
}
|
||||
|
||||
private static Item parseItem( boolean isDigit, String buf )
|
||||
{
|
||||
return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false );
|
||||
private static Item parseItem(boolean isDigit, String buf) {
|
||||
return isDigit ? new IntegerItem(buf) : new StringItem(buf, false);
|
||||
}
|
||||
|
||||
public int compareTo( ComparableVersion o )
|
||||
{
|
||||
return items.compareTo( o.items );
|
||||
@Override
|
||||
public int compareTo(ComparableVersion o) {
|
||||
return items.compareTo(o.items);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
public int compareTo(String version) {
|
||||
return compareTo(new ComparableVersion(version));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical );
|
||||
public String toCanonicalString() {
|
||||
return canonical;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion) o).canonical);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return canonical.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
58
src/main/java/de/diddiz/util/CuboidRegion.java
Normal file
58
src/main/java/de/diddiz/util/CuboidRegion.java
Normal file
@ -0,0 +1,58 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
public class CuboidRegion implements Cloneable {
|
||||
|
||||
private World world;
|
||||
private BlockVector min = new BlockVector();
|
||||
private BlockVector max = new BlockVector();
|
||||
|
||||
public CuboidRegion(World world, BlockVector first, BlockVector second) {
|
||||
this.world = world;
|
||||
this.min.setX(Math.min(first.getBlockX(), second.getBlockX()));
|
||||
this.min.setY(Math.min(first.getBlockY(), second.getBlockY()));
|
||||
this.min.setZ(Math.min(first.getBlockZ(), second.getBlockZ()));
|
||||
this.max.setX(Math.max(first.getBlockX(), second.getBlockX()));
|
||||
this.max.setY(Math.max(first.getBlockY(), second.getBlockY()));
|
||||
this.max.setZ(Math.max(first.getBlockZ(), second.getBlockZ()));
|
||||
}
|
||||
|
||||
public static CuboidRegion fromCorners(World world, Location first, Location second) {
|
||||
return new CuboidRegion(world, new BlockVector(first.getBlockX(), first.getBlockY(), first.getBlockZ()), new BlockVector(second.getBlockX(), second.getBlockY(), second.getBlockZ()));
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public BlockVector getMinimumPoint() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public BlockVector getMaximumPoint() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public int getSizeX() {
|
||||
return max.getBlockX() - min.getBlockX() + 1;
|
||||
}
|
||||
|
||||
public int getSizeZ() {
|
||||
return max.getBlockZ() - min.getBlockZ() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CuboidRegion clone() {
|
||||
try {
|
||||
CuboidRegion clone = (CuboidRegion) super.clone();
|
||||
clone.min = min.clone();
|
||||
clone.max = max.clone();
|
||||
return clone;
|
||||
} catch (final CloneNotSupportedException ex) {
|
||||
throw new Error("CuboidRegion should be cloneable", ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,13 +6,18 @@ import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Directional;
|
||||
|
||||
import org.bukkit.block.data.type.Bell;
|
||||
import org.bukkit.block.data.type.Bell.Attachment;
|
||||
import org.bukkit.block.data.type.Lantern;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.TNTPrimed;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
import java.util.List;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
|
||||
@ -20,6 +25,54 @@ import static de.diddiz.LogBlock.config.Config.mb4;
|
||||
|
||||
public class LoggingUtil {
|
||||
|
||||
public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) {
|
||||
Location loc = replaced.getLocation();
|
||||
Material placedType = placed.getType();
|
||||
if (!placedType.hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) {
|
||||
if (placedType == Material.TWISTING_VINES) {
|
||||
Block below = placed.getBlock().getRelative(BlockFace.DOWN);
|
||||
if (below.getType() == Material.TWISTING_VINES) {
|
||||
consumer.queueBlockReplace(actor, below.getState(), Material.TWISTING_VINES_PLANT.createBlockData());
|
||||
}
|
||||
}
|
||||
if (placedType == Material.WEEPING_VINES) {
|
||||
Block above = placed.getBlock().getRelative(BlockFace.UP);
|
||||
if (above.getType() == Material.WEEPING_VINES) {
|
||||
consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES_PLANT.createBlockData());
|
||||
}
|
||||
}
|
||||
if (BukkitUtils.isEmpty(replaced.getType())) {
|
||||
consumer.queueBlockPlace(actor, placed);
|
||||
} else {
|
||||
consumer.queueBlockReplace(actor, replaced, placed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int x = loc.getBlockX();
|
||||
int initialy = loc.getBlockY();
|
||||
int y = initialy;
|
||||
int z = loc.getBlockZ();
|
||||
while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) {
|
||||
y--;
|
||||
}
|
||||
if (initialy != y && !BukkitUtils.isEmpty(replaced.getType())) {
|
||||
// this is not the final location but the block got removed (vines etc)
|
||||
consumer.queueBlockBreak(actor, replaced);
|
||||
}
|
||||
// If y is 0 then the block fell out of the world :(
|
||||
if (y != 0) {
|
||||
// Run this check to avoid false positives
|
||||
Location finalLoc = new Location(loc.getWorld(), x, y, z);
|
||||
if (y == initialy || !BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) {
|
||||
if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) {
|
||||
consumer.queueBlockPlace(actor, finalLoc, placed.getBlockData());
|
||||
} else {
|
||||
consumer.queueBlockReplace(actor, finalLoc.getBlock().getState(), placed.getBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void smartLogFallables(Consumer consumer, Actor actor, Block origin) {
|
||||
|
||||
WorldConfig wcfg = getWorldConfig(origin.getWorld());
|
||||
@ -41,7 +94,7 @@ public class LoggingUtil {
|
||||
int x = loc.getBlockX();
|
||||
int y = loc.getBlockY();
|
||||
int z = loc.getBlockZ();
|
||||
while (y > 0 && BukkitUtils.canFall(loc.getWorld(), x, (y - 1), z)) {
|
||||
while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) {
|
||||
y--;
|
||||
}
|
||||
// If y is 0 then the sand block fell out of the world :(
|
||||
@ -63,32 +116,51 @@ public class LoggingUtil {
|
||||
}
|
||||
checkBlock = checkBlock.getRelative(BlockFace.UP);
|
||||
}
|
||||
if (wcfg.isLogging(Logging.SCAFFOLDING) && checkBlock.getType() == Material.SCAFFOLDING && consumer.getLogblock().getScaffoldingLogging() != null) {
|
||||
consumer.getLogblock().getScaffoldingLogging().addScaffoldingBreaker(actor, checkBlock);
|
||||
}
|
||||
}
|
||||
|
||||
public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) {
|
||||
smartLogBlockReplace(consumer, actor, origin, null);
|
||||
}
|
||||
|
||||
public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block origin, BlockData replacedWith) {
|
||||
|
||||
WorldConfig wcfg = getWorldConfig(origin.getWorld());
|
||||
if (wcfg == null) {
|
||||
return;
|
||||
}
|
||||
Material replacedType = origin.getType();
|
||||
if (replacedType == Material.TWISTING_VINES || replacedType == Material.TWISTING_VINES_PLANT) {
|
||||
Block below = origin.getRelative(BlockFace.DOWN);
|
||||
if (below.getType() == Material.TWISTING_VINES_PLANT) {
|
||||
consumer.queueBlockReplace(actor, below.getState(), Material.TWISTING_VINES.createBlockData());
|
||||
}
|
||||
}
|
||||
if (replacedType == Material.WEEPING_VINES || replacedType == Material.WEEPING_VINES_PLANT) {
|
||||
Block above = origin.getRelative(BlockFace.UP);
|
||||
if (above.getType() == Material.WEEPING_VINES_PLANT) {
|
||||
consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES.createBlockData());
|
||||
}
|
||||
}
|
||||
|
||||
Block checkBlock = origin.getRelative(BlockFace.UP);
|
||||
if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) {
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN) {
|
||||
consumer.queueSignBreak(actor, (Sign) checkBlock.getState());
|
||||
} else if (checkBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(checkBlock.getType())) {
|
||||
Material typeAbove = checkBlock.getType();
|
||||
if (BukkitUtils.getRelativeTopBreakabls().contains(typeAbove)) {
|
||||
if (typeAbove == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(typeAbove)) {
|
||||
Block doorBlock = checkBlock;
|
||||
// If the doorBlock is the top half a door the player simply punched a door
|
||||
// this will be handled later.
|
||||
if (!BukkitUtils.isTop(doorBlock.getBlockData())) {
|
||||
doorBlock = doorBlock.getRelative(BlockFace.UP);
|
||||
// Fall back check just in case the top half wasn't a door
|
||||
if (doorBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(doorBlock.getType())) {
|
||||
if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) {
|
||||
consumer.queueBlockBreak(actor, doorBlock.getState());
|
||||
}
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
}
|
||||
} else if (BukkitUtils.isDoublePlant(checkBlock.getType())) {
|
||||
} else if (BukkitUtils.isDoublePlant(typeAbove)) {
|
||||
Block plantBlock = checkBlock;
|
||||
// If the plantBlock is the top half of a double plant the player simply
|
||||
// punched the plant this will be handled later.
|
||||
@ -102,6 +174,48 @@ public class LoggingUtil {
|
||||
}
|
||||
} else {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
// check next blocks above
|
||||
checkBlock = checkBlock.getRelative(BlockFace.UP);
|
||||
typeAbove = checkBlock.getType();
|
||||
while (BukkitUtils.getRelativeTopBreakabls().contains(typeAbove)) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
checkBlock = checkBlock.getRelative(BlockFace.UP);
|
||||
typeAbove = checkBlock.getType();
|
||||
}
|
||||
}
|
||||
} else if (typeAbove == Material.LANTERN) {
|
||||
Lantern lantern = (Lantern) checkBlock.getBlockData();
|
||||
if (!lantern.isHanging()) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
}
|
||||
} else if (typeAbove == Material.BELL) {
|
||||
Bell bell = (Bell) checkBlock.getBlockData();
|
||||
if (bell.getAttachment() == Attachment.FLOOR) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
}
|
||||
}
|
||||
|
||||
checkBlock = origin.getRelative(BlockFace.DOWN);
|
||||
Material typeBelow = checkBlock.getType();
|
||||
if (typeBelow == Material.LANTERN) {
|
||||
Lantern lantern = (Lantern) checkBlock.getBlockData();
|
||||
if (lantern.isHanging()) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
}
|
||||
} else if (typeBelow == Material.BELL) {
|
||||
Bell bell = (Bell) checkBlock.getBlockData();
|
||||
if (bell.getAttachment() == Attachment.CEILING) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
}
|
||||
} else if (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
// check next blocks above
|
||||
checkBlock = checkBlock.getRelative(BlockFace.DOWN);
|
||||
typeBelow = checkBlock.getType();
|
||||
while (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT) {
|
||||
consumer.queueBlockBreak(actor, checkBlock.getState());
|
||||
checkBlock = checkBlock.getRelative(BlockFace.DOWN);
|
||||
typeBelow = checkBlock.getType();
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,10 +225,14 @@ public class LoggingUtil {
|
||||
Block block = location.getBlock();
|
||||
BlockData blockData = block.getBlockData();
|
||||
if (blockData instanceof Directional) {
|
||||
if (block.getRelative(((Directional) blockData).getFacing()).equals(origin)) {
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT) && block.getType() == Material.WALL_SIGN) {
|
||||
consumer.queueSignBreak(actor, (Sign) block.getState());
|
||||
} else {
|
||||
if (blockData.getMaterial() == Material.BELL) {
|
||||
if (((Bell) blockData).getAttachment() == Attachment.SINGLE_WALL) {
|
||||
if (block.getRelative(((Bell) blockData).getFacing()).equals(origin)) {
|
||||
consumer.queueBlockBreak(actor, block.getState());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) {
|
||||
consumer.queueBlockBreak(actor, block.getState());
|
||||
}
|
||||
}
|
||||
@ -123,7 +241,7 @@ public class LoggingUtil {
|
||||
}
|
||||
|
||||
// Special door check
|
||||
if (origin.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(origin.getType())) {
|
||||
if (replacedType == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(replacedType)) {
|
||||
Block doorBlock = origin;
|
||||
|
||||
// Up or down?
|
||||
@ -133,10 +251,10 @@ public class LoggingUtil {
|
||||
doorBlock = doorBlock.getRelative(BlockFace.DOWN);
|
||||
}
|
||||
|
||||
if (doorBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(doorBlock.getType())) {
|
||||
if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) {
|
||||
consumer.queueBlockBreak(actor, doorBlock.getState());
|
||||
}
|
||||
} else if (BukkitUtils.isDoublePlant(origin.getType())) { // Special double plant check
|
||||
} else if (BukkitUtils.isDoublePlant(replacedType)) { // Special double plant check
|
||||
Block plantBlock = origin;
|
||||
|
||||
// Up or down?
|
||||
@ -152,7 +270,11 @@ public class LoggingUtil {
|
||||
}
|
||||
|
||||
// Do this down here so that the block is added after blocks sitting on it
|
||||
consumer.queueBlockBreak(actor, origin.getState());
|
||||
if (replacedWith == null) {
|
||||
consumer.queueBlockBreak(actor, origin.getState());
|
||||
} else {
|
||||
consumer.queueBlockReplace(actor, origin.getState(), replacedWith);
|
||||
}
|
||||
}
|
||||
|
||||
public static String checkText(String text) {
|
||||
@ -164,4 +286,20 @@ public class LoggingUtil {
|
||||
}
|
||||
return text.replaceAll("[^\\u0000-\\uFFFF]", "?");
|
||||
}
|
||||
|
||||
public static Entity getRealDamager(Entity damager) {
|
||||
if (damager instanceof Projectile) {
|
||||
ProjectileSource realDamager = ((Projectile) damager).getShooter();
|
||||
if (realDamager instanceof Entity) {
|
||||
damager = (Entity) realDamager;
|
||||
}
|
||||
}
|
||||
if (damager instanceof TNTPrimed) {
|
||||
Entity realRemover = ((TNTPrimed) damager).getSource();
|
||||
if (realRemover != null) {
|
||||
damager = realRemover;
|
||||
}
|
||||
}
|
||||
return damager;
|
||||
}
|
||||
}
|
||||
|
123
src/main/java/de/diddiz/util/MessagingUtil.java
Normal file
123
src/main/java/de/diddiz/util/MessagingUtil.java
Normal file
@ -0,0 +1,123 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
import static de.diddiz.util.ActionColor.CREATE;
|
||||
import static de.diddiz.util.ActionColor.DESTROY;
|
||||
import static de.diddiz.util.TypeColor.DEFAULT;
|
||||
import static de.diddiz.util.Utils.spaces;
|
||||
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public class MessagingUtil {
|
||||
public static BaseComponent[] formatSummarizedChanges(int created, int destroyed, BaseComponent actor, int createdWidth, int destroyedWidth, float spaceFactor) {
|
||||
TextComponent textCreated = createTextComponentWithColor(created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)), CREATE.getColor());
|
||||
TextComponent textDestroyed = createTextComponentWithColor(destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)), DESTROY.getColor());
|
||||
return new BaseComponent[] { textCreated, textDestroyed, actor };
|
||||
}
|
||||
|
||||
public static TextComponent createTextComponentWithColor(String text, ChatColor color) {
|
||||
TextComponent tc = new TextComponent(text);
|
||||
tc.setColor(color);
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static TextComponent brackets(BracketType type, BaseComponent... content) {
|
||||
TextComponent tc = createTextComponentWithColor(type.getStarting(), TypeColor.BRACKETS.getColor());
|
||||
for (BaseComponent c : content) {
|
||||
tc.addExtra(c);
|
||||
}
|
||||
tc.addExtra(new TextComponent(type.getEnding()));
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static TextComponent prettyDate(long date) {
|
||||
TextComponent tc = brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatterShort.format(date), TypeColor.DATE.getColor()));
|
||||
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Config.formatter.format(date))));
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static TextComponent prettyState(String stateName) {
|
||||
return createTextComponentWithColor(stateName, TypeColor.STATE.getColor());
|
||||
}
|
||||
|
||||
public static TextComponent prettyState(int stateValue) {
|
||||
return prettyState(Integer.toString(stateValue));
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> TextComponent prettyState(E enumerator) {
|
||||
return prettyState(enumerator.toString());
|
||||
}
|
||||
|
||||
public static TextComponent prettyMaterial(String materialName) {
|
||||
return createTextComponentWithColor(materialName.toUpperCase(), TypeColor.MATERIAL.getColor());
|
||||
}
|
||||
|
||||
public static TextComponent prettyMaterial(Material material) {
|
||||
return prettyMaterial(material.name());
|
||||
}
|
||||
|
||||
public static TextComponent prettyMaterial(BlockData material) {
|
||||
TextComponent tc = prettyMaterial(material.getMaterial());
|
||||
String bdString = material.getAsString();
|
||||
int bracket = bdString.indexOf("[");
|
||||
if (bracket >= 0) {
|
||||
int bracket2 = bdString.indexOf("]", bracket);
|
||||
if (bracket2 >= 0) {
|
||||
String state = bdString.substring(bracket + 1, bracket2).replace(',', '\n');
|
||||
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(state)));
|
||||
}
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static TextComponent prettyEntityType(EntityType type) {
|
||||
return prettyMaterial(type.name());
|
||||
}
|
||||
|
||||
public static TextComponent prettyLocation(Location loc, int entryId) {
|
||||
return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entryId);
|
||||
}
|
||||
|
||||
public static TextComponent prettyLocation(int x, int y, int z, int entryId) {
|
||||
TextComponent tc = createTextComponentWithColor("", DEFAULT.getColor());
|
||||
tc.addExtra(createTextComponentWithColor(Integer.toString(x), TypeColor.COORDINATE.getColor()));
|
||||
tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor()));
|
||||
tc.addExtra(createTextComponentWithColor(Integer.toString(y), TypeColor.COORDINATE.getColor()));
|
||||
tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor()));
|
||||
tc.addExtra(createTextComponentWithColor(Integer.toString(z), TypeColor.COORDINATE.getColor()));
|
||||
if (entryId > 0) {
|
||||
tc.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb tp " + entryId));
|
||||
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Teleport here")));
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
|
||||
public enum BracketType {
|
||||
STANDARD("[", "]"),
|
||||
ANGLE("<", ">");
|
||||
|
||||
private String starting, ending;
|
||||
|
||||
BracketType(String starting, String ending) {
|
||||
this.starting = starting;
|
||||
this.ending = ending;
|
||||
}
|
||||
|
||||
public String getStarting() {
|
||||
return starting;
|
||||
}
|
||||
|
||||
public String getEnding() {
|
||||
return ending;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ public class MySQLConnectionPool implements Closeable {
|
||||
|
||||
private final HikariDataSource ds;
|
||||
|
||||
public MySQLConnectionPool(String url, String user, String password) {
|
||||
public MySQLConnectionPool(String url, String user, String password, boolean useSSL, boolean requireSSL) {
|
||||
this.ds = new HikariDataSource();
|
||||
ds.setJdbcUrl(url);
|
||||
ds.setUsername(user);
|
||||
@ -28,6 +28,11 @@ public class MySQLConnectionPool implements Closeable {
|
||||
ds.addDataSourceProperty("cachePrepStmts", "true");
|
||||
ds.addDataSourceProperty("prepStmtCacheSize", "250");
|
||||
ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
||||
ds.addDataSourceProperty("useServerPrepStmts", "true");
|
||||
|
||||
ds.addDataSourceProperty("useSSL", Boolean.toString(useSSL));
|
||||
ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL));
|
||||
ds.addDataSourceProperty("verifyServerCertificate", "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
24
src/main/java/de/diddiz/util/SqlUtil.java
Normal file
24
src/main/java/de/diddiz/util/SqlUtil.java
Normal file
@ -0,0 +1,24 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
public class SqlUtil {
|
||||
public static String escapeString(String s) {
|
||||
return escapeString(s, false);
|
||||
}
|
||||
|
||||
public static String escapeString(String s, boolean escapeMatcher) {
|
||||
s = s.replace("\u0000", "\\0");
|
||||
s = s.replace("\u0026", "\\Z");
|
||||
s = s.replace("\\", "\\\\");
|
||||
s = s.replace("'", "\\'");
|
||||
s = s.replace("\"", "\\\"");
|
||||
s = s.replace("\b", "\\b");
|
||||
s = s.replace("\n", "\\n");
|
||||
s = s.replace("\r", "\\r");
|
||||
s = s.replace("\t", "\\t");
|
||||
if (escapeMatcher) {
|
||||
s = s.replace("%", "\\%");
|
||||
s = s.replace("_", "\\_");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
29
src/main/java/de/diddiz/util/TypeColor.java
Normal file
29
src/main/java/de/diddiz/util/TypeColor.java
Normal file
@ -0,0 +1,29 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
public enum TypeColor {
|
||||
DEFAULT(ChatColor.YELLOW),
|
||||
MATERIAL(ChatColor.BLUE),
|
||||
STATE(ChatColor.BLUE),
|
||||
DATE(ChatColor.DARK_AQUA),
|
||||
BRACKETS(ChatColor.DARK_GRAY),
|
||||
COORDINATE(ChatColor.WHITE),
|
||||
HEADER(ChatColor.GOLD),
|
||||
ERROR(ChatColor.RED);
|
||||
|
||||
private final ChatColor color;
|
||||
|
||||
TypeColor(ChatColor color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public ChatColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return color.toString();
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
package de.diddiz.util;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -19,19 +19,19 @@ import java.util.UUID;
|
||||
public class UUIDFetcher {
|
||||
|
||||
private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
|
||||
private static final JSONParser jsonParser = new JSONParser();
|
||||
private static final Gson gson = new GsonBuilder().setLenient().create();
|
||||
|
||||
public static Map<String, UUID> getUUIDs(List<String> names) throws Exception {
|
||||
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
||||
Map<String, UUID> uuidMap = new HashMap<>();
|
||||
HttpURLConnection connection = createConnection();
|
||||
String body = JSONArray.toJSONString(names);
|
||||
String body = gson.toJson(names);
|
||||
writeBody(connection, body);
|
||||
JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
|
||||
for (Object profile : array) {
|
||||
JSONObject jsonProfile = (JSONObject) profile;
|
||||
String id = (String) jsonProfile.get("id");
|
||||
String name = (String) jsonProfile.get("name");
|
||||
UUID uuid = UUIDFetcher.getUUID(id);
|
||||
JsonArray array = gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonArray.class);
|
||||
for (JsonElement profile : array) {
|
||||
JsonObject jsonProfile = (JsonObject) profile;
|
||||
String id = jsonProfile.get("id").getAsString();
|
||||
String name = jsonProfile.get("name").getAsString();
|
||||
UUID uuid = getUUID(id);
|
||||
uuidMap.put(name, uuid);
|
||||
}
|
||||
return uuidMap;
|
||||
@ -58,22 +58,4 @@ public class UUIDFetcher {
|
||||
private static UUID getUUID(String id) {
|
||||
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32));
|
||||
}
|
||||
|
||||
public static byte[] toBytes(UUID uuid) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
||||
byteBuffer.putLong(uuid.getMostSignificantBits());
|
||||
byteBuffer.putLong(uuid.getLeastSignificantBits());
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
public static UUID fromBytes(byte[] array) {
|
||||
if (array.length != 16) {
|
||||
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
|
||||
}
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
|
||||
long mostSignificant = byteBuffer.getLong();
|
||||
long leastSignificant = byteBuffer.getLong();
|
||||
return new UUID(mostSignificant, leastSignificant);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,11 +15,14 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
|
||||
public class Utils {
|
||||
public static String newline = System.getProperty("line.separator");
|
||||
|
||||
@ -178,7 +181,7 @@ public class Utils {
|
||||
* @return A new list with the quoted arguments parsed to single values
|
||||
*/
|
||||
public static List<String> parseQuotes(List<String> args) {
|
||||
List<String> newArguments = new ArrayList<String>();
|
||||
List<String> newArguments = new ArrayList<>();
|
||||
String subjectString = join(args.toArray(new String[args.size()]), " ");
|
||||
|
||||
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
|
||||
@ -194,7 +197,7 @@ public class Utils {
|
||||
private final String ext;
|
||||
|
||||
public ExtensionFilenameFilter(String ext) {
|
||||
this.ext = ext;
|
||||
this.ext = "." + ext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -217,6 +220,13 @@ public class Utils {
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
public static String mysqlPrepareBytesForInsertAllowNull(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return "null";
|
||||
}
|
||||
return "'" + mysqlEscapeBytes(bytes) + "'";
|
||||
}
|
||||
|
||||
public static String mysqlTextEscape(String untrusted) {
|
||||
return untrusted.replace("\\", "\\\\").replace("'", "\\'");
|
||||
}
|
||||
@ -225,33 +235,53 @@ public class Utils {
|
||||
if (data == null || data.length == 0) {
|
||||
return null;
|
||||
}
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
try {
|
||||
InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8");
|
||||
conf.load(reader);
|
||||
reader.close();
|
||||
return conf.getItemStack("stack");
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
YamlConfiguration conf = deserializeYamlConfiguration(data);
|
||||
return conf == null ? null : conf.getItemStack("stack");
|
||||
}
|
||||
|
||||
public static byte[] saveItemStack(ItemStack stack) {
|
||||
if (stack == null || BukkitUtils.isEmpty(stack.getType())) {
|
||||
return null;
|
||||
}
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("stack", stack);
|
||||
return serializeYamlConfiguration(conf);
|
||||
}
|
||||
|
||||
public static YamlConfiguration deserializeYamlConfiguration(byte[] data) {
|
||||
if (data == null || data.length == 0) {
|
||||
return null;
|
||||
}
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
try {
|
||||
InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8");
|
||||
conf.load(reader);
|
||||
reader.close();
|
||||
return conf;
|
||||
} catch (ZipException | InvalidConfigurationException e) {
|
||||
LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage());
|
||||
return conf;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] serializeYamlConfiguration(YamlConfiguration conf) {
|
||||
if (conf == null || conf.getKeys(false).isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("stack", stack);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8");
|
||||
writer.write(conf.saveToString());
|
||||
writer.close();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String serializeForSQL(YamlConfiguration conf) {
|
||||
return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf));
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
package de.diddiz.worldedit;
|
||||
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class RegionContainer {
|
||||
|
||||
private Region selection;
|
||||
|
||||
public RegionContainer(Region sel) {
|
||||
this.selection = sel;
|
||||
}
|
||||
|
||||
public static RegionContainer fromPlayerSelection(Player player, Plugin plugin) {
|
||||
LocalSession session = ((WorldEditPlugin) plugin).getSession(player);
|
||||
com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(player.getWorld());
|
||||
if (!weWorld.equals(session.getSelectionWorld())) {
|
||||
throw new IllegalArgumentException("No selection defined");
|
||||
}
|
||||
Region selection;
|
||||
try {
|
||||
selection = session.getSelection(weWorld);
|
||||
} catch (IncompleteRegionException e) {
|
||||
throw new IllegalArgumentException("No selection defined");
|
||||
}
|
||||
if (selection == null) {
|
||||
throw new IllegalArgumentException("No selection defined");
|
||||
}
|
||||
if (!(selection instanceof CuboidRegion)) {
|
||||
throw new IllegalArgumentException("You have to define a cuboid selection");
|
||||
}
|
||||
return new RegionContainer(selection);
|
||||
}
|
||||
|
||||
public static RegionContainer fromCorners(World world, Location first, Location second) {
|
||||
com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world);
|
||||
Vector firstVector = BukkitAdapter.asVector(first);
|
||||
Vector secondVector = BukkitAdapter.asVector(second);
|
||||
|
||||
return new RegionContainer(new CuboidRegion(weWorld, firstVector, secondVector));
|
||||
}
|
||||
|
||||
public Region getSelection() {
|
||||
return selection;
|
||||
}
|
||||
|
||||
public void setSelection(Region selection) {
|
||||
this.selection = selection;
|
||||
}
|
||||
}
|
181
src/main/java/de/diddiz/worldedit/WorldEditHelper.java
Normal file
181
src/main/java/de/diddiz/worldedit/WorldEditHelper.java
Normal file
@ -0,0 +1,181 @@
|
||||
package de.diddiz.worldedit;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.util.CuboidRegion;
|
||||
|
||||
public class WorldEditHelper {
|
||||
private static boolean checkedForWorldEdit;
|
||||
private static boolean hasWorldEdit;
|
||||
|
||||
public static boolean hasWorldEdit() {
|
||||
if (!checkedForWorldEdit) {
|
||||
checkedForWorldEdit = true;
|
||||
Plugin worldEdit = Bukkit.getPluginManager().getPlugin("WorldEdit");
|
||||
hasWorldEdit = worldEdit != null;
|
||||
if (worldEdit != null) {
|
||||
Internal.setWorldEdit(worldEdit);
|
||||
}
|
||||
}
|
||||
return hasWorldEdit;
|
||||
}
|
||||
|
||||
public static boolean hasFullWorldEdit() {
|
||||
return hasWorldEdit && Internal.hasBukkitImplAdapter();
|
||||
}
|
||||
|
||||
public static byte[] serializeEntity(Entity entity) {
|
||||
if (!hasWorldEdit()) {
|
||||
return null;
|
||||
}
|
||||
return Internal.serializeEntity(entity);
|
||||
}
|
||||
|
||||
public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) {
|
||||
if (!hasWorldEdit()) {
|
||||
return null;
|
||||
}
|
||||
return Internal.restoreEntity(location, type, serialized);
|
||||
}
|
||||
|
||||
public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgumentException {
|
||||
if (!hasWorldEdit()) {
|
||||
throw new IllegalArgumentException("WorldEdit not found!");
|
||||
}
|
||||
return Internal.getSelectedRegion(player);
|
||||
}
|
||||
|
||||
private static class Internal {
|
||||
private static WorldEditPlugin worldEdit;
|
||||
private static Method getBukkitImplAdapter;
|
||||
|
||||
public static void setWorldEdit(Plugin worldEdit) {
|
||||
Internal.worldEdit = (WorldEditPlugin) worldEdit;
|
||||
}
|
||||
|
||||
public static boolean hasBukkitImplAdapter() {
|
||||
if (getBukkitImplAdapter == null) {
|
||||
try {
|
||||
getBukkitImplAdapter = WorldEditPlugin.class.getDeclaredMethod("getBukkitImplAdapter");
|
||||
getBukkitImplAdapter.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while checking for BukkitImplAdapter", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return getBukkitImplAdapter.invoke(worldEdit) != null;
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while checking for BukkitImplAdapter", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) {
|
||||
com.sk89q.worldedit.world.entity.EntityType weType = BukkitAdapter.adapt(type);
|
||||
com.sk89q.worldedit.util.Location weLocation = BukkitAdapter.adapt(location);
|
||||
try {
|
||||
NBTInputStream nbtis = new NBTInputStream(new ByteArrayInputStream(serialized));
|
||||
NamedTag namedTag = nbtis.readNamedTag();
|
||||
nbtis.close();
|
||||
UUID newUUID = null;
|
||||
if (namedTag.getName().equals("entity") && namedTag.getTag() instanceof CompoundTag) {
|
||||
CompoundTag serializedState = (CompoundTag) namedTag.getTag();
|
||||
BaseEntity state = new BaseEntity(weType, serializedState);
|
||||
com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state);
|
||||
if (weEntity != null) {
|
||||
CompoundTag newNbt = weEntity.getState().getNbtData();
|
||||
int[] uuidInts = newNbt.getIntArray("UUID");
|
||||
if (uuidInts != null && uuidInts.length >= 4) {
|
||||
newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL));
|
||||
} else {
|
||||
newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); // pre 1.16
|
||||
}
|
||||
}
|
||||
}
|
||||
return newUUID == null ? null : Bukkit.getEntity(newUUID);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("This IOException should be impossible", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] serializeEntity(Entity entity) {
|
||||
com.sk89q.worldedit.entity.Entity weEntity = BukkitAdapter.adapt(entity);
|
||||
BaseEntity state = weEntity.getState();
|
||||
if (state != null) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
NBTOutputStream nbtos = new NBTOutputStream(baos);
|
||||
CompoundTag nbt = state.getNbtData();
|
||||
LinkedHashMap<String, Tag> value = new LinkedHashMap<>(nbt.getValue());
|
||||
value.put("Health", new FloatTag(20.0f));
|
||||
value.put("Motion", new ListTag(DoubleTag.class, Arrays.asList(new DoubleTag[] { new DoubleTag(0), new DoubleTag(0), new DoubleTag(0) })));
|
||||
value.put("Fire", new ShortTag((short) -20));
|
||||
value.put("HurtTime", new ShortTag((short) 0));
|
||||
nbtos.writeNamedTag("entity", new CompoundTag(value));
|
||||
nbtos.close();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("This IOException should be impossible", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgumentException {
|
||||
LocalSession session = worldEdit.getSession(player);
|
||||
World world = player.getWorld();
|
||||
com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world);
|
||||
if (!weWorld.equals(session.getSelectionWorld())) {
|
||||
throw new IllegalArgumentException("No selection defined");
|
||||
}
|
||||
Region selection;
|
||||
try {
|
||||
selection = session.getSelection(weWorld);
|
||||
} catch (IncompleteRegionException e) {
|
||||
throw new IllegalArgumentException("No selection defined");
|
||||
}
|
||||
if (selection == null) {
|
||||
throw new IllegalArgumentException("No selection defined");
|
||||
}
|
||||
if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) {
|
||||
throw new IllegalArgumentException("You have to define a cuboid selection");
|
||||
}
|
||||
BlockVector3 min = selection.getMinimumPoint();
|
||||
BlockVector3 max = selection.getMaximumPoint();
|
||||
return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ()));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +1,26 @@
|
||||
package de.diddiz.worldedit;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.util.eventbus.Subscribe;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.logging.Level;
|
||||
@ -46,20 +43,6 @@ public class WorldEditLoggingHook {
|
||||
return new de.diddiz.LogBlock.Actor(weActor.getName());
|
||||
}
|
||||
|
||||
private World adapt(com.sk89q.worldedit.world.World weWorld) {
|
||||
if (weWorld == null) {
|
||||
throw new NullPointerException("[Logblock-Worldedit] The provided world was null.");
|
||||
}
|
||||
if (weWorld instanceof BukkitWorld) {
|
||||
return ((BukkitWorld) weWorld).getWorld();
|
||||
}
|
||||
World world = Bukkit.getServer().getWorld(weWorld.getName());
|
||||
if (world == null) {
|
||||
throw new IllegalArgumentException("Can't find a Bukkit world for " + weWorld);
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
public void hook() {
|
||||
WorldEdit.getInstance().getEventBus().register(new Object() {
|
||||
@Subscribe
|
||||
@ -72,9 +55,8 @@ public class WorldEditLoggingHook {
|
||||
|
||||
// Check to ensure the world should be logged
|
||||
final World world;
|
||||
final com.sk89q.worldedit.world.World k = event.getWorld();
|
||||
try {
|
||||
world = adapt(k);
|
||||
world = BukkitAdapter.adapt(event.getWorld());
|
||||
} catch (RuntimeException ex) {
|
||||
plugin.getLogger().warning("Failed to register logging for WorldEdit!");
|
||||
plugin.getLogger().log(Level.WARNING, ex.getMessage(), ex);
|
||||
@ -88,31 +70,34 @@ public class WorldEditLoggingHook {
|
||||
|
||||
event.setExtent(new AbstractDelegateExtent(event.getExtent()) {
|
||||
@Override
|
||||
public final boolean setBlock(Vector position, @SuppressWarnings("rawtypes") BlockStateHolder block) throws WorldEditException {
|
||||
public final <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block) throws WorldEditException {
|
||||
onBlockChange(position, block);
|
||||
return super.setBlock(position, block);
|
||||
}
|
||||
|
||||
protected void onBlockChange(Vector pt, BlockStateHolder<?> block) {
|
||||
|
||||
protected <B extends BlockStateHolder<B>> void onBlockChange(BlockVector3 pt, B block) {
|
||||
|
||||
if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
Block origin = location.getBlock();
|
||||
Material typeBefore = origin.getType();
|
||||
Location location = BukkitAdapter.adapt(world, pt);
|
||||
Block blockBefore = location.getBlock();
|
||||
BlockData blockDataBefore = blockBefore.getBlockData();
|
||||
Material typeBefore = blockDataBefore.getMaterial();
|
||||
|
||||
// Check to see if we've broken a sign
|
||||
if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN)) {
|
||||
BlockState stateBefore = origin.getState();
|
||||
plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore);
|
||||
} else if (!origin.isEmpty()) {
|
||||
plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData());
|
||||
}
|
||||
BlockData newBlock = BukkitAdapter.adapt(block);
|
||||
if (newBlock != null && !BukkitUtils.isEmpty(newBlock.getMaterial())) {
|
||||
plugin.getConsumer().queueBlockPlace(lbActor, location, newBlock);
|
||||
BlockData blockDataNew = BukkitAdapter.adapt(block);
|
||||
|
||||
if (!blockDataBefore.equals(blockDataNew)) {
|
||||
// Check to see if we've broken a sign
|
||||
if (BlockStateCodecs.hasCodec(typeBefore)) {
|
||||
plugin.getConsumer().queueBlockBreak(lbActor, blockBefore.getState());
|
||||
} else if (!BukkitUtils.isEmpty(typeBefore)) {
|
||||
plugin.getConsumer().queueBlockBreak(lbActor, location, blockDataBefore);
|
||||
}
|
||||
if (!BukkitUtils.isEmpty(blockDataNew.getMaterial())) {
|
||||
plugin.getConsumer().queueBlockPlace(lbActor, location, blockDataNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -309,7 +309,7 @@
|
||||
43:13,minecraft:stone_brick_slab[type=double,waterlogged=false]
|
||||
43:14,minecraft:nether_brick_slab[type=double,waterlogged=false]
|
||||
43:15,minecraft:smooth_quartz
|
||||
44:0,minecraft:stone_slab[type=bottom,waterlogged=false]
|
||||
44:0,minecraft:smooth_stone_slab[type=bottom,waterlogged=false]
|
||||
44:1,minecraft:sandstone_slab[type=bottom,waterlogged=false]
|
||||
44:2,minecraft:petrified_oak_slab[type=bottom,waterlogged=false]
|
||||
44:3,minecraft:cobblestone_slab[type=bottom,waterlogged=false]
|
||||
@ -317,7 +317,7 @@
|
||||
44:5,minecraft:stone_brick_slab[type=bottom,waterlogged=false]
|
||||
44:6,minecraft:nether_brick_slab[type=bottom,waterlogged=false]
|
||||
44:7,minecraft:quartz_slab[type=bottom,waterlogged=false]
|
||||
44:8,minecraft:stone_slab[type=top,waterlogged=false]
|
||||
44:8,minecraft:smooth_stone_slab[type=top,waterlogged=false]
|
||||
44:9,minecraft:sandstone_slab[type=top,waterlogged=false]
|
||||
44:10,minecraft:petrified_oak_slab[type=top,waterlogged=false]
|
||||
44:11,minecraft:cobblestone_slab[type=top,waterlogged=false]
|
||||
@ -440,22 +440,22 @@
|
||||
62:10,minecraft:furnace[facing=west,lit=false]
|
||||
62:11,minecraft:furnace[facing=east,lit=false]
|
||||
62:15,minecraft:furnace[facing=south,lit=false]
|
||||
63:0,minecraft:sign[rotation=0,waterlogged=false]
|
||||
63:1,minecraft:sign[rotation=1,waterlogged=false]
|
||||
63:2,minecraft:sign[rotation=2,waterlogged=false]
|
||||
63:3,minecraft:sign[rotation=3,waterlogged=false]
|
||||
63:4,minecraft:sign[rotation=4,waterlogged=false]
|
||||
63:5,minecraft:sign[rotation=5,waterlogged=false]
|
||||
63:6,minecraft:sign[rotation=6,waterlogged=false]
|
||||
63:7,minecraft:sign[rotation=7,waterlogged=false]
|
||||
63:8,minecraft:sign[rotation=8,waterlogged=false]
|
||||
63:9,minecraft:sign[rotation=9,waterlogged=false]
|
||||
63:10,minecraft:sign[rotation=10,waterlogged=false]
|
||||
63:11,minecraft:sign[rotation=11,waterlogged=false]
|
||||
63:12,minecraft:sign[rotation=12,waterlogged=false]
|
||||
63:13,minecraft:sign[rotation=13,waterlogged=false]
|
||||
63:14,minecraft:sign[rotation=14,waterlogged=false]
|
||||
63:15,minecraft:sign[rotation=15,waterlogged=false]
|
||||
63:0,minecraft:oak_sign[rotation=0,waterlogged=false]
|
||||
63:1,minecraft:oak_sign[rotation=1,waterlogged=false]
|
||||
63:2,minecraft:oak_sign[rotation=2,waterlogged=false]
|
||||
63:3,minecraft:oak_sign[rotation=3,waterlogged=false]
|
||||
63:4,minecraft:oak_sign[rotation=4,waterlogged=false]
|
||||
63:5,minecraft:oak_sign[rotation=5,waterlogged=false]
|
||||
63:6,minecraft:oak_sign[rotation=6,waterlogged=false]
|
||||
63:7,minecraft:oak_sign[rotation=7,waterlogged=false]
|
||||
63:8,minecraft:oak_sign[rotation=8,waterlogged=false]
|
||||
63:9,minecraft:oak_sign[rotation=9,waterlogged=false]
|
||||
63:10,minecraft:oak_sign[rotation=10,waterlogged=false]
|
||||
63:11,minecraft:oak_sign[rotation=11,waterlogged=false]
|
||||
63:12,minecraft:oak_sign[rotation=12,waterlogged=false]
|
||||
63:13,minecraft:oak_sign[rotation=13,waterlogged=false]
|
||||
63:14,minecraft:oak_sign[rotation=14,waterlogged=false]
|
||||
63:15,minecraft:oak_sign[rotation=15,waterlogged=false]
|
||||
64:0,minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false]
|
||||
64:1,minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false]
|
||||
64:2,minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false]
|
||||
@ -496,14 +496,14 @@
|
||||
67:13,minecraft:cobblestone_stairs[facing=west,half=top,shape=straight,waterlogged=false]
|
||||
67:14,minecraft:cobblestone_stairs[facing=south,half=top,shape=straight,waterlogged=false]
|
||||
67:15,minecraft:cobblestone_stairs[facing=north,half=top,shape=straight,waterlogged=false]
|
||||
68:0,minecraft:wall_sign[facing=north,waterlogged=false]
|
||||
68:3,minecraft:wall_sign[facing=south,waterlogged=false]
|
||||
68:4,minecraft:wall_sign[facing=west,waterlogged=false]
|
||||
68:5,minecraft:wall_sign[facing=east,waterlogged=false]
|
||||
68:9,minecraft:wall_sign[facing=south,waterlogged=false]
|
||||
68:10,minecraft:wall_sign[facing=west,waterlogged=false]
|
||||
68:11,minecraft:wall_sign[facing=east,waterlogged=false]
|
||||
68:15,minecraft:wall_sign[facing=south,waterlogged=false]
|
||||
68:0,minecraft:oak_wall_sign[facing=north,waterlogged=false]
|
||||
68:3,minecraft:oak_wall_sign[facing=south,waterlogged=false]
|
||||
68:4,minecraft:oak_wall_sign[facing=west,waterlogged=false]
|
||||
68:5,minecraft:oak_wall_sign[facing=east,waterlogged=false]
|
||||
68:9,minecraft:oak_wall_sign[facing=south,waterlogged=false]
|
||||
68:10,minecraft:oak_wall_sign[facing=west,waterlogged=false]
|
||||
68:11,minecraft:oak_wall_sign[facing=east,waterlogged=false]
|
||||
68:15,minecraft:oak_wall_sign[facing=south,waterlogged=false]
|
||||
69:0,minecraft:lever[face=ceiling,facing=west,powered=false]
|
||||
69:1,minecraft:lever[face=wall,facing=east,powered=false]
|
||||
69:2,minecraft:lever[face=wall,facing=west,powered=false]
|
||||
@ -1113,8 +1113,8 @@
|
||||
137:14,minecraft:command_block[conditional=true,facing=down]
|
||||
137:15,minecraft:command_block[conditional=true,facing=up]
|
||||
138:0,minecraft:beacon
|
||||
139:0,minecraft:cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false]
|
||||
139:1,minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false]
|
||||
139:0,minecraft:cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=false,west=none]
|
||||
139:1,minecraft:mossy_cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=false,west=none]
|
||||
140:0,minecraft:flower_pot
|
||||
141:0,minecraft:carrots[age=0]
|
||||
141:1,minecraft:carrots[age=1]
|
||||
|
@ -114,7 +114,7 @@
|
||||
40:0,minecraft:red_mushroom
|
||||
41:0,minecraft:gold_block
|
||||
42:0,minecraft:iron_block
|
||||
43:0,minecraft:stone_slab
|
||||
43:0,minecraft:smooth_stone_slab
|
||||
43:1,minecraft:sandstone_slab
|
||||
43:2,minecraft:petrified_oak_slab
|
||||
43:3,minecraft:cobblestone_slab
|
||||
@ -171,16 +171,16 @@
|
||||
62:3,minecraft:furnace
|
||||
62:4,minecraft:furnace
|
||||
62:5,minecraft:furnace
|
||||
63:0,minecraft:sign
|
||||
63:0,minecraft:oak_sign
|
||||
64:0,minecraft:oak_door
|
||||
65:0,minecraft:ladder
|
||||
66:0,minecraft:rail
|
||||
67:0,minecraft:cobblestone_stairs
|
||||
68:0,minecraft:air
|
||||
68:2,minecraft:wall_sign
|
||||
68:3,minecraft:wall_sign
|
||||
68:4,minecraft:wall_sign
|
||||
68:5,minecraft:wall_sign
|
||||
68:2,minecraft:oak_wall_sign
|
||||
68:3,minecraft:oak_wall_sign
|
||||
68:4,minecraft:oak_wall_sign
|
||||
68:5,minecraft:oak_wall_sign
|
||||
69:0,minecraft:lever
|
||||
70:0,minecraft:stone_pressure_plate
|
||||
71:0,minecraft:iron_door
|
||||
@ -599,7 +599,7 @@
|
||||
321:0,minecraft:painting
|
||||
322:0,minecraft:golden_apple
|
||||
322:1,minecraft:enchanted_golden_apple
|
||||
323:0,minecraft:sign
|
||||
323:0,minecraft:oak_sign
|
||||
324:0,minecraft:oak_door
|
||||
325:0,minecraft:bucket
|
||||
326:0,minecraft:water_bucket
|
||||
@ -632,8 +632,8 @@
|
||||
350:0,minecraft:cooked_cod
|
||||
350:1,minecraft:cooked_salmon
|
||||
351:0,minecraft:ink_sac
|
||||
351:1,minecraft:rose_red
|
||||
351:2,minecraft:cactus_green
|
||||
351:1,minecraft:red_dye
|
||||
351:2,minecraft:green_dye
|
||||
351:3,minecraft:cocoa_beans
|
||||
351:4,minecraft:lapis_lazuli
|
||||
351:5,minecraft:purple_dye
|
||||
@ -642,7 +642,7 @@
|
||||
351:8,minecraft:gray_dye
|
||||
351:9,minecraft:pink_dye
|
||||
351:10,minecraft:lime_dye
|
||||
351:11,minecraft:dandelion_yellow
|
||||
351:11,minecraft:yellow_dye
|
||||
351:12,minecraft:light_blue_dye
|
||||
351:13,minecraft:magenta_dye
|
||||
351:14,minecraft:orange_dye
|
||||
|
@ -5,8 +5,8 @@ authors: [md_5, ammar2, frymaster]
|
||||
website: http://dev.bukkit.org/server-mods/logblock/
|
||||
main: de.diddiz.LogBlock.LogBlock
|
||||
description: ${project.description}
|
||||
softdepend: [LogBlockQuestioner, WorldEdit]
|
||||
api-version: 1.13
|
||||
softdepend: [WorldEdit]
|
||||
api-version: 1.14
|
||||
commands:
|
||||
lb:
|
||||
description: 'LogBlock plugin commands'
|
||||
|
@ -1,6 +1,5 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
|
||||
import de.diddiz.util.Utils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
Reference in New Issue
Block a user