Threaded BlockState DB-Connection
This commit is contained in:
parent
7506a7f1c1
commit
e32bbbd105
22 changed files with 1275 additions and 458 deletions
|
@ -1,5 +1,7 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative;
|
||||
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.jaschastarke.bukkit.lib.CoreModule;
|
||||
import de.jaschastarke.bukkit.lib.commands.AliasHelpedCommand;
|
||||
import de.jaschastarke.bukkit.lib.modules.AdditionalBlockBreaks;
|
||||
|
@ -7,10 +9,11 @@ import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockListener;
|
|||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockStateCommand;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockStateConfig;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DependencyListener;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.HangingListener;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.PlayerListener;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.SyncronizedModel;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.ThreadedModel;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.worldedit.LCEditSessionFactory;
|
||||
import de.jaschastarke.modularize.IModule;
|
||||
import de.jaschastarke.modularize.ModuleEntry;
|
||||
|
@ -19,7 +22,6 @@ import de.jaschastarke.modularize.ModuleEntry.ModuleState;
|
|||
public class ModBlockStates extends CoreModule<LimitedCreative> {
|
||||
private BlockStateConfig config;
|
||||
private FeatureBlockItemSpawn blockDrops;
|
||||
private DBQueries queries;
|
||||
private BlockStateCommand command;
|
||||
private DBModel model;
|
||||
|
||||
|
@ -56,8 +58,15 @@ public class ModBlockStates extends CoreModule<LimitedCreative> {
|
|||
@Override
|
||||
public void onEnable() {
|
||||
try {
|
||||
queries = new DBQueries(this, getPlugin().getDatabaseConnection());
|
||||
queries.initTable();
|
||||
if (model == null) {
|
||||
if (config.getUseThreading())
|
||||
model = new ThreadedModel(this);
|
||||
else
|
||||
model = new SyncronizedModel(this);
|
||||
}
|
||||
if (model instanceof Listener)
|
||||
listeners.addListener((Listener) model);
|
||||
model.onEnable();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
getLog().warn(plugin.getLocale().trans("block_state.error.sql_connection_failed", getName()));
|
||||
|
@ -79,7 +88,11 @@ public class ModBlockStates extends CoreModule<LimitedCreative> {
|
|||
}
|
||||
@Override
|
||||
public void onDisable() {
|
||||
model.onDisable();
|
||||
super.onDisable();
|
||||
if (model instanceof Listener)
|
||||
listeners.removeListener((Listener) model);
|
||||
model = null;
|
||||
}
|
||||
|
||||
public BlockStateConfig getConfig() {
|
||||
|
@ -88,12 +101,7 @@ public class ModBlockStates extends CoreModule<LimitedCreative> {
|
|||
public FeatureBlockItemSpawn getBlockSpawn() {
|
||||
return blockDrops;
|
||||
}
|
||||
public DBQueries getQueries() {
|
||||
return queries;
|
||||
}
|
||||
public DBModel getModel() {
|
||||
if (model == null)
|
||||
model = new DBModel(this);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.metadata.Metadatable;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public abstract class AbstractModel {
|
||||
protected static final String BSMDKEY = "blockstate";
|
||||
protected MetadataValue metadataNull;
|
||||
private Plugin plugin;
|
||||
|
||||
protected AbstractModel(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
metadataNull = new FixedMetadataValue(plugin, new Boolean(null));
|
||||
}
|
||||
|
||||
protected void moveMetaState(Block from, Block to) {
|
||||
HasBlockState metaBlock = getMetaBlock(from);
|
||||
if (metaBlock.set && metaBlock.state != null) {
|
||||
BlockState state = metaBlock.state;
|
||||
state.setLocation(to.getLocation());
|
||||
setMetaBlock(to, state);
|
||||
} else {
|
||||
removeMetaBlock(to);
|
||||
}
|
||||
setMetaBlock(from, null);
|
||||
}
|
||||
|
||||
protected boolean hasMetaBlock(Metadatable m) {
|
||||
List<MetadataValue> metadata = m.getMetadata(BSMDKEY);
|
||||
for (MetadataValue v : metadata) {
|
||||
if (v.value() instanceof BlockState)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected void setMetaBlock(Metadatable m, BlockState s) {
|
||||
if (s == null)
|
||||
m.setMetadata(BSMDKEY, metadataNull);
|
||||
else
|
||||
m.setMetadata(BSMDKEY, new FixedMetadataValue(plugin, s));
|
||||
}
|
||||
protected HasBlockState getMetaBlock(Metadatable m) {
|
||||
HasBlockState has = new HasBlockState();
|
||||
List<MetadataValue> metadata = m.getMetadata(BSMDKEY);
|
||||
for (MetadataValue v : metadata) {
|
||||
if (v.value() instanceof BlockState) {
|
||||
has.set = true;
|
||||
has.state = (BlockState) v.value();
|
||||
break;
|
||||
} else if (v == metadataNull) {
|
||||
has.set = true;
|
||||
has.state = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return has;
|
||||
}
|
||||
protected void removeMetaBlock(Metadatable m) {
|
||||
m.removeMetadata(BSMDKEY, plugin);
|
||||
}
|
||||
|
||||
public static class HasBlockState {
|
||||
public boolean set = false;
|
||||
public BlockState state = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -21,6 +20,7 @@ import org.bukkit.metadata.FixedMetadataValue;
|
|||
|
||||
import de.jaschastarke.bukkit.lib.events.BlockDestroyedEvent;
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.DBTransaction;
|
||||
|
||||
public class BlockListener implements Listener {
|
||||
private ModBlockStates mod;
|
||||
|
@ -30,96 +30,62 @@ public class BlockListener implements Listener {
|
|||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(event.getBlock());
|
||||
if (s != null) {
|
||||
if (mod.getModel().isRestricted(event.getBlock())) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking bad, err.. block: " + event.getBlock().getLocation().toString());
|
||||
|
||||
if (event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking bad, err.. block: " + s.toString());
|
||||
|
||||
if (s.isRestricted() && event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
mod.getBlockSpawn().block(event.getBlock(), event.getPlayer());
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
|
||||
mod.getModel().removeState(s);
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
mod.getBlockSpawn().block(event.getBlock(), event.getPlayer());
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onBlockBreak: "+e.getMessage());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
mod.getModel().removeState(event.getBlock());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onOtherBlockDestroy(BlockDestroyedEvent event) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(event.getBlock());
|
||||
if (s != null) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking attached block: " + s.toString());
|
||||
if (mod.getModel().isRestricted(event.getBlock())) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking attached block: " + event.getBlock().getLocation().toString());
|
||||
|
||||
if (s.isRestricted()) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
mod.getBlockSpawn().block(event.getBlock());
|
||||
}
|
||||
|
||||
mod.getModel().removeState(s);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onBlockBreak: "+e.getMessage());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
mod.getBlockSpawn().block(event.getBlock());
|
||||
}
|
||||
mod.getModel().removeState(event.getBlock());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBlocksBreakByExplosion(EntityExplodeEvent event) {
|
||||
try {
|
||||
Map<Block, BlockState> states = mod.getModel().getStates(event.blockList());
|
||||
for (Block block : event.blockList()) {
|
||||
BlockState s = states.get(block);
|
||||
if (s != null) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking bad, err.. block: " + s.toString());
|
||||
Map<Block, Boolean> states = mod.getModel().getRestrictedStates(event.blockList());
|
||||
DBTransaction update = mod.getModel().groupUpdate();
|
||||
for (Block block : event.blockList()) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking bad, err.. block: " + block.getLocation().toString());
|
||||
|
||||
if (s.isRestricted()) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
mod.getBlockSpawn().block(block);
|
||||
}
|
||||
|
||||
mod.getModel().removeState(s);
|
||||
}
|
||||
if (states.get(block)) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
mod.getBlockSpawn().block(block);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onBlockBreakByExplosion: "+e.getMessage());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
update.removeState(block);
|
||||
}
|
||||
update.finish();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(event.getBlock());
|
||||
if (s != null) {
|
||||
// This shouldn't happen
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Replacing current BlockState: " + s.toString());
|
||||
} else {
|
||||
s = new BlockState();
|
||||
s.setLocation(event.getBlock().getLocation());
|
||||
}
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
BlockState s = new BlockState();
|
||||
s.setLocation(event.getBlock().getLocation());
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
|
||||
mod.getModel().setState(s);
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onBlockPlace: "+e.getMessage());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
mod.getModel().setState(s);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
|
@ -138,25 +104,16 @@ public class BlockListener implements Listener {
|
|||
source = source.getRelative(event.getDirection());
|
||||
}
|
||||
|
||||
try {
|
||||
if (movedBlocks.size() > 0) {
|
||||
mod.getQueries().getDB().startTransaction();
|
||||
for (Block sblock : movedBlocks) {
|
||||
Block dest = sblock.getRelative(event.getDirection());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("PistionExtend moves "+sblock.getType()+"-Block from "+sblock.getLocation()+" to "+dest.getLocation());
|
||||
if (movedBlocks.size() > 0) {
|
||||
DBTransaction update = mod.getModel().groupUpdate();
|
||||
for (Block sblock : movedBlocks) {
|
||||
Block dest = sblock.getRelative(event.getDirection());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("PistionExtend moves "+sblock.getType()+"-Block from "+sblock.getLocation()+" to "+dest.getLocation());
|
||||
|
||||
mod.getModel().moveState(sblock, dest);
|
||||
}
|
||||
mod.getQueries().getDB().endTransaction();
|
||||
update.moveState(sblock, dest);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
try {
|
||||
mod.getQueries().getDB().revertTransaction();
|
||||
} catch (SQLException e1) {
|
||||
}
|
||||
mod.getLog().warn("DB-Error while onBlockMove (extend): "+e.getMessage());
|
||||
//event.setCancelled(true);
|
||||
update.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,18 +124,9 @@ public class BlockListener implements Listener {
|
|||
Block dest = event.getBlock().getRelative(event.getDirection());
|
||||
Block source = dest.getRelative(event.getDirection());
|
||||
if (event.isSticky() && source.getType() != Material.AIR) {
|
||||
try {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("PistionRetract moves "+source.getType()+"-Block from "+source.getLocation()+" to "+dest.getLocation());
|
||||
mod.getModel().moveState(source, source.getRelative(event.getDirection().getOppositeFace()));
|
||||
} catch (SQLException e) {
|
||||
try {
|
||||
mod.getQueries().getDB().revertTransaction();
|
||||
} catch (SQLException e1) {
|
||||
}
|
||||
mod.getLog().warn("DB-Error while onBlockMove (retract): "+e.getMessage());
|
||||
//event.setCancelled(true);
|
||||
}
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("PistionRetract moves "+source.getType()+"-Block from "+source.getLocation()+" to "+dest.getLocation());
|
||||
mod.getModel().moveState(source, source.getRelative(event.getDirection().getOppositeFace()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
|
@ -25,7 +24,8 @@ import de.jaschastarke.maven.ArchiveDocComments;
|
|||
import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission;
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState.Source;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries.Cuboid;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.Cuboid;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.DBTransaction;
|
||||
|
||||
/**
|
||||
* LimitedCreative-BlockState-Command: modify blockstate database to prevent drops of selected blocks (requires WorldEdit)
|
||||
|
@ -130,45 +130,35 @@ public class BlockStateCommand extends BukkitCommand implements IHelpDescribed {
|
|||
public void run() {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Scheduler: Asynchronous Task run");
|
||||
DBQueries q = mod.getQueries();
|
||||
try {
|
||||
q.getDB().startTransaction();
|
||||
int count = 0;
|
||||
World w = selection.getWorld();
|
||||
DBTransaction update = mod.getModel().groupUpdate();
|
||||
int count = 0;
|
||||
World w = selection.getWorld();
|
||||
|
||||
Cuboid c = new Cuboid();
|
||||
c.add(min);
|
||||
c.add(max);
|
||||
mod.getModel().cacheStates(c);
|
||||
Cuboid c = new Cuboid();
|
||||
c.add(min);
|
||||
c.add(max);
|
||||
mod.getModel().cacheStates(c);
|
||||
|
||||
BlockState seed = new BlockState();
|
||||
seed.setPlayer(context.getPlayer());
|
||||
seed.setGameMode(tgm);
|
||||
seed.setSource(Source.COMMAND);
|
||||
seed.setDate(new Date());
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
|
||||
Location loc = new Location(w, x, y, z);
|
||||
if (w.getBlockAt(loc).getType() != Material.AIR && selection.contains(loc)) {
|
||||
seed.setLocation(loc);
|
||||
mod.getModel().setState(new BlockState(seed));
|
||||
count++;
|
||||
}
|
||||
BlockState seed = new BlockState();
|
||||
seed.setPlayer(context.getPlayer());
|
||||
seed.setGameMode(tgm);
|
||||
seed.setSource(Source.COMMAND);
|
||||
seed.setDate(new Date());
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
|
||||
Location loc = new Location(w, x, y, z);
|
||||
if (w.getBlockAt(loc).getType() != Material.AIR && selection.contains(loc)) {
|
||||
seed.setLocation(loc);
|
||||
update.setState(new BlockState(seed));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
q.getDB().endTransaction();
|
||||
|
||||
context.response(L("command.blockstate.command_updated", count));
|
||||
} catch (SQLException e) {
|
||||
try {
|
||||
q.getDB().revertTransaction();
|
||||
} catch (SQLException e1) {
|
||||
}
|
||||
mod.getLog().warn("Failed to update blocks in region: " + e.getMessage());
|
||||
context.response(L("command.blockstate.command_failed"));
|
||||
}
|
||||
update.finish();
|
||||
|
||||
context.response(L("command.blockstate.command_updated", count));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
|
|
|
@ -43,6 +43,11 @@ public class BlockStateConfig extends Configuration implements IConfigurationSub
|
|||
} else {
|
||||
entry.disable();
|
||||
}
|
||||
} else if (node.getName().equals("useThreading")) {
|
||||
if (entry.getState() == ModuleState.ENABLED) {
|
||||
entry.disable();
|
||||
entry.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,6 +82,20 @@ public class BlockStateConfig extends Configuration implements IConfigurationSub
|
|||
return config.getBoolean("enabled", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* BlockStateThreading
|
||||
*
|
||||
* This experimental variant of the experimental Feature uses Threading to minimize lag. This fully relies on
|
||||
* Bukkit metadata implementation. You only should need this, if there are often plays more then 10 players at once
|
||||
* on your server. Be aware that this requires more memory.
|
||||
*
|
||||
* default: false
|
||||
*/
|
||||
@IsConfigurationNode(order = 150)
|
||||
public boolean getUseThreading() {
|
||||
return config.getBoolean("useThreading", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* BlockStateTool
|
||||
*
|
||||
|
|
|
@ -1,149 +1,86 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.metadata.Metadatable;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries.Cuboid;
|
||||
|
||||
public class DBModel {
|
||||
private static final String BSMDKEY = "blockstate";
|
||||
private ModBlockStates mod;
|
||||
private DBQueries q;
|
||||
|
||||
public DBModel(ModBlockStates mod) {
|
||||
this.mod = mod;
|
||||
this.q = mod.getQueries();
|
||||
}
|
||||
|
||||
public void moveState(Block from, Block to) throws SQLException {
|
||||
q.delete(to.getLocation());
|
||||
q.move(from.getLocation(), to.getLocation());
|
||||
HasBlockState metaBlock = getMetaBlock(from);
|
||||
if (metaBlock.set && metaBlock.state != null) {
|
||||
BlockState state = metaBlock.state;
|
||||
state.setLocation(to.getLocation());
|
||||
setMetaBlock(to, state);
|
||||
} else {
|
||||
removeMetaBlock(to);
|
||||
}
|
||||
setMetaBlock(from, null);
|
||||
}
|
||||
public void removeState(BlockState state) throws SQLException {
|
||||
//removeMetaBlock(state.getLocation().getBlock());
|
||||
setMetaBlock(state.getLocation().getBlock(), null);
|
||||
q.delete(state);
|
||||
}
|
||||
public Map<Block, BlockState> getStates(List<Block> blocks) throws SQLException {
|
||||
Map<Block, BlockState> ret = new HashMap<Block, BlockState>();
|
||||
|
||||
Cuboid c = new Cuboid();
|
||||
for (Block block : blocks) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (has.set) {
|
||||
ret.put(block, has.state);
|
||||
public interface DBModel {
|
||||
public static class Cuboid {
|
||||
private World w = null;
|
||||
private int minx, miny, minz;
|
||||
private int maxx, maxy, maxz;
|
||||
public void add(Location loc) {
|
||||
if (w == null) {
|
||||
w = loc.getWorld();
|
||||
minx = maxx = loc.getBlockX();
|
||||
miny = maxy = loc.getBlockY();
|
||||
minz = maxz = loc.getBlockZ();
|
||||
} else {
|
||||
c.add(block.getLocation());
|
||||
if (w != loc.getWorld())
|
||||
throw new IllegalArgumentException("Point is from a different world");
|
||||
if (minx > loc.getBlockX())
|
||||
minx = loc.getBlockX();
|
||||
if (maxx < loc.getBlockX())
|
||||
maxx = loc.getBlockX();
|
||||
if (miny > loc.getBlockY())
|
||||
miny = loc.getBlockY();
|
||||
if (maxy < loc.getBlockY())
|
||||
maxy = loc.getBlockY();
|
||||
if (minz > loc.getBlockZ())
|
||||
minz = loc.getBlockZ();
|
||||
if (maxz < loc.getBlockZ())
|
||||
maxz = loc.getBlockZ();
|
||||
}
|
||||
}
|
||||
if (!c.isEmpty()) {
|
||||
List<BlockState> dbb = q.findAllIn(c);
|
||||
for (BlockState bs : dbb) {
|
||||
setMetaBlock(bs.getLocation().getBlock(), bs);
|
||||
if (blocks.contains(bs.getLocation().getBlock()))
|
||||
ret.put(bs.getLocation().getBlock(), bs);
|
||||
}
|
||||
for (Block block : blocks) {
|
||||
if (!ret.containsKey(block)) {
|
||||
ret.put(block, null);
|
||||
setMetaBlock(block, null);
|
||||
}
|
||||
}
|
||||
public int getMinX() {
|
||||
return minx;
|
||||
}
|
||||
/*for (Block block : blocks) {
|
||||
if (ret.containsKey(block))
|
||||
ret.put(block, getState(block));
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
public void cacheStates(Cuboid c) throws SQLException {
|
||||
if (!c.isEmpty()) {
|
||||
List<BlockState> dbb = q.findAllIn(c);
|
||||
for (BlockState bs : dbb) {
|
||||
setMetaBlock(bs.getLocation().getBlock(), bs);
|
||||
}
|
||||
public int getMinY() {
|
||||
return miny;
|
||||
}
|
||||
}
|
||||
public BlockState getState(Block block) throws SQLException {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (!has.set) {
|
||||
BlockState state = q.find(block.getLocation());
|
||||
setMetaBlock(block, state);
|
||||
return state;
|
||||
public int getMinZ() {
|
||||
return minz;
|
||||
}
|
||||
return has.state;
|
||||
}
|
||||
public void setState(BlockState state) throws SQLException {
|
||||
Block block = state.getLocation().getBlock();
|
||||
boolean update = hasMetaBlock(block);
|
||||
boolean store = state.isRestricted() || mod.getConfig().getLogSurvival();
|
||||
|
||||
setMetaBlock(block, store ? state : null);
|
||||
|
||||
if (update) {
|
||||
if (!store)
|
||||
q.delete(state);
|
||||
else if (!q.update(state))
|
||||
q.insert(state);
|
||||
} else {
|
||||
if (store)
|
||||
q.insert(state);
|
||||
public int getMaxX() {
|
||||
return maxx;
|
||||
}
|
||||
public int getMaxY() {
|
||||
return maxy;
|
||||
}
|
||||
public int getMaxZ() {
|
||||
return maxz;
|
||||
}
|
||||
public World getWorld() {
|
||||
return w;
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return w == null;
|
||||
}
|
||||
public String toString() {
|
||||
return "Cuboid{world="+w.getName()+", min_x="+minx+", max_x="+maxx+", min_y="+miny+", max_y="+maxy+", min_z="+minz+", max_z="+maxz+"}";
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasMetaBlock(Metadatable m) {
|
||||
List<MetadataValue> metadata = m.getMetadata(BSMDKEY);
|
||||
for (MetadataValue v : metadata) {
|
||||
if (v.value() instanceof BlockState)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected void setMetaBlock(Metadatable m, BlockState s) {
|
||||
if (s == null)
|
||||
m.setMetadata(BSMDKEY, new FixedMetadataValue(mod.getPlugin(), new Boolean(false)));
|
||||
else
|
||||
m.setMetadata(BSMDKEY, new FixedMetadataValue(mod.getPlugin(), s));
|
||||
}
|
||||
protected HasBlockState getMetaBlock(Metadatable m) {
|
||||
HasBlockState has = new HasBlockState();
|
||||
List<MetadataValue> metadata = m.getMetadata(BSMDKEY);
|
||||
for (MetadataValue v : metadata) {
|
||||
if (v.value() instanceof BlockState) {
|
||||
has.set = true;
|
||||
has.state = (BlockState) v.value();
|
||||
break;
|
||||
} else if (v.getOwningPlugin() == mod.getPlugin()) {
|
||||
has.set = true;
|
||||
has.state = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return has;
|
||||
}
|
||||
protected void removeMetaBlock(Metadatable m) {
|
||||
m.removeMetadata(BSMDKEY, mod.getPlugin());
|
||||
}
|
||||
public void onEnable() throws Exception;
|
||||
public void onDisable();
|
||||
public void moveState(Block from, Block to);
|
||||
public void removeState(BlockState state);
|
||||
public void removeState(Block block);
|
||||
public Map<Block, BlockState> getStates(List<Block> blocks);
|
||||
public Map<Block, Boolean> getRestrictedStates(List<Block> blocks);
|
||||
public void cacheStates(DBModel.Cuboid c);
|
||||
public BlockState getState(Block block);
|
||||
public boolean isRestricted(Block block);
|
||||
public void setState(BlockState state);
|
||||
public DBTransaction groupUpdate();
|
||||
|
||||
protected static class HasBlockState {
|
||||
public boolean set = false;
|
||||
public BlockState state = null;
|
||||
public static interface DBTransaction {
|
||||
public void moveState(Block from, Block to);
|
||||
public void setState(BlockState state);
|
||||
public void removeState(Block block);
|
||||
public void finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.List;
|
|||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import de.jaschastarke.database.Type;
|
||||
import de.jaschastarke.database.db.Database;
|
||||
|
@ -49,7 +48,7 @@ public class DBQueries {
|
|||
}
|
||||
|
||||
private PreparedStatement findall = null;
|
||||
public List<BlockState> findAllIn(Cuboid c) throws SQLException {
|
||||
public List<BlockState> findAllIn(DBModel.Cuboid c) throws SQLException {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("DBQuery: findAllIn: " + c.toString());
|
||||
List<BlockState> blocks = new ArrayList<BlockState>();
|
||||
|
@ -268,60 +267,4 @@ public class DBQueries {
|
|||
public Database getDB() {
|
||||
return db;
|
||||
}
|
||||
|
||||
public static class Cuboid {
|
||||
private World w = null;
|
||||
private int minx, miny, minz;
|
||||
private int maxx, maxy, maxz;
|
||||
public void add(Location loc) {
|
||||
if (w == null) {
|
||||
w = loc.getWorld();
|
||||
minx = maxx = loc.getBlockX();
|
||||
miny = maxy = loc.getBlockY();
|
||||
minz = maxz = loc.getBlockZ();
|
||||
} else {
|
||||
if (w != loc.getWorld())
|
||||
throw new IllegalArgumentException("Point is from a different world");
|
||||
if (minx > loc.getBlockX())
|
||||
minx = loc.getBlockX();
|
||||
if (maxx < loc.getBlockX())
|
||||
maxx = loc.getBlockX();
|
||||
if (miny > loc.getBlockY())
|
||||
miny = loc.getBlockY();
|
||||
if (maxy < loc.getBlockY())
|
||||
maxy = loc.getBlockY();
|
||||
if (minz > loc.getBlockZ())
|
||||
minz = loc.getBlockZ();
|
||||
if (maxz < loc.getBlockZ())
|
||||
maxz = loc.getBlockZ();
|
||||
}
|
||||
}
|
||||
public int getMinX() {
|
||||
return minx;
|
||||
}
|
||||
public int getMinY() {
|
||||
return miny;
|
||||
}
|
||||
public int getMinZ() {
|
||||
return minz;
|
||||
}
|
||||
public int getMaxX() {
|
||||
return maxx;
|
||||
}
|
||||
public int getMaxY() {
|
||||
return maxy;
|
||||
}
|
||||
public int getMaxZ() {
|
||||
return maxz;
|
||||
}
|
||||
public World getWorld() {
|
||||
return w;
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return w == null;
|
||||
}
|
||||
public String toString() {
|
||||
return "Cuboid{world="+w.getName()+", min_x="+minx+", max_x="+maxx+", min_y="+miny+", max_y="+maxy+", min_z="+minz+", max_z="+maxz+"}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
|
@ -14,7 +13,6 @@ import org.bukkit.event.hanging.HangingPlaceEvent;
|
|||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState.Source;
|
||||
|
||||
public class HangingListener implements Listener {
|
||||
private ModBlockStates mod;
|
||||
|
@ -25,36 +23,26 @@ public class HangingListener implements Listener {
|
|||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||
if (event.getRightClicked() instanceof ItemFrame) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(event.getRightClicked().getLocation().getBlock());
|
||||
if (s != null) {
|
||||
if (mod.getModel().isRestricted(event.getRightClicked().getLocation().getBlock())) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Modifying hanging: " + event.getRightClicked().getLocation().toString());
|
||||
|
||||
if (event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Modifying hanging: " + s.toString());
|
||||
|
||||
if ((s.getGameMode() == GameMode.CREATIVE || s.getSource() == Source.EDIT) && event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Modify prevented");
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
} else {
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
mod.getModel().setState(s);
|
||||
}
|
||||
} else {
|
||||
s = new BlockState();
|
||||
s.setLocation(event.getRightClicked().getLocation().getBlock().getLocation());
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
|
||||
mod.getModel().setState(s);
|
||||
mod.getLog().debug("... was placed by creative. Modify prevented");
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onHangingInteract: "+e.getMessage());
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
BlockState s = new BlockState();
|
||||
s.setLocation(event.getRightClicked().getLocation().getBlock().getLocation());
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
|
||||
mod.getModel().setState(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,52 +50,32 @@ public class HangingListener implements Listener {
|
|||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onHangingBreak(HangingBreakEvent event) {
|
||||
if (event.getEntity() instanceof ItemFrame) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(event.getEntity().getLocation().getBlock());
|
||||
if (s != null) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking hanging: " + s.toString());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Breaking hanging: " + event.getEntity().getLocation().toString());
|
||||
|
||||
if (s.getGameMode() == GameMode.CREATIVE || s.getSource() == Source.EDIT) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
//mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation());
|
||||
mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation(), Material.ITEM_FRAME);
|
||||
mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation(), ((ItemFrame) event.getEntity()).getItem().getType());
|
||||
}
|
||||
if (mod.getModel().isRestricted(event.getEntity().getLocation().getBlock())) {
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||
|
||||
mod.getModel().removeState(s);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onHangingBreak: "+e.getMessage());
|
||||
event.setCancelled(true);
|
||||
mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation(), Material.ITEM_FRAME);
|
||||
mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation(), ((ItemFrame) event.getEntity()).getItem().getType());
|
||||
}
|
||||
|
||||
mod.getModel().removeState(event.getEntity().getLocation().getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onHangingPlace(HangingPlaceEvent event) {
|
||||
if (event.getEntity() instanceof ItemFrame) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(event.getEntity().getLocation().getBlock());
|
||||
if (s != null) {
|
||||
// This shouldn't happen
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Replacing current BlockState: " + s.toString());
|
||||
} else {
|
||||
s = new BlockState();
|
||||
s.setLocation(event.getEntity().getLocation().getBlock().getLocation());
|
||||
}
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
BlockState s = new BlockState();
|
||||
s.setLocation(event.getEntity().getLocation().getBlock().getLocation());
|
||||
s.setPlayer(event.getPlayer());
|
||||
s.setDate(new Date());
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
|
||||
mod.getModel().setState(s);
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onHangingPlace: "+e.getMessage());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
mod.getModel().setState(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
@ -46,40 +44,36 @@ public class PlayerListener implements Listener {
|
|||
}
|
||||
|
||||
private void showInfo(Player pl, Location loc, Material type) {
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(loc.getBlock());
|
||||
InGameFormatter f = new InGameFormatter(mod.getPlugin().getLang());
|
||||
String ret = null;
|
||||
if (s == null || s.getSource() == Source.UNKNOWN) {
|
||||
ret = f.formatString(ChatFormattings.ERROR, f.getString("block_state.tool_info.unknown", type.toString()));
|
||||
} else {
|
||||
String k = "block_state.tool_info." + s.getSource().name().toLowerCase();
|
||||
String gm = "";
|
||||
if (s.getGameMode() != null) {
|
||||
switch (s.getGameMode()) {
|
||||
case CREATIVE:
|
||||
gm = ChatColor.GOLD + s.getGameMode().toString().toLowerCase() + ChatColor.RESET;
|
||||
break;
|
||||
case SURVIVAL:
|
||||
gm = ChatColor.GREEN + s.getGameMode().toString().toLowerCase() + ChatColor.RESET;
|
||||
break;
|
||||
case ADVENTURE:
|
||||
gm = ChatColor.DARK_GREEN + s.getGameMode().toString().toLowerCase() + ChatColor.RESET;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BlockState s = mod.getModel().getState(loc.getBlock());
|
||||
InGameFormatter f = new InGameFormatter(mod.getPlugin().getLang());
|
||||
String ret = null;
|
||||
if (s == null || s.getSource() == Source.UNKNOWN) {
|
||||
ret = f.formatString(ChatFormattings.ERROR, f.getString("block_state.tool_info.unknown", type.toString()));
|
||||
} else {
|
||||
String k = "block_state.tool_info." + s.getSource().name().toLowerCase();
|
||||
String gm = "";
|
||||
if (s.getGameMode() != null) {
|
||||
switch (s.getGameMode()) {
|
||||
case CREATIVE:
|
||||
gm = ChatColor.GOLD + s.getGameMode().toString().toLowerCase() + ChatColor.RESET;
|
||||
break;
|
||||
case SURVIVAL:
|
||||
gm = ChatColor.GREEN + s.getGameMode().toString().toLowerCase() + ChatColor.RESET;
|
||||
break;
|
||||
case ADVENTURE:
|
||||
gm = ChatColor.DARK_GREEN + s.getGameMode().toString().toLowerCase() + ChatColor.RESET;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = f.formatString(ChatFormattings.INFO, f.getString(k, type.toString(),
|
||||
s.getPlayerName(),
|
||||
gm,
|
||||
s.getDate()));
|
||||
}
|
||||
if (ret != null)
|
||||
pl.sendMessage(ret);
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onPlayerInteract: "+e.getMessage());
|
||||
|
||||
ret = f.formatString(ChatFormattings.INFO, f.getString(k, type.toString(),
|
||||
s.getPlayerName(),
|
||||
gm,
|
||||
s.getDate()));
|
||||
}
|
||||
if (ret != null)
|
||||
pl.sendMessage(ret);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.jaschastarke.database.DatabaseConfigurationException;
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
|
||||
/**
|
||||
* @internal I'm not happy with the error-handling here, especially in the Transaction, but I'll focus on the asynchronous
|
||||
* variant, where all errors have to be handled in a separate thread.
|
||||
*/
|
||||
public class SyncronizedModel extends AbstractModel implements DBModel {
|
||||
private ModBlockStates mod;
|
||||
private DBQueries q;
|
||||
|
||||
public SyncronizedModel(ModBlockStates mod) throws DatabaseConfigurationException {
|
||||
super(mod.getPlugin());
|
||||
this.mod = mod;
|
||||
this.q = new DBQueries(mod, mod.getPlugin().getDatabaseConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() throws SQLException {
|
||||
this.q.initTable();
|
||||
}
|
||||
@Override
|
||||
public void onDisable() {
|
||||
}
|
||||
|
||||
public void moveState(Block from, Block to) {
|
||||
try {
|
||||
q.delete(to.getLocation());
|
||||
q.move(from.getLocation(), to.getLocation());
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
mod.getLog().warn("Failed to move BlockState in DB from " + from.getLocation().toString() + " to " + to.getLocation().toString());
|
||||
}
|
||||
moveMetaState(from, to);
|
||||
}
|
||||
public void removeState(BlockState state) {
|
||||
removeState(state.getLocation().getBlock());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeState(Block block) {
|
||||
setMetaBlock(block, null);
|
||||
try {
|
||||
q.delete(block.getLocation());
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
mod.getLog().warn("Failed to delete BlockState in DB from " + block.getLocation().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Block, Boolean> getRestrictedStates(List<Block> blocks) {
|
||||
Map<Block, Boolean> ret = new HashMap<Block, Boolean>();
|
||||
for (Map.Entry<Block, BlockState> entry : getStates(blocks).entrySet()) {
|
||||
ret.put(entry.getKey(), entry.getValue().isRestricted());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
public Map<Block, BlockState> getStates(List<Block> blocks) {
|
||||
Map<Block, BlockState> ret = new HashMap<Block, BlockState>();
|
||||
|
||||
Cuboid c = new Cuboid();
|
||||
for (Block block : blocks) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (has.set) {
|
||||
ret.put(block, has.state);
|
||||
} else {
|
||||
c.add(block.getLocation());
|
||||
}
|
||||
}
|
||||
if (!c.isEmpty()) {
|
||||
try {
|
||||
List<BlockState> dbb = q.findAllIn(c);
|
||||
for (BlockState bs : dbb) {
|
||||
setMetaBlock(bs.getLocation().getBlock(), bs);
|
||||
if (blocks.contains(bs.getLocation().getBlock()))
|
||||
ret.put(bs.getLocation().getBlock(), bs);
|
||||
}
|
||||
for (Block block : blocks) {
|
||||
if (!ret.containsKey(block)) {
|
||||
ret.put(block, null);
|
||||
setMetaBlock(block, null);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
mod.getLog().warn("Failed to fetch BlockState from DB in " + c.toString());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
public void cacheStates(Cuboid c) {
|
||||
if (!c.isEmpty()) {
|
||||
try {
|
||||
List<BlockState> dbb = q.findAllIn(c);
|
||||
for (BlockState bs : dbb) {
|
||||
setMetaBlock(bs.getLocation().getBlock(), bs);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
mod.getLog().warn("Failed to fetch BlockState (for caching) from DB in " + c.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRestricted(Block block) {
|
||||
BlockState state = getState(block);
|
||||
return state != null ? state.isRestricted() : null;
|
||||
}
|
||||
|
||||
public BlockState getState(Block block) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (!has.set) {
|
||||
try {
|
||||
BlockState state = q.find(block.getLocation());
|
||||
setMetaBlock(block, state);
|
||||
return state;
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
mod.getLog().warn("Failed to fetch BlockState (for caching) from DB at " + block.getLocation().toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return has.state;
|
||||
}
|
||||
public void setState(BlockState state) {
|
||||
Block block = state.getLocation().getBlock();
|
||||
boolean update = hasMetaBlock(block);
|
||||
boolean store = state.isRestricted() || mod.getConfig().getLogSurvival();
|
||||
|
||||
setMetaBlock(block, store ? state : null);
|
||||
|
||||
try {
|
||||
if (update) {
|
||||
if (!store)
|
||||
q.delete(state);
|
||||
else if (!q.update(state))
|
||||
q.insert(state);
|
||||
} else {
|
||||
if (store)
|
||||
q.insert(state);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
mod.getLog().warn("Failed to update BlockState in DB at " + block.getLocation().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTransaction groupUpdate() {
|
||||
return new Transaction();
|
||||
}
|
||||
|
||||
private class Transaction implements DBTransaction {
|
||||
private boolean finished = false;
|
||||
private Transaction() {
|
||||
try {
|
||||
q.getDB().startTransaction();
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveState(Block from, Block to) {
|
||||
if (finished)
|
||||
throw new IllegalAccessError("Transaction already ended");
|
||||
SyncronizedModel.this.moveState(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(BlockState state) {
|
||||
if (finished)
|
||||
throw new IllegalAccessError("Transaction already ended");
|
||||
SyncronizedModel.this.setState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeState(Block block) {
|
||||
if (finished)
|
||||
throw new IllegalAccessError("Transaction already ended");
|
||||
SyncronizedModel.this.removeState(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
try {
|
||||
q.getDB().endTransaction();
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().severe(e.getMessage());
|
||||
} finally {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.metadata.Metadatable;
|
||||
|
||||
import de.jaschastarke.database.DatabaseConfigurationException;
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.thread.ThreadLink;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.thread.Transaction;
|
||||
|
||||
public class ThreadedModel extends AbstractModel implements DBModel, Listener {
|
||||
private ModBlockStates mod;
|
||||
private ThreadLink threads;
|
||||
private MetadataValue metadataSet;
|
||||
private MetadataValue metadataSetRestricted;
|
||||
|
||||
public ThreadedModel(ModBlockStates mod) {
|
||||
super(mod.getPlugin());
|
||||
this.mod = mod;
|
||||
metadataSet = new FixedMetadataValue(mod.getPlugin(), new Boolean(true));
|
||||
metadataSetRestricted = new FixedMetadataValue(mod.getPlugin(), new Object());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() throws SQLException, DatabaseConfigurationException {
|
||||
DBQueries queries = new DBQueries(mod, mod.getPlugin().getDatabaseConnection());
|
||||
queries.initTable();
|
||||
threads = new ThreadLink(this, queries);
|
||||
// We don't keep any reference to queries, because it contains the DB-Connection, which should be only used
|
||||
// from the thread from now on (as SQLite may not threadsafe)
|
||||
for (World w : mod.getPlugin().getServer().getWorlds()) {
|
||||
for (Chunk chunk : w.getLoadedChunks()) {
|
||||
threads.queueChunkLoad(chunk);
|
||||
}
|
||||
}
|
||||
threads.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
try {
|
||||
threads.shutdown();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
mod.getLog().severe("Failed to clean end Database-Thread, maybe BlockStates haven't been saved");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
threads.queueChunkLoad(event.getChunk());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveState(Block from, Block to) {
|
||||
threads.queueMetaMove(from.getLocation(), to.getLocation());
|
||||
moveMetaState(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeState(BlockState state) {
|
||||
removeState(state.getLocation().getBlock());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeState(Block block) {
|
||||
setMetaBlock(block, null);
|
||||
threads.queueUpdate(block);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<Block, Boolean> getRestrictedStates(List<Block> blocks) {
|
||||
Map<Block, Boolean> ret = new HashMap<Block, Boolean>();
|
||||
Cuboid c;
|
||||
do {
|
||||
c = new Cuboid();
|
||||
for (Block block : blocks) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (has.set) {
|
||||
ret.put(block, has.restricted);
|
||||
} else {
|
||||
c.add(block.getLocation());
|
||||
ret.put(block, null);
|
||||
}
|
||||
}
|
||||
if (!c.isEmpty())
|
||||
threads.callUpdate(c);
|
||||
} while(!c.isEmpty());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Block, BlockState> getStates(List<Block> blocks) {
|
||||
Map<Block, BlockState> ret = new HashMap<Block, BlockState>();
|
||||
Cuboid c;
|
||||
do {
|
||||
c = new Cuboid();
|
||||
for (Block block : blocks) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (has.set) {
|
||||
ret.put(block, has.state);
|
||||
} else {
|
||||
c.add(block.getLocation());
|
||||
ret.put(block, null);
|
||||
}
|
||||
}
|
||||
if (!c.isEmpty())
|
||||
threads.callUpdate(c);
|
||||
} while(!c.isEmpty());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheStates(Cuboid c) {
|
||||
threads.callUpdate(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getState(Block block) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (!has.set || (has.dbSet && has.state == null)) {
|
||||
return threads.callUpdate(block);
|
||||
}
|
||||
return has.state;
|
||||
}
|
||||
@Override
|
||||
public boolean isRestricted(Block block) {
|
||||
HasBlockState has = getMetaBlock(block);
|
||||
if (!has.set) {
|
||||
BlockState state = threads.callUpdate(block);
|
||||
return state != null ? state.isRestricted() : false;
|
||||
}
|
||||
return getMetaBlock(block).restricted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(BlockState state) {
|
||||
Block block = state.getLocation().getBlock();
|
||||
boolean store = state.isRestricted() || mod.getConfig().getLogSurvival();
|
||||
|
||||
setMetaBlock(block, store ? state : null);
|
||||
|
||||
threads.queueUpdate(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTransaction groupUpdate() {
|
||||
return new GroupUpdate(threads);
|
||||
}
|
||||
|
||||
private class GroupUpdate extends Transaction {
|
||||
public GroupUpdate(ThreadLink threads) {
|
||||
super(threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveState(Block from, Block to) {
|
||||
moveMetaState(from, to);
|
||||
|
||||
super.moveState(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(BlockState state) {
|
||||
Block block = state.getLocation().getBlock();
|
||||
boolean store = state.isRestricted() || mod.getConfig().getLogSurvival();
|
||||
|
||||
setMetaBlock(block, store ? state : null);
|
||||
|
||||
super.setState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeState(Block block) {
|
||||
setMetaBlock(block, null);
|
||||
|
||||
super.setState(block);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata-Interface for the Thread-Link
|
||||
*/
|
||||
public HasBlockState getMetaState(Block block) {
|
||||
return getMetaBlock(block);
|
||||
}
|
||||
/**
|
||||
* Metadata-Interface for the Thread-Link
|
||||
*/
|
||||
public void setMetaState(Block block, BlockState state) {
|
||||
super.setMetaBlock(block, state);
|
||||
}
|
||||
public void setSimpleMetaDataState(Block block, BlockState state) {
|
||||
if (state == null)
|
||||
super.setMetaBlock(block, null);
|
||||
else if (state.isRestricted())
|
||||
block.setMetadata(BSMDKEY, metadataSetRestricted);
|
||||
else
|
||||
block.setMetadata(BSMDKEY, metadataSet);
|
||||
}
|
||||
protected HasBlockState getMetaBlock(Metadatable m) {
|
||||
HasBlockState has = new HasBlockState();
|
||||
List<MetadataValue> metadata = m.getMetadata(BSMDKEY);
|
||||
for (MetadataValue v : metadata) {
|
||||
if (v.value() instanceof BlockState) {
|
||||
has.set = true;
|
||||
has.state = (BlockState) v.value();
|
||||
has.dbSet = true;
|
||||
has.restricted = has.state.isRestricted();
|
||||
break;
|
||||
} else if (v.getOwningPlugin() == mod.getPlugin()) {
|
||||
if (v == metadataNull) {
|
||||
has.set = true;
|
||||
has.state = null;
|
||||
} else if (v == metadataSet) {
|
||||
has.set = true;
|
||||
has.state = null;
|
||||
has.dbSet = true;
|
||||
} else if (v == metadataSetRestricted) {
|
||||
has.set = true;
|
||||
has.state = null;
|
||||
has.dbSet = true;
|
||||
has.restricted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return has;
|
||||
}
|
||||
public static class HasBlockState extends AbstractModel.HasBlockState {
|
||||
public boolean dbSet = false;
|
||||
public boolean restricted = false;
|
||||
}
|
||||
|
||||
public ModBlockStates getModel() {
|
||||
return mod;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* @internal Executed from asynchronous Thread. Only Thread-Safe methods should be called.
|
||||
*/
|
||||
void process(ThreadLink link, DBQueries q);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.Cuboid;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
public class CacheChunkAction implements Action {
|
||||
private static final int CHUNK_SIZE = 16;
|
||||
|
||||
private Chunk chunk;
|
||||
|
||||
public CacheChunkAction(Chunk chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ThreadLink link, DBQueries q) {
|
||||
if (!chunk.isLoaded())
|
||||
return;
|
||||
Set<Block> knownBlocks = new HashSet<Block>();
|
||||
try {
|
||||
for (BlockState state : q.findAllIn(getBlocks())) {
|
||||
Block b = state.getLocation().getBlock();
|
||||
knownBlocks.add(b);
|
||||
link.setSimpleMetaState(b, state);
|
||||
}
|
||||
/*int h = chunk.getWorld().getMaxHeight();
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < CHUNK_SIZE; x++) {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
Block b = chunk.getBlock(x, y, z);
|
||||
if (!knownBlocks.contains(b) && b.getType() != Material.AIR) {
|
||||
link.setSimpleMetaState(b, null);
|
||||
link.blockCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
} catch (SQLException e) {
|
||||
link.getLog().severe(e.getMessage());
|
||||
link.getLog().warn("Thread " + Thread.currentThread().getName() + " failed to load BlockStates for Chunk " + chunk.getX() + "/" + chunk.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
protected Cuboid getBlocks() {
|
||||
Cuboid c = new Cuboid();
|
||||
c.add(chunk.getBlock(0, 0, 0).getLocation());
|
||||
|
||||
int h = chunk.getWorld().getMaxHeight();
|
||||
c.add(chunk.getBlock(CHUNK_SIZE - 1, h - 1, CHUNK_SIZE - 1).getLocation());
|
||||
return c;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
public abstract class CallableAction<E> implements Action {
|
||||
protected boolean returnSet = false;
|
||||
protected E returnValue = null;
|
||||
|
||||
public E getValue() {
|
||||
synchronized (this) {
|
||||
try {
|
||||
while (!returnSet)
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
public class FetchBlockStateAction extends CallableAction<BlockState> {
|
||||
private Block block;
|
||||
|
||||
public FetchBlockStateAction(Block block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ThreadLink link, DBQueries q) {
|
||||
BlockState state = null;
|
||||
try {
|
||||
state = q.find(block.getLocation());
|
||||
link.setMetaState(block, state);
|
||||
} catch (SQLException e) {
|
||||
link.getLog().severe(e.getMessage());
|
||||
link.getLog().warn("Thread " + Thread.currentThread().getName() + " failed to fetch BlockState from DB: " + block.getLocation());
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
returnValue = state;
|
||||
returnSet = true;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.Cuboid;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
public class FetchCuboidAction extends CallableAction<List<BlockState>> {
|
||||
private Cuboid cuboid;
|
||||
|
||||
public FetchCuboidAction(Cuboid cuboid) {
|
||||
this.cuboid = cuboid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ThreadLink link, DBQueries q) {
|
||||
List<BlockState> states = null;
|
||||
try {
|
||||
states = q.findAllIn(cuboid);
|
||||
for (BlockState bs : states) {
|
||||
link.setMetaState(bs.getLocation().getBlock(), bs);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
link.getLog().severe(e.getMessage());
|
||||
link.getLog().warn("Thread " + Thread.currentThread().getName() + " failed to fetch BlockState from DB: " + cuboid);
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
returnValue = states;
|
||||
returnSet = true;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
public class MoveBlockStateAction extends TransactionAction implements Action {
|
||||
private Location from;
|
||||
private Location to;
|
||||
|
||||
public MoveBlockStateAction(Location from, Location to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ThreadLink link, DBQueries q) {
|
||||
try {
|
||||
processInTransaction(link, q);
|
||||
} catch (SQLException e) {
|
||||
link.getLog().severe(e.getMessage());
|
||||
link.getLog().warn("Thread " + Thread.currentThread().getName() + " failed to move BlockState in DB from " + from.toString() + " to " + to.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processInTransaction(ThreadLink link, DBQueries q) throws SQLException {
|
||||
q.delete(to);
|
||||
q.move(from, to);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.jaschastarke.bukkit.lib.ModuleLogger;
|
||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.AbstractModel.HasBlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.Cuboid;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.ThreadedModel;
|
||||
|
||||
public class ThreadLink {
|
||||
private static final int BATCH_ACTION_LENGTH = 10;
|
||||
private Stack<Action> updateQueue = new Stack<Action>();
|
||||
|
||||
private boolean shutdown = false;
|
||||
private ModuleLogger log;
|
||||
private ThreadedModel model;
|
||||
private Thread thread;
|
||||
|
||||
public ThreadLink(ThreadedModel threadedModel, DBQueries queries) {
|
||||
model = threadedModel;
|
||||
log = threadedModel.getModel().getLog();
|
||||
|
||||
/*
|
||||
* In theory we could add multiple threads, e.g. 1 write and 2 read threads.
|
||||
*/
|
||||
thread = new DBThread(queries);
|
||||
thread.setName("LC BlockState DB-Thread");
|
||||
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable e) {
|
||||
e.printStackTrace();
|
||||
log.severe("Thread " + thread.getName() + " encoutered an uncaught Exception: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class DBThread extends Thread {
|
||||
private DBQueries q;
|
||||
public DBThread(DBQueries queries) {
|
||||
super();
|
||||
this.q = queries;
|
||||
}
|
||||
public void run() {
|
||||
if (getModule().isDebug())
|
||||
log.debug("DB-Thread '" + Thread.currentThread().getName() + "' started.");
|
||||
while (!shutdown || !updateQueue.isEmpty()) {
|
||||
try {
|
||||
List<Action> acts = new LinkedList<Action>();
|
||||
synchronized (updateQueue) {
|
||||
while (updateQueue.isEmpty() && !shutdown)
|
||||
updateQueue.wait();
|
||||
for (int i = 0; i < BATCH_ACTION_LENGTH && !updateQueue.isEmpty(); i++) {
|
||||
acts.add(updateQueue.pop());
|
||||
}
|
||||
}
|
||||
if (getModule().isDebug())
|
||||
log.debug("DB-Thread '" + Thread.currentThread().getName() + "' run: " + acts.size());
|
||||
for (Action act : acts) {
|
||||
if (!shutdown || !(act instanceof CacheChunkAction)) {
|
||||
if (act instanceof CallableAction) {
|
||||
synchronized (act) {
|
||||
act.process(ThreadLink.this, this.q);
|
||||
act.notify();
|
||||
}
|
||||
} else {
|
||||
act.process(ThreadLink.this, this.q);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
log.severe("DB-Thread '" + Thread.currentThread().getName() + "' was harmfull interupted");
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
if (getModule().isDebug())
|
||||
log.debug("DB-Thread " + Thread.currentThread().getName() + " finished.");
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (!thread.isAlive())
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
public void queueUpdate(Block block) {
|
||||
synchronized (updateQueue) {
|
||||
updateQueue.add(new UpdateBlockStateAction(block));
|
||||
updateQueue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState callUpdate(Block block) {
|
||||
FetchBlockStateAction action = new FetchBlockStateAction(block);
|
||||
synchronized (updateQueue) {
|
||||
updateQueue.push(action);
|
||||
updateQueue.notify();
|
||||
}
|
||||
return action.getValue();
|
||||
}
|
||||
|
||||
public List<BlockState> callUpdate(Cuboid c) {
|
||||
FetchCuboidAction action = new FetchCuboidAction(c);
|
||||
synchronized (updateQueue) {
|
||||
updateQueue.push(action);
|
||||
updateQueue.notify();
|
||||
}
|
||||
return action.getValue();
|
||||
}
|
||||
|
||||
public void queueMetaMove(Location from, Location to) {
|
||||
synchronized (updateQueue) {
|
||||
updateQueue.add(new MoveBlockStateAction(from, to));
|
||||
updateQueue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void queueChunkLoad(Chunk chunk) {
|
||||
synchronized (updateQueue) {
|
||||
updateQueue.add(new CacheChunkAction(chunk));
|
||||
updateQueue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void queueTransaction(Transaction transaction) {
|
||||
synchronized (updateQueue) {
|
||||
updateQueue.add(transaction);
|
||||
updateQueue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() throws InterruptedException {
|
||||
synchronized (updateQueue) {
|
||||
shutdown = true;
|
||||
updateQueue.notify();
|
||||
}
|
||||
thread.join();
|
||||
}
|
||||
|
||||
public HasBlockState getMetaState(Block block) {
|
||||
return model.getMetaState(block);
|
||||
}
|
||||
public void setMetaState(Block block, BlockState state) {
|
||||
model.setMetaState(block, state);
|
||||
}
|
||||
public void setSimpleMetaState(Block block, BlockState state) {
|
||||
model.setSimpleMetaDataState(block, state);
|
||||
}
|
||||
|
||||
public ModBlockStates getModule() {
|
||||
return model.getModel();
|
||||
}
|
||||
|
||||
public ModuleLogger getLog() {
|
||||
return log;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.DBTransaction;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
abstract public class Transaction implements DBTransaction, Action {
|
||||
protected boolean finished = false;
|
||||
private List<TransactionAction> actions = new LinkedList<TransactionAction>();
|
||||
private ThreadLink link;
|
||||
|
||||
public Transaction(ThreadLink link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveState(Block from, Block to) {
|
||||
if (finished)
|
||||
throw new IllegalAccessError("Transaction already ended");
|
||||
|
||||
actions.add(new MoveBlockStateAction(from.getLocation(), to.getLocation()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(BlockState state) {
|
||||
if (finished)
|
||||
throw new IllegalAccessError("Transaction already ended");
|
||||
|
||||
Block block = state.getLocation().getBlock();
|
||||
actions.add(new UpdateBlockStateAction(block));
|
||||
}
|
||||
|
||||
public void setState(Block block) {
|
||||
if (finished)
|
||||
throw new IllegalAccessError("Transaction already ended");
|
||||
|
||||
actions.add(new UpdateBlockStateAction(block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (finished)
|
||||
return;
|
||||
link.queueTransaction(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Executed from asynchronous Thread. Only Thread-Safe methods should be called.
|
||||
*/
|
||||
@Override
|
||||
public void process(ThreadLink link, DBQueries q) {
|
||||
if (actions.isEmpty())
|
||||
return;
|
||||
try {
|
||||
q.getDB().startTransaction();
|
||||
for (TransactionAction act : actions) {
|
||||
act.processInTransaction(link, q);
|
||||
}
|
||||
q.getDB().endTransaction();
|
||||
} catch (SQLException e) {
|
||||
try {
|
||||
q.getDB().revertTransaction();
|
||||
} catch (SQLException e1) {}
|
||||
link.getLog().severe(e.getMessage());
|
||||
link.getLog().warn("Thread " + Thread.currentThread().getName() + " failed to write Transaction to the Database");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
abstract public class TransactionAction implements Action {
|
||||
abstract public void processInTransaction(ThreadLink link, DBQueries q) throws SQLException;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.thread;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.AbstractModel.HasBlockState;
|
||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries;
|
||||
|
||||
public class UpdateBlockStateAction extends TransactionAction implements Action {
|
||||
private Block block;
|
||||
public UpdateBlockStateAction(Block block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ThreadLink link, DBQueries q) {
|
||||
HasBlockState state = link.getMetaState(block);
|
||||
if (state.set) {
|
||||
try {
|
||||
q.delete(block.getLocation());
|
||||
if (state.state != null)
|
||||
q.insert(state.state);
|
||||
} catch (SQLException e) {
|
||||
link.getLog().severe(e.getMessage());
|
||||
link.getLog().warn("Thread " + Thread.currentThread().getName() + " failed to save BlockState to DB: " + state.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processInTransaction(ThreadLink link, DBQueries q) throws SQLException {
|
||||
HasBlockState state = link.getMetaState(block);
|
||||
if (state.set) {
|
||||
q.delete(block.getLocation());
|
||||
if (state.state != null)
|
||||
q.insert(state.state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.blockstate.worldedit;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
@ -153,24 +152,19 @@ public class LCEditSessionFactory extends EditSessionFactory {
|
|||
public boolean onBlockEdit(LocalPlayer player, Vector pt, BaseBlock block) {
|
||||
if (player != null) {
|
||||
Location loc = new Location(((BukkitWorld) player.getWorld()).getWorld(), pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
try {
|
||||
BlockState s = mod.getModel().getState(loc.getBlock());
|
||||
if (s == null) {
|
||||
s = new BlockState();
|
||||
s.setLocation(loc);
|
||||
}
|
||||
s.setGameMode(null);
|
||||
s.setPlayerName(player.getName());
|
||||
s.setDate(new Date());
|
||||
s.setSource(Source.EDIT);
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
|
||||
mod.getModel().setState(s);
|
||||
} catch (SQLException e) {
|
||||
mod.getLog().warn("DB-Error while onBlockEdit: "+e.getMessage());
|
||||
return false;
|
||||
BlockState s = mod.getModel().getState(loc.getBlock());
|
||||
if (s == null) {
|
||||
s = new BlockState();
|
||||
s.setLocation(loc);
|
||||
}
|
||||
s.setGameMode(null);
|
||||
s.setPlayerName(player.getName());
|
||||
s.setDate(new Date());
|
||||
s.setSource(Source.EDIT);
|
||||
if (mod.isDebug())
|
||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||
|
||||
mod.getModel().setState(s);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue