Finish fixing bugs and downgrading

This commit is contained in:
Tara 2023-01-07 01:30:54 -07:00
parent db76b314e5
commit 1126306c2c
11 changed files with 171 additions and 840 deletions

View file

@ -38,8 +38,6 @@ import net.minecraftforge.registries.ForgeRegistries;
import org.slf4j.Logger;
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.chat.ChatServerOverride;
import dev.zontreck.otemod.commands.CommandRegistry;
@ -155,7 +153,7 @@ public class OTEMod
try {
OTEMod.DB = new Database(this);
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

View file

@ -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;
}
}

View file

@ -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");
}
}

View file

@ -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();
}
}
}

View file

@ -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){}
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}
}

View file

@ -15,7 +15,7 @@ public class BlockContainerList {
private final Lock lock;
private final List<StoredBlock> containers;
private BlockContainerList()
public BlockContainerList()
{
this.lock = new ReentrantLock();
this.containers = new ArrayList<>();

View file

@ -25,11 +25,6 @@ public class BlockSaver {
executor=service;
}
public static void InitialLoad()
{
}
public void start()
{
executor.scheduleAtFixedRate(()->{

View file

@ -1,6 +1,13 @@
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.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
public class EventHandler {
@ -8,6 +15,51 @@ public class EventHandler {
@SubscribeEvent
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();
}
}
}
}

View 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;
}
}