Skip to content

Commit ae65473

Browse files
Merge 26.1 with 26.2
5.27.5 - commit.2
2 parents 11022ef + 6276479 commit ae65473

4 files changed

Lines changed: 126 additions & 5 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx2G
44

55
# Mod properties
66
mod_id=modernfix
7-
version=5.27.5-build.1
7+
version=5.27.5-build.2
88

99
# Minecraft/Fabric
1010
minecraft_version=26.2-snapshot-2
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
2+
3+
import com.llamalad7.mixinextras.sugar.Local;
4+
import com.mojang.serialization.JsonOps;
5+
import net.minecraft.client.renderer.item.ClientItem;
6+
import net.minecraft.client.resources.model.ClientItemInfoLoader;
7+
import net.minecraft.core.RegistryAccess;
8+
import net.minecraft.resources.FileToIdConverter;
9+
import net.minecraft.resources.Identifier;
10+
import net.minecraft.server.packs.resources.Resource;
11+
import net.minecraft.util.PlaceholderLookupProvider;
12+
import net.minecraft.util.StrictJsonParser;
13+
import org.embeddedt.modernfix.ModernFix;
14+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
15+
import org.embeddedt.modernfix.dynresources.DynamicModelSystem;
16+
import org.spongepowered.asm.mixin.Mixin;
17+
import org.spongepowered.asm.mixin.Unique;
18+
import org.spongepowered.asm.mixin.injection.At;
19+
import org.spongepowered.asm.mixin.injection.ModifyArg;
20+
21+
import java.util.Map;
22+
import java.util.concurrent.CompletableFuture;
23+
import java.util.concurrent.CompletionStage;
24+
import java.util.function.Function;
25+
26+
@Mixin(ClientItemInfoLoader.class)
27+
@ClientOnlyMixin
28+
public abstract class MixinClientItemInfoLoader {
29+
@Unique
30+
private static final FileToIdConverter MFIX$ITEM_LISTER = FileToIdConverter.json("items");
31+
32+
@Unique
33+
private static volatile boolean MFIX$DYNAMIC_CLIENT_ITEMS_ENABLED = true;
34+
35+
@Unique
36+
private static volatile boolean MFIX$DYNAMIC_CLIENT_ITEMS_FAILURE_LOGGED = false;
37+
38+
@Unique
39+
private static ClientItem mfix$loadSingleClientItemInfo(Identifier resourceFileId, Resource resource, RegistryAccess.Frozen staticRegistries) {
40+
Identifier itemId = MFIX$ITEM_LISTER.fileToId(resourceFileId);
41+
try (var reader = resource.openAsReader()) {
42+
PlaceholderLookupProvider placeholderLookupProvider = new PlaceholderLookupProvider(staticRegistries);
43+
var context = placeholderLookupProvider.createSerializationContext(JsonOps.INSTANCE);
44+
return ClientItem.CODEC.parse(context, StrictJsonParser.parse(reader))
45+
.ifError(error -> ModernFix.LOGGER.error("Couldn't parse item model '{}' from pack '{}': {}", itemId, resource.sourcePackId(), error.message()))
46+
.result()
47+
.map(clientItem -> placeholderLookupProvider.hasRegisteredPlaceholders() ? clientItem.withRegistrySwapper(placeholderLookupProvider.createSwapper()) : clientItem)
48+
.orElse(null);
49+
} catch (Exception e) {
50+
ModernFix.LOGGER.error("Failed to open item model {} from pack '{}'", resourceFileId, resource.sourcePackId(), e);
51+
return null;
52+
}
53+
}
54+
55+
/**
56+
* @author embeddedt
57+
* @reason Load client item infos dynamically instead of all at once.
58+
*/
59+
@ModifyArg(method = "scheduleLoad", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenCompose(Ljava/util/function/Function;)Ljava/util/concurrent/CompletableFuture;"))
60+
private static Function<Map<Identifier, Resource>, ? extends CompletionStage<ClientItemInfoLoader.LoadedClientInfos>> skipAOTClientItemLoad(
61+
Function<Map<Identifier, Resource>, ? extends CompletionStage<ClientItemInfoLoader.LoadedClientInfos>> original,
62+
@Local(ordinal = 0) RegistryAccess.Frozen staticRegistries) {
63+
if (!MFIX$DYNAMIC_CLIENT_ITEMS_ENABLED) {
64+
return original;
65+
}
66+
return resourceMap -> CompletableFuture.completedFuture(DynamicModelSystem.createDynamicClientInfos(resourceMap, (resourceFileId, resource) -> {
67+
if (!MFIX$DYNAMIC_CLIENT_ITEMS_ENABLED) {
68+
return null;
69+
}
70+
try {
71+
return mfix$loadSingleClientItemInfo(resourceFileId, resource, staticRegistries);
72+
} catch (RuntimeException e) {
73+
MFIX$DYNAMIC_CLIENT_ITEMS_ENABLED = false;
74+
if (!MFIX$DYNAMIC_CLIENT_ITEMS_FAILURE_LOGGED) {
75+
MFIX$DYNAMIC_CLIENT_ITEMS_FAILURE_LOGGED = true;
76+
ModernFix.LOGGER.warn("Disabling dynamic client item info loading due to runtime failure", e);
77+
}
78+
return null;
79+
}
80+
}));
81+
}
82+
}

src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import it.unimi.dsi.fastutil.objects.ReferenceSets;
1414
import net.fabricmc.fabric.impl.client.model.loading.UnbakedModelDeserializerRegistry;
1515
import net.minecraft.client.color.block.BlockColors;
16+
import net.minecraft.client.renderer.item.ClientItem;
1617
import net.minecraft.client.renderer.block.dispatch.BlockStateModel;
1718
import net.minecraft.client.resources.model.cuboid.ItemModelGenerator;
1819
import net.minecraft.client.resources.model.BlockStateModelLoader;
@@ -32,6 +33,7 @@
3233
import org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.BlockStateDefinitionsAccessor;
3334
import org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.IdMapperAccessor;
3435
import org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.ModelDiscoveryAccessor;
36+
import org.jetbrains.annotations.Nullable;
3537

3638
import java.io.Reader;
3739
import java.util.AbstractSet;
@@ -46,6 +48,7 @@
4648
public class DynamicModelSystem {
4749
private static final FileToIdConverter MODEL_LISTER = FileToIdConverter.json("models");
4850
private static final FileToIdConverter BLOCKSTATE_LISTER = FileToIdConverter.json("blockstates");
51+
private static final FileToIdConverter ITEM_LISTER = FileToIdConverter.json("items");
4952

5053
public static final boolean DEBUG_DYNAMIC_MODEL_LOADING = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
5154

@@ -104,6 +107,41 @@ public BlockStateModelLoader.LoadedModels load(Identifier key) throws Exception
104107
}));
105108
}
106109

110+
public interface SingleClientItemEntryLoader {
111+
@Nullable ClientItem loadEntry(Identifier resourceFileId, Resource resource);
112+
}
113+
114+
public static ClientItemInfoLoader.LoadedClientInfos createDynamicClientInfos(Map<Identifier, Resource> resourceMap, SingleClientItemEntryLoader entryLoader) {
115+
Set<Identifier> itemIdSet = resourceMap.keySet().stream().map(ITEM_LISTER::fileToId).collect(Collectors.toUnmodifiableSet());
116+
LoadingCache<Identifier, Object> clientItemCache = CacheBuilder.newBuilder().softValues().maximumSize(1000).build(new CacheLoader<>() {
117+
@Override
118+
public Object load(Identifier key) {
119+
Identifier fileId = ITEM_LISTER.idToFile(key);
120+
Resource resource = resourceMap.get(fileId);
121+
if (resource == null) {
122+
return NULL_SENTINEL;
123+
}
124+
if (DEBUG_DYNAMIC_MODEL_LOADING) {
125+
ModernFix.LOGGER.info("Loading client item info {}", key);
126+
}
127+
try {
128+
ClientItem result = entryLoader.loadEntry(fileId, resource);
129+
return result != null ? result : NULL_SENTINEL;
130+
} catch (RuntimeException e) {
131+
ModernFix.LOGGER.warn("Failed to build dynamic client item info for {}", key, e);
132+
return NULL_SENTINEL;
133+
}
134+
}
135+
});
136+
return new ClientItemInfoLoader.LoadedClientInfos(Maps.asMap(itemIdSet, key -> {
137+
if (key == null) {
138+
return null;
139+
}
140+
Object value = clientItemCache.getUnchecked(key);
141+
return value == NULL_SENTINEL ? null : (ClientItem) value;
142+
}));
143+
}
144+
107145
public record DynamicResolver(Map<Identifier, UnbakedModel> inputModels,
108146
BlockStateModelLoader.LoadedModels loadedModels,
109147
ClientItemInfoLoader.LoadedClientInfos loadedClientInfos) {
@@ -167,7 +205,7 @@ public int getInt(Object key) {
167205
}
168206
}
169207

170-
private static final Object NULL_BAKED = new Object();
208+
private static final Object NULL_SENTINEL = new Object();
171209

172210
public static <K, U, V> Map<K, V> createDynamicBakedRegistry(Map<K, U> input, BiFunction<K, U, V> baker) {
173211
// TODO: support persistence of overrides
@@ -181,14 +219,14 @@ public Object load(K key) throws Exception {
181219
}
182220
return baker.apply(key, unbaked);
183221
} else {
184-
return NULL_BAKED;
222+
return NULL_SENTINEL;
185223
}
186224
}
187225
});
188226
return new DynamicRegistryMap<>(input.keySet(), k -> {
189227
if (k != null) {
190228
Object value = bakedCache.getUnchecked(k);
191-
if (value == NULL_BAKED) {
229+
if (value == NULL_SENTINEL) {
192230
value = null;
193231
}
194232
return (V) value;
@@ -197,4 +235,4 @@ public Object load(K key) throws Exception {
197235
}
198236
});
199237
}
200-
}
238+
}

src/main/resources/modernfix-common.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
"perf.dynamic_resources.IdMapperAccessor",
102102
"perf.dynamic_resources.MixinBlockState",
103103
"perf.dynamic_resources.MixinBlockStateModelLoader",
104+
"perf.dynamic_resources.MixinClientItemInfoLoader",
104105
"perf.dynamic_resources.MixinModelBakery",
105106
"perf.dynamic_resources.MixinModelManager",
106107
"perf.dynamic_resources.ModelDiscoveryAccessor",

0 commit comments

Comments
 (0)