2020-07-13 20:37:21 +00:00
|
|
|
package com.thebrokenrail.energonrelics.component;
|
|
|
|
|
|
|
|
import com.thebrokenrail.energonrelics.EnergonRelics;
|
2020-07-24 17:25:50 +00:00
|
|
|
import com.thebrokenrail.energonrelics.energy.core.EnergyProviderBlockEntity;
|
2020-07-21 02:39:30 +00:00
|
|
|
import com.thebrokenrail.energonrelics.util.BlockPosWithDimension;
|
2020-07-13 20:37:21 +00:00
|
|
|
import net.minecraft.block.entity.BlockEntity;
|
2020-07-21 02:39:30 +00:00
|
|
|
import net.minecraft.datafixer.NbtOps;
|
2020-07-13 20:37:21 +00:00
|
|
|
import net.minecraft.nbt.CompoundTag;
|
|
|
|
import net.minecraft.nbt.ListTag;
|
|
|
|
import net.minecraft.nbt.Tag;
|
|
|
|
import net.minecraft.server.world.ServerWorld;
|
2020-07-21 02:39:30 +00:00
|
|
|
import net.minecraft.util.Identifier;
|
2020-07-13 20:37:21 +00:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
2020-07-21 02:39:30 +00:00
|
|
|
import net.minecraft.util.registry.RegistryKey;
|
2020-07-13 20:37:21 +00:00
|
|
|
import net.minecraft.world.PersistentState;
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
2020-07-27 18:06:46 +00:00
|
|
|
import java.util.HashMap;
|
2020-07-13 20:37:21 +00:00
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.List;
|
2020-07-27 18:06:46 +00:00
|
|
|
import java.util.Map;
|
2020-07-13 20:37:21 +00:00
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
public class NetworkComponent extends PersistentState {
|
|
|
|
private static class Entry {
|
2020-07-21 02:39:30 +00:00
|
|
|
private final List<BlockPosWithDimension> sources = new ArrayList<>();
|
2020-07-13 20:37:21 +00:00
|
|
|
private int id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private final List<Entry> networks = new ArrayList<>();
|
|
|
|
|
|
|
|
private NetworkComponent() {
|
|
|
|
super(EnergonRelics.NAMESPACE);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void fromTag(CompoundTag tag) {
|
|
|
|
networks.clear();
|
|
|
|
Tag list = tag.get("Networks");
|
|
|
|
if (list instanceof ListTag) {
|
2020-07-13 21:53:05 +00:00
|
|
|
ListTag networksTag = (ListTag) list;
|
|
|
|
for (int i = 0; i < networksTag.size(); i++) {
|
|
|
|
networks.add(getEntry(networksTag.getCompound(i)));
|
2020-07-13 20:37:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Entry getEntry(CompoundTag tag) {
|
|
|
|
Entry entry = new Entry();
|
|
|
|
entry.id = tag.getInt("ID");
|
|
|
|
entry.sources.clear();
|
|
|
|
Tag list = tag.get("Sources");
|
|
|
|
if (list instanceof ListTag) {
|
|
|
|
ListTag sources = (ListTag) list;
|
|
|
|
for (int i = 0; i < sources.size(); i++) {
|
|
|
|
int x = sources.getCompound(i).getInt("X");
|
|
|
|
int y = sources.getCompound(i).getInt("Y");
|
|
|
|
int z = sources.getCompound(i).getInt("Z");
|
2020-07-21 02:39:30 +00:00
|
|
|
RegistryKey<World> dimension = World.CODEC.parse(NbtOps.INSTANCE, sources.getCompound(i).get("Dimension")).result().orElse(World.OVERWORLD);
|
|
|
|
entry.sources.add(new BlockPosWithDimension(new BlockPos(x, y, z), dimension));
|
2020-07-13 20:37:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
private CompoundTag saveEntry(Entry entry) {
|
|
|
|
CompoundTag tag = new CompoundTag();
|
|
|
|
tag.putInt("ID", entry.id);
|
|
|
|
ListTag sources = new ListTag();
|
2020-07-21 02:39:30 +00:00
|
|
|
for (BlockPosWithDimension pos : entry.sources) {
|
2020-07-13 20:37:21 +00:00
|
|
|
CompoundTag posTag = new CompoundTag();
|
2020-07-21 02:39:30 +00:00
|
|
|
posTag.putInt("X", pos.pos.getX());
|
|
|
|
posTag.putInt("Y", pos.pos.getY());
|
|
|
|
posTag.putInt("Z", pos.pos.getZ());
|
|
|
|
Identifier.CODEC.encodeStart(NbtOps.INSTANCE, pos.dimension.getValue()).result().ifPresent(tags -> posTag.put("Dimension", tags));
|
2020-07-13 20:37:21 +00:00
|
|
|
sources.add(posTag);
|
|
|
|
}
|
|
|
|
tag.put("Sources", sources);
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public CompoundTag toTag(CompoundTag tag) {
|
|
|
|
ListTag networksTag = new ListTag();
|
|
|
|
for (Entry entry : networks) {
|
|
|
|
networksTag.add(saveEntry(entry));
|
|
|
|
}
|
|
|
|
tag.put("Networks", networksTag);
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Entry getOrCreate(int id) {
|
|
|
|
for (Entry entry : networks) {
|
|
|
|
if (entry.id == id) {
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Entry entry = new Entry();
|
|
|
|
entry.id = id;
|
|
|
|
entry.sources.clear();
|
|
|
|
networks.add(entry);
|
2020-07-27 18:08:21 +00:00
|
|
|
markDirty();
|
2020-07-13 20:37:21 +00:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static NetworkComponent getInstance(ServerWorld world) {
|
|
|
|
return Objects.requireNonNull(world.getServer().getWorld(World.OVERWORLD)).getPersistentStateManager().getOrCreate(NetworkComponent::new, EnergonRelics.NAMESPACE);
|
|
|
|
}
|
|
|
|
|
2020-07-27 18:06:46 +00:00
|
|
|
public List<BlockPosWithDimension> getSourcesPos(int id) {
|
2020-07-13 20:37:21 +00:00
|
|
|
Entry entry = getOrCreate(id);
|
|
|
|
return entry.sources;
|
|
|
|
}
|
|
|
|
|
2020-07-27 18:06:46 +00:00
|
|
|
private final Map<Integer, List<EnergyProviderBlockEntity>> cache = new HashMap<>();
|
|
|
|
|
|
|
|
private List<EnergyProviderBlockEntity> getSourcesFromCache(World world, int id) {
|
|
|
|
if (cache.containsKey(id)) {
|
|
|
|
world.getProfiler().push("getSourcesFromCache");
|
|
|
|
|
|
|
|
List<EnergyProviderBlockEntity> list = cache.get(id);
|
|
|
|
|
|
|
|
boolean valid = true;
|
|
|
|
for (EnergyProviderBlockEntity entity : list) {
|
|
|
|
if (!entity.isNetwork(id) || entity.isRemoved()) {
|
|
|
|
valid = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
world.getProfiler().pop();
|
|
|
|
|
|
|
|
if (valid) {
|
2020-07-28 22:22:44 +00:00
|
|
|
Collections.shuffle(list, world.random);
|
2020-07-27 18:06:46 +00:00
|
|
|
|
|
|
|
return list;
|
|
|
|
} else {
|
|
|
|
cache.remove(id);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<EnergyProviderBlockEntity> getSourcesFromCacheMiss(World world, int id) {
|
|
|
|
world.getProfiler().push("getSourcesFromCacheMiss");
|
|
|
|
|
|
|
|
List<BlockPosWithDimension> sources = getSourcesPos(id);
|
2020-07-21 02:39:30 +00:00
|
|
|
List<BlockPosWithDimension> valid = new ArrayList<>();
|
|
|
|
Iterator<BlockPosWithDimension> iterator = sources.iterator();
|
2020-07-24 17:25:50 +00:00
|
|
|
List<EnergyProviderBlockEntity> providers = new ArrayList<>();
|
2020-07-13 20:37:21 +00:00
|
|
|
boolean dirty = false;
|
|
|
|
while (iterator.hasNext()) {
|
2020-07-21 02:39:30 +00:00
|
|
|
BlockPosWithDimension pos = iterator.next();
|
2020-07-13 20:37:21 +00:00
|
|
|
if (!valid.contains(pos)) {
|
2020-07-21 02:39:30 +00:00
|
|
|
BlockEntity entity = Objects.requireNonNull(Objects.requireNonNull(world.getServer()).getWorld(pos.dimension)).getBlockEntity(pos.pos);
|
2020-07-24 17:25:50 +00:00
|
|
|
if (entity instanceof EnergyProviderBlockEntity && ((EnergyProviderBlockEntity) entity).isNetwork(id)) {
|
|
|
|
providers.add((EnergyProviderBlockEntity) entity);
|
2020-07-13 20:37:21 +00:00
|
|
|
} else {
|
|
|
|
iterator.remove();
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
valid.add(pos);
|
|
|
|
} else {
|
|
|
|
iterator.remove();
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dirty) {
|
|
|
|
markDirty();
|
|
|
|
}
|
2020-07-28 22:22:44 +00:00
|
|
|
Collections.shuffle(providers, world.random);
|
2020-07-27 18:06:46 +00:00
|
|
|
|
|
|
|
cache.put(id, providers);
|
|
|
|
|
|
|
|
world.getProfiler().pop();
|
2020-07-13 20:37:21 +00:00
|
|
|
return providers;
|
|
|
|
}
|
|
|
|
|
2020-07-27 18:06:46 +00:00
|
|
|
public List<EnergyProviderBlockEntity> getSources(World world, int id) {
|
|
|
|
world.getProfiler().push("getSources");
|
|
|
|
|
|
|
|
List<EnergyProviderBlockEntity> result;
|
|
|
|
|
|
|
|
List<EnergyProviderBlockEntity> cacheResult = getSourcesFromCache(world, id);
|
|
|
|
if (cacheResult != null) {
|
|
|
|
result = cacheResult;
|
|
|
|
} else {
|
|
|
|
result = getSourcesFromCacheMiss(world, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
world.getProfiler().pop();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearCache() {
|
|
|
|
cache.clear();
|
|
|
|
}
|
|
|
|
|
2020-07-21 02:39:30 +00:00
|
|
|
public void addSource(int id, BlockPosWithDimension pos) {
|
2020-07-13 20:37:21 +00:00
|
|
|
Entry entry = getOrCreate(id);
|
|
|
|
if (!entry.sources.contains(pos)) {
|
|
|
|
entry.sources.add(pos);
|
|
|
|
}
|
|
|
|
markDirty();
|
|
|
|
}
|
|
|
|
|
2020-07-21 02:39:30 +00:00
|
|
|
public void removeSource(int id, BlockPosWithDimension pos) {
|
2020-07-13 20:37:21 +00:00
|
|
|
Entry entry = getOrCreate(id);
|
|
|
|
entry.sources.remove(pos);
|
|
|
|
markDirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
public int create() {
|
|
|
|
int id = -1;
|
|
|
|
for (Entry entry : networks) {
|
|
|
|
id = Math.max(id, entry.id);
|
|
|
|
}
|
|
|
|
return getOrCreate(id + 1).id;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void markDirty() {
|
|
|
|
List<Integer> ids = new ArrayList<>();
|
2020-07-21 02:39:30 +00:00
|
|
|
List<BlockPosWithDimension> positions = new ArrayList<>();
|
2020-07-13 20:37:21 +00:00
|
|
|
Iterator<Entry> iterator = networks.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
Entry entry = iterator.next();
|
|
|
|
boolean remove = false;
|
|
|
|
if (ids.contains(entry.id)) {
|
|
|
|
remove = true;
|
|
|
|
} else {
|
|
|
|
ids.add(entry.id);
|
|
|
|
}
|
|
|
|
if (!Collections.disjoint(positions, entry.sources)) {
|
|
|
|
remove = true;
|
|
|
|
} else {
|
|
|
|
positions.addAll(entry.sources);
|
|
|
|
}
|
|
|
|
if (remove) {
|
|
|
|
iterator.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
super.markDirty();
|
|
|
|
}
|
|
|
|
}
|