Added DynamicRegistryEntryAddedCallback

This commit is contained in:
CheaterCodes 2020-08-19 18:31:52 +02:00
parent 74685c149c
commit e9c7de9661
8 changed files with 213 additions and 36 deletions
build.gradle
fabric-registry-sync-v0/src
main
testmod/java/net/fabricmc/fabric/test/registry/sync

View file

@ -73,7 +73,7 @@ allprojects {
dependencies {
minecraft "com.mojang:minecraft:$Globals.mcVersion"
mappings "net.fabricmc:yarn:${Globals.mcVersion}${Globals.yarnVersion}:v2"
modCompile "net.fabricmc:fabric-loader:0.8.9+build.203"
modCompile "net.fabricmc:fabric-loader:0.9.2+build.206"
}
configurations {

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.event.registry;
import net.minecraft.util.registry.MutableRegistry;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.impl.registry.sync.DynamicRegistryEvents;
@FunctionalInterface
public interface DynamicRegistryEntryAddedCallback {
void onEntryAdded(int rawId, RegistryKey<?> key, Object object, MutableRegistry<?> registry);
static Event<DynamicRegistryEntryAddedCallback> event(RegistryKey<? extends Registry<?>> registryKey) {
if (!DynamicRegistryEvents.ADD_ENTRY_EVENTS.containsKey(registryKey)) {
throw new IllegalArgumentException("Unsupported registry: " + registryKey);
}
return DynamicRegistryEvents.ADD_ENTRY_EVENTS.get(registryKey);
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.registry.sync;
import java.util.Map;
import com.google.common.collect.Maps;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.event.registry.DynamicRegistryEntryAddedCallback;
import net.fabricmc.fabric.mixin.registry.sync.DynamicRegistryManagerAccessor;
public abstract class DynamicRegistryEvents {
public static Map<RegistryKey<? extends Registry<?>>, Event<DynamicRegistryEntryAddedCallback>> ADD_ENTRY_EVENTS;
static {
ADD_ENTRY_EVENTS = Maps.newLinkedHashMap();
for (RegistryKey<? extends Registry<?>> registryKey : DynamicRegistryManagerAccessor.getInfos().keySet()) {
ADD_ENTRY_EVENTS.put(registryKey,
EventFactory.createArrayBacked(
DynamicRegistryEntryAddedCallback.class,
callbacks -> (rawId, key, object, registry) -> {
for (DynamicRegistryEntryAddedCallback callback : callbacks) {
callback.onEntryAdded(rawId, key, object, registry);
}
}));
}
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.registry.sync;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
@Mixin(DynamicRegistryManager.class)
public interface DynamicRegistryManagerAccessor {
@Accessor("INFOS")
static Map<RegistryKey<? extends Registry<?>>, ?> getInfos() {
throw new AbstractMethodError();
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.registry.sync;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.registry.DynamicRegistryEntryAddedCallback;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import net.fabricmc.fabric.impl.registry.sync.DynamicRegistryEvents;
@Mixin(DynamicRegistryManager.class)
public class DynamicRegistryManagerMixin {
@Inject(method = "create", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/dynamic/RegistryOps$class_5506$class_5507;<init>()V"), locals = LocalCapture.CAPTURE_FAILHARD)
private static void onCreateImpl(CallbackInfoReturnable<DynamicRegistryManager.Impl> cir, DynamicRegistryManager.Impl registryManager) {
for (Map.Entry<RegistryKey<? extends Registry<?>>, Event<DynamicRegistryEntryAddedCallback>> event : DynamicRegistryEvents.ADD_ENTRY_EVENTS.entrySet()) {
//noinspection unchecked
RegistryKey<? extends Registry<Object>> registryKey = (RegistryKey<? extends Registry<Object>>) event.getKey();
RegistryEntryAddedCallback.event(registryManager.get(registryKey)).register((rawId, id, object) -> {
RegistryKey<?> key = RegistryKey.of(registryKey, id);
event.getValue().invoker().onEntryAdded(rawId, key, object, registryManager.get(registryKey));
});
}
}
}

View file

@ -45,8 +45,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.SimpleRegistry;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
@ -62,16 +62,16 @@ import net.fabricmc.fabric.impl.registry.sync.RemappableRegistry;
public abstract class MixinIdRegistry<T> implements RemappableRegistry, ListenableRegistry {
@Shadow
@Final
private ObjectList<T> rawIdToEntry;
private ObjectList<T> field_26682;
@Shadow
@Final
private Object2IntMap<T> entryToRawId;
private Object2IntMap<T> field_26683;
@Shadow
@Final
private BiMap<Identifier, T> idToEntry;
private BiMap<Identifier, T> entriesById;
@Shadow
@Final
private BiMap<RegistryKey<T>, T> keyToEntry;
private BiMap<RegistryKey<T>, T> entriesByKey;
@Shadow
private int nextId;
@Unique
@ -135,23 +135,23 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
private boolean fabric_isObjectNew = false;
@SuppressWarnings({"unchecked", "ConstantConditions"})
@Inject(method = "set", at = @At("HEAD"))
public void setPre(int id, RegistryKey<T> registryId, Object object, Lifecycle lifecycle, CallbackInfoReturnable info) {
int indexedEntriesId = entryToRawId.getInt((T) object);
@Inject(method = "method_31051", at = @At("HEAD"))
public void setPre(int id, RegistryKey<T> registryId, Object object, Lifecycle lifecycle, boolean checkDuplicateKeys, CallbackInfoReturnable info) {
int indexedEntriesId = field_26683.getInt((T) object);
if (indexedEntriesId >= 0) {
throw new RuntimeException("Attempted to register object " + object + " twice! (at raw IDs " + indexedEntriesId + " and " + id + " )");
}
if (!idToEntry.containsKey(registryId.getValue())) {
if (!entriesById.containsKey(registryId.getValue())) {
fabric_isObjectNew = true;
} else {
T oldObject = idToEntry.get(registryId.getValue());
T oldObject = entriesById.get(registryId.getValue());
if (oldObject != null && oldObject != object) {
int oldId = entryToRawId.getInt(oldObject);
int oldId = field_26683.getInt(oldObject);
if (oldId != id) {
if (oldId != id && checkDuplicateKeys) {
throw new RuntimeException("Attempted to register ID " + registryId + " at different raw IDs (" + oldId + ", " + id + ")! If you're trying to override an item, use .set(), not .register()!");
}
@ -164,8 +164,8 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
}
@SuppressWarnings("unchecked")
@Inject(method = "set", at = @At("RETURN"))
public void setPost(int id, RegistryKey<T> registryId, Object object, Lifecycle lifecycle, CallbackInfoReturnable info) {
@Inject(method = "method_31051", at = @At("RETURN"))
public void setPost(int id, RegistryKey<T> registryId, Object object, Lifecycle lifecycle, boolean checkDuplicateKeys, CallbackInfoReturnable info) {
if (fabric_isObjectNew) {
fabric_addObjectEvent.invoker().onEntryAdded(id, registryId.getValue(), object);
}
@ -184,7 +184,7 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
List<String> strings = null;
for (Identifier remoteId : remoteIndexedEntries.keySet()) {
if (!idToEntry.keySet().contains(remoteId)) {
if (!entriesById.keySet().contains(remoteId)) {
if (strings == null) {
strings = new ArrayList<>();
}
@ -206,11 +206,11 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
break;
}
case EXACT: {
if (!idToEntry.keySet().equals(remoteIndexedEntries.keySet())) {
if (!entriesById.keySet().equals(remoteIndexedEntries.keySet())) {
List<String> strings = new ArrayList<>();
for (Identifier remoteId : remoteIndexedEntries.keySet()) {
if (!idToEntry.keySet().contains(remoteId)) {
if (!entriesById.keySet().contains(remoteId)) {
strings.add(" - " + remoteId + " (missing on local)");
}
}
@ -242,7 +242,7 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
// compatibility.
if (fabric_prevIndexedEntries == null) {
fabric_prevIndexedEntries = new Object2IntOpenHashMap<>();
fabric_prevEntries = HashBiMap.create(idToEntry);
fabric_prevEntries = HashBiMap.create(entriesById);
for (Object o : registry) {
fabric_prevIndexedEntries.put(registry.getId(o), registry.getRawId(o));
@ -297,8 +297,8 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
}
// note: indexedEntries cannot be safely remove()d from
idToEntry.keySet().removeAll(droppedIds);
keyToEntry.keySet().removeIf(registryKey -> droppedIds.contains(registryKey.getValue()));
entriesById.keySet().removeAll(droppedIds);
entriesByKey.keySet().removeIf(registryKey -> droppedIds.contains(registryKey.getValue()));
break;
}
@ -306,7 +306,7 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
Int2IntMap idMap = new Int2IntOpenHashMap();
for (Object o : rawIdToEntry) {
for (Object o : field_26682) {
Identifier id = registry.getId(o);
int rid = registry.getRawId(o);
@ -317,8 +317,8 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
}
// entries was handled above, if it was necessary.
rawIdToEntry.clear();
entryToRawId.clear();
field_26682.clear();
field_26683.clear();
nextId = 0;
List<Identifier> orderedRemoteEntries = new ArrayList<>(remoteIndexedEntries.keySet());
@ -326,7 +326,7 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
for (Identifier identifier : orderedRemoteEntries) {
int id = remoteIndexedEntries.getInt(identifier);
T object = idToEntry.get(identifier);
T object = entriesById.get(identifier);
// Warn if an object is missing from the local registry.
// This should only happen in AUTHORITATIVE mode, and as such we
@ -342,9 +342,9 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
}
// Add the new object, increment nextId to match.
rawIdToEntry.size(Math.max(this.rawIdToEntry.size(), id + 1));
rawIdToEntry.set(id, object);
entryToRawId.put(object, id);
field_26682.size(Math.max(this.field_26682.size(), id + 1));
field_26682.set(id, object);
field_26683.put(object, id);
if (nextId <= id) {
nextId = id + 1;
@ -362,26 +362,26 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
// Emit AddObject events for previously culled objects.
for (Identifier id : fabric_prevEntries.keySet()) {
if (!idToEntry.containsKey(id)) {
if (!entriesById.containsKey(id)) {
assert fabric_prevIndexedEntries.containsKey(id);
addedIds.add(id);
}
}
idToEntry.clear();
keyToEntry.clear();
entriesById.clear();
entriesByKey.clear();
idToEntry.putAll(fabric_prevEntries);
entriesById.putAll(fabric_prevEntries);
for (Map.Entry<Identifier, T> entry : fabric_prevEntries.entrySet()) {
//noinspection unchecked
keyToEntry.put(RegistryKey.of(RegistryKey.ofRegistry(((Registry) Registry.REGISTRIES).getId(this)), entry.getKey()), entry.getValue());
entriesByKey.put(RegistryKey.of(RegistryKey.ofRegistry(((Registry) Registry.REGISTRIES).getId(this)), entry.getKey()), entry.getValue());
}
remap(name, fabric_prevIndexedEntries, RemapMode.AUTHORITATIVE);
for (Identifier id : addedIds) {
fabric_getAddObjectEvent().invoker().onEntryAdded(entryToRawId.getInt(idToEntry.get(id)), id, idToEntry.get(id));
fabric_getAddObjectEvent().invoker().onEntryAdded(field_26683.getInt(entriesById.get(id)), id, entriesById.get(id));
}
fabric_prevIndexedEntries = null;

View file

@ -10,7 +10,9 @@
"MixinPlayerManager",
"MixinLevelStorageSession",
"MixinRegistry",
"MixinSimpleRegistry"
"MixinSimpleRegistry",
"DynamicRegistryManagerAccessor",
"DynamicRegistryManagerMixin"
],
"client": [
"client.MixinBlockColorMap",

View file

@ -28,9 +28,10 @@ import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.registry.DynamicRegistryEntryAddedCallback;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
import net.fabricmc.fabric.api.event.registry.RegistryAttributeHolder;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
public class RegistrySyncTest implements ModInitializer {
/**
@ -65,8 +66,14 @@ public class RegistrySyncTest implements ModInitializer {
Registry.register(fabricRegistry, new Identifier("registry_sync", "test"), "test");
Validate.isTrue(Registry.REGISTRIES.getIds().contains(new Identifier("registry_sync", "fabric_registry")));
Validate.isTrue(RegistryAttributeHolder.get(fabricRegistry).hasAttribute(RegistryAttribute.MODDED));
Validate.isTrue(RegistryAttributeHolder.get(fabricRegistry).hasAttribute(RegistryAttribute.SYNCED));
Validate.isTrue(!RegistryAttributeHolder.get(fabricRegistry).hasAttribute(RegistryAttribute.PERSISTED));
DynamicRegistryEntryAddedCallback.event(Registry.BIOME_KEY).register((rawId, key, object, registry) -> {
System.out.println(key);
});
}
}