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;
|
package de.jaschastarke.minecraft.limitedcreative;
|
||||||
|
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
import de.jaschastarke.bukkit.lib.CoreModule;
|
import de.jaschastarke.bukkit.lib.CoreModule;
|
||||||
import de.jaschastarke.bukkit.lib.commands.AliasHelpedCommand;
|
import de.jaschastarke.bukkit.lib.commands.AliasHelpedCommand;
|
||||||
import de.jaschastarke.bukkit.lib.modules.AdditionalBlockBreaks;
|
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.BlockStateCommand;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockStateConfig;
|
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockStateConfig;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel;
|
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.DependencyListener;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.HangingListener;
|
import de.jaschastarke.minecraft.limitedcreative.blockstate.HangingListener;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.PlayerListener;
|
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.minecraft.limitedcreative.blockstate.worldedit.LCEditSessionFactory;
|
||||||
import de.jaschastarke.modularize.IModule;
|
import de.jaschastarke.modularize.IModule;
|
||||||
import de.jaschastarke.modularize.ModuleEntry;
|
import de.jaschastarke.modularize.ModuleEntry;
|
||||||
|
@ -19,7 +22,6 @@ import de.jaschastarke.modularize.ModuleEntry.ModuleState;
|
||||||
public class ModBlockStates extends CoreModule<LimitedCreative> {
|
public class ModBlockStates extends CoreModule<LimitedCreative> {
|
||||||
private BlockStateConfig config;
|
private BlockStateConfig config;
|
||||||
private FeatureBlockItemSpawn blockDrops;
|
private FeatureBlockItemSpawn blockDrops;
|
||||||
private DBQueries queries;
|
|
||||||
private BlockStateCommand command;
|
private BlockStateCommand command;
|
||||||
private DBModel model;
|
private DBModel model;
|
||||||
|
|
||||||
|
@ -56,8 +58,15 @@ public class ModBlockStates extends CoreModule<LimitedCreative> {
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
try {
|
try {
|
||||||
queries = new DBQueries(this, getPlugin().getDatabaseConnection());
|
if (model == null) {
|
||||||
queries.initTable();
|
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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
getLog().warn(plugin.getLocale().trans("block_state.error.sql_connection_failed", getName()));
|
getLog().warn(plugin.getLocale().trans("block_state.error.sql_connection_failed", getName()));
|
||||||
|
@ -79,7 +88,11 @@ public class ModBlockStates extends CoreModule<LimitedCreative> {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
model.onDisable();
|
||||||
super.onDisable();
|
super.onDisable();
|
||||||
|
if (model instanceof Listener)
|
||||||
|
listeners.removeListener((Listener) model);
|
||||||
|
model = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockStateConfig getConfig() {
|
public BlockStateConfig getConfig() {
|
||||||
|
@ -88,12 +101,7 @@ public class ModBlockStates extends CoreModule<LimitedCreative> {
|
||||||
public FeatureBlockItemSpawn getBlockSpawn() {
|
public FeatureBlockItemSpawn getBlockSpawn() {
|
||||||
return blockDrops;
|
return blockDrops;
|
||||||
}
|
}
|
||||||
public DBQueries getQueries() {
|
|
||||||
return queries;
|
|
||||||
}
|
|
||||||
public DBModel getModel() {
|
public DBModel getModel() {
|
||||||
if (model == null)
|
|
||||||
model = new DBModel(this);
|
|
||||||
return model;
|
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;
|
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -21,6 +20,7 @@ import org.bukkit.metadata.FixedMetadataValue;
|
||||||
|
|
||||||
import de.jaschastarke.bukkit.lib.events.BlockDestroyedEvent;
|
import de.jaschastarke.bukkit.lib.events.BlockDestroyedEvent;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||||
|
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.DBTransaction;
|
||||||
|
|
||||||
public class BlockListener implements Listener {
|
public class BlockListener implements Listener {
|
||||||
private ModBlockStates mod;
|
private ModBlockStates mod;
|
||||||
|
@ -30,96 +30,62 @@ public class BlockListener implements Listener {
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
try {
|
if (mod.getModel().isRestricted(event.getBlock())) {
|
||||||
BlockState s = mod.getModel().getState(event.getBlock());
|
|
||||||
if (s != null) {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Breaking bad, err.. block: " + s.toString());
|
mod.getLog().debug("Breaking bad, err.. block: " + event.getBlock().getLocation().toString());
|
||||||
|
|
||||||
if (s.isRestricted() && event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
if (event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||||
mod.getBlockSpawn().block(event.getBlock(), event.getPlayer());
|
mod.getBlockSpawn().block(event.getBlock(), event.getPlayer());
|
||||||
event.setExpToDrop(0);
|
event.setExpToDrop(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod.getModel().removeState(s);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onBlockBreak: "+e.getMessage());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
|
mod.getModel().removeState(event.getBlock());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onOtherBlockDestroy(BlockDestroyedEvent event) {
|
public void onOtherBlockDestroy(BlockDestroyedEvent event) {
|
||||||
try {
|
if (mod.getModel().isRestricted(event.getBlock())) {
|
||||||
BlockState s = mod.getModel().getState(event.getBlock());
|
|
||||||
if (s != null) {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Breaking attached block: " + s.toString());
|
mod.getLog().debug("Breaking attached block: " + event.getBlock().getLocation().toString());
|
||||||
|
|
||||||
if (s.isRestricted()) {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||||
mod.getBlockSpawn().block(event.getBlock());
|
mod.getBlockSpawn().block(event.getBlock());
|
||||||
}
|
}
|
||||||
|
mod.getModel().removeState(event.getBlock());
|
||||||
mod.getModel().removeState(s);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onBlockBreak: "+e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onBlocksBreakByExplosion(EntityExplodeEvent event) {
|
public void onBlocksBreakByExplosion(EntityExplodeEvent event) {
|
||||||
try {
|
Map<Block, Boolean> states = mod.getModel().getRestrictedStates(event.blockList());
|
||||||
Map<Block, BlockState> states = mod.getModel().getStates(event.blockList());
|
DBTransaction update = mod.getModel().groupUpdate();
|
||||||
for (Block block : event.blockList()) {
|
for (Block block : event.blockList()) {
|
||||||
BlockState s = states.get(block);
|
|
||||||
if (s != null) {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Breaking bad, err.. block: " + s.toString());
|
mod.getLog().debug("Breaking bad, err.. block: " + block.getLocation().toString());
|
||||||
|
|
||||||
if (s.isRestricted()) {
|
if (states.get(block)) {
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
mod.getLog().debug("... was placed by creative. Drop prevented");
|
||||||
mod.getBlockSpawn().block(block);
|
mod.getBlockSpawn().block(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod.getModel().removeState(s);
|
update.removeState(block);
|
||||||
}
|
}
|
||||||
|
update.finish();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onBlockBreakByExplosion: "+e.getMessage());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onBlockPlace(BlockPlaceEvent event) {
|
public void onBlockPlace(BlockPlaceEvent event) {
|
||||||
try {
|
BlockState s = new BlockState();
|
||||||
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.setLocation(event.getBlock().getLocation());
|
||||||
}
|
|
||||||
s.setPlayer(event.getPlayer());
|
s.setPlayer(event.getPlayer());
|
||||||
s.setDate(new Date());
|
s.setDate(new Date());
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||||
|
|
||||||
mod.getModel().setState(s);
|
mod.getModel().setState(s);
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onBlockPlace: "+e.getMessage());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
|
@ -138,25 +104,16 @@ public class BlockListener implements Listener {
|
||||||
source = source.getRelative(event.getDirection());
|
source = source.getRelative(event.getDirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
if (movedBlocks.size() > 0) {
|
if (movedBlocks.size() > 0) {
|
||||||
mod.getQueries().getDB().startTransaction();
|
DBTransaction update = mod.getModel().groupUpdate();
|
||||||
for (Block sblock : movedBlocks) {
|
for (Block sblock : movedBlocks) {
|
||||||
Block dest = sblock.getRelative(event.getDirection());
|
Block dest = sblock.getRelative(event.getDirection());
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("PistionExtend moves "+sblock.getType()+"-Block from "+sblock.getLocation()+" to "+dest.getLocation());
|
mod.getLog().debug("PistionExtend moves "+sblock.getType()+"-Block from "+sblock.getLocation()+" to "+dest.getLocation());
|
||||||
|
|
||||||
mod.getModel().moveState(sblock, dest);
|
update.moveState(sblock, dest);
|
||||||
}
|
}
|
||||||
mod.getQueries().getDB().endTransaction();
|
update.finish();
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
try {
|
|
||||||
mod.getQueries().getDB().revertTransaction();
|
|
||||||
} catch (SQLException e1) {
|
|
||||||
}
|
|
||||||
mod.getLog().warn("DB-Error while onBlockMove (extend): "+e.getMessage());
|
|
||||||
//event.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,18 +124,9 @@ public class BlockListener implements Listener {
|
||||||
Block dest = event.getBlock().getRelative(event.getDirection());
|
Block dest = event.getBlock().getRelative(event.getDirection());
|
||||||
Block source = dest.getRelative(event.getDirection());
|
Block source = dest.getRelative(event.getDirection());
|
||||||
if (event.isSticky() && source.getType() != Material.AIR) {
|
if (event.isSticky() && source.getType() != Material.AIR) {
|
||||||
try {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("PistionRetract moves "+source.getType()+"-Block from "+source.getLocation()+" to "+dest.getLocation());
|
mod.getLog().debug("PistionRetract moves "+source.getType()+"-Block from "+source.getLocation()+" to "+dest.getLocation());
|
||||||
mod.getModel().moveState(source, source.getRelative(event.getDirection().getOppositeFace()));
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
|
@ -25,7 +24,8 @@ import de.jaschastarke.maven.ArchiveDocComments;
|
||||||
import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission;
|
import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState.Source;
|
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)
|
* LimitedCreative-BlockState-Command: modify blockstate database to prevent drops of selected blocks (requires WorldEdit)
|
||||||
|
@ -130,9 +130,7 @@ public class BlockStateCommand extends BukkitCommand implements IHelpDescribed {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Scheduler: Asynchronous Task run");
|
mod.getLog().debug("Scheduler: Asynchronous Task run");
|
||||||
DBQueries q = mod.getQueries();
|
DBTransaction update = mod.getModel().groupUpdate();
|
||||||
try {
|
|
||||||
q.getDB().startTransaction();
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
World w = selection.getWorld();
|
World w = selection.getWorld();
|
||||||
|
|
||||||
|
@ -152,23 +150,15 @@ public class BlockStateCommand extends BukkitCommand implements IHelpDescribed {
|
||||||
Location loc = new Location(w, x, y, z);
|
Location loc = new Location(w, x, y, z);
|
||||||
if (w.getBlockAt(loc).getType() != Material.AIR && selection.contains(loc)) {
|
if (w.getBlockAt(loc).getType() != Material.AIR && selection.contains(loc)) {
|
||||||
seed.setLocation(loc);
|
seed.setLocation(loc);
|
||||||
mod.getModel().setState(new BlockState(seed));
|
update.setState(new BlockState(seed));
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q.getDB().endTransaction();
|
update.finish();
|
||||||
|
|
||||||
context.response(L("command.blockstate.command_updated", count));
|
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"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -43,6 +43,11 @@ public class BlockStateConfig extends Configuration implements IConfigurationSub
|
||||||
} else {
|
} else {
|
||||||
entry.disable();
|
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);
|
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
|
* BlockStateTool
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,149 +1,86 @@
|
||||||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
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;
|
public interface DBModel {
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.DBQueries.Cuboid;
|
public static class Cuboid {
|
||||||
|
private World w = null;
|
||||||
public class DBModel {
|
private int minx, miny, minz;
|
||||||
private static final String BSMDKEY = "blockstate";
|
private int maxx, maxy, maxz;
|
||||||
private ModBlockStates mod;
|
public void add(Location loc) {
|
||||||
private DBQueries q;
|
if (w == null) {
|
||||||
|
w = loc.getWorld();
|
||||||
public DBModel(ModBlockStates mod) {
|
minx = maxx = loc.getBlockX();
|
||||||
this.mod = mod;
|
miny = maxy = loc.getBlockY();
|
||||||
this.q = mod.getQueries();
|
minz = maxz = loc.getBlockZ();
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
removeMetaBlock(to);
|
if (w != loc.getWorld())
|
||||||
}
|
throw new IllegalArgumentException("Point is from a different world");
|
||||||
setMetaBlock(from, null);
|
if (minx > loc.getBlockX())
|
||||||
}
|
minx = loc.getBlockX();
|
||||||
public void removeState(BlockState state) throws SQLException {
|
if (maxx < loc.getBlockX())
|
||||||
//removeMetaBlock(state.getLocation().getBlock());
|
maxx = loc.getBlockX();
|
||||||
setMetaBlock(state.getLocation().getBlock(), null);
|
if (miny > loc.getBlockY())
|
||||||
q.delete(state);
|
miny = loc.getBlockY();
|
||||||
}
|
if (maxy < loc.getBlockY())
|
||||||
public Map<Block, BlockState> getStates(List<Block> blocks) throws SQLException {
|
maxy = loc.getBlockY();
|
||||||
Map<Block, BlockState> ret = new HashMap<Block, BlockState>();
|
if (minz > loc.getBlockZ())
|
||||||
|
minz = loc.getBlockZ();
|
||||||
Cuboid c = new Cuboid();
|
if (maxz < loc.getBlockZ())
|
||||||
for (Block block : blocks) {
|
maxz = loc.getBlockZ();
|
||||||
HasBlockState has = getMetaBlock(block);
|
|
||||||
if (has.set) {
|
|
||||||
ret.put(block, has.state);
|
|
||||||
} else {
|
|
||||||
c.add(block.getLocation());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!c.isEmpty()) {
|
public int getMinX() {
|
||||||
List<BlockState> dbb = q.findAllIn(c);
|
return minx;
|
||||||
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) {
|
public int getMinY() {
|
||||||
if (!ret.containsKey(block)) {
|
return miny;
|
||||||
ret.put(block, null);
|
|
||||||
setMetaBlock(block, null);
|
|
||||||
}
|
}
|
||||||
|
public int getMinZ() {
|
||||||
|
return minz;
|
||||||
}
|
}
|
||||||
|
public int getMaxX() {
|
||||||
|
return maxx;
|
||||||
}
|
}
|
||||||
/*for (Block block : blocks) {
|
public int getMaxY() {
|
||||||
if (ret.containsKey(block))
|
return maxy;
|
||||||
ret.put(block, getState(block));
|
|
||||||
}*/
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
public void cacheStates(Cuboid c) throws SQLException {
|
public int getMaxZ() {
|
||||||
if (!c.isEmpty()) {
|
return maxz;
|
||||||
List<BlockState> dbb = q.findAllIn(c);
|
|
||||||
for (BlockState bs : dbb) {
|
|
||||||
setMetaBlock(bs.getLocation().getBlock(), bs);
|
|
||||||
}
|
}
|
||||||
|
public World getWorld() {
|
||||||
|
return w;
|
||||||
}
|
}
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return w == null;
|
||||||
}
|
}
|
||||||
public BlockState getState(Block block) throws SQLException {
|
public String toString() {
|
||||||
HasBlockState has = getMetaBlock(block);
|
return "Cuboid{world="+w.getName()+", min_x="+minx+", max_x="+maxx+", min_y="+miny+", max_y="+maxy+", min_z="+minz+", max_z="+maxz+"}";
|
||||||
if (!has.set) {
|
|
||||||
BlockState state = q.find(block.getLocation());
|
|
||||||
setMetaBlock(block, state);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hasMetaBlock(Metadatable m) {
|
public void onEnable() throws Exception;
|
||||||
List<MetadataValue> metadata = m.getMetadata(BSMDKEY);
|
public void onDisable();
|
||||||
for (MetadataValue v : metadata) {
|
public void moveState(Block from, Block to);
|
||||||
if (v.value() instanceof BlockState)
|
public void removeState(BlockState state);
|
||||||
return true;
|
public void removeState(Block block);
|
||||||
}
|
public Map<Block, BlockState> getStates(List<Block> blocks);
|
||||||
return false;
|
public Map<Block, Boolean> getRestrictedStates(List<Block> blocks);
|
||||||
}
|
public void cacheStates(DBModel.Cuboid c);
|
||||||
protected void setMetaBlock(Metadatable m, BlockState s) {
|
public BlockState getState(Block block);
|
||||||
if (s == null)
|
public boolean isRestricted(Block block);
|
||||||
m.setMetadata(BSMDKEY, new FixedMetadataValue(mod.getPlugin(), new Boolean(false)));
|
public void setState(BlockState state);
|
||||||
else
|
public DBTransaction groupUpdate();
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class HasBlockState {
|
public static interface DBTransaction {
|
||||||
public boolean set = false;
|
public void moveState(Block from, Block to);
|
||||||
public BlockState state = null;
|
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.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
import de.jaschastarke.database.Type;
|
import de.jaschastarke.database.Type;
|
||||||
import de.jaschastarke.database.db.Database;
|
import de.jaschastarke.database.db.Database;
|
||||||
|
@ -49,7 +48,7 @@ public class DBQueries {
|
||||||
}
|
}
|
||||||
|
|
||||||
private PreparedStatement findall = null;
|
private PreparedStatement findall = null;
|
||||||
public List<BlockState> findAllIn(Cuboid c) throws SQLException {
|
public List<BlockState> findAllIn(DBModel.Cuboid c) throws SQLException {
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("DBQuery: findAllIn: " + c.toString());
|
mod.getLog().debug("DBQuery: findAllIn: " + c.toString());
|
||||||
List<BlockState> blocks = new ArrayList<BlockState>();
|
List<BlockState> blocks = new ArrayList<BlockState>();
|
||||||
|
@ -268,60 +267,4 @@ public class DBQueries {
|
||||||
public Database getDB() {
|
public Database getDB() {
|
||||||
return db;
|
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;
|
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
|
@ -14,7 +13,6 @@ import org.bukkit.event.hanging.HangingPlaceEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||||
|
|
||||||
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
import de.jaschastarke.minecraft.limitedcreative.ModBlockStates;
|
||||||
import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState.Source;
|
|
||||||
|
|
||||||
public class HangingListener implements Listener {
|
public class HangingListener implements Listener {
|
||||||
private ModBlockStates mod;
|
private ModBlockStates mod;
|
||||||
|
@ -25,24 +23,18 @@ public class HangingListener implements Listener {
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||||
if (event.getRightClicked() instanceof ItemFrame) {
|
if (event.getRightClicked() instanceof ItemFrame) {
|
||||||
try {
|
if (mod.getModel().isRestricted(event.getRightClicked().getLocation().getBlock())) {
|
||||||
BlockState s = mod.getModel().getState(event.getRightClicked().getLocation().getBlock());
|
|
||||||
if (s != null) {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Modifying hanging: " + s.toString());
|
mod.getLog().debug("Modifying hanging: " + event.getRightClicked().getLocation().toString());
|
||||||
|
|
||||||
if ((s.getGameMode() == GameMode.CREATIVE || s.getSource() == Source.EDIT) && event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
if (event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("... was placed by creative. Modify prevented");
|
mod.getLog().debug("... was placed by creative. Modify prevented");
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
s.setPlayer(event.getPlayer());
|
|
||||||
s.setDate(new Date());
|
|
||||||
mod.getModel().setState(s);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s = new BlockState();
|
BlockState s = new BlockState();
|
||||||
s.setLocation(event.getRightClicked().getLocation().getBlock().getLocation());
|
s.setLocation(event.getRightClicked().getLocation().getBlock().getLocation());
|
||||||
s.setPlayer(event.getPlayer());
|
s.setPlayer(event.getPlayer());
|
||||||
s.setDate(new Date());
|
s.setDate(new Date());
|
||||||
|
@ -52,62 +44,38 @@ public class HangingListener implements Listener {
|
||||||
|
|
||||||
mod.getModel().setState(s);
|
mod.getModel().setState(s);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onHangingInteract: "+e.getMessage());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onHangingBreak(HangingBreakEvent event) {
|
public void onHangingBreak(HangingBreakEvent event) {
|
||||||
if (event.getEntity() instanceof ItemFrame) {
|
if (event.getEntity() instanceof ItemFrame) {
|
||||||
try {
|
|
||||||
BlockState s = mod.getModel().getState(event.getEntity().getLocation().getBlock());
|
|
||||||
if (s != null) {
|
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Breaking hanging: " + s.toString());
|
mod.getLog().debug("Breaking hanging: " + event.getEntity().getLocation().toString());
|
||||||
|
|
||||||
if (s.getGameMode() == GameMode.CREATIVE || s.getSource() == Source.EDIT) {
|
if (mod.getModel().isRestricted(event.getEntity().getLocation().getBlock())) {
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("... was placed by creative. Drop prevented");
|
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(), Material.ITEM_FRAME);
|
||||||
mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation(), ((ItemFrame) event.getEntity()).getItem().getType());
|
mod.getBlockSpawn().block(event.getEntity().getLocation().getBlock().getLocation(), ((ItemFrame) event.getEntity()).getItem().getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
mod.getModel().removeState(s);
|
mod.getModel().removeState(event.getEntity().getLocation().getBlock());
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onHangingBreak: "+e.getMessage());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
public void onHangingPlace(HangingPlaceEvent event) {
|
public void onHangingPlace(HangingPlaceEvent event) {
|
||||||
if (event.getEntity() instanceof ItemFrame) {
|
if (event.getEntity() instanceof ItemFrame) {
|
||||||
try {
|
BlockState s = new BlockState();
|
||||||
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.setLocation(event.getEntity().getLocation().getBlock().getLocation());
|
||||||
}
|
|
||||||
s.setPlayer(event.getPlayer());
|
s.setPlayer(event.getPlayer());
|
||||||
s.setDate(new Date());
|
s.setDate(new Date());
|
||||||
if (mod.isDebug())
|
if (mod.isDebug())
|
||||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||||
|
|
||||||
mod.getModel().setState(s);
|
mod.getModel().setState(s);
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onHangingPlace: "+e.getMessage());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
package de.jaschastarke.minecraft.limitedcreative.blockstate;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
@ -46,7 +44,6 @@ public class PlayerListener implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showInfo(Player pl, Location loc, Material type) {
|
private void showInfo(Player pl, Location loc, Material type) {
|
||||||
try {
|
|
||||||
BlockState s = mod.getModel().getState(loc.getBlock());
|
BlockState s = mod.getModel().getState(loc.getBlock());
|
||||||
InGameFormatter f = new InGameFormatter(mod.getPlugin().getLang());
|
InGameFormatter f = new InGameFormatter(mod.getPlugin().getLang());
|
||||||
String ret = null;
|
String ret = null;
|
||||||
|
@ -78,8 +75,5 @@ public class PlayerListener implements Listener {
|
||||||
}
|
}
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
pl.sendMessage(ret);
|
pl.sendMessage(ret);
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onPlayerInteract: "+e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package de.jaschastarke.minecraft.limitedcreative.blockstate.worldedit;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
@ -153,7 +152,6 @@ public class LCEditSessionFactory extends EditSessionFactory {
|
||||||
public boolean onBlockEdit(LocalPlayer player, Vector pt, BaseBlock block) {
|
public boolean onBlockEdit(LocalPlayer player, Vector pt, BaseBlock block) {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
Location loc = new Location(((BukkitWorld) player.getWorld()).getWorld(), pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
Location loc = new Location(((BukkitWorld) player.getWorld()).getWorld(), pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||||
try {
|
|
||||||
BlockState s = mod.getModel().getState(loc.getBlock());
|
BlockState s = mod.getModel().getState(loc.getBlock());
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
s = new BlockState();
|
s = new BlockState();
|
||||||
|
@ -167,10 +165,6 @@ public class LCEditSessionFactory extends EditSessionFactory {
|
||||||
mod.getLog().debug("Saving BlockState: " + s.toString());
|
mod.getLog().debug("Saving BlockState: " + s.toString());
|
||||||
|
|
||||||
mod.getModel().setState(s);
|
mod.getModel().setState(s);
|
||||||
} catch (SQLException e) {
|
|
||||||
mod.getLog().warn("DB-Error while onBlockEdit: "+e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue