From 4d26f9bab4f19b98438cb7baec64cecf689cb7e1 Mon Sep 17 00:00:00 2001
From: asie <kontakt@asie.pl>
Date: Tue, 28 May 2019 19:08:33 +0200
Subject: [PATCH] [fabric-registry-sync] fix StateIdTracker

---
 fabric-registry-sync-v0/build.gradle          |  2 +-
 .../registry/trackers/StateIdTracker.java     | 45 +++++++++++++++++--
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/fabric-registry-sync-v0/build.gradle b/fabric-registry-sync-v0/build.gradle
index 52e75945a..f794ba336 100644
--- a/fabric-registry-sync-v0/build.gradle
+++ b/fabric-registry-sync-v0/build.gradle
@@ -1,5 +1,5 @@
 archivesBaseName = "fabric-registry-sync-v0"
-version = getSubprojectVersion(project, "0.2.0")
+version = getSubprojectVersion(project, "0.2.1")
 
 dependencies {
 	compile project(path: ':fabric-api-base', configuration: 'dev')
diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/trackers/StateIdTracker.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/trackers/StateIdTracker.java
index 426eaaa6d..594b134a5 100644
--- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/trackers/StateIdTracker.java
+++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/trackers/StateIdTracker.java
@@ -18,37 +18,76 @@ package net.fabricmc.fabric.impl.registry.trackers;
 
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
+import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
 import net.fabricmc.fabric.api.event.registry.RegistryIdRemapCallback;
 import net.fabricmc.fabric.impl.registry.RemovableIdList;
 import net.minecraft.util.IdList;
+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.Collection;
 import java.util.function.Function;
 
-public final class StateIdTracker<T, S> implements RegistryIdRemapCallback<T> {
+public final class StateIdTracker<T, S> implements RegistryIdRemapCallback<T>, RegistryEntryAddedCallback<T> {
+	private final Logger logger = LogManager.getLogger();
 	private final Registry<T> registry;
 	private final IdList<S> stateList;
 	private final Function<T, Collection<S>> stateGetter;
+	private int currentHighestId = 0;
 
 	public static <T, S> void register(Registry<T> registry, IdList<S> stateList, Function<T, Collection<S>> stateGetter) {
-		RegistryIdRemapCallback.event(registry).register(new StateIdTracker<>(registry, stateList, stateGetter));
+		StateIdTracker<T, S> tracker = new StateIdTracker<>(registry, stateList, stateGetter);
+		RegistryEntryAddedCallback.event(registry).register(tracker);
+		RegistryIdRemapCallback.event(registry).register(tracker);
 	}
 
 	private StateIdTracker(Registry<T> registry, IdList<S> stateList, Function<T, Collection<S>> stateGetter) {
 		this.registry = registry;
 		this.stateList = stateList;
 		this.stateGetter = stateGetter;
+
+		recalcHighestId();
+	}
+
+	@Override
+	public void onEntryAdded(int rawId, Identifier id, T object) {
+		if (rawId == currentHighestId + 1) {
+			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...");
+			recalcStateMap();
+		}
 	}
 
 	@Override
 	public void onRemap(RemapState<T> state) {
+		recalcStateMap();
+	}
+
+	private void recalcStateMap() {
 		((RemovableIdList) stateList).fabric_clear();
 
 		Int2ObjectMap<T> sortedBlocks = new Int2ObjectRBTreeMap<>();
-		registry.forEach((t) -> sortedBlocks.put(registry.getRawId(t), t));
+
+		currentHighestId = 0;
+		registry.forEach((t) -> {
+			int rawId = registry.getRawId(t);
+			currentHighestId = Math.max(currentHighestId, rawId);
+			sortedBlocks.put(rawId, t);
+		});
+
 		for (T b : sortedBlocks.values()) {
 			stateGetter.apply(b).forEach(stateList::add);
 		}
 	}
+
+	private void recalcHighestId() {
+		currentHighestId = 0;
+		for (T object : registry) {
+			currentHighestId = Math.max(currentHighestId, registry.getRawId(object));
+		}
+	}
 }