Finish fixing bugs and downgrading
This commit is contained in:
parent
db76b314e5
commit
1126306c2c
11 changed files with 171 additions and 840 deletions
|
@ -38,8 +38,6 @@ import net.minecraftforge.registries.ForgeRegistries;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import dev.zontreck.libzontreck.chat.ChatColor;
|
import dev.zontreck.libzontreck.chat.ChatColor;
|
||||||
import dev.zontreck.otemod.antigrief.HealerManager;
|
|
||||||
import dev.zontreck.otemod.antigrief.HealerQueue;
|
|
||||||
import dev.zontreck.otemod.blocks.ModBlocks;
|
import dev.zontreck.otemod.blocks.ModBlocks;
|
||||||
import dev.zontreck.otemod.chat.ChatServerOverride;
|
import dev.zontreck.otemod.chat.ChatServerOverride;
|
||||||
import dev.zontreck.otemod.commands.CommandRegistry;
|
import dev.zontreck.otemod.commands.CommandRegistry;
|
||||||
|
@ -155,7 +153,7 @@ public class OTEMod
|
||||||
try {
|
try {
|
||||||
OTEMod.DB = new Database(this);
|
OTEMod.DB = new Database(this);
|
||||||
OTEMod.ALIVE=true;
|
OTEMod.ALIVE=true;
|
||||||
HealerQueue.Initialize(); // Set up the queue
|
//HealerQueue.Initialize(); // Set up the queue
|
||||||
|
|
||||||
|
|
||||||
// Validate that the database has been established and that tables exist
|
// Validate that the database has been established and that tables exist
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
package dev.zontreck.otemod.antigrief;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dev.zontreck.libzontreck.vectors.Vector3;
|
|
||||||
import dev.zontreck.libzontreck.vectors.WorldPosition;
|
|
||||||
import dev.zontreck.otemod.OTEMod;
|
|
||||||
import dev.zontreck.otemod.configs.OTEServerConfig;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.level.BlockEventData;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.event.entity.item.ItemEvent;
|
|
||||||
import net.minecraftforge.event.level.BlockEvent;
|
|
||||||
import net.minecraftforge.event.level.ChunkDataEvent;
|
|
||||||
import net.minecraftforge.event.level.ExplosionEvent;
|
|
||||||
import net.minecraftforge.event.level.BlockEvent.NeighborNotifyEvent;
|
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
||||||
import net.minecraftforge.fml.common.Mod;
|
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
|
||||||
|
|
||||||
@EventBusSubscriber(modid = OTEMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE)
|
|
||||||
public class Handler
|
|
||||||
{
|
|
||||||
private static final String EXPLOSION_HEAL_TAG = "OTEEH";
|
|
||||||
|
|
||||||
|
|
||||||
/*@OnlyIn(Dist.DEDICATED_SERVER)
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onChunkLoad(final ChunkDataEvent.Load event)
|
|
||||||
{
|
|
||||||
final CompoundTag EHTag = event.getData().getCompound(EXPLOSION_HEAL_TAG);
|
|
||||||
if(!EHTag.isEmpty())
|
|
||||||
{
|
|
||||||
final CompoundTag healer = EHTag.getCompound("healer");
|
|
||||||
if(!healer.isEmpty()){
|
|
||||||
// This would re-queue the healer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
@OnlyIn(Dist.DEDICATED_SERVER)
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onDetonation(ExplosionEvent.Detonate event)
|
|
||||||
{
|
|
||||||
ServerLevel level = (ServerLevel)event.getLevel();
|
|
||||||
|
|
||||||
Entity exploder = event.getExplosion().getExploder();
|
|
||||||
|
|
||||||
if(exploder==null)return ; // TODO: Make this check config
|
|
||||||
|
|
||||||
final Collection<StoredBlock> affectedBlocks = buildBlocks(level, event.getAffectedBlocks());
|
|
||||||
Collection<StoredBlock> toHeal = new ArrayList<StoredBlock>(affectedBlocks.size());
|
|
||||||
|
|
||||||
Block tnt = Blocks.TNT;
|
|
||||||
|
|
||||||
for(final StoredBlock data : affectedBlocks)
|
|
||||||
{
|
|
||||||
// Check an exclusions list
|
|
||||||
if(!OTEServerConfig.EXCLUDE_DIMENSIONS.get().contains(data.getWorldPosition().Dimension))
|
|
||||||
if(!data.getState().is(tnt))
|
|
||||||
toHeal.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process Block Entities
|
|
||||||
|
|
||||||
for(final StoredBlock sb : toHeal)
|
|
||||||
{
|
|
||||||
if(sb.getState().hasBlockEntity())
|
|
||||||
{
|
|
||||||
BlockEntity be = level.getBlockEntity(sb.getPos());
|
|
||||||
if(be != null){
|
|
||||||
sb.setBlockEntity(be);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the existing blocks from the world to prevent item duplication
|
|
||||||
// Begin
|
|
||||||
for(StoredBlock data : toHeal)
|
|
||||||
{
|
|
||||||
if(data.getBlockEntity()!=null)
|
|
||||||
data.getWorldPosition().getActualDimension().removeBlockEntity(data.getPos());
|
|
||||||
|
|
||||||
data.getWorldPosition().getActualDimension().destroyBlock(data.getPos(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to the healing queue
|
|
||||||
List<StoredBlock> mainList = new ArrayList<>();
|
|
||||||
mainList.addAll(toHeal);
|
|
||||||
mainList = HealerQueue.removeSame(mainList);
|
|
||||||
|
|
||||||
HealerWorker work = new HealerWorker(mainList);
|
|
||||||
HealerQueue.ManagerInstance.registerWorker(work);
|
|
||||||
Thread tx = new Thread(work);
|
|
||||||
tx.start();
|
|
||||||
|
|
||||||
HealerQueue.ToHeal.addAll(mainList);
|
|
||||||
|
|
||||||
|
|
||||||
HealerQueue.Pass=0;
|
|
||||||
|
|
||||||
HealerQueue.Shuffle();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<StoredBlock> buildBlocks(ServerLevel level, Collection<BlockPos> positions)
|
|
||||||
{
|
|
||||||
Collection<StoredBlock> healables = new LinkedList<StoredBlock>();
|
|
||||||
for(final BlockPos pos : positions)
|
|
||||||
{
|
|
||||||
final BlockState state = level.getBlockState(pos);
|
|
||||||
StoredBlock sb = new StoredBlock(pos, state, level);
|
|
||||||
|
|
||||||
if(state !=null)
|
|
||||||
healables.add(sb);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return healables;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
package dev.zontreck.otemod.antigrief;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dev.zontreck.otemod.OTEMod;
|
|
||||||
import dev.zontreck.otemod.configs.OTEServerConfig;
|
|
||||||
|
|
||||||
public class HealerManager implements Runnable
|
|
||||||
{
|
|
||||||
private List<HealerWorker> Workers = new ArrayList<>();
|
|
||||||
public HealerManager(){
|
|
||||||
|
|
||||||
}
|
|
||||||
public void registerWorker(HealerWorker worker)
|
|
||||||
{
|
|
||||||
Workers.add(worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deregisterWorker(HealerWorker worker)
|
|
||||||
{
|
|
||||||
Workers.remove(worker);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void run(){
|
|
||||||
boolean skipWait=false;
|
|
||||||
int skipCount=0;
|
|
||||||
long lastSave = 0;
|
|
||||||
final long saveInterval = (2*60); // Every 2 minutes
|
|
||||||
boolean lastWait = false;
|
|
||||||
// Heal pass 1 is set all positions to bedrock
|
|
||||||
// Pass 2 is assert all solid blocks (Not air)
|
|
||||||
// Pass 3 is to set the air blocks and remove bedrock
|
|
||||||
|
|
||||||
|
|
||||||
while(OTEMod.ALIVE)
|
|
||||||
{
|
|
||||||
try{
|
|
||||||
try{
|
|
||||||
if(!skipWait) Thread.sleep(OTEServerConfig.HEALER_TIMER.get());
|
|
||||||
}catch(Exception E){}
|
|
||||||
|
|
||||||
if(lastWait != OTEMod.HEALER_WAIT) OTEMod.LOGGER.info("Healer Wait Flag was Toggled");
|
|
||||||
lastWait = OTEMod.HEALER_WAIT;
|
|
||||||
if(OTEMod.HEALER_WAIT) continue; // Wait to process until import completes
|
|
||||||
|
|
||||||
if(!OTEMod.ALIVE) break; // Begin tear down, server has shut down
|
|
||||||
|
|
||||||
for (HealerWorker healerWorker : Workers) {
|
|
||||||
healerWorker.doTick=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}catch(Exception e){}
|
|
||||||
}
|
|
||||||
|
|
||||||
OTEMod.LOGGER.info("Tearing down healer jobs. Saving remaining queue, stand by...");
|
|
||||||
try {
|
|
||||||
HealerQueue.dump();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
OTEMod.LOGGER.info("Finished tearing down Healer - Good bye");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,327 +0,0 @@
|
||||||
package dev.zontreck.otemod.antigrief;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dev.zontreck.libzontreck.vectors.Vector3;
|
|
||||||
import dev.zontreck.libzontreck.vectors.WorldPosition;
|
|
||||||
import dev.zontreck.otemod.OTEMod;
|
|
||||||
import dev.zontreck.otemod.configs.OTEServerConfig;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.nbt.ListTag;
|
|
||||||
import net.minecraft.nbt.NbtIo;
|
|
||||||
import net.minecraft.nbt.NbtUtils;
|
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraftforge.fml.loading.FMLConfig;
|
|
||||||
import net.minecraftforge.fml.loading.FMLPaths;
|
|
||||||
|
|
||||||
public class HealerQueue {
|
|
||||||
// Healer Queue's data source is a NBT File in the config folder
|
|
||||||
public static final String HealerQueueFile = "OTEHealerLastQueue.nbt";
|
|
||||||
public static final String HealerQueueDebugFile = "OTEHealerLastQueue.snbt";
|
|
||||||
|
|
||||||
public static List<StoredBlock> ToHeal = new ArrayList<StoredBlock>(); // Air and Solid Blocks get set to bedrock initially
|
|
||||||
|
|
||||||
public static int Pass = 0;
|
|
||||||
|
|
||||||
|
|
||||||
private static List<StoredBlock> LastToHeal = new ArrayList<StoredBlock>();
|
|
||||||
private static int LastPass = 0;
|
|
||||||
|
|
||||||
public static HealerManager ManagerInstance=null;
|
|
||||||
|
|
||||||
|
|
||||||
public static Path getPath()
|
|
||||||
{
|
|
||||||
|
|
||||||
Path configDir = FMLPaths.GAMEDIR.get().resolve(FMLConfig.defaultConfigPath());
|
|
||||||
Path configFile = null;
|
|
||||||
if(OTEServerConfig.DEBUG_HEALER.get())
|
|
||||||
{
|
|
||||||
configFile = configDir.resolve(HealerQueue.HealerQueueDebugFile);
|
|
||||||
|
|
||||||
}else {
|
|
||||||
configFile = configDir.resolve(HealerQueue.HealerQueueFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
//OTEMod.LOGGER.info("OTE HEALER TEMPORARY FILE: "+configFile.toFile().getAbsolutePath());
|
|
||||||
return configFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StoredBlock locateHighestBlock(List<StoredBlock> list)
|
|
||||||
{
|
|
||||||
StoredBlock sb = null;
|
|
||||||
double currentY = 0;
|
|
||||||
for (StoredBlock storedBlock : ToHeal) {
|
|
||||||
if(storedBlock.getWorldPosition().Position.y > currentY)
|
|
||||||
{
|
|
||||||
currentY = storedBlock.getWorldPosition().Position.y;
|
|
||||||
sb=storedBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StoredBlock locateLowestBlock(List<StoredBlock> list)
|
|
||||||
{
|
|
||||||
StoredBlock sb = null;
|
|
||||||
double currentY = 300;
|
|
||||||
for (StoredBlock storedBlock : ToHeal) {
|
|
||||||
if(storedBlock.getWorldPosition().Position.y < currentY)
|
|
||||||
{
|
|
||||||
currentY = storedBlock.getWorldPosition().Position.y;
|
|
||||||
sb=storedBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StoredBlock locateLowestBlockForWorker(List<StoredBlock> list, HealerWorker worker)
|
|
||||||
{
|
|
||||||
StoredBlock sb = null;
|
|
||||||
double currentY = 300;
|
|
||||||
for (StoredBlock storedBlock : ToHeal) {
|
|
||||||
if(storedBlock.getWorldPosition().Position.y < currentY && storedBlock.isClaimedBy(worker))
|
|
||||||
{
|
|
||||||
currentY = storedBlock.getWorldPosition().Position.y;
|
|
||||||
sb=storedBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<StoredBlock> getBlocksByWorker(HealerWorker worker)
|
|
||||||
{
|
|
||||||
List<StoredBlock> blocks = new ArrayList<>();
|
|
||||||
for (StoredBlock storedBlock : ToHeal) {
|
|
||||||
if(storedBlock.isClaimedBy(worker))blocks.add(storedBlock);
|
|
||||||
}
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StoredBlock getExact(WorldPosition wp)
|
|
||||||
{
|
|
||||||
for (StoredBlock storedBlock : ToHeal) {
|
|
||||||
if(storedBlock.getWorldPosition().same(wp))
|
|
||||||
{
|
|
||||||
return storedBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean HasValidatePosition(BlockPos pos, ServerLevel lvl)
|
|
||||||
{
|
|
||||||
Vector3 realPos = new Vector3(pos);
|
|
||||||
WorldPosition real = new WorldPosition(realPos, lvl);
|
|
||||||
|
|
||||||
for (StoredBlock storedBlock : ToHeal) {
|
|
||||||
if(storedBlock.getWorldPosition().same(real))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Initialize()
|
|
||||||
{
|
|
||||||
Thread tx = new Thread(new Runnable(){
|
|
||||||
public void run(){
|
|
||||||
if(OTEServerConfig.DEBUG_HEALER.get())
|
|
||||||
{
|
|
||||||
// Load the sNBT file
|
|
||||||
Path configFile = getPath();
|
|
||||||
File x = configFile.toFile();
|
|
||||||
String FinalStr = "";
|
|
||||||
try {
|
|
||||||
BufferedReader br = new BufferedReader(new FileReader(x));
|
|
||||||
while(br.ready())
|
|
||||||
{
|
|
||||||
FinalStr += br.readLine();
|
|
||||||
}
|
|
||||||
br.close();
|
|
||||||
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch(IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HealerQueue.deserialize(NbtUtils.snbtToStructure(FinalStr));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Load from normal NBT
|
|
||||||
Path configFile = getPath();
|
|
||||||
File x = configFile.toFile();
|
|
||||||
// Load binary
|
|
||||||
try {
|
|
||||||
CompoundTag tag = NbtIo.readCompressed(x);
|
|
||||||
HealerQueue.deserialize(tag);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OTEMod.HEALER_WAIT=false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tx.start();
|
|
||||||
|
|
||||||
// Set up the HealerManager / Runner
|
|
||||||
ManagerInstance = new HealerManager();
|
|
||||||
Thread txx = new Thread(ManagerInstance);
|
|
||||||
txx.start();
|
|
||||||
|
|
||||||
HealerWorker worker = new HealerWorker(ToHeal);
|
|
||||||
Thread txxx = new Thread(worker);
|
|
||||||
ManagerInstance.registerWorker(worker);
|
|
||||||
txxx.start();
|
|
||||||
|
|
||||||
OTEMod.HEALER_THREAD = txx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CompoundTag serialize()
|
|
||||||
{
|
|
||||||
CompoundTag tag = new CompoundTag();
|
|
||||||
// Save entire list
|
|
||||||
ListTag lst = new ListTag();
|
|
||||||
for(final StoredBlock block : HealerQueue.ToHeal)
|
|
||||||
{
|
|
||||||
lst.add(block.serialize());
|
|
||||||
}
|
|
||||||
|
|
||||||
tag.put("queue", lst);
|
|
||||||
tag.putInt("pass", HealerQueue.Pass);
|
|
||||||
|
|
||||||
//OTEMod.LOGGER.info("HEAL ["+HealerQueue.ToHeal.size()+"] / VALIDATE ["+HealerQueue.ToValidate.size()+"]");
|
|
||||||
|
|
||||||
// OK
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<StoredBlock> removeSame(List<StoredBlock> other)
|
|
||||||
{
|
|
||||||
other=removeSameFrom(ToHeal, other);
|
|
||||||
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<StoredBlock> removeSameFrom(List<StoredBlock> stored, List<StoredBlock> other)
|
|
||||||
{
|
|
||||||
|
|
||||||
for(int i = 0;i<stored.size();i++)
|
|
||||||
{
|
|
||||||
for(int x = 0;x<other.size();x++)
|
|
||||||
{
|
|
||||||
if(other.get(x).getWorldPosition().same(stored.get(i).getWorldPosition()))
|
|
||||||
{
|
|
||||||
// Both are same
|
|
||||||
other.remove(x);
|
|
||||||
x=-1; // Reset indexing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeExact(WorldPosition pos)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < ToHeal.size(); i++) {
|
|
||||||
if(ToHeal.get(i).getWorldPosition().same(pos)){
|
|
||||||
ToHeal.remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void deserialize(CompoundTag tag)
|
|
||||||
{
|
|
||||||
OTEMod.HEALER_WAIT=true;
|
|
||||||
// Begin parsing
|
|
||||||
if(tag.contains("queue"))
|
|
||||||
{
|
|
||||||
HealerQueue.ToHeal.clear();
|
|
||||||
// Read the list
|
|
||||||
|
|
||||||
ListTag items = tag.getList("queue", Tag.TAG_COMPOUND);
|
|
||||||
|
|
||||||
|
|
||||||
for(int i=0;i<items.size();i++)
|
|
||||||
{
|
|
||||||
CompoundTag stored = items.getCompound(i);
|
|
||||||
StoredBlock sb = new StoredBlock(stored);
|
|
||||||
HealerQueue.ToHeal.add(sb);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OTEMod.LOGGER.info("Finished loading the queue ["+HealerQueue.ToHeal.size()+"] items");
|
|
||||||
|
|
||||||
|
|
||||||
HealerQueue.Pass = tag.getInt("pass");
|
|
||||||
|
|
||||||
OTEMod.HEALER_WAIT=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean dirty()
|
|
||||||
{
|
|
||||||
if(ToHeal!=LastToHeal)return true;
|
|
||||||
if(Pass != LastPass)return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void dump() throws IOException
|
|
||||||
{
|
|
||||||
LastToHeal = ToHeal;
|
|
||||||
LastPass = Pass;
|
|
||||||
CompoundTag serialized = HealerQueue.serialize();
|
|
||||||
if(OTEServerConfig.DEBUG_HEALER.get())
|
|
||||||
{
|
|
||||||
// Save to sNBT
|
|
||||||
String prettyOutput = NbtUtils.structureToSnbt(serialized);
|
|
||||||
Path storage = getPath();
|
|
||||||
File x = storage.toFile();
|
|
||||||
BufferedWriter bw = new BufferedWriter(new FileWriter(x));
|
|
||||||
bw.write(prettyOutput);
|
|
||||||
bw.close();
|
|
||||||
|
|
||||||
}else {
|
|
||||||
NbtIo.writeCompressed(serialized, getPath().toFile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Shuffle()
|
|
||||||
{
|
|
||||||
Collections.shuffle(ToHeal);
|
|
||||||
|
|
||||||
if(OTEServerConfig.DEBUG_HEALER.get())
|
|
||||||
try {
|
|
||||||
dump();// Push contents to disk if in debug mode for easier analyzing on change
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
package dev.zontreck.otemod.antigrief;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
|
|
||||||
import dev.zontreck.libzontreck.vectors.WorldPosition;
|
|
||||||
import dev.zontreck.otemod.OTEMod;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
|
|
||||||
public class HealerWorker implements Runnable
|
|
||||||
{
|
|
||||||
private List<StoredBlock> proc;
|
|
||||||
public boolean alive=false; // These are the
|
|
||||||
public boolean doTick = false;
|
|
||||||
public Thread MyThread;
|
|
||||||
|
|
||||||
private boolean skipWait;
|
|
||||||
|
|
||||||
public int Pass; // A local pass for this worker
|
|
||||||
|
|
||||||
|
|
||||||
public HealerWorker(List<StoredBlock> toProcess)
|
|
||||||
{
|
|
||||||
// TODO: Make this a individualized heal worker that does the task of the current HealerManager, but with a central list of positions for de-duplication. But that a second worker would not process the same positions
|
|
||||||
// The goal is to have a worker so a second explosion elsewhere does not reset the entire thing
|
|
||||||
for (StoredBlock sBlock : toProcess) {
|
|
||||||
if(!sBlock.claimed()) // Checks if a thread has been set on this storage block yet or not. This data does not get serialized.
|
|
||||||
sBlock.setClaimed(); // We are not yet in a new thread but we know we will be soon.
|
|
||||||
}
|
|
||||||
proc = toProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
alive=true;
|
|
||||||
MyThread=Thread.currentThread();
|
|
||||||
HealerQueue.ManagerInstance.registerWorker(this);
|
|
||||||
OTEMod.LOGGER.info("Hello from Healer Worker "+Thread.currentThread().getName());
|
|
||||||
|
|
||||||
for(int i=0;i<proc.size();i++){
|
|
||||||
StoredBlock sb = proc.get(i);
|
|
||||||
sb.setClaimedBy(MyThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
while(alive && OTEMod.ALIVE){
|
|
||||||
// Stay alive
|
|
||||||
// The tick event will be fired when appropriate
|
|
||||||
if(doTick)tick();
|
|
||||||
if(skipWait)tick();
|
|
||||||
|
|
||||||
|
|
||||||
doTick=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OTEMod.LOGGER.info(Thread.currentThread().getName()+" has completed healing an area. Worker is now dismantling");
|
|
||||||
|
|
||||||
HealerQueue.ManagerInstance.deregisterWorker(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tick()
|
|
||||||
{
|
|
||||||
|
|
||||||
try{
|
|
||||||
|
|
||||||
// A tick in the healer worker tells it to repair a block
|
|
||||||
// The healer manager is responsible for dispatching ticks
|
|
||||||
|
|
||||||
|
|
||||||
if(proc.size()==0 && HealerQueue.getBlocksByWorker(this).size()==0)
|
|
||||||
{
|
|
||||||
alive=false;
|
|
||||||
if(HealerQueue.dirty())
|
|
||||||
HealerQueue.dump();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the first block in the list
|
|
||||||
final StoredBlock sb = HealerQueue.locateLowestBlock(proc);
|
|
||||||
ServerLevel level = null;
|
|
||||||
StoredBlock below = null;
|
|
||||||
|
|
||||||
if(sb != null)
|
|
||||||
{
|
|
||||||
level = sb.getWorldPosition().getActualDimension();
|
|
||||||
below = HealerQueue.getExact(new WorldPosition(sb.getWorldPosition().Position.moveDown(), level));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch(Pass)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
// Pass 1. Set all positions to bedrock
|
|
||||||
// The code will check is the block is solid. If the block below it is not solid, it will set it to air, regardless of if it is a falling block of not
|
|
||||||
|
|
||||||
if(proc.size()==0)
|
|
||||||
{
|
|
||||||
// Move the validate list back into healer queue, and increment pass
|
|
||||||
OTEMod.LOGGER.info("Pass 1 completed, moving to pass 2");
|
|
||||||
Pass=1;
|
|
||||||
proc = HealerQueue.getBlocksByWorker(this);
|
|
||||||
HealerQueue.dump();
|
|
||||||
break; // Exit this loop
|
|
||||||
}
|
|
||||||
|
|
||||||
if(below == null){
|
|
||||||
// This line will prevent the block below from getting set to Sculk
|
|
||||||
below = StoredBlock.getSculk(new WorldPosition(sb.getWorldPosition().Position.moveDown(), level)); // below is null so it is a unknown, accept a loss if its a falling block
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(!sb.getState().isAir() && below.getState().isAir())
|
|
||||||
{
|
|
||||||
HealRunner.scheduleHeal(StoredBlock.getSculk(below.getWorldPosition()));
|
|
||||||
skipWait=false;
|
|
||||||
}else {
|
|
||||||
if(!sb.getState().isAir())
|
|
||||||
{
|
|
||||||
HealRunner.scheduleHeal(StoredBlock.getSculk(sb.getWorldPosition()));
|
|
||||||
skipWait=false;
|
|
||||||
} else {
|
|
||||||
skipWait=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proc.remove(sb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// Pass 2 only sets the solid blocks
|
|
||||||
if(proc.size()==0)
|
|
||||||
{
|
|
||||||
OTEMod.LOGGER.info("Pass 2 completed, moving to pass 3");
|
|
||||||
Pass++;
|
|
||||||
proc = HealerQueue.getBlocksByWorker(this);
|
|
||||||
HealerQueue.dump();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!sb.getState().isAir())
|
|
||||||
{
|
|
||||||
skipWait=false;
|
|
||||||
HealRunner.scheduleHeal(sb);
|
|
||||||
HealerQueue.ToHeal.remove(sb);
|
|
||||||
}else{
|
|
||||||
skipWait=true;
|
|
||||||
|
|
||||||
}
|
|
||||||
proc.remove(sb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
// Pass 3 removes bedrock by setting blocks that are air
|
|
||||||
if(proc.size()==0)
|
|
||||||
{
|
|
||||||
OTEMod.LOGGER.info("Pass 3 has been completed. Ending restore");
|
|
||||||
Pass=0;
|
|
||||||
proc.clear();
|
|
||||||
HealerQueue.dump();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
proc.remove(sb);
|
|
||||||
HealerQueue.ToHeal.remove(sb);
|
|
||||||
|
|
||||||
if(sb.getState().isAir())
|
|
||||||
{
|
|
||||||
BlockState bs = sb.getWorldPosition().getActualDimension().getBlockState(sb.getPos());
|
|
||||||
if(!bs.isAir() && !bs.is(Blocks.SCULK))
|
|
||||||
{
|
|
||||||
skipWait=true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!bs.isAir()){
|
|
||||||
skipWait=false;
|
|
||||||
HealRunner.scheduleHeal(sb);
|
|
||||||
}else skipWait=true;
|
|
||||||
}else skipWait=true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
Pass=0;
|
|
||||||
OTEMod.LOGGER.info("/!\\ ALERT /!\\\n\nWARNING: Unknown pass operation was added to the HealQueue");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}catch(Exception e){}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package dev.zontreck.otemod.antigrief2;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import dev.zontreck.otemod.OTEMod;
|
|
||||||
import dev.zontreck.otemod.antigrief.HealRunner;
|
|
||||||
import dev.zontreck.otemod.antigrief.StoredBlock;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.saveddata.SavedData;
|
|
||||||
import net.minecraftforge.event.level.ExplosionEvent;
|
|
||||||
|
|
||||||
public class Healer extends SavedData implements Supplier<Object>
|
|
||||||
{
|
|
||||||
private Level world;
|
|
||||||
private TickingHealerTask task;
|
|
||||||
static final String DATAKEY = OTEMod.MOD_ID+":"+Healer.class.getSimpleName();
|
|
||||||
|
|
||||||
public Healer()
|
|
||||||
{
|
|
||||||
task = new TickingHealerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTick()
|
|
||||||
{
|
|
||||||
Collection<StoredBlock> blocks = task.tick();
|
|
||||||
if(blocks != null)
|
|
||||||
{
|
|
||||||
for(StoredBlock bdata : blocks)
|
|
||||||
{
|
|
||||||
HealRunner.scheduleHeal(bdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDetonate(ExplosionEvent.Detonate event)
|
|
||||||
{
|
|
||||||
Level world = event.getLevel();
|
|
||||||
int maxTicks = 0;
|
|
||||||
for(BlockPos posExplode : event.getAffectedBlocks())
|
|
||||||
{
|
|
||||||
BlockState stateExplode = world.getBlockState(posExplode);
|
|
||||||
if(!isValid(stateExplode))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(!stateExplode.isAir())
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object get() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundTag save(CompoundTag p_77763_) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package dev.zontreck.otemod.antigrief2.handlers;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import dev.zontreck.otemod.antigrief2.Healer;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraftforge.event.level.LevelEvent;
|
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
||||||
|
|
||||||
public class WorldEventHandler {
|
|
||||||
private Map<ServerLevel, Healer> healers = new HashMap<ServerLevel, Healer>();
|
|
||||||
|
|
||||||
public Map<ServerLevel, Healer> getHealers()
|
|
||||||
{
|
|
||||||
return healers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onLoadLevel(LevelEvent.Load ev)
|
|
||||||
{
|
|
||||||
if(!ev.getLevel().isClientSide() && ev.getLevel() instanceof ServerLevel)
|
|
||||||
{
|
|
||||||
healers.put((ServerLevel)ev.getLevel(), Healer.acquire((ServerLevel)ev.getLevel()));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onUnload(LevelEvent.Unload ev)
|
|
||||||
{
|
|
||||||
if(!ev.getLevel().isClientSide())
|
|
||||||
{
|
|
||||||
healers.remove(ev.getLevel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ public class BlockContainerList {
|
||||||
private final Lock lock;
|
private final Lock lock;
|
||||||
private final List<StoredBlock> containers;
|
private final List<StoredBlock> containers;
|
||||||
|
|
||||||
private BlockContainerList()
|
public BlockContainerList()
|
||||||
{
|
{
|
||||||
this.lock = new ReentrantLock();
|
this.lock = new ReentrantLock();
|
||||||
this.containers = new ArrayList<>();
|
this.containers = new ArrayList<>();
|
||||||
|
|
|
@ -25,11 +25,6 @@ public class BlockSaver {
|
||||||
executor=service;
|
executor=service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InitialLoad()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start()
|
public void start()
|
||||||
{
|
{
|
||||||
executor.scheduleAtFixedRate(()->{
|
executor.scheduleAtFixedRate(()->{
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
package dev.zontreck.otemod.zschem;
|
package dev.zontreck.otemod.zschem;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraftforge.event.TickEvent;
|
||||||
import net.minecraftforge.event.level.ExplosionEvent;
|
import net.minecraftforge.event.level.ExplosionEvent;
|
||||||
|
import net.minecraftforge.event.level.LevelEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
public class EventHandler {
|
public class EventHandler {
|
||||||
|
@ -8,6 +15,51 @@ public class EventHandler {
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onDetonate(ExplosionEvent.Detonate ev)
|
public void onDetonate(ExplosionEvent.Detonate ev)
|
||||||
{
|
{
|
||||||
|
if(ev.getLevel().isClientSide)return;
|
||||||
|
|
||||||
|
Entity explodes = ev.getExplosion().getSourceMob();
|
||||||
|
// Register blocks to be healed
|
||||||
|
WorldProp wp = WorldProp.acquire((ServerLevel)ev.getLevel());
|
||||||
|
if(wp!=null){
|
||||||
|
wp.onDetonate(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<ServerLevel, WorldProp> healers = new HashMap<ServerLevel, WorldProp>();
|
||||||
|
|
||||||
|
public Map<ServerLevel, WorldProp> getHealers()
|
||||||
|
{
|
||||||
|
return healers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLoadLevel(LevelEvent.Load ev)
|
||||||
|
{
|
||||||
|
if(!ev.getLevel().isClientSide() && ev.getLevel() instanceof ServerLevel)
|
||||||
|
{
|
||||||
|
healers.put((ServerLevel)ev.getLevel(), WorldProp.acquire((ServerLevel)ev.getLevel()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onUnload(LevelEvent.Unload ev)
|
||||||
|
{
|
||||||
|
if(!ev.getLevel().isClientSide())
|
||||||
|
{
|
||||||
|
healers.remove(ev.getLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLevelTick(TickEvent.LevelTickEvent ev)
|
||||||
|
{
|
||||||
|
if(!ev.level.isClientSide){
|
||||||
|
WorldProp wp = WorldProp.acquire((ServerLevel)ev.level);
|
||||||
|
if(wp!=null){
|
||||||
|
wp.onTick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
116
src/main/java/dev/zontreck/otemod/zschem/WorldProp.java
Normal file
116
src/main/java/dev/zontreck/otemod/zschem/WorldProp.java
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package dev.zontreck.otemod.zschem;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import dev.zontreck.otemod.OTEMod;
|
||||||
|
import dev.zontreck.otemod.configs.OTEServerConfig;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.tags.BlockTags;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.saveddata.SavedData;
|
||||||
|
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||||
|
import net.minecraftforge.event.level.ExplosionEvent;
|
||||||
|
|
||||||
|
public class WorldProp extends SavedData implements Supplier<Object>
|
||||||
|
{
|
||||||
|
private Level world;
|
||||||
|
private BlockContainerList task;
|
||||||
|
static final String KEY = OTEMod.MOD_ID + ":" + WorldProp.class.getSimpleName();
|
||||||
|
|
||||||
|
public WorldProp(){
|
||||||
|
task = new BlockContainerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTick()
|
||||||
|
{
|
||||||
|
task.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDetonate(ExplosionEvent.Detonate ev)
|
||||||
|
{
|
||||||
|
Level w = ev.getLevel();
|
||||||
|
int maxTicks = 0;
|
||||||
|
|
||||||
|
for(BlockPos p : ev.getAffectedBlocks())
|
||||||
|
{
|
||||||
|
BlockState bsExplode = w.getBlockState(p);
|
||||||
|
if(!isValid(bsExplode))continue;
|
||||||
|
|
||||||
|
if(!bsExplode.isAir()){
|
||||||
|
int ticks = OTEServerConfig.HEALER_TIMER.get() + w.random.nextInt();
|
||||||
|
if(ticks > maxTicks){
|
||||||
|
maxTicks = ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addHeal(p, bsExplode, world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxTicks ++;
|
||||||
|
for(BlockPos p : ev.getAffectedBlocks())
|
||||||
|
{
|
||||||
|
BlockState bsE = w.getBlockState(p);
|
||||||
|
if(!isValid(bsE))continue;
|
||||||
|
if(!bsE.isAir()){
|
||||||
|
addHeal(p, bsE, world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addHeal(BlockPos p, BlockState s, Level w)
|
||||||
|
{
|
||||||
|
task.add(new StoredBlock(p, s, (ServerLevel)w));
|
||||||
|
world.removeBlockEntity(p);
|
||||||
|
world.setBlock(p, Blocks.AIR.defaultBlockState(), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValid(BlockState bs)
|
||||||
|
{
|
||||||
|
if(bs.is(BlockTags.DOORS) || bs.is(BlockTags.BEDS) || bs.is(BlockTags.TALL_FLOWERS)){
|
||||||
|
return false;
|
||||||
|
} else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag save(CompoundTag tag){
|
||||||
|
|
||||||
|
return (CompoundTag) tag.put("task", task.save(tag));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(CompoundTag tag)
|
||||||
|
{
|
||||||
|
CompoundTag ct = tag.getCompound("task");
|
||||||
|
task = BlockContainerList.load(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WorldProp acquire(ServerLevel w)
|
||||||
|
{
|
||||||
|
DimensionDataStorage dds = w.getDataStorage();
|
||||||
|
WorldProp wp = dds.computeIfAbsent(p->{
|
||||||
|
WorldProp swp = new WorldProp();
|
||||||
|
swp.load(p);
|
||||||
|
return swp;
|
||||||
|
}, ()->{
|
||||||
|
return new WorldProp();
|
||||||
|
}, KEY);
|
||||||
|
wp.world = w;
|
||||||
|
return wp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirty(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object get()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue