2021-01-26 21:32:19 +01:00
|
|
|
package com.minelittlepony.unicopia;
|
|
|
|
|
|
|
|
import com.minelittlepony.unicopia.network.Channel;
|
|
|
|
import com.minelittlepony.unicopia.network.MsgBlockDestruction;
|
|
|
|
|
|
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
|
|
import net.minecraft.server.world.ServerWorld;
|
|
|
|
import net.minecraft.util.math.BlockPos;
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
public class BlockDestructionManager {
|
|
|
|
|
|
|
|
public static final int UNSET_DAMAGE = -1;
|
|
|
|
public static final int MAX_DAMAGE = 10;
|
|
|
|
|
2021-01-27 17:03:35 +01:00
|
|
|
private final Destruction emptyDestruction = new Destruction();
|
2021-01-26 21:32:19 +01:00
|
|
|
|
|
|
|
private final World world;
|
|
|
|
|
|
|
|
private final Long2ObjectMap<Destruction> destructions = new Long2ObjectOpenHashMap<>();
|
|
|
|
|
|
|
|
private final Object locker = new Object();
|
|
|
|
|
|
|
|
public BlockDestructionManager(World world) {
|
|
|
|
this.world = world;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getBlockDestruction(BlockPos pos) {
|
|
|
|
return destructions.getOrDefault(pos.asLong(), emptyDestruction).amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearBlockDestruction(BlockPos pos) {
|
|
|
|
setBlockDestruction(pos, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setBlockDestruction(BlockPos pos, int amount) {
|
|
|
|
synchronized (locker) {
|
2021-01-27 17:03:35 +01:00
|
|
|
destructions.computeIfAbsent(pos.asLong(), p -> new Destruction()).set(amount);
|
2021-01-26 21:32:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int damageBlock(BlockPos pos, int amount) {
|
2021-01-27 16:16:15 +01:00
|
|
|
if (amount == 0) {
|
|
|
|
return getBlockDestruction(pos);
|
|
|
|
}
|
2021-01-26 21:32:19 +01:00
|
|
|
amount = Math.max(getBlockDestruction(pos), 0) + amount;
|
|
|
|
setBlockDestruction(pos, amount);
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void tick() {
|
|
|
|
synchronized (locker) {
|
|
|
|
destructions.long2ObjectEntrySet().removeIf(entry -> entry.getValue().tick());
|
2021-01-27 17:03:35 +01:00
|
|
|
|
|
|
|
if (world instanceof ServerWorld) {
|
|
|
|
Long2ObjectMap<Integer> sent = new Long2ObjectOpenHashMap<>();
|
|
|
|
destructions.forEach((p, item) -> {
|
|
|
|
if (item.dirty) {
|
|
|
|
sent.put(p.longValue(), (Integer)item.amount);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (!sent.isEmpty()) {
|
|
|
|
Channel.SERVER_BLOCK_DESTRUCTION.send(world, new MsgBlockDestruction(sent));
|
|
|
|
}
|
|
|
|
}
|
2021-01-26 21:32:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class Destruction {
|
|
|
|
int amount = -1;
|
|
|
|
int age = 50;
|
2021-01-27 17:03:35 +01:00
|
|
|
boolean dirty;
|
2021-01-26 21:32:19 +01:00
|
|
|
|
|
|
|
boolean tick() {
|
|
|
|
if (age-- > 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amount >= 0) {
|
|
|
|
set(amount - 1);
|
|
|
|
}
|
|
|
|
return amount < 0 || age-- <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(int amount) {
|
|
|
|
this.age = 50;
|
|
|
|
this.amount = amount >= 0 && amount < MAX_DAMAGE ? amount : UNSET_DAMAGE;
|
2021-01-27 17:03:35 +01:00
|
|
|
this.dirty = true;
|
2021-01-26 21:32:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface Source {
|
|
|
|
BlockDestructionManager getDestructionManager();
|
|
|
|
}
|
|
|
|
}
|