mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-15 00:14:28 -04:00
fabric-registry-sync: lots of fixes and debug functionality
This commit is contained in:
parent
229941196c
commit
baba33ba30
13 changed files with 262 additions and 104 deletions
fabric-registry-sync-v0
build.gradle
src/main/java/net/fabricmc/fabric
impl/registry
mixin/registry
|
@ -1,5 +1,5 @@
|
|||
archivesBaseName = "fabric-registry-sync-v0"
|
||||
version = getSubprojectVersion(project, "0.2.1")
|
||||
version = getSubprojectVersion(project, "0.2.2")
|
||||
|
||||
dependencies {
|
||||
compile project(path: ':fabric-api-base', configuration: 'dev')
|
||||
|
|
|
@ -31,7 +31,7 @@ public class FabricRegistryClientInit implements ClientModInitializer {
|
|||
public void onInitializeClient() {
|
||||
ClientSidePacketRegistry.INSTANCE.register(RegistrySyncManager.ID, (ctx, buf) -> {
|
||||
// if not hosting server, apply packet
|
||||
RegistrySyncManager.receivePacket(ctx, buf, !MinecraftClient.getInstance().isInSingleplayer(), (e) -> {
|
||||
RegistrySyncManager.receivePacket(ctx, buf, RegistrySyncManager.DEBUG || !MinecraftClient.getInstance().isInSingleplayer(), (e) -> {
|
||||
LOGGER.error("Registry remapping failed!", e);
|
||||
MinecraftClient.getInstance().execute(() -> {
|
||||
((ClientPlayerEntity) ctx.getPlayer()).networkHandler.getClientConnection().disconnect(
|
||||
|
|
|
@ -16,8 +16,12 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.registry;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.fabricmc.fabric.api.network.PacketContext;
|
||||
|
@ -29,7 +33,13 @@ import net.minecraft.util.PacketByteBuf;
|
|||
import net.minecraft.util.registry.MutableRegistry;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.SimpleRegistry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -37,7 +47,10 @@ import java.util.concurrent.TimeoutException;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
public final class RegistrySyncManager {
|
||||
public static final Identifier ID = new Identifier("fabric", "registry/sync");
|
||||
static final boolean DEBUG = System.getProperty("fabric.registry.debug", "false").equalsIgnoreCase("true");
|
||||
static final Identifier ID = new Identifier("fabric", "registry/sync");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final boolean DEBUG_WRITE_REGISTRY_DATA = System.getProperty("fabric.registry.debug.writeContentsAsCsv", "false").equalsIgnoreCase("true");
|
||||
private static final Set<Identifier> REGISTRY_BLACKLIST = ImmutableSet.of();
|
||||
private static final Set<Identifier> REGISTRY_BLACKLIST_NETWORK = ImmutableSet.of();
|
||||
|
||||
|
@ -80,6 +93,39 @@ public final class RegistrySyncManager {
|
|||
CompoundTag mainTag = new CompoundTag();
|
||||
|
||||
for (Identifier registryId : Registry.REGISTRIES.getIds()) {
|
||||
if (DEBUG_WRITE_REGISTRY_DATA) {
|
||||
File location = new File(".fabric" + File.separatorChar + "debug" + File.separatorChar + "registry");
|
||||
boolean c = true;
|
||||
if (!location.exists()) {
|
||||
if (!location.mkdirs()) {
|
||||
LOGGER.warn("[fabric-registry-sync debug] Could not create " + location.getAbsolutePath() + " directory!");
|
||||
c = false;
|
||||
}
|
||||
}
|
||||
|
||||
MutableRegistry registry = Registry.REGISTRIES.get(registryId);
|
||||
if (c && registry != null) {
|
||||
File file = new File(location, registryId.toString().replace(':', '.').replace('/', '.') + ".csv");
|
||||
try (FileOutputStream stream = new FileOutputStream(file)) {
|
||||
StringBuilder builder = new StringBuilder("Raw ID,String ID,Class Type\n");
|
||||
for (Object o : registry) {
|
||||
String classType = (o == null) ? "null" : o.getClass().getName();
|
||||
//noinspection unchecked
|
||||
Identifier id = registry.getId(o);
|
||||
if (id == null) continue;
|
||||
|
||||
//noinspection unchecked
|
||||
int rawId = registry.getRawId(o);
|
||||
String stringId = id.toString();
|
||||
builder.append("\"").append(rawId).append("\",\"").append(stringId).append("\",\"").append(classType).append("\"\n");
|
||||
}
|
||||
stream.write(builder.toString().getBytes(StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("[fabric-registry-sync debug] Could not write to " + file.getAbsolutePath() + "!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (REGISTRY_BLACKLIST.contains(registryId)) {
|
||||
continue;
|
||||
} else if (isClientSync && REGISTRY_BLACKLIST_NETWORK.contains(registryId)) {
|
||||
|
@ -87,12 +133,35 @@ public final class RegistrySyncManager {
|
|||
}
|
||||
|
||||
MutableRegistry registry = Registry.REGISTRIES.get(registryId);
|
||||
if (registry instanceof SimpleRegistry && registry instanceof RemappableRegistry) {
|
||||
if (registry instanceof RemappableRegistry) {
|
||||
CompoundTag registryTag = new CompoundTag();
|
||||
//noinspection unchecked
|
||||
for (Identifier identifier : (Set<Identifier>) registry.getIds()) {
|
||||
registryTag.putInt(identifier.toString(), registry.getRawId(registry.get(identifier)));
|
||||
IntSet rawIdsFound = DEBUG ? new IntOpenHashSet() : null;
|
||||
|
||||
for (Object o : registry) {
|
||||
//noinspection unchecked
|
||||
Identifier id = registry.getId(o);
|
||||
if (id == null) continue;
|
||||
|
||||
//noinspection unchecked
|
||||
int rawId = registry.getRawId(o);
|
||||
|
||||
if (DEBUG) {
|
||||
if (registry.get(id) != o) {
|
||||
LOGGER.error("[fabric-registry-sync] Inconsistency detected in " + registryId + ": object " + o + " -> string ID " + id + " -> object " + registry.get(id) + "!");
|
||||
}
|
||||
|
||||
if (registry.get(rawId) != o) {
|
||||
LOGGER.error("[fabric-registry-sync] Inconsistency detected in " + registryId + ": object " + o + " -> integer ID " + rawId + " -> object " + registry.get(rawId) + "!");
|
||||
}
|
||||
|
||||
if (!rawIdsFound.add(rawId)) {
|
||||
LOGGER.error("[fabric-registry-sync] Inconsistency detected in " + registryId + ": multiple objects hold the raw ID " + rawId + " (this one is " + id + ")");
|
||||
}
|
||||
}
|
||||
|
||||
registryTag.putInt(id.toString(), rawId);
|
||||
}
|
||||
|
||||
mainTag.put(registryId.toString(), registryTag);
|
||||
}
|
||||
}
|
||||
|
@ -106,22 +175,29 @@ public final class RegistrySyncManager {
|
|||
|
||||
public static void apply(CompoundTag tag, RemappableRegistry.RemapMode mode) throws RemapException {
|
||||
CompoundTag mainTag = tag.getCompound("registries");
|
||||
Set<String> containedRegistries = Sets.newHashSet(mainTag.getKeys());
|
||||
|
||||
for (Identifier registryId : Registry.REGISTRIES.getIds()) {
|
||||
if (!mainTag.containsKey(registryId.toString())) {
|
||||
if (!containedRegistries.remove(registryId.toString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CompoundTag registryTag = mainTag.getCompound(registryId.toString());
|
||||
MutableRegistry registry = Registry.REGISTRIES.get(registryId);
|
||||
if (registry instanceof SimpleRegistry && registry instanceof RemappableRegistry) {
|
||||
|
||||
if (registry instanceof RemappableRegistry) {
|
||||
Object2IntMap<Identifier> idMap = new Object2IntOpenHashMap<>();
|
||||
for (String key : registryTag.getKeys()) {
|
||||
idMap.put(new Identifier(key), registryTag.getInt(key));
|
||||
}
|
||||
|
||||
((RemappableRegistry) registry).remap(registryId.toString(), idMap, mode);
|
||||
}
|
||||
}
|
||||
|
||||
if (!containedRegistries.isEmpty()) {
|
||||
LOGGER.warn("[fabric-registry-sync] Could not find the following registries: " + Joiner.on(", ").join(containedRegistries));
|
||||
}
|
||||
}
|
||||
|
||||
public static void unmap() throws RemapException {
|
||||
|
|
|
@ -25,10 +25,12 @@ import net.minecraft.util.registry.Registry;
|
|||
|
||||
public class RemapStateImpl<T> implements RegistryIdRemapCallback.RemapState<T> {
|
||||
private final Int2IntMap rawIdChangeMap;
|
||||
private final Int2ObjectMap<Identifier> oldIdMap;
|
||||
private final Int2ObjectMap<Identifier> newIdMap;
|
||||
|
||||
public RemapStateImpl(Registry<T> registry, Int2IntMap rawIdChangeMap) {
|
||||
public RemapStateImpl(Registry<T> registry, Int2ObjectMap<Identifier> oldIdMap, Int2IntMap rawIdChangeMap) {
|
||||
this.rawIdChangeMap = rawIdChangeMap;
|
||||
this.oldIdMap = oldIdMap;
|
||||
this.newIdMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
for (Int2IntMap.Entry entry : rawIdChangeMap.int2IntEntrySet()) {
|
||||
|
@ -44,7 +46,7 @@ public class RemapStateImpl<T> implements RegistryIdRemapCallback.RemapState<T>
|
|||
|
||||
@Override
|
||||
public Identifier getIdFromOld(int oldRawId) {
|
||||
return newIdMap.get(rawIdChangeMap.getOrDefault(oldRawId, -1));
|
||||
return oldIdMap.get(oldRawId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,15 +28,17 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
public class IdListTracker<V, OV> implements RegistryEntryAddedCallback<V>, RegistryIdRemapCallback<V>, RegistryEntryRemovedCallback<V> {
|
||||
private final String name;
|
||||
private final IdList<OV> mappers;
|
||||
private Map<Identifier, OV> removedMapperCache = new HashMap<>();
|
||||
|
||||
private IdListTracker(IdList<OV> mappers) {
|
||||
private IdListTracker(String name, IdList<OV> mappers) {
|
||||
this.name = name;
|
||||
this.mappers = mappers;
|
||||
}
|
||||
|
||||
public static <V, OV> void register(Registry<V> registry, IdList<OV> mappers) {
|
||||
IdListTracker<V, OV> updater = new IdListTracker<>(mappers);
|
||||
public static <V, OV> void register(Registry<V> registry, String name, IdList<OV> mappers) {
|
||||
IdListTracker<V, OV> updater = new IdListTracker<>(name, mappers);
|
||||
RegistryEntryAddedCallback.event(registry).register(updater);
|
||||
RegistryIdRemapCallback.event(registry).register(updater);
|
||||
RegistryEntryRemovedCallback.event(registry).register(updater);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.registry.trackers;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
|
||||
|
@ -23,20 +25,27 @@ import net.fabricmc.fabric.api.event.registry.RegistryIdRemapCallback;
|
|||
import net.fabricmc.fabric.api.event.registry.RegistryEntryRemovedCallback;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Int2ObjectMapTracker<V, OV> implements RegistryEntryAddedCallback<V>, RegistryIdRemapCallback<V>, RegistryEntryRemovedCallback<V> {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final String name;
|
||||
private final Int2ObjectMap<OV> mappers;
|
||||
private Map<Identifier, OV> removedMapperCache = new HashMap<>();
|
||||
|
||||
private Int2ObjectMapTracker(Int2ObjectMap<OV> mappers) {
|
||||
private Int2ObjectMapTracker(String name, Int2ObjectMap<OV> mappers) {
|
||||
this.name = name;
|
||||
this.mappers = mappers;
|
||||
}
|
||||
|
||||
public static <V, OV> void register(Registry<V> registry, Int2ObjectMap<OV> mappers) {
|
||||
Int2ObjectMapTracker<V, OV> updater = new Int2ObjectMapTracker<>(mappers);
|
||||
public static <V, OV> void register(Registry<V> registry, String name, Int2ObjectMap<OV> mappers) {
|
||||
Int2ObjectMapTracker<V, OV> updater = new Int2ObjectMapTracker<>(name, mappers);
|
||||
RegistryEntryAddedCallback.event(registry).register(updater);
|
||||
RegistryIdRemapCallback.event(registry).register(updater);
|
||||
RegistryEntryRemovedCallback.event(registry).register(updater);
|
||||
|
@ -52,22 +61,38 @@ public class Int2ObjectMapTracker<V, OV> implements RegistryEntryAddedCallback<V
|
|||
@Override
|
||||
public void onRemap(RemapState<V> state) {
|
||||
Int2ObjectMap<OV> oldMappers = new Int2ObjectOpenHashMap<>(mappers);
|
||||
Int2IntMap remapMap = state.getRawIdChangeMap();
|
||||
List<String> errors = null;
|
||||
|
||||
mappers.clear();
|
||||
for (int i : oldMappers.keySet()) {
|
||||
int newI = state.getRawIdChangeMap().getOrDefault(i, i);
|
||||
if (mappers.containsKey(newI)) {
|
||||
throw new RuntimeException("Int2ObjectMap contained two equal IDs " + newI + " (" + state.getIdFromOld(i) + "/" + i + " -> " + state.getIdFromNew(newI) + "/" + newI + ")!");
|
||||
}
|
||||
int newI = remapMap.getOrDefault(i, Integer.MIN_VALUE);
|
||||
if (newI >= 0) {
|
||||
if (mappers.containsKey(newI)) {
|
||||
if (errors == null) {
|
||||
errors = new ArrayList<>();
|
||||
}
|
||||
|
||||
mappers.put(newI, oldMappers.get(i));
|
||||
errors.add(" - Map contained two equal IDs " + newI + " (" + state.getIdFromOld(i) + "/" + i + " -> " + state.getIdFromNew(newI) + "/" + newI + ")!");
|
||||
} else {
|
||||
mappers.put(newI, oldMappers.get(i));
|
||||
}
|
||||
} else {
|
||||
LOGGER.warn("[fabric-registry-sync] Int2ObjectMap " + name + " is dropping mapping for integer ID " + i + " (" + state.getIdFromOld(i) + ") - should not happen!");
|
||||
removedMapperCache.put(state.getIdFromOld(i), oldMappers.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (errors != null) {
|
||||
throw new RuntimeException("Errors while remapping Int2ObjectMap " + name + " found:\n" + Joiner.on('\n').join(errors));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryRemoved(int rawId, Identifier id, V object) {
|
||||
if (mappers.containsKey(rawId)) {
|
||||
removedMapperCache.put(id, mappers.remove(rawId));
|
||||
OV mapper = mappers.remove(rawId);
|
||||
if (mapper != null) {
|
||||
removedMapperCache.put(id, mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public final class StateIdTracker<T, S> implements RegistryIdRemapCallback<T>, R
|
|||
stateGetter.apply(object).forEach(stateList::add);
|
||||
currentHighestId = rawId;
|
||||
} else {
|
||||
logger.debug("[fabric-registry-sync] Non-sequential RegistryEntryAddedCallback for state ID tracker (at " + id + "), forcing state map recalculation...");
|
||||
logger.debug("[fabric-registry-sync] Non-sequential RegistryEntryAddedCallback for " + object.getClass().getSimpleName() + " ID tracker (at " + id + "), forcing state map recalculation...");
|
||||
recalcStateMap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ package net.fabricmc.fabric.mixin.registry;
|
|||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
|
@ -116,12 +115,21 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
|
|||
@SuppressWarnings({"unchecked", "ConstantConditions"})
|
||||
@Inject(method = "set", at = @At("HEAD"))
|
||||
public void setPre(int id, Identifier identifier, Object object, CallbackInfoReturnable info) {
|
||||
int indexedEntriesId = indexedEntries.getId((T) object);
|
||||
if (indexedEntriesId >= 0) {
|
||||
throw new RuntimeException("Attempted to register object " + object + " twice! (at raw IDs " + indexedEntriesId + " and " + id + " )");
|
||||
}
|
||||
|
||||
if (!entries.containsKey(identifier)) {
|
||||
fabric_isObjectNew = true;
|
||||
} else {
|
||||
T oldObject = entries.get(identifier);
|
||||
int oldId = indexedEntries.getId(oldObject);
|
||||
if (oldObject != object || oldId != id) {
|
||||
if (oldObject != null && oldObject != object) {
|
||||
int oldId = indexedEntries.getId(oldObject);
|
||||
if (oldId != id) {
|
||||
throw new RuntimeException("Attempted to register ID " + identifier + " at different raw IDs (" + oldId + ", " + id + ")! If you're trying to override an item, use .set(), not .register()!");
|
||||
}
|
||||
|
||||
fabric_removeObjectEvent.invoker().onEntryRemoved(oldId, identifier, oldObject);
|
||||
fabric_isObjectNew = true;
|
||||
} else {
|
||||
|
@ -148,14 +156,18 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
|
|||
case AUTHORITATIVE:
|
||||
break;
|
||||
case REMOTE: {
|
||||
List<String> strings = new ArrayList<>();
|
||||
List<String> strings = null;
|
||||
for (Identifier remoteId : remoteIndexedEntries.keySet()) {
|
||||
if (!registry.getIds().contains(remoteId)) {
|
||||
if (!entries.keySet().contains(remoteId)) {
|
||||
if (strings == null) {
|
||||
strings = new ArrayList<>();
|
||||
}
|
||||
|
||||
strings.add(" - " + remoteId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!strings.isEmpty()) {
|
||||
if (strings != null) {
|
||||
StringBuilder builder = new StringBuilder("Received ID map for " + name + " contains IDs unknown to the receiver!");
|
||||
for (String s : strings) {
|
||||
builder.append('\n').append(s);
|
||||
|
@ -164,10 +176,10 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
|
|||
}
|
||||
} break;
|
||||
case EXACT: {
|
||||
if (!registry.getIds().equals(remoteIndexedEntries.keySet())) {
|
||||
if (!entries.keySet().equals(remoteIndexedEntries.keySet())) {
|
||||
List<String> strings = new ArrayList<>();
|
||||
for (Identifier remoteId : remoteIndexedEntries.keySet()) {
|
||||
if (!registry.getIds().contains(remoteId)) {
|
||||
if (!entries.keySet().contains(remoteId)) {
|
||||
strings.add(" - " + remoteId + " (missing on local)");
|
||||
}
|
||||
}
|
||||
|
@ -196,53 +208,68 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
|
|||
if (fabric_prevIndexedEntries == null) {
|
||||
fabric_prevIndexedEntries = new Object2IntOpenHashMap<>();
|
||||
fabric_prevEntries = HashBiMap.create(entries);
|
||||
for (Identifier id : registry.getIds()) {
|
||||
//noinspection unchecked
|
||||
fabric_prevIndexedEntries.put(id, registry.getRawId(registry.get(id)));
|
||||
for (Object o : registry) {
|
||||
fabric_prevIndexedEntries.put(registry.getId(o), registry.getRawId(o));
|
||||
}
|
||||
}
|
||||
|
||||
Int2ObjectMap<Identifier> oldIdMap = new Int2ObjectOpenHashMap<>();
|
||||
for (Object o : registry) {
|
||||
oldIdMap.put(registry.getRawId(o), registry.getId(o));
|
||||
}
|
||||
|
||||
// If we're AUTHORITATIVE, we append entries which only exist on the
|
||||
// local side to the new entry list. For REMOTE, we instead drop them.
|
||||
if (mode == RemapMode.AUTHORITATIVE) {
|
||||
int maxValue = 0;
|
||||
switch (mode) {
|
||||
case AUTHORITATIVE: {
|
||||
int maxValue = 0;
|
||||
|
||||
Object2IntMap<Identifier> oldRemoteIndexedEntries = remoteIndexedEntries;
|
||||
remoteIndexedEntries = new Object2IntOpenHashMap<>();
|
||||
for (Identifier id : oldRemoteIndexedEntries.keySet()) {
|
||||
int v = oldRemoteIndexedEntries.getInt(id);
|
||||
remoteIndexedEntries.put(id, v);
|
||||
if (v > maxValue) maxValue = v;
|
||||
}
|
||||
|
||||
for (Identifier id : registry.getIds()) {
|
||||
if (!remoteIndexedEntries.containsKey(id)) {
|
||||
FABRIC_LOGGER.warn("Adding " + id + " to saved/remote registry.");
|
||||
remoteIndexedEntries.put(id, ++maxValue);
|
||||
Object2IntMap<Identifier> oldRemoteIndexedEntries = remoteIndexedEntries;
|
||||
remoteIndexedEntries = new Object2IntOpenHashMap<>();
|
||||
for (Identifier id : oldRemoteIndexedEntries.keySet()) {
|
||||
int v = oldRemoteIndexedEntries.getInt(id);
|
||||
remoteIndexedEntries.put(id, v);
|
||||
if (v > maxValue) maxValue = v;
|
||||
}
|
||||
}
|
||||
} else if (mode == RemapMode.REMOTE) {
|
||||
// TODO: Is this what mods really want?
|
||||
Set<Identifier> droppedIds = new HashSet<>();
|
||||
|
||||
for (Identifier id : registry.getIds()) {
|
||||
if (!remoteIndexedEntries.containsKey(id)) {
|
||||
droppedIds.add(id);
|
||||
Object object = registry.get(id);
|
||||
|
||||
// Emit RemoveObject events for removed objects.
|
||||
//noinspection unchecked
|
||||
fabric_getRemoveObjectEvent().invoker().onEntryRemoved(registry.getRawId(object), id, (T) object);
|
||||
for (Identifier id : registry.getIds()) {
|
||||
if (!remoteIndexedEntries.containsKey(id)) {
|
||||
FABRIC_LOGGER.warn("Adding " + id + " to saved/remote registry.");
|
||||
remoteIndexedEntries.put(id, ++maxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case REMOTE: {
|
||||
// TODO: Is this what mods really want?
|
||||
Set<Identifier> droppedIds = new HashSet<>();
|
||||
|
||||
entries.keySet().removeAll(droppedIds);
|
||||
for (Identifier id : registry.getIds()) {
|
||||
if (!remoteIndexedEntries.containsKey(id)) {
|
||||
Object object = registry.get(id);
|
||||
int rid = registry.getRawId(object);
|
||||
|
||||
droppedIds.add(id);
|
||||
|
||||
// Emit RemoveObject events for removed objects.
|
||||
//noinspection unchecked
|
||||
fabric_getRemoveObjectEvent().invoker().onEntryRemoved(rid, id, (T) object);
|
||||
}
|
||||
}
|
||||
|
||||
// note: indexedEntries cannot be safely remove()d from
|
||||
entries.keySet().removeAll(droppedIds);
|
||||
} break;
|
||||
}
|
||||
|
||||
Int2IntMap idMap = new Int2IntOpenHashMap();
|
||||
for (Object o : indexedEntries) {
|
||||
Identifier id = registry.getId(o);
|
||||
idMap.put(registry.getRawId(o), remoteIndexedEntries.getInt(id));
|
||||
int rid = registry.getRawId(o);
|
||||
|
||||
// see above note
|
||||
if (remoteIndexedEntries.containsKey(id)) {
|
||||
idMap.put(rid, remoteIndexedEntries.getInt(id));
|
||||
}
|
||||
}
|
||||
|
||||
// entries was handled above, if it was necessary.
|
||||
|
@ -276,7 +303,7 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
|
|||
}
|
||||
|
||||
//noinspection unchecked
|
||||
fabric_getRemapEvent().invoker().onRemap(new RemapStateImpl(registry, idMap));
|
||||
fabric_getRemapEvent().invoker().onRemap(new RemapStateImpl(registry, oldIdMap, idMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,12 +30,10 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
|
||||
@Mixin(WorldSaveHandler.class)
|
||||
public class MixinWorldSaveHandler {
|
||||
|
@ -49,6 +47,7 @@ public class MixinWorldSaveHandler {
|
|||
@Unique
|
||||
private CompoundTag fabric_lastSavedIdMap = null;
|
||||
|
||||
@Unique
|
||||
private boolean fabric_readIdMapFile(File file) throws IOException, RemapException {
|
||||
if (file.exists()) {
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
|
@ -63,20 +62,69 @@ public class MixinWorldSaveHandler {
|
|||
return false;
|
||||
}
|
||||
|
||||
private File getWorldIdMapFile(int i) {
|
||||
@Unique
|
||||
private File fabric_getWorldIdMapFile(int i) {
|
||||
return new File(new File(worldDir, "data"), "fabricRegistry" + ".dat" + (i == 0 ? "" : ("." + i)));
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void fabric_saveRegistryData() {
|
||||
CompoundTag newIdMap = RegistrySyncManager.toTag(false);
|
||||
if (!newIdMap.equals(fabric_lastSavedIdMap)) {
|
||||
for (int i = FABRIC_ID_REGISTRY_BACKUPS - 1; i >= 0; i--) {
|
||||
File file = fabric_getWorldIdMapFile(i);
|
||||
if (file.exists()) {
|
||||
if (i == FABRIC_ID_REGISTRY_BACKUPS - 1) {
|
||||
file.delete();
|
||||
} else {
|
||||
File target = fabric_getWorldIdMapFile(i + 1);
|
||||
file.renameTo(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File file = fabric_getWorldIdMapFile(0);
|
||||
File parentFile = file.getParentFile();
|
||||
if (!parentFile.exists()) {
|
||||
if (!parentFile.mkdirs()) {
|
||||
FABRIC_LOGGER.warn("[fabric-registry-sync] Could not create directory " + parentFile + "!");
|
||||
}
|
||||
}
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(file);
|
||||
NbtIo.writeCompressed(newIdMap, fileOutputStream);
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
FABRIC_LOGGER.warn("[fabric-registry-sync] Failed to save registry file!", e);
|
||||
}
|
||||
|
||||
fabric_lastSavedIdMap = newIdMap;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "saveWorld", at = @At("HEAD"))
|
||||
public void saveWorld(LevelProperties levelProperties, CompoundTag compoundTag, CallbackInfo info) {
|
||||
if (!worldDir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fabric_saveRegistryData();
|
||||
}
|
||||
|
||||
// TODO: stop double save on client?
|
||||
@Inject(method = "readProperties", at = @At("HEAD"))
|
||||
public void readWorldProperties(CallbackInfoReturnable<LevelProperties> callbackInfo) {
|
||||
// Load
|
||||
for (int i = 0; i < FABRIC_ID_REGISTRY_BACKUPS; i++) {
|
||||
FABRIC_LOGGER.info("Loading Fabric registry [file " + (i + 1) + "/" + (FABRIC_ID_REGISTRY_BACKUPS + 1) + "]");
|
||||
FABRIC_LOGGER.trace("[fabric-registry-sync] Loading Fabric registry [file " + (i + 1) + "/" + (FABRIC_ID_REGISTRY_BACKUPS + 1) + "]");
|
||||
try {
|
||||
if (fabric_readIdMapFile(getWorldIdMapFile(i))) {
|
||||
break;
|
||||
if (fabric_readIdMapFile(fabric_getWorldIdMapFile(i))) {
|
||||
FABRIC_LOGGER.info("[fabric-registry-sync] Loaded registry data [file " + (i + 1) + "/" + (FABRIC_ID_REGISTRY_BACKUPS + 1) + "]");
|
||||
return;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// pass
|
||||
} catch (IOException e) {
|
||||
if (i >= FABRIC_ID_REGISTRY_BACKUPS - 1) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -88,29 +136,7 @@ public class MixinWorldSaveHandler {
|
|||
}
|
||||
}
|
||||
|
||||
CompoundTag newIdMap = RegistrySyncManager.toTag(false);
|
||||
if (!newIdMap.equals(fabric_lastSavedIdMap)) {
|
||||
for (int i = FABRIC_ID_REGISTRY_BACKUPS - 1; i >= 0; i--) {
|
||||
File file = getWorldIdMapFile(i);
|
||||
if (file.exists()) {
|
||||
if (i == FABRIC_ID_REGISTRY_BACKUPS - 1) {
|
||||
file.delete();
|
||||
} else {
|
||||
File target = getWorldIdMapFile(i + 1);
|
||||
file.renameTo(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(getWorldIdMapFile(0));
|
||||
NbtIo.writeCompressed(newIdMap, fileOutputStream);
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
FABRIC_LOGGER.warn("Failed to save registry file!", e);
|
||||
}
|
||||
|
||||
fabric_lastSavedIdMap = newIdMap;
|
||||
}
|
||||
// If not returned (not present), try saving the registry data
|
||||
fabric_saveRegistryData();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,6 @@ public class MixinBlockColorMap {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void create(CallbackInfo info) {
|
||||
IdListTracker.register(Registry.BLOCK, providers);
|
||||
IdListTracker.register(Registry.BLOCK, "BlockColors.providers", providers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,6 @@ public class MixinItemColorMap {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void create(CallbackInfo info) {
|
||||
IdListTracker.register(Registry.ITEM, providers);
|
||||
IdListTracker.register(Registry.ITEM, "ItemColors.providers", providers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class MixinItemModelMap {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
public void onInit(BakedModelManager bakedModelManager, CallbackInfo info) {
|
||||
Int2ObjectMapTracker.register(Registry.ITEM, modelIds);
|
||||
Int2ObjectMapTracker.register(Registry.ITEM, models);
|
||||
Int2ObjectMapTracker.register(Registry.ITEM, "ItemModels.modelIds", modelIds);
|
||||
Int2ObjectMapTracker.register(Registry.ITEM, "ItemModels.models", models);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,6 @@ public class MixinParticleManager {
|
|||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
public void onInit(World world, TextureManager textureManager, CallbackInfo info) {
|
||||
Int2ObjectMapTracker.register(Registry.PARTICLE_TYPE, factories);
|
||||
Int2ObjectMapTracker.register(Registry.PARTICLE_TYPE, "ParticleManager.factories", factories);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue