Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed block logging bugs #2

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
41 changes: 21 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
# WIP rollback for mcpe
### Simple
- This can log block breaking and placement (more events will be added later).
- Quickly inspect blocks by left clicking with a clock (crouch to inspect the adjacent block)
- Rollback using a single command `/rollback <user> <radius> <time>`

### Scalable
- Small database (12MB per million blocks) (MySQL compression)
- Works well with hundreds of players
- Lookup and rollback time does not degrade with database size

### Fast
- Can log hundreds of thousands of blocks a second
- Rollback millions of blocks without lag
- Inspect areas instantly

### TODO
- Logging entity / all NBT
- More events + configuration
- Translatable messages
# WIP rollback for NukkitX

### Simple
- This can log block breaking and placement (more events will be added later).
- Quickly inspect blocks by left clicking with a clock (crouch to inspect the adjacent block)
- Rollback using a single command `/rollback <user> <radius> <time>`

### Scalable
- Small database (12MB per million blocks) (MySQL compression)
- Works well with hundreds of players
- Lookup and rollback time does not degrade with database size

### Fast
- Can log hundreds of thousands of blocks a second
- Rollback millions of blocks without lag
- Inspect areas instantly

### TODO
- Logging entity / all NBT
- More events + configuration
- Translatable messages
59 changes: 6 additions & 53 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@ buildscript {
jcenter()
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/"}
}
dependencies {
classpath 'org.ajoberstar:grgit:1.7.0'
}
}

repositories {
maven {url "https://hub.spigotmc.org/nexus/content/groups/public/"}
maven {url "http://empcraft.com/maven2"}
maven {url "http://repo.mcstats.org/content/repositories/public"}
maven {url "http://repo.nukkitx.com/main/"}
maven {url "http://maven.sk89q.com/repo/"}
maven {url "http://repo.maven.apache.org/maven2"}
maven {url "http://ci.athion.net/job/FastAsyncWorldEdit/ws/mvn/"}
Expand All @@ -26,61 +23,17 @@ repositories {
}

dependencies {
compile 'org.ajoberstar:grgit:1.7.0'
compile group: "com.boydti", name: "fawe-api", version: "latest", changing: true
compile 'cn.nukkit:nukkit:1.0-SNAPSHOT'
compile(group: 'com.sk89q.worldedit', name: 'worldedit-core', version:'6.1.3-SNAPSHOT') {
exclude(module: 'bukkit-classloader-check')
}
}

def revision = ""
def buildNumber = ""
def semver = ""
def date = ""
ext {
git = org.ajoberstar.grgit.Grgit.open(file(".git"))
date = git.head().date.format("yy.MM.dd")
revision = "-${git.head().abbreviatedId}"
parents = git.head().parentIds;
index = 0; // Offset to mach CI
int major, minor, patch;
major = minor = patch = 0;
for (;parents != null && !parents.isEmpty();index++) {
int majorCount, minorCount, patchCount;
patchCount = minor == 0 && major == 0 ? 1 : 0;
commit = git.getResolve().toCommit(parents.get(0));
for (String line : commit.fullMessage.tokenize("\n")) {
switch (line.replaceAll("- ", "").split(" ")[0].toLowerCase()) {
case "minor":
case "added":
case "add":
case "change":
case "changed":
case "changes":
if (major == 0) {minorCount = 1; patchCount = 0;}
break;
case "refactor":
case "remove":
case "major":
patchCount = minorCount = 0;
majorCount = 1;
break;
}
}
major += majorCount;
minor += minorCount;
patch += patchCount;
parents = commit.getParentIds()
}
buildNumber = "-${index}"
semver = "-${major}.${minor}.${patch}"
}

version = date + revision + buildNumber + semver
if ( project.hasProperty("lzNoVersion") ) { // gradle build -PlzNoVersion
version = "unknown";
}

version = "1.0";

description = rootProject.name

clean{
Expand All @@ -98,7 +51,7 @@ processResources {
}
jar {
enabled = true
archiveName = "${rootProject.name}-${project.version}.jar"
archiveName = "${rootProject.name}.jar"
destinationDir = file 'target'
}
println sourceSets.main.output.classesDir
println sourceSets.main.output.classesDir
2 changes: 1 addition & 1 deletion src/main/java/com/boydti/rollback/api/AbstractLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void logPlayerBreak(Player player, Block block, boolean track) {
}

public void logBreak(String name, Block block, boolean creative, boolean track) {
logBreak(name, block.getFloorX(), block.getFloorY(), block.getFloorZ(), creative, track);
logBreak(name, block.getFloorX(), block.getFloorY() - 1, block.getFloorZ(), creative, track);
}

public void logBreak(String name, int x, int y, int z, boolean creative, boolean track) {
Expand Down
12 changes: 5 additions & 7 deletions src/main/java/com/boydti/rollback/cmd/Rollback.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.exception.FaweException;
Expand All @@ -25,8 +24,8 @@
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import com.sk89q.worldedit.regions.Region;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class Rollback {
Expand Down Expand Up @@ -61,11 +60,10 @@ public Rollback(final Player player, String[] args) {
player.sendMessage(BBC.color(Config.PREFIX + BBC.COMMAND_SYNTAX.format("/rollback " + args[0] + " " + args[1] + " <time>")));
return;
}
final RegionWrapper[] regions = WEManager.IMP.getMask(fp, FaweMaskManager.MaskType.OWNER);
final Region[] regions = WEManager.IMP.getMask(fp, FaweMaskManager.MaskType.OWNER);
// Rollback
Location loc = player.getLocation();
final int x = loc.getFloorX();
int y = loc.getFloorY();
final int z = loc.getFloorZ();

if (fp.getMeta("fawe_action") != null) {
Expand Down Expand Up @@ -100,9 +98,9 @@ public void run() {
@Override
public void run(SimpleBlockChange change) {
BaseBlock block = FaweCache.CACHE_BLOCK[change.combinedFrom];
mutable.x = change.x;
mutable.y = change.y;
mutable.z = change.z;
mutable.setX(change.x);
mutable.setY(change.y);
mutable.setY(change.z);
if (change.tileFrom != null) {
block = new BaseBlock(block.getId(), block.getData(), change.tileFrom);
}
Expand Down
17 changes: 9 additions & 8 deletions src/main/java/com/boydti/rollback/database/SQLDatabase.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.boydti.rollback.database;

import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager;
Expand Down Expand Up @@ -150,7 +149,7 @@ public static byte[] compress(byte[] src) {
return finalCompressedArray;
}

private final byte[] buffer = new byte[Settings.HISTORY.BUFFER_SIZE];
private final byte[] buffer = new byte[531441]; //This is probably awful ( 531441 was from fawe.config.Settings.HISTORY.BUFFER_SIZE )

public CompoundTag toTag(byte[] compressed) {
if (compressed == null) {
Expand Down Expand Up @@ -369,7 +368,7 @@ public void purge(int diff) {
stmt.executeUpdate();
}
try (PreparedStatement stmt = connection.prepareStatement(UPDATE_TIME_BLOCKSNBT.replace("$", table + "").replace("?", "" + shift))) {
stmt.executeUpdate();
stmt.executeUpdate(); //TODO: Error (seemingly) randomly thrown here (https://hastebin.com/nucuxovahu.pl)
}
} catch (SQLException e) {
e.printStackTrace();
Expand Down Expand Up @@ -472,11 +471,13 @@ public void init() {
DatabaseMetaData dbm = connection.getMetaData();
ResultSet tables = dbm.getTables(null, null, prefix + "timestamp", null);
if (tables.next()) {
// Table exists
try (PreparedStatement stmt = connection.prepareStatement("SELECT `time` from `" + prefix + "timestamp`")) {
ResultSet r = stmt.executeQuery();
BASE_TIME = r.getLong(1);
}
// Table exists
while(tables.next()) {
try (PreparedStatement stmt = connection.prepareStatement("SELECT `time` from `" + prefix + "timestamp`")) {
ResultSet r = stmt.executeQuery();
BASE_TIME = r.getLong("time");
}
}
} else {
BASE_TIME = (System.currentTimeMillis() >> TIME_PARTITION);
try (Statement stmt = connection.createStatement()) {
Expand Down
31 changes: 5 additions & 26 deletions src/main/java/com/boydti/rollback/event/PlayerEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import cn.nukkit.event.block.BlockBreakEvent;
import cn.nukkit.event.player.PlayerInteractEvent;
import cn.nukkit.item.Item;
import cn.nukkit.math.Vector3;
import cn.nukkit.plugin.Plugin;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
Expand All @@ -19,8 +18,6 @@
import com.boydti.rollback.database.SQLDatabase;
import com.boydti.rollback.database.SimpleBlockChange;
import com.boydti.rollback.util.LogUser;
import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.WorldVectorFace;
import java.util.List;

public class PlayerEvents implements Listener {
Expand Down Expand Up @@ -53,37 +50,18 @@ public void onInteract(PlayerInteractEvent event) {
}
Block block;
switch (event.getAction()) {
case PlayerInteractEvent.LEFT_CLICK_AIR:
block = player.getTargetBlock(64);
case LEFT_CLICK_AIR:
block = player.getLevelBlock();
if (block == null) {
return;
}
break;
case PlayerInteractEvent.RIGHT_CLICK_AIR:
FawePlayer fp = FawePlayer.wrap(player);
com.sk89q.worldedit.entity.Player wePlayer = fp.getPlayer();
WorldVectorFace pos = wePlayer.getBlockTraceFace(256, true);
if (pos == null) {
return;
}
WorldVector face = pos.getFaceVector();
block = player.getLevel().getBlock(new Vector3(face.getBlockX(), face.getBlockY(), face.getBlockZ()));
if (block == null) {
return;
}
break;
case PlayerInteractEvent.RIGHT_CLICK_BLOCK:
case RIGHT_CLICK_BLOCK:
block = event.getBlock().getSide(event.getFace());
break;
case PlayerInteractEvent.LEFT_CLICK_BLOCK:
block = event.getBlock();
break;
default:
return;
}
if (player.isSneaking()) {
block = block.getSide(event.getFace());
}
event.setCancelled(true);
interact(player, block);
}
Expand All @@ -105,12 +83,13 @@ public void run() {
if (changes.isEmpty()) {
fp.sendMessage(BBC.color(Config.PREFIX + "No changes."));
} else {
player.sendMessage(BBC.color(Config.PREFIX + "===== (" + fblock.getFloorX() + ", " + fblock.getFloorY() + ", " + fblock.getFloorZ() + ") ====="));
for (SimpleBlockChange change : changes) {
String name = LogUser.getName(change.player);
String age = MainUtil.secToTime((System.currentTimeMillis() - change.timestamp) / 1000);
String from = Item.get(FaweCache.getId(change.combinedFrom), FaweCache.getData(change.combinedFrom)).getName();
String to = Item.get(FaweCache.getId(change.combinedTo), FaweCache.getData(change.combinedTo)).getName();
player.sendMessage(BBC.color(Config.PREFIX + name + ": " + from + " -> " + to + " (" + age+")"));
player.sendMessage(BBC.color(name + ": " + from + " -> " + to + " (" + age +")"));
}
}
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import cn.nukkit.event.entity.EntitySpawnEvent;
import cn.nukkit.level.Level;
import cn.nukkit.level.Location;
import cn.nukkit.math.AxisAlignedBB;
import cn.nukkit.math.SimpleAxisAlignedBB;
import cn.nukkit.metadata.MetadataValue;
import cn.nukkit.plugin.Plugin;
import com.boydti.fawe.FaweCache;
Expand Down Expand Up @@ -39,7 +39,7 @@ public void onBlockFall(EntitySpawnEvent event) {
Block block = level.getBlock(loc);
String name = logger.getNameRelative(block);
if (name == null) {
AxisAlignedBB bb = new AxisAlignedBB(loc.getX() - 1, loc.getY() - 1, loc.getZ() - 1, loc.getX() + 1, loc.getY() + 1, loc.getZ() + 1);
SimpleAxisAlignedBB bb = new SimpleAxisAlignedBB(loc.getX() - 1, loc.getY() - 1, loc.getZ() - 1, loc.getX() + 1, loc.getY() + 1, loc.getZ() + 1);
Entity[] nearby = level.getNearbyEntities(bb, entity);
name = LogUser.FALLING_BLOCK.ID;
for (Entity ent : nearby) {
Expand Down
15 changes: 6 additions & 9 deletions src/main/java/com/boydti/rollback/listeners/BlockPlace.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import cn.nukkit.plugin.Plugin;
import com.boydti.fawe.FaweCache;
import com.boydti.rollback.LogAPI;
import com.boydti.rollback.api.AbstractLogger;
import com.boydti.rollback.config.Loggers;

public class BlockPlace extends BasicListener {
Expand All @@ -22,18 +21,16 @@ public BlockPlace(Plugin plugin) {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) {
Player player = event.getPlayer();
Block state = event.getBlock();
AbstractLogger logger = LogAPI.getLogger(player.getLevel());
int combinedTo = FaweCache.getCombined(state.getId(), state.getDamage());
logger.logPlace(player.getName(), state.getFloorX(), state.getFloorY(), state.getFloorZ(), (short) combinedTo, null);
Block block = event.getBlock();
int combinedTo = FaweCache.getCombined(block.getId(), block.getDamage());
LogAPI.getLogger(player.getLevel()).logPlace(player.getName(), block.getFloorX(), block.getFloorY(), block.getFloorZ(), (short) combinedTo, null);
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
Player player = event.getPlayer();
Block block = event.getBlockClicked().getSide(event.getBlockFace());
Block block = event.getBlockClicked();
Item bucket = event.getBucket();
int type = bucket.getDamage();
LogAPI.getLogger(player.getLevel()).logBlock(player.getName(), block.getFloorX(), block.getFloorY(), block.getFloorZ(), (short) 0, (short) FaweCache.getCombined(type, 0));
}
LogAPI.getLogger(player.getLevel()).logBlock(player.getName(), block.getFloorX(), block.getFloorY(), block.getFloorZ(), (short) 0, (short) FaweCache.getCombined(bucket.getDamage(), 0));
}
}
12 changes: 6 additions & 6 deletions src/main/java/com/boydti/rollback/listeners/PhysicsEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ public void onBlockPhysics(BlockUpdateEvent event) {
return;
}
Block block = event.getBlock();
AbstractLogger logger = LogAPI.getLogger(block.getLevel());
switch (block.getId()) {
case 8: // Liquids
case 9:
case 10:
case 11:
AbstractLogger logger = LogAPI.getLogger(block.getLevel());
case 8: // flowing water
case 9: //water
case 10: //flowing lava
case 11: //lava
logger.trackLiquid(LogUser.LIQUID.ID, block);
return;
default:
LogAPI.getLogger(block.getLevel()).logPhysics(block);
logger.logPhysics(block);
return;
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/boydti/rollback/we/RollbackChangeSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.boydti.rollback.database.SQLDatabase;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.world.biome.BaseBiome;

import java.util.Iterator;

public class RollbackChangeSet extends FaweChangeSet {
Expand Down Expand Up @@ -59,5 +61,11 @@ public void addTileRemove(CompoundTag tag) {
public Iterator<Change> getIterator(boolean dir) {
return parent.getIterator(dir);
}

@Override
public void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to) {
//Not implemented.

}

}