179 lines
5.5 KiB
Java
179 lines
5.5 KiB
Java
package dev.zontreck.fire.events;
|
|
|
|
import dev.zontreck.fire.FireMod;
|
|
import dev.zontreck.fire.config.server.FireServerConfig;
|
|
import dev.zontreck.fire.data.BlockSnapshot;
|
|
import dev.zontreck.libzontreck.util.ServerUtilities;
|
|
import dev.zontreck.libzontreck.vectors.WorldPosition;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.Container;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.ChestBlock;
|
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.event.TickEvent;
|
|
import net.minecraftforge.event.level.BlockEvent;
|
|
import net.minecraftforge.event.server.ServerStoppingEvent;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
|
|
import java.time.Instant;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
import java.util.concurrent.locks.Lock;
|
|
|
|
public class EventHandler {
|
|
static {
|
|
MinecraftForge.EVENT_BUS.register(EventHandler.class);
|
|
}
|
|
|
|
private static final AtomicLong ALIVE_TICKS = new AtomicLong(0);
|
|
|
|
@SubscribeEvent
|
|
public void onBlockBreak(BlockEvent.NeighborNotifyEvent event) {
|
|
if (ServerUtilities.isClient()) return;
|
|
if(!FireMod.ENABLED)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ServerLevel world = (ServerLevel) event.getLevel();
|
|
if(FireServerConfig.restore.blacklistedDimensions.contains(WorldPosition.getDim(world)))
|
|
{
|
|
//FireMod.LOGGER.info("Blacklisted dimension, ignoring");
|
|
return; // Ignore it.
|
|
}
|
|
BlockPos pos = event.getPos();
|
|
BlockState blockState = event.getState();
|
|
boolean bBurning=false;
|
|
if(blockState.isBurning(world, pos))
|
|
{
|
|
bBurning=true;
|
|
}
|
|
|
|
if(!bBurning)return;
|
|
|
|
for(Direction dir : event.getNotifiedSides())
|
|
{
|
|
switch(dir)
|
|
{
|
|
case UP -> {
|
|
pos = event.getPos().above();
|
|
break;
|
|
}
|
|
case DOWN -> {
|
|
pos = event.getPos().below();
|
|
break;
|
|
}
|
|
case EAST -> {
|
|
pos = event.getPos().east();
|
|
break;
|
|
}
|
|
case WEST -> {
|
|
pos = event.getPos().west();
|
|
break;
|
|
}
|
|
case NORTH -> {
|
|
pos = event.getPos().north();
|
|
break;
|
|
}
|
|
case SOUTH -> {
|
|
pos = event.getPos().south();
|
|
break;
|
|
}
|
|
}
|
|
|
|
blockState = world.getBlockState(pos);
|
|
|
|
if (blockState.is(Blocks.FIRE) || blockState.isAir() || !blockState.isFlammable(world, pos, dir)) {
|
|
continue; // DO NOT CACHE FIRE OR AIR BLOCKS, OR NON-FLAMMABLE BLOCKS
|
|
}
|
|
|
|
// Do not cache containers and their inventories. This could be used as a duplication exploit in that case
|
|
BlockEntity entity = world.getBlockEntity(pos);
|
|
if(entity instanceof BaseContainerBlockEntity && FireServerConfig.restore.restoreContainers)
|
|
{
|
|
if(blockState.isFlammable(world, pos, dir))
|
|
{
|
|
// We're caching it, remove it from the world immediately to prevent a dupe. It will be restored afterwards
|
|
|
|
world.setBlock(pos, Blocks.AIR.defaultBlockState(), ChestBlock.UPDATE_ALL);
|
|
}
|
|
}
|
|
|
|
//FireMod.LOGGER.info("Fire detected");
|
|
FireMod.blockRestoreData.add(new BlockSnapshot(world, pos));
|
|
|
|
}
|
|
|
|
FireMod.blockRestoreData.commit();
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onServerTick(TickEvent.LevelTickEvent event) {
|
|
if(ServerUtilities.isClient()) return;
|
|
if(!FireMod.ENABLED)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (event.phase == TickEvent.Phase.END) {
|
|
if(ALIVE_TICKS.getAndIncrement() % 10 == 0)
|
|
{
|
|
|
|
if(restoreBurnedBlocks())
|
|
FireMod.blockRestoreData.commit();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onServerStopping(ServerStoppingEvent event)
|
|
{
|
|
if(ServerUtilities.isClient()) return;
|
|
|
|
FireMod.ENABLED=false;
|
|
FireMod.blockRestoreData.commit();
|
|
|
|
|
|
}
|
|
|
|
public boolean restoreBurnedBlocks() {
|
|
long currentTime = Instant.now().getEpochSecond();
|
|
|
|
Lock lock = FireMod.blockRestoreData.acquireWriteLock();
|
|
lock.lock();
|
|
|
|
try {
|
|
// Restore one block per tick, after it hasnt burned for long enough
|
|
Iterator<Map.Entry<BlockPos, BlockSnapshot>> it = FireMod.blockRestoreData.snapshots.entrySet().iterator();
|
|
while(it.hasNext())
|
|
{
|
|
|
|
var entry = it.next();
|
|
|
|
if((currentTime - entry.getValue().burnTime) >= FireServerConfig.restore.delayForRestore + (FireMod.blockRestoreData.snapshots.size()))
|
|
{
|
|
it.remove();
|
|
entry.getValue().restore();
|
|
|
|
//FireMod.LOGGER.info("Restoring burned block");
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}finally {
|
|
lock.unlock();
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|