/
MultiblockManager.java
149 lines (126 loc) · 5.02 KB
/
MultiblockManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package mekanism.common.lib.multiblock;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import mekanism.api.Coord4D;
import mekanism.common.tile.prefab.TileEntityMultiblock;
import mekanism.common.util.WorldUtils;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
public class MultiblockManager<T extends MultiblockData> {
private static final Set<MultiblockManager<?>> managers = new ObjectOpenHashSet<>();
private final String name;
private final String nameLower;
private final Supplier<MultiblockCache<T>> cacheSupplier;
private final Supplier<IStructureValidator<T>> validatorSupplier;
/**
* A map containing references to all multiblock inventory caches.
*/
public final Map<UUID, CacheWrapper> inventories = new Object2ObjectOpenHashMap<>();
public MultiblockManager(String name, Supplier<MultiblockCache<T>> cacheSupplier, Supplier<IStructureValidator<T>> validatorSupplier) {
this.name = name;
this.nameLower = name.toLowerCase(Locale.ROOT);
this.cacheSupplier = cacheSupplier;
this.validatorSupplier = validatorSupplier;
managers.add(this);
}
public MultiblockCache<T> createCache() {
return cacheSupplier.get();
}
public IStructureValidator<T> createValidator() {
return validatorSupplier.get();
}
public String getName() {
return name;
}
public String getNameLower() {
return nameLower;
}
@Nullable
public static UUID getMultiblockID(TileEntityMultiblock<?> tile) {
return tile.getMultiblock().inventoryID;
}
public boolean isCompatible(TileEntity tile) {
if (tile instanceof IMultiblock) {
return ((IMultiblock<?>) tile).getManager() == this;
}
return false;
}
public static void reset() {
for (MultiblockManager<?> manager : managers) {
manager.inventories.clear();
}
}
public void invalidate(IMultiblock<?> multiblock) {
CacheWrapper cache = inventories.get(multiblock.getCacheID());
if (cache != null) {
cache.locations.remove(multiblock.getTileCoord());
if (cache.locations.isEmpty()) {
inventories.remove(multiblock.getCacheID());
}
}
}
/**
* Grabs an inventory from the world's caches, and removes all the world's references to it. NOTE: this is not guaranteed to remove all references if somehow blocks
* with this inventory ID exist in unloaded chunks when the inventory is pulled. We should consider whether we should implement a way to mitigate this.
*
* @param world - world the cache is stored in
* @param id - inventory ID to pull
*
* @return correct multiblock inventory cache
*/
public MultiblockCache<T> pullInventory(World world, UUID id) {
CacheWrapper toReturn = inventories.get(id);
for (Coord4D obj : toReturn.locations) {
TileEntity tile = WorldUtils.getTileEntity(TileEntity.class, world, obj.getPos());
if (tile instanceof IMultiblock) {
((IMultiblock<?>) tile).resetCache();
}
}
inventories.remove(id);
return toReturn.getCache();
}
/**
* Grabs a unique inventory ID for a multiblock.
*
* @return unique inventory ID
*/
public UUID getUniqueInventoryID() {
return UUID.randomUUID();
}
public void updateCache(IMultiblock<T> tile, T multiblock) {
inventories.computeIfAbsent(tile.getCacheID(), id -> new CacheWrapper()).update(tile, multiblock);
}
private class CacheWrapper {
private MultiblockCache<T> cache;
private final Set<Coord4D> locations = new ObjectOpenHashSet<>();
public MultiblockCache<T> getCache() {
return cache;
}
public void update(IMultiblock<T> tile, T multiblock) {
locations.add(tile.getTileCoord());
if (multiblock.isFormed()) {
if (tile.isMaster()) {
// create a new cache for the tile if it needs one
if (!tile.hasCache()) {
tile.setCache(createCache());
}
// if this is the master tile, sync the cache with the multiblock and then update our reference
tile.getCache().sync(multiblock);
cache = tile.getCache();
}
} else if (tile.hasCache()) {
// if the tile doesn't have a formed multiblock but has a cache, update our reference
cache = tile.getCache();
} else if (cache != null) {
// if the tile doesn't have a cache but we do, update the tile's reference
tile.setCache(cache);
}
}
}
}