mirror of
https://github.com/FabricMC/fabric.git
synced 2025-07-29 15:39:55 -04:00
Added DynamicRegistryEntryAddedCallback
This commit is contained in:
parent
74685c149c
commit
e9c7de9661
8 changed files with 213 additions and 36 deletions
build.gradle
fabric-registry-sync-v0/src
main
java/net/fabricmc/fabric
api/event/registry
impl/registry/sync
mixin/registry/sync
resources
testmod/java/net/fabricmc/fabric/test/registry/sync
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
"MixinPlayerManager",
|
||||
"MixinLevelStorageSession",
|
||||
"MixinRegistry",
|
||||
"MixinSimpleRegistry"
|
||||
"MixinSimpleRegistry",
|
||||
"DynamicRegistryManagerAccessor",
|
||||
"DynamicRegistryManagerMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.MixinBlockColorMap",
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue