[#183] [fabric-registry-sync] major cleanup/DRY refactors

This commit is contained in:
Adrian Siekierka 2019-05-17 16:39:51 +02:00
parent eff4f58df6
commit 168284d8b5
25 changed files with 514 additions and 377 deletions

View file

@ -1,5 +1,5 @@
archivesBaseName = "fabric-registry-sync-v0"
version = getSubprojectVersion(project, "0.1.0")
version = getSubprojectVersion(project, "0.1.1")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')

View file

@ -1,62 +0,0 @@
/*
* 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;
import net.minecraft.util.IdList;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import java.util.HashMap;
import java.util.Map;
public class IdListUpdater<K, V> implements RegistryListener<K> {
public interface Container<V> {
IdList<V> getIdListForRegistryUpdating();
}
private final IdList<V> mappers;
private Map<Identifier, V> mapperCache = new HashMap<>();
public IdListUpdater(Container<V> container) {
this(container.getIdListForRegistryUpdating());
}
public IdListUpdater(IdList<V> mappers) {
this.mappers = mappers;
}
@Override
public void beforeRegistryCleared(Registry<K> registry) {
mapperCache.clear();
for (Identifier id : registry.getIds()) {
int rawId = registry.getRawId(registry.get(id));
V mapper = mappers.get(rawId);
if (mapper != null) {
mapperCache.put(id, mapper);
}
}
((ExtendedIdList) mappers).clear();
}
@Override
public void beforeRegistryRegistration(Registry<K> registry, int id, Identifier identifier, K object, boolean isNew) {
if (mapperCache.containsKey(identifier)) {
mappers.set(mapperCache.get(identifier), id);
}
}
}

View file

@ -16,6 +16,13 @@
package net.fabricmc.fabric.impl.registry;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPostRegisterCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreRegisterCallback;
public interface ListenableRegistry<T> {
void registerListener(RegistryListener<T> listener);
Event<RegistryPreClearCallback<T>> getPreClearEvent();
Event<RegistryPreRegisterCallback<T>> getPreRegisterEvent();
Event<RegistryPostRegisterCallback<T>> getPostRegisterEvent();
}

View file

@ -16,6 +16,8 @@
package net.fabricmc.fabric.impl.registry;
public interface ExtendedIdList {
public interface RemovableIdList<T> {
void clear();
void remove(T o);
void removeId(int i);
}

View file

@ -0,0 +1,20 @@
/*
* 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.callbacks;
public interface RegistryCallback<T> {
}

View file

@ -14,18 +14,11 @@
* limitations under the License.
*/
package net.fabricmc.fabric.impl.registry;
package net.fabricmc.fabric.impl.registry.callbacks;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public interface RegistryListener<T> {
default void beforeRegistryCleared(Registry<T> registry) {
}
default void beforeRegistryRegistration(Registry<T> registry, int id, Identifier identifier, T object, boolean isNew) {
}
default void afterRegistryRegistration(Registry<T> registry, int id, Identifier identifier, T object) {
}
@FunctionalInterface
public interface RegistryPostRegisterCallback<T> extends RegistryCallback<T> {
void onPostRegister(int rawId, Identifier id, T object);
}

View file

@ -0,0 +1,22 @@
/*
* 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.callbacks;
@FunctionalInterface
public interface RegistryPreClearCallback<T> extends RegistryCallback<T> {
void onPreClear();
}

View file

@ -0,0 +1,24 @@
/*
* 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.callbacks;
import net.minecraft.util.Identifier;
@FunctionalInterface
public interface RegistryPreRegisterCallback<T> extends RegistryCallback<T> {
void onPreRegister(int rawId, Identifier id, T object, boolean isNewToRegistry);
}

View file

@ -0,0 +1,66 @@
/*
* 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.trackers;
import net.fabricmc.fabric.impl.registry.RemovableIdList;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreRegisterCallback;
import net.minecraft.util.IdList;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import java.util.HashMap;
import java.util.Map;
public class IdListTracker<V, OV> implements RegistryPreClearCallback<V>, RegistryPreRegisterCallback<V> {
private final IdList<OV> mappers;
private final Registry<V> registry;
private Map<Identifier, OV> mapperCache = new HashMap<>();
private IdListTracker(Registry<V> registry, IdList<OV> mappers) {
this.registry = registry;
this.mappers = mappers;
}
public static <V, OV> void register(Registry<V> registry, IdList<OV> mappers) {
IdListTracker<V, OV> updater = new IdListTracker<>(registry, mappers);
((ListenableRegistry<V>) registry).getPreClearEvent().register(updater);
((ListenableRegistry<V>) registry).getPreRegisterEvent().register(updater);
}
@Override
public void onPreClear() {
mapperCache.clear();
for (Identifier id : registry.getIds()) {
int rawId = registry.getRawId(registry.get(id));
OV mapper = mappers.get(rawId);
if (mapper != null) {
mapperCache.put(id, mapper);
}
}
((RemovableIdList) mappers).clear();
}
@Override
public void onPreRegister(int id, Identifier identifier, V object, boolean isNewToRegistry) {
if (mapperCache.containsKey(identifier)) {
mappers.set(mapperCache.get(identifier), id);
}
}
}

View file

@ -0,0 +1,65 @@
/*
* 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.trackers;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreRegisterCallback;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import java.util.HashMap;
import java.util.Map;
public class Int2ObjectMapTracker<V, OV> implements RegistryPreClearCallback<V>, RegistryPreRegisterCallback<V> {
private final Int2ObjectMap<OV> mappers;
private final Registry<V> registry;
private Map<Identifier, OV> mapperCache = new HashMap<>();
private Int2ObjectMapTracker(Registry<V> registry, Int2ObjectMap<OV> mappers) {
this.registry = registry;
this.mappers = mappers;
}
public static <V, OV> void register(Registry<V> registry, Int2ObjectMap<OV> mappers) {
Int2ObjectMapTracker<V, OV> updater = new Int2ObjectMapTracker<>(registry, mappers);
((ListenableRegistry<V>) registry).getPreClearEvent().register(updater);
((ListenableRegistry<V>) registry).getPreRegisterEvent().register(updater);
}
@Override
public void onPreClear() {
mapperCache.clear();
for (Identifier id : registry.getIds()) {
int rawId = registry.getRawId(registry.get(id));
OV mapper = mappers.get(rawId);
if (mapper != null) {
mapperCache.put(id, mapper);
}
}
mappers.clear();
}
@Override
public void onPreRegister(int id, Identifier identifier, V object, boolean isNewToRegistry) {
if (mapperCache.containsKey(identifier)) {
mappers.put(id, mapperCache.get(identifier));
}
}
}

View file

@ -0,0 +1,54 @@
/*
* 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.trackers;
import net.fabricmc.fabric.impl.registry.RemovableIdList;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPostRegisterCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.minecraft.util.IdList;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.SimpleRegistry;
import java.util.Collection;
import java.util.function.Function;
public final class StateIdTracker<T, S> implements RegistryPreClearCallback<T>, RegistryPostRegisterCallback<T> {
private final IdList<S> stateList;
private final Function<T, Collection<S>> stateGetter;
public static <T, S> void register(SimpleRegistry<T> registry, IdList<S> stateList, Function<T, Collection<S>> stateGetter) {
StateIdTracker<T, S> tracker = new StateIdTracker<>(stateList, stateGetter);
((ListenableRegistry<T>) registry).getPreClearEvent().register(tracker);
((ListenableRegistry<T>) registry).getPostRegisterEvent().register(tracker);
}
private StateIdTracker(IdList<S> stateList, Function<T, Collection<S>> stateGetter) {
this.stateList = stateList;
this.stateGetter = stateGetter;
}
@Override
public void onPreClear() {
((RemovableIdList) stateList).clear();
}
@Override
public void onPostRegister(int rawId, Identifier id, T object) {
stateGetter.apply(object).forEach(stateList::add);
}
}

View file

@ -0,0 +1,51 @@
/*
* 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.trackers.vanilla;
import net.fabricmc.fabric.impl.registry.RemovableIdList;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPostRegisterCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
public final class BiomeParentTracker implements RegistryPreClearCallback<Biome>, RegistryPostRegisterCallback<Biome> {
private final Registry<Biome> registry;
private BiomeParentTracker(Registry<Biome> registry) {
this.registry = registry;
}
public static void register(Registry<Biome> registry) {
BiomeParentTracker tracker = new BiomeParentTracker(registry);
((ListenableRegistry<Biome>) registry).getPreClearEvent().register(tracker);
((ListenableRegistry<Biome>) registry).getPostRegisterEvent().register(tracker);
}
@Override
public void onPostRegister(int rawId, Identifier id, Biome object) {
if (object.hasParent()) {
Biome.PARENT_BIOME_ID_MAP.set(object, registry.getRawId(registry.get(new Identifier(object.getParent()))));
}
}
@Override
public void onPreClear() {
((RemovableIdList) Biome.PARENT_BIOME_ID_MAP).clear();
}
}

View file

@ -0,0 +1,47 @@
/*
* 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.trackers.vanilla;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPostRegisterCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreRegisterCallback;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.SimpleRegistry;
public final class BlockInitTracker implements RegistryPreRegisterCallback<Block> {
private BlockInitTracker() {
}
public static void register(SimpleRegistry<Block> registry) {
BlockInitTracker tracker = new BlockInitTracker();
((ListenableRegistry<Block>) registry).getPreRegisterEvent().register(tracker);
}
@Override
public void onPreRegister(int rawId, Identifier id, Block object, boolean isNewToRegistry) {
if (isNewToRegistry) {
object.getStateFactory().getStates().forEach(BlockState::initShapeCache);
object.getDropTableId();
}
}
}

View file

@ -14,25 +14,36 @@
* limitations under the License.
*/
package net.fabricmc.fabric.impl.registry.vanilla;
package net.fabricmc.fabric.impl.registry.trackers.vanilla;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPostRegisterCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
public class BootstrapItemRegistryListener implements RegistryListener<Item> {
@Override
public void beforeRegistryCleared(Registry<Item> registry) {
Item.BLOCK_ITEM_MAP.clear();
public final class BlockItemTracker implements RegistryPreClearCallback<Item>, RegistryPostRegisterCallback<Item> {
private BlockItemTracker() {
}
public static void register(SimpleRegistry<Item> registry) {
BlockItemTracker tracker = new BlockItemTracker();
((ListenableRegistry<Item>) registry).getPreClearEvent().register(tracker);
((ListenableRegistry<Item>) registry).getPostRegisterEvent().register(tracker);
}
@Override
public void beforeRegistryRegistration(Registry<Item> registry, int id, Identifier identifier, Item object, boolean isNew) {
// refer net.minecraft.item.Items
public void onPostRegister(int rawId, Identifier id, Item object) {
if (object instanceof BlockItem) {
((BlockItem) object).registerBlockItemMap(Item.BLOCK_ITEM_MAP, object);
}
}
@Override
public void onPreClear() {
Item.BLOCK_ITEM_MAP.clear();
}
}

View file

@ -1,38 +0,0 @@
/*
* 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.vanilla;
import net.fabricmc.fabric.impl.registry.ExtendedIdList;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
public class BootstrapBiomeRegistryListener implements RegistryListener<Biome> {
@Override
public void beforeRegistryCleared(Registry<Biome> registry) {
((ExtendedIdList) Biome.PARENT_BIOME_ID_MAP).clear();
}
@Override
public void beforeRegistryRegistration(Registry<Biome> registry, int id, Identifier identifier, Biome object, boolean isNew) {
// refer net.minecraft.biome.Biomes
if (object.hasParent()) {
Biome.PARENT_BIOME_ID_MAP.set(object, id);
}
}
}

View file

@ -1,46 +0,0 @@
/*
* 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.vanilla;
import net.fabricmc.fabric.impl.registry.ExtendedIdList;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public class BootstrapBlockRegistryListener implements RegistryListener<Block> {
@Override
public void beforeRegistryCleared(Registry<Block> registry) {
((ExtendedIdList) Block.STATE_IDS).clear();
}
@Override
public void beforeRegistryRegistration(Registry<Block> registry, int id, Identifier identifier, Block object, boolean isNew) {
// refer net.minecraft.block.Blocks
for (BlockState state : object.getStateFactory().getStates()) {
state.initShapeCache();
Block.STATE_IDS.add(state);
}
}
@Override
public void afterRegistryRegistration(Registry<Block> registry, int id, Identifier identifier, Block object) {
// refer net.minecraft.block.Blocks
object.getDropTableId();
}
}

View file

@ -1,39 +0,0 @@
/*
* 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.vanilla;
import net.fabricmc.fabric.impl.registry.ExtendedIdList;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public class BootstrapFluidRegistryListener implements RegistryListener<Fluid> {
@Override
public void beforeRegistryCleared(Registry<Fluid> registry) {
((ExtendedIdList) Fluid.STATE_IDS).clear();
}
@Override
public void beforeRegistryRegistration(Registry<Fluid> registry, int id, Identifier identifier, Fluid object, boolean isNew) {
// refer net.minecraft.fluid.Fluids
for (FluidState state : object.getStateFactory().getStates()) {
Fluid.STATE_IDS.add(state);
}
}
}

View file

@ -17,19 +17,18 @@
package net.fabricmc.fabric.mixin.registry;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.vanilla.BootstrapBiomeRegistryListener;
import net.fabricmc.fabric.impl.registry.vanilla.BootstrapBlockRegistryListener;
import net.fabricmc.fabric.impl.registry.vanilla.BootstrapFluidRegistryListener;
import net.fabricmc.fabric.impl.registry.vanilla.BootstrapItemRegistryListener;
import net.fabricmc.fabric.impl.registry.trackers.*;
import net.fabricmc.fabric.impl.registry.trackers.vanilla.BiomeParentTracker;
import net.fabricmc.fabric.impl.registry.trackers.vanilla.BlockInitTracker;
import net.fabricmc.fabric.impl.registry.trackers.vanilla.BlockItemTracker;
import net.minecraft.Bootstrap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -38,17 +37,27 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Bootstrap.class)
public class MixinBootstrap {
@SuppressWarnings("unchecked")
@Inject(method = "setOutputStreams", at = @At("RETURN"))
private static void initialize(CallbackInfo info) {
// access Blocks, Items, ...
Object o0 = Biomes.THE_END;
Object o1 = Blocks.AIR;
Object o3 = Fluids.EMPTY;
Object o2 = Items.AIR;
// These seemingly pointless accesses are done to make sure each
// static initializer is called, to register vanilla-provided blocks
// and items from the respective classes - otherwise, they would
// duplicate our calls from below.
Object oBiome = Biomes.THE_END;
Object oBlock = Blocks.AIR;
Object oFluid = Fluids.EMPTY;
Object oItem = Items.AIR;
((ListenableRegistry<Biome>) Registry.BIOME).registerListener(new BootstrapBiomeRegistryListener());
((ListenableRegistry<Block>) Registry.BLOCK).registerListener(new BootstrapBlockRegistryListener());
((ListenableRegistry<Fluid>) Registry.FLUID).registerListener(new BootstrapFluidRegistryListener());
((ListenableRegistry<Item>) Registry.ITEM).registerListener(new BootstrapItemRegistryListener());
// state ID tracking
StateIdTracker.register(Registry.BLOCK, Block.STATE_IDS, (block) -> block.getStateFactory().getStates());
StateIdTracker.register(Registry.FLUID, Fluid.STATE_IDS, (fluid) -> fluid.getStateFactory().getStates());
// map tracking
BiomeParentTracker.register(Registry.BIOME);
BlockItemTracker.register(Registry.ITEM);
// block initialization, like Blocks
BlockInitTracker.register(Registry.BLOCK);
}
}

View file

@ -16,22 +16,23 @@
package net.fabricmc.fabric.mixin.registry;
import net.fabricmc.fabric.impl.registry.ExtendedIdList;
import net.fabricmc.fabric.impl.registry.RemovableIdList;
import net.minecraft.util.IdList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import java.util.IdentityHashMap;
import java.util.List;
@Mixin(IdList.class)
public class MixinIdList implements ExtendedIdList {
public class MixinIdList implements RemovableIdList<Object> {
@Shadow
private int nextId;
@Shadow
private IdentityHashMap idMap;
private IdentityHashMap<Object, Integer> idMap;
@Shadow
private List list;
private List<Object> list;
@Override
public void clear() {
@ -39,4 +40,28 @@ public class MixinIdList implements ExtendedIdList {
idMap.clear();
list.clear();
}
@Unique
private void fabric_removeInner(Object o) {
int value = idMap.remove(o);
list.set(value, null);
while (nextId > 1 && list.get(nextId - 1) == null) {
nextId--;
}
}
@Override
public void remove(Object o) {
if (idMap.containsKey(o)) {
fabric_removeInner(o);
}
}
@Override
public void removeId(int i) {
Object obj = list.get(i);
if (obj != null) {
fabric_removeInner(obj);
}
}
}

View file

@ -20,10 +20,14 @@ import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.fabricmc.fabric.impl.registry.RemapException;
import net.fabricmc.fabric.impl.registry.RemappableRegistry;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPostRegisterCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreClearCallback;
import net.fabricmc.fabric.impl.registry.callbacks.RegistryPreRegisterCallback;
import net.minecraft.util.Identifier;
import net.minecraft.util.Int2ObjectBiMap;
import net.minecraft.util.registry.SimpleRegistry;
@ -37,7 +41,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.*;
@Mixin(SimpleRegistry.class)
public abstract class MixinIdRegistry<T> implements RemappableRegistry, ListenableRegistry<T>, RegistryListener<T> {
public abstract class MixinIdRegistry<T> implements RemappableRegistry, ListenableRegistry<T> {
@Shadow
protected static Logger LOGGER;
@Shadow
@ -47,42 +51,65 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
@Shadow
private int nextId;
private final Event<RegistryPreClearCallback> fabric_preClearEvent = EventFactory.createArrayBacked(RegistryPreClearCallback.class,
(callbacks) -> () -> {
for (RegistryPreClearCallback callback : callbacks) {
callback.onPreClear();
}
}
);
private final Event<RegistryPreRegisterCallback> fabric_preRegisterEvent = EventFactory.createArrayBacked(RegistryPreRegisterCallback.class,
(callbacks) -> (a, b, c, d) -> {
for (RegistryPreRegisterCallback callback : callbacks) {
//noinspection unchecked
callback.onPreRegister(a, b, c, d);
}
}
);
private final Event<RegistryPostRegisterCallback> fabric_postRegisterEvent = EventFactory.createArrayBacked(RegistryPostRegisterCallback.class,
(callbacks) -> (a, b, c) -> {
for (RegistryPostRegisterCallback callback : callbacks) {
//noinspection unchecked
callback.onPostRegister(a, b, c);
}
}
);
private Object2IntMap<Identifier> fabric_prevIndexedEntries;
private BiMap<Identifier, T> fabric_prevEntries;
private RegistryListener[] fabric_listeners;
@Override
public void registerListener(RegistryListener<T> listener) {
if (fabric_listeners == null) {
fabric_listeners = new RegistryListener[]{listener};
} else {
RegistryListener[] newListeners = new RegistryListener[fabric_listeners.length + 1];
System.arraycopy(fabric_listeners, 0, newListeners, 0, fabric_listeners.length);
newListeners[fabric_listeners.length] = listener;
fabric_listeners = newListeners;
public Event<RegistryPreClearCallback<T>> getPreClearEvent() {
//noinspection unchecked
return (Event<RegistryPreClearCallback<T>>) (Event) fabric_preClearEvent;
}
@Override
public Event<RegistryPreRegisterCallback<T>> getPreRegisterEvent() {
//noinspection unchecked
return (Event<RegistryPreRegisterCallback<T>>) (Event) fabric_preRegisterEvent;
}
@Override
public Event<RegistryPostRegisterCallback<T>> getPostRegisterEvent() {
//noinspection unchecked
return (Event<RegistryPostRegisterCallback<T>>) (Event) fabric_postRegisterEvent;
}
@SuppressWarnings({"unchecked", "ConstantConditions"})
@Inject(method = "set", at = @At("HEAD"))
public void setPre(int id, Identifier identifier, Object object, CallbackInfoReturnable info) {
SimpleRegistry<Object> registry = (SimpleRegistry<Object>) (Object) this;
if (fabric_listeners != null) {
for (RegistryListener listener : fabric_listeners) {
listener.beforeRegistryRegistration(registry, id, identifier, object, !entries.containsKey(identifier));
}
}
boolean isNewToRegistry = !entries.containsKey(identifier);
fabric_preRegisterEvent.invoker().onPreRegister(id, identifier, object, isNewToRegistry);
}
@SuppressWarnings({"unchecked", "ConstantConditions"})
@Inject(method = "set", at = @At("RETURN"))
public void setPost(int id, Identifier identifier, Object object, CallbackInfoReturnable info) {
SimpleRegistry<Object> registry = (SimpleRegistry<Object>) (Object) this;
if (fabric_listeners != null) {
for (RegistryListener listener : fabric_listeners) {
listener.afterRegistryRegistration(registry, id, identifier, object);
}
}
fabric_postRegisterEvent.invoker().onPostRegister(id, identifier, object);
}
@Override
@ -182,11 +209,7 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
}
// Inform about registry clearing.
if (fabric_listeners != null) {
for (RegistryListener listener : fabric_listeners) {
listener.beforeRegistryCleared(registry);
}
}
fabric_preClearEvent.invoker().onPreClear();
// entries was handled above, if it was necessary.
indexedEntries.clear();
@ -211,18 +234,17 @@ public abstract class MixinIdRegistry<T> implements RemappableRegistry, Listenab
continue;
}
//noinspection unchecked
fabric_preRegisterEvent.invoker().onPreRegister(id, identifier, object, false);
// Add the new object, increment nextId to match.
indexedEntries.put(object, id);
if (nextId <= id) {
nextId = id + 1;
}
// Notify listeners about the ID change.
if (fabric_listeners != null) {
for (RegistryListener listener : fabric_listeners) {
listener.beforeRegistryRegistration(registry, id, identifier, object, false);
}
}
//noinspection unchecked
fabric_postRegisterEvent.invoker().onPostRegister(id, identifier, object);
}
}

View file

@ -16,9 +16,7 @@
package net.fabricmc.fabric.mixin.registry.client;
import net.fabricmc.fabric.impl.registry.IdListUpdater;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.minecraft.block.Block;
import net.fabricmc.fabric.impl.registry.trackers.IdListTracker;
import net.minecraft.client.color.block.BlockColorProvider;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.util.IdList;
@ -27,20 +25,15 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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.CallbackInfo;
@Mixin(BlockColors.class)
public class MixinBlockColorMap implements IdListUpdater.Container<BlockColorProvider> {
public class MixinBlockColorMap {
@Shadow
private IdList<BlockColorProvider> providers;
@Inject(method = "create", at = @At("RETURN"))
private static void create(CallbackInfoReturnable<BlockColors> info) {
((ListenableRegistry) Registry.BLOCK).registerListener(new IdListUpdater<Block, BlockColorProvider>((IdListUpdater.Container<BlockColorProvider>) (Object) info.getReturnValue()));
}
@Override
public IdList<BlockColorProvider> getIdListForRegistryUpdating() {
return providers;
@Inject(method = "<init>", at = @At("RETURN"))
private void create(CallbackInfo info) {
IdListTracker.register(Registry.BLOCK, providers);
}
}

View file

@ -16,32 +16,24 @@
package net.fabricmc.fabric.mixin.registry.client;
import net.fabricmc.fabric.impl.registry.IdListUpdater;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.minecraft.client.color.block.BlockColors;
import net.fabricmc.fabric.impl.registry.trackers.IdListTracker;
import net.minecraft.client.color.item.ItemColorProvider;
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.item.Item;
import net.minecraft.util.IdList;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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.CallbackInfo;
@Mixin(ItemColors.class)
public class MixinItemColorMap implements IdListUpdater.Container<ItemColorProvider> {
public class MixinItemColorMap {
@Shadow
private IdList<ItemColorProvider> providers;
@Inject(method = "create", at = @At("RETURN"))
private static void create(BlockColors blockMap, CallbackInfoReturnable<ItemColors> info) {
((ListenableRegistry) Registry.ITEM).registerListener(new IdListUpdater<Item, ItemColorProvider>((IdListUpdater.Container<ItemColorProvider>) (Object) info.getReturnValue()));
}
@Override
public IdList<ItemColorProvider> getIdListForRegistryUpdating() {
return providers;
@Inject(method = "<init>", at = @At("RETURN"))
private void create(CallbackInfo info) {
IdListTracker.register(Registry.ITEM, providers);
}
}

View file

@ -17,14 +17,11 @@
package net.fabricmc.fabric.mixin.registry.client;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.fabricmc.fabric.impl.registry.trackers.Int2ObjectMapTracker;
import net.minecraft.client.render.item.ItemModels;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -32,59 +29,16 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
import java.util.Map;
@Mixin(ItemModels.class)
public class MixinItemModelMap implements RegistryListener<Item> {
public class MixinItemModelMap {
@Shadow
public Int2ObjectMap<ModelIdentifier> modelIds;
@Shadow
private Int2ObjectMap<BakedModel> models;
private Map<Identifier, ModelIdentifier> fabricModelIdMap;
private Map<Identifier, BakedModel> fabricModelMap;
@Inject(method = "<init>", at = @At("RETURN"))
public void onInit(BakedModelManager bakedModelManager, CallbackInfo info) {
((ListenableRegistry<Item>) Registry.ITEM).registerListener(this);
Int2ObjectMapTracker.register(Registry.ITEM, modelIds);
Int2ObjectMapTracker.register(Registry.ITEM, models);
}
@Override
public void beforeRegistryCleared(Registry<Item> registry) {
if (fabricModelIdMap == null) {
fabricModelIdMap = new HashMap<>();
fabricModelMap = new HashMap<>();
}
for (Identifier id : registry.getIds()) {
Item object = registry.get(id);
int rawId = registry.getRawId(object);
ModelIdentifier modelId = modelIds.get(rawId);
BakedModel bakedModel = models.get(rawId);
if (modelId != null) {
fabricModelIdMap.put(id, modelId);
}
if (bakedModel != null) {
fabricModelMap.put(id, bakedModel);
}
}
modelIds.clear();
models.clear();
}
@Override
public void beforeRegistryRegistration(Registry<Item> registry, int id, Identifier identifier, Item object, boolean isNew) {
if (fabricModelIdMap != null && fabricModelIdMap.containsKey(identifier)) {
modelIds.put(id, fabricModelIdMap.get(identifier));
}
if (fabricModelMap != null && fabricModelMap.containsKey(identifier)) {
models.put(id, fabricModelMap.get(identifier));
}
}
}

View file

@ -36,8 +36,6 @@ public class MixinMinecraftClient {
// Unmap the registry before loading a new SP/MP setup.
@Inject(at = @At("RETURN"), method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V")
public void disconnectAfter(Screen screen_1, CallbackInfo info) {
ClientSidePacketRegistryImpl.invalidateRegisteredIdList();
try {
RegistrySyncManager.unmap();
} catch (RemapException e) {

View file

@ -17,13 +17,10 @@
package net.fabricmc.fabric.mixin.registry.client;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.fabricmc.fabric.impl.registry.ListenableRegistry;
import net.fabricmc.fabric.impl.registry.RegistryListener;
import net.fabricmc.fabric.impl.registry.trackers.Int2ObjectMapTracker;
import net.minecraft.client.particle.ParticleFactory;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.client.texture.TextureManager;
import net.minecraft.particle.ParticleType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
@ -32,43 +29,13 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
import java.util.Map;
@Mixin(ParticleManager.class)
public class MixinParticleManager implements RegistryListener<ParticleType> {
public class MixinParticleManager {
@Shadow
private Int2ObjectMap<ParticleFactory<?>> factories;
private Map<Identifier, ParticleFactory<?>> fabricFactoryMap;
@Inject(method = "<init>", at = @At("RETURN"))
public void onInit(World world, TextureManager textureManager, CallbackInfo info) {
((ListenableRegistry<ParticleType>) Registry.PARTICLE_TYPE).registerListener(this);
}
@Override
public void beforeRegistryCleared(Registry<ParticleType> registry) {
if (fabricFactoryMap == null) {
fabricFactoryMap = new HashMap<>();
}
for (Identifier id : registry.getIds()) {
ParticleType object = registry.get(id);
int rawId = registry.getRawId(object);
ParticleFactory<?> factory = factories.get(rawId);
if (factory != null) {
fabricFactoryMap.put(id, factory);
}
}
factories.clear();
}
@Override
public void beforeRegistryRegistration(Registry<ParticleType> registry, int id, Identifier identifier, ParticleType object, boolean isNew) {
if (fabricFactoryMap != null && fabricFactoryMap.containsKey(identifier)) {
factories.put(id, fabricFactoryMap.get(identifier));
}
Int2ObjectMapTracker.register(Registry.PARTICLE_TYPE, factories);
}
}