This repository has been archived on 2024-07-25. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
Fire/src/main/java/dev/zontreck/fire/events/EventHandler.java
2024-02-13 23:47:11 -07:00

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