Skip to content

Commit 3c29f16

Browse files
committed
Added mechanism to allow resource packs with modified core shaders to declare compatible features
Closes #323
1 parent 19e6d05 commit 3c29f16

File tree

2 files changed

+94
-26
lines changed

2 files changed

+94
-26
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* This file is part of ImmediatelyFast - https://github.com/RaphiMC/ImmediatelyFast
3+
* Copyright (C) 2023-2025 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package net.raphimc.immediatelyfast.feature.core;
19+
20+
import com.mojang.serialization.Codec;
21+
import com.mojang.serialization.codecs.RecordCodecBuilder;
22+
import net.minecraft.resource.metadata.ResourceMetadataSerializer;
23+
24+
import java.util.Collections;
25+
import java.util.List;
26+
27+
public record ImmediatelyFastResourcePackMetadata(List<String> compatibleFeatures) {
28+
29+
public static final ImmediatelyFastResourcePackMetadata DEFAULT = new ImmediatelyFastResourcePackMetadata(Collections.emptyList());
30+
public static final Codec<ImmediatelyFastResourcePackMetadata> CODEC = RecordCodecBuilder.create(instance ->
31+
instance.group(
32+
Codec.STRING.listOf().fieldOf("compatible_features").forGetter(ImmediatelyFastResourcePackMetadata::compatibleFeatures)
33+
).apply(instance, ImmediatelyFastResourcePackMetadata::new)
34+
);
35+
public static final ResourceMetadataSerializer<ImmediatelyFastResourcePackMetadata> SERIALIZER = ResourceMetadataSerializer.fromCodec("immediatelyfast", CODEC);
36+
37+
}

common/src/main/java/net/raphimc/immediatelyfast/injection/mixins/core/compat/MixinGameRenderer.java

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import net.minecraft.client.render.GameRenderer;
2323
import net.minecraft.resource.Resource;
2424
import net.minecraft.resource.ResourceFactory;
25+
import net.minecraft.resource.ResourcePack;
2526
import net.minecraft.util.Identifier;
2627
import net.raphimc.immediatelyfast.ImmediatelyFast;
2728
import net.raphimc.immediatelyfast.compat.CoreShaderBlacklist;
29+
import net.raphimc.immediatelyfast.feature.core.ImmediatelyFastResourcePackMetadata;
2830
import org.spongepowered.asm.mixin.Final;
2931
import org.spongepowered.asm.mixin.Mixin;
3032
import org.spongepowered.asm.mixin.Shadow;
@@ -33,55 +35,84 @@
3335
import org.spongepowered.asm.mixin.injection.Inject;
3436
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
3537

38+
import java.io.IOException;
39+
import java.util.HashSet;
3640
import java.util.Map;
41+
import java.util.Set;
3742

3843
@Mixin(GameRenderer.class)
3944
public abstract class MixinGameRenderer {
4045

41-
@Shadow
42-
@Final
43-
MinecraftClient client;
44-
4546
@Shadow
4647
@Final
4748
private Map<String, ShaderProgram> programs;
4849

4950
@Inject(method = "loadPrograms", at = @At("RETURN"))
5051
private void checkForCoreShaderModifications(ResourceFactory factory, CallbackInfo ci) {
51-
boolean modified = false;
52-
for (Map.Entry<String, ShaderProgram> shaderProgramEntry : this.programs.entrySet()) {
53-
if (!CoreShaderBlacklist.isBlacklisted(shaderProgramEntry.getKey())) continue;
52+
if (ImmediatelyFast.config.experimental_disable_resource_pack_conflict_handling) {
53+
return;
54+
}
5455

55-
final Identifier vertexShaderIdentifier = Identifier.of("shaders/core/" + shaderProgramEntry.getValue().getVertexShader().getName() + ".vsh");
56-
final Resource vertexShaderResource = factory.getResource(vertexShaderIdentifier).orElse(null);
57-
if (vertexShaderResource != null && !vertexShaderResource.getPack().equals(this.client.getDefaultResourcePack())) {
58-
modified = true;
59-
break;
56+
ResourcePack resourcePackWhichBreaksFontAtlasResizing = null;
57+
ResourcePack resourcePackWhichBreaksHudBatching = null;
58+
ResourcePack resourcePackWhichBreaksScreenBatching = null;
59+
try {
60+
final Set<ResourcePack> breakingResourcePacks = new HashSet<>();
61+
for (Map.Entry<String, ShaderProgram> shaderProgramEntry : this.programs.entrySet()) {
62+
if (!CoreShaderBlacklist.isBlacklisted(shaderProgramEntry.getKey())) continue;
63+
64+
final Identifier vertexShaderIdentifier = Identifier.of("shaders/core/" + shaderProgramEntry.getValue().getVertexShader().getName() + ".vsh");
65+
final ResourcePack vertexShaderResourcePack = factory.getResource(vertexShaderIdentifier).map(Resource::getPack).orElse(null);
66+
if (vertexShaderResourcePack != null && !vertexShaderResourcePack.equals(MinecraftClient.getInstance().getDefaultResourcePack())) {
67+
breakingResourcePacks.add(vertexShaderResourcePack);
68+
}
69+
final Identifier fragmentShaderIdentifier = Identifier.of("shaders/core/" + shaderProgramEntry.getValue().getFragmentShader().getName() + ".fsh");
70+
final ResourcePack fragmentShaderResourcePack = factory.getResource(fragmentShaderIdentifier).map(Resource::getPack).orElse(null);
71+
if (fragmentShaderResourcePack != null && !fragmentShaderResourcePack.equals(MinecraftClient.getInstance().getDefaultResourcePack())) {
72+
breakingResourcePacks.add(fragmentShaderResourcePack);
73+
}
6074
}
61-
final Identifier fragmentShaderIdentifier = Identifier.of("shaders/core/" + shaderProgramEntry.getValue().getFragmentShader().getName() + ".fsh");
62-
final Resource fragmentShaderResource = factory.getResource(fragmentShaderIdentifier).orElse(null);
63-
if (fragmentShaderResource != null && !fragmentShaderResource.getPack().equals(this.client.getDefaultResourcePack())) {
64-
modified = true;
65-
break;
75+
for (ResourcePack resourcePack : breakingResourcePacks) {
76+
ImmediatelyFastResourcePackMetadata metadata = resourcePack.parseMetadata(ImmediatelyFastResourcePackMetadata.SERIALIZER);
77+
if (metadata == null) {
78+
metadata = ImmediatelyFastResourcePackMetadata.DEFAULT;
79+
}
80+
if (!metadata.compatibleFeatures().contains("font_atlas_resizing")) {
81+
resourcePackWhichBreaksFontAtlasResizing = resourcePack;
82+
}
83+
if (!metadata.compatibleFeatures().contains("hud_batching")) {
84+
resourcePackWhichBreaksHudBatching = resourcePack;
85+
}
86+
if (!metadata.compatibleFeatures().contains("experimental_screen_batching")) {
87+
resourcePackWhichBreaksScreenBatching = resourcePack;
88+
}
6689
}
90+
} catch (IOException e) {
91+
ImmediatelyFast.LOGGER.error("Failed to check for core shader modifications", e);
6792
}
6893

69-
if (modified && !ImmediatelyFast.config.experimental_disable_resource_pack_conflict_handling) {
70-
ImmediatelyFast.LOGGER.warn("Core shader modifications detected. Temporarily disabling some parts of ImmediatelyFast.");
71-
if (ImmediatelyFast.runtimeConfig.font_atlas_resizing) {
72-
ImmediatelyFast.runtimeConfig.font_atlas_resizing = false;
73-
this.immediatelyFast$reloadFontStorages();
74-
}
75-
76-
ImmediatelyFast.runtimeConfig.hud_batching = false;
94+
if (ImmediatelyFast.runtimeConfig.font_atlas_resizing && resourcePackWhichBreaksFontAtlasResizing != null) {
95+
ImmediatelyFast.LOGGER.warn("Resource pack " + resourcePackWhichBreaksFontAtlasResizing.getId() + " is not compatible with font atlas resizing. Temporarily disabling font atlas resizing.");
96+
ImmediatelyFast.runtimeConfig.font_atlas_resizing = false;
97+
this.immediatelyFast$reloadFontStorages();
7798
} else {
7899
if (!ImmediatelyFast.runtimeConfig.font_atlas_resizing && ImmediatelyFast.config.font_atlas_resizing) {
79100
ImmediatelyFast.runtimeConfig.font_atlas_resizing = true;
80101
this.immediatelyFast$reloadFontStorages();
81102
}
82-
103+
}
104+
if (ImmediatelyFast.runtimeConfig.hud_batching && resourcePackWhichBreaksHudBatching != null) {
105+
ImmediatelyFast.LOGGER.warn("Resource pack " + resourcePackWhichBreaksHudBatching.getId() + " is not compatible with HUD batching. Temporarily disabling HUD batching.");
106+
ImmediatelyFast.runtimeConfig.hud_batching = false;
107+
} else {
83108
ImmediatelyFast.runtimeConfig.hud_batching = ImmediatelyFast.config.hud_batching;
84109
}
110+
if (ImmediatelyFast.runtimeConfig.experimental_screen_batching && resourcePackWhichBreaksScreenBatching != null) {
111+
ImmediatelyFast.LOGGER.warn("Resource pack " + resourcePackWhichBreaksScreenBatching.getId() + " is not compatible with experimental screen batching. Temporarily disabling experimental screen batching.");
112+
ImmediatelyFast.runtimeConfig.experimental_screen_batching = false;
113+
} else {
114+
ImmediatelyFast.runtimeConfig.experimental_screen_batching = ImmediatelyFast.config.experimental_screen_batching;
115+
}
85116
}
86117

87118
@Unique

0 commit comments

Comments
 (0)