diff --git a/build.gradle b/build.gradle index 70bb6c0..b9c4a82 100644 --- a/build.gradle +++ b/build.gradle @@ -149,8 +149,6 @@ dependencies { // Examples using mod jars from ./libs // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") - api 'org.apache.commons:commons-math3:3.6.1' - implementation 'com.google.guava:guava:22.0' implementation 'org.mariadb.jdbc:mariadb-java-client:3.0.8' compileOnly 'org.mariadb.jdbc:mariadb-java-client' // For more info... diff --git a/gradle.properties b/gradle.properties index bccd495..28cb2dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,9 +3,9 @@ org.gradle.jvmargs=-Xmx8G org.gradle.daemon=false -my_version=1.3.4.3 +my_version=1.3.4.4 mc_version=1.19.2 -forge_version=43.1.32 -jei_version=11.3.0.262 -libz_version=1.0.1.0 \ No newline at end of file +forge_version=43.1.40 +jei_version=11.3.0.271 +libz_version=1.0.1.2 \ No newline at end of file diff --git a/src/main/java/dev/zontreck/otemod/OTEMod.java b/src/main/java/dev/zontreck/otemod/OTEMod.java index b122684..70603e5 100644 --- a/src/main/java/dev/zontreck/otemod/OTEMod.java +++ b/src/main/java/dev/zontreck/otemod/OTEMod.java @@ -70,6 +70,8 @@ public class OTEMod public static List TeleportRegistry = new ArrayList<>(); public static MinecraftServer THE_SERVER; public static boolean ALIVE; + public static boolean HEALER_WAIT=true; // Only on loading finish should this unlock + public static Thread HEALER_THREAD; public static boolean DEVELOPER=false; private static Thread MasterThread; diff --git a/src/main/java/dev/zontreck/otemod/antigrief/Handler.java b/src/main/java/dev/zontreck/otemod/antigrief/Handler.java index 135919d..e041b27 100644 --- a/src/main/java/dev/zontreck/otemod/antigrief/Handler.java +++ b/src/main/java/dev/zontreck/otemod/antigrief/Handler.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; +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; @@ -22,6 +24,7 @@ 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; diff --git a/src/main/java/dev/zontreck/otemod/antigrief/HealerManager.java b/src/main/java/dev/zontreck/otemod/antigrief/HealerManager.java index d950ec6..23712fa 100644 --- a/src/main/java/dev/zontreck/otemod/antigrief/HealerManager.java +++ b/src/main/java/dev/zontreck/otemod/antigrief/HealerManager.java @@ -1,17 +1,25 @@ package dev.zontreck.otemod.antigrief; import java.io.IOException; +import java.time.Instant; import java.util.Random; import dev.zontreck.libzontreck.vectors.Vector3; import dev.zontreck.otemod.OTEMod; import dev.zontreck.otemod.configs.OTEServerConfig; +import net.minecraft.server.commands.SetBlockCommand; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.FallingBlock; +import net.minecraft.world.level.block.SandBlock; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.util.BlockSnapshot; public class HealerManager implements Runnable { @@ -21,111 +29,174 @@ public class HealerManager implements Runnable @Override public void run(){ boolean skipWait=false; + int skipCount=0; + long lastSave = 0; + final long saveInterval = (2*60); // Every 2 minutes + boolean lastWait = false; + while(OTEMod.ALIVE) { - // Run the queue - // We want to restore one block per run, then halt for number of seconds in config - try { - if(!skipWait) - Thread.sleep(OTEServerConfig.HEALER_TIMER.get()); - } catch (NumberFormatException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + try{ + // Run the queue + // We want to restore one block per run, then halt for number of seconds in config + try { + if(!skipWait) + Thread.sleep(OTEServerConfig.HEALER_TIMER.get()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if(lastWait != OTEMod.HEALER_WAIT){ + OTEMod.LOGGER.info("Healer wait flag was toggled"); + } + lastWait = OTEMod.HEALER_WAIT; + if(OTEMod.HEALER_WAIT) + continue; // Wait until the saved queue has been fully imported - if(!OTEMod.ALIVE) - { - // Server has begun to shut down while we were sleeping - // Begin tear down - break; - } - - // Loop back to start if no items in queue - if(HealerQueue.ToHeal.size()==0){ - - if(HealerQueue.ToValidate.size()==0)continue; - - // Validate success - for(StoredBlock sb : HealerQueue.ToValidate) + if(!OTEMod.ALIVE) { - final ServerLevel level = sb.getWorldPosition().getActualDimension(); - if(!level.getBlockState(sb.getPos()).is(sb.getState().getBlock())) + // Server has begun to shut down while we were sleeping + // Begin tear down + break; + } + + // Loop back to start if no items in queue + if(HealerQueue.ToHeal.size()==0){ + + if(HealerQueue.ToValidate.size()==0)continue; + + boolean redo = false; + // Validate success + for(StoredBlock sb : HealerQueue.ToValidate) { - // Redo restore - HealerQueue.ToHeal.addAll(HealerQueue.ToValidate); - HealerQueue.ToValidate.clear(); - break; + try{ + + final ServerLevel level = sb.getWorldPosition().getActualDimension(); + if(!level.getBlockState(sb.getPos()).is(sb.getState().getBlock())) + { + redo=true; + // Redo restore + HealerQueue.ToHeal.add(sb); + } + }catch(Exception e){} + } + + HealerQueue.ToValidate.clear(); + OTEMod.LOGGER.info("Validation of restore completed"); + HealerQueue.dump(); + + if(redo) + { + HealerQueue.Shuffle(); + OTEMod.LOGGER.info("Validation was not successful, and the repair will be repeated"); + } + continue; + } + + // Play a popping sound at the block position + final SoundEvent pop = SoundEvents.ITEM_PICKUP; + // Get the first block in the list + final StoredBlock sb = HealerQueue.locateHighestBlock(HealerQueue.ToHeal); + final ServerLevel level = sb.getWorldPosition().getActualDimension(); + + + // Remove the block from the queue now to prevent further issues + if( !HealerQueue.ToValidate.add(sb) ) + { + OTEMod.LOGGER.info("Failed to add Block to Validation queue!!! Verification of restore will not work"); + }else + HealerQueue.ToHeal.remove(sb); + + // Healer object should have been added to the validation list + + + // Check if the block to restore, and the block at position are air. + if(level.getBlockState(sb.getPos()).isAir() && sb.getState().isAir()){ + skipWait=true; + continue; // Skip the wait, and this block + } else skipWait=false; + + + if(skipWait) + { + if(skipCount > 5){ + skipCount=0; + skipWait=false;// Give the server a chance to breathe + } + else { + skipCount++; + } + }else skipCount=0; + + + level.getServer().execute(new Runnable(){ + public void run() + { + + //BlockSnapshot bs = BlockSnapshot.create(level.dimension(), level, sb.getPos()); + + //BlockState current = level.getBlockState(sb.getPos()); + BlockState nState = Block.updateFromNeighbourShapes(sb.getState(), level, sb.getPos()); + level.setBlock(sb.getPos(), nState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // no update? + + + //level.setBlocksDirty(sb.getPos(), sb.getState(), level.getBlockState(sb.getPos())); + //level.markAndNotifyBlock(sb.getPos(), level.getChunkAt(sb.getPos()), sb.getState(), level.getBlockState(sb.getPos()), 2, 0); + + //level.getChunkAt(sb.getPos()).setBlockState(sb.getPos(), sb.getState(), false); + + BlockEntity be = level.getBlockEntity(sb.getPos()); + + if(be!=null){ + //be.deserializeNBT(sb.getBlockEntity()); + be.load(sb.getBlockEntity()); + be.setChanged(); + + } + + // Everything is restored, play sound + SoundSource ss = SoundSource.NEUTRAL; + Vector3 v3 = sb.getWorldPosition().Position; + Random rng = new Random(); + + level.playSound(null, v3.asBlockPos(), pop, ss, rng.nextFloat(0.75f,1.0f), rng.nextFloat(1)); + + /*for(ServerPlayer player : level.players()) + { + Vector3 playerPos = new Vector3(player.position()); + if(sb.getWorldPosition().Position.distance(playerPos) < 15) + { + // have player's client play sound (Packet?) + } + }*/ + + + + } + }); + + + + if(!skipWait) // Only save the queue when sleeping appropriately + { + + if(lastSave+saveInterval < Instant.now().getEpochSecond()){ + + try { + HealerQueue.dump(); + lastSave = Instant.now().getEpochSecond(); + OTEMod.LOGGER.info("Flushing current healer queue to disk..."); + } catch (IOException e) { + e.printStackTrace(); + } } } - - HealerQueue.ToValidate.clear(); - OTEMod.LOGGER.info("Validation of restore completed"); - - continue; - } - // Play a popping sound at the block position - final SoundEvent pop = SoundEvents.ITEM_PICKUP; - // Get the first block in the list - final StoredBlock sb = HealerQueue.ToHeal.get(0); - final ServerLevel level = sb.getWorldPosition().getActualDimension(); - - - // Remove the block from the queue now to prevent further issues - HealerQueue.ToHeal.remove(sb); - if( !HealerQueue.ToValidate.add(sb) ) + }catch (Exception e) { - OTEMod.LOGGER.info("Failed to add Block to Validation queue!!! Verification of restore will not work"); - } - - // Healer object should have been added to the validation list - - - // Check if the block to restore, and the block at the location are identical - if(level.getBlockState(sb.getPos()).is(sb.getState().getBlock())){ - skipWait=true; - continue; // Skip the wait, and this block - } else skipWait=false; - - - level.getServer().execute(new Runnable(){ - public void run() - { - - level.setBlockAndUpdate(sb.getPos(), sb.getState()); - BlockEntity be = level.getBlockEntity(sb.getPos()); - - if(be!=null) - be.deserializeNBT(sb.getBlockEntity()); - - // Everything is restored, play sound - SoundSource ss = SoundSource.NEUTRAL; - Vector3 v3 = sb.getWorldPosition().Position; - Random rng = new Random(); - - level.playSound(null, v3.asBlockPos(), pop, ss, rng.nextFloat(0.75f,1.0f), rng.nextFloat(1)); - - /*for(ServerPlayer player : level.players()) - { - Vector3 playerPos = new Vector3(player.position()); - if(sb.getWorldPosition().Position.distance(playerPos) < 15) - { - // have player's client play sound (Packet?) - } - }*/ - - - - } - }); - - - - try { - HealerQueue.dump(); - } catch (IOException e) { e.printStackTrace(); } + } OTEMod.LOGGER.info("Tearing down healer jobs. Saving remaining queue, stand by..."); diff --git a/src/main/java/dev/zontreck/otemod/antigrief/HealerQueue.java b/src/main/java/dev/zontreck/otemod/antigrief/HealerQueue.java index b945dad..555716e 100644 --- a/src/main/java/dev/zontreck/otemod/antigrief/HealerQueue.java +++ b/src/main/java/dev/zontreck/otemod/antigrief/HealerQueue.java @@ -12,15 +12,17 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.mojang.brigadier.exceptions.CommandSyntaxException; - +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; @@ -31,10 +33,12 @@ public class HealerQueue { public static List ToHeal = new ArrayList(); public static List ToValidate = new ArrayList(); + public static List FinishedBlocks = new ArrayList(); + public static Path getPath() { - + Path configDir = FMLPaths.GAMEDIR.get().resolve(FMLConfig.defaultConfigPath()); Path configFile = null; if(OTEServerConfig.DEBUG_HEALER.get()) @@ -49,6 +53,39 @@ public class HealerQueue { return configFile; } + public static StoredBlock locateHighestBlock(List 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 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; + } + } + for (StoredBlock storedBlock : ToValidate) { + if(storedBlock.getWorldPosition().same(real))return true; + } + + return false; + } + public static void Initialize() { Thread tx = new Thread(new Runnable(){ @@ -76,7 +113,7 @@ public class HealerQueue { try { HealerQueue.deserialize(NbtUtils.snbtToStructure(FinalStr)); - } catch (CommandSyntaxException e) { + } catch (Exception e) { e.printStackTrace(); } } else { @@ -91,7 +128,7 @@ public class HealerQueue { e.printStackTrace(); } } - + OTEMod.HEALER_WAIT=false; } }); tx.start(); @@ -99,6 +136,8 @@ public class HealerQueue { // Set up the HealerManager / Runner Thread txx = new Thread(new HealerManager()); txx.start(); + + OTEMod.HEALER_THREAD = txx; } public static CompoundTag serialize() @@ -128,6 +167,7 @@ public class HealerQueue { public static void deserialize(CompoundTag tag) { + OTEMod.HEALER_WAIT=true; // Begin parsing if(tag.contains("queue")) { @@ -144,7 +184,7 @@ public class HealerQueue { } } - OTEMod.LOGGER.info("Finished loading the queue"); + OTEMod.LOGGER.info("Finished loading the queue ["+HealerQueue.ToHeal.size()+"] items"); if(tag.contains("validate")) { @@ -159,7 +199,8 @@ public class HealerQueue { } } - OTEMod.LOGGER.info("Finished loading validation queue for healer"); + OTEMod.LOGGER.info("Finished loading validation queue for healer ["+HealerQueue.ToValidate.size()+"] items"); + OTEMod.HEALER_WAIT=false; } public static void dump() throws IOException {