Skip to content

Commit 90e8caa

Browse files
committed
Added mechanism to allow resource packs with modified core shaders to declare compatible features
Closes #323
1 parent 1fd3cd3 commit 90e8caa

File tree

2 files changed

+86
-20
lines changed

2 files changed

+86
-20
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 = new ResourceMetadataSerializer<>("immediatelyfast", CODEC);
36+
37+
}

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

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import net.minecraft.client.gl.ShaderProgramKey;
2424
import net.minecraft.resource.Resource;
2525
import net.minecraft.resource.ResourceManager;
26+
import net.minecraft.resource.ResourcePack;
2627
import net.minecraft.util.Identifier;
2728
import net.minecraft.util.profiler.Profiler;
2829
import net.raphimc.immediatelyfast.ImmediatelyFast;
2930
import net.raphimc.immediatelyfast.compat.CoreShaderBlacklist;
31+
import net.raphimc.immediatelyfast.feature.core.ImmediatelyFastResourcePackMetadata;
3032
import net.raphimc.immediatelyfast.injection.interfaces.IShaderProgram;
3133
import org.spongepowered.asm.mixin.Mixin;
3234
import org.spongepowered.asm.mixin.Shadow;
@@ -35,6 +37,10 @@
3537
import org.spongepowered.asm.mixin.injection.Inject;
3638
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
3739

40+
import java.io.IOException;
41+
import java.util.HashSet;
42+
import java.util.Set;
43+
3844
@Mixin(ShaderLoader.class)
3945
public abstract class MixinShaderLoader {
4046

@@ -43,48 +49,71 @@ public abstract class MixinShaderLoader {
4349

4450
@Inject(method = "apply(Lnet/minecraft/client/gl/ShaderLoader$Definitions;Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/profiler/Profiler;)V", at = @At("RETURN"))
4551
private void checkForCoreShaderModifications(ShaderLoader.Definitions definitions, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci) {
46-
boolean modified = false;
52+
if (ImmediatelyFast.config.experimental_disable_resource_pack_conflict_handling) {
53+
return;
54+
}
4755

56+
ResourcePack resourcePackWhichBreaksFontAtlasResizing = null;
57+
ResourcePack resourcePackWhichBreaksHudBatching = null;
58+
ResourcePack resourcePackWhichBreaksScreenBatching = null;
4859
try {
60+
final Set<ResourcePack> breakingResourcePacks = new HashSet<>();
4961
for (ShaderProgramKey shaderProgramKey : CoreShaderBlacklist.getBlacklist()) {
5062
if (this.cache.getOrLoadProgram(shaderProgramKey) instanceof IShaderProgram mixinShaderProgram) {
5163
if (mixinShaderProgram.immediatelyFast$getVertexShader() == null || mixinShaderProgram.immediatelyFast$getFragmentShader() == null) {
5264
continue;
5365
}
5466
final Identifier vertexShaderIdentifier = CompiledShader.Type.VERTEX.createFinder().toResourcePath(mixinShaderProgram.immediatelyFast$getVertexShader().getId());
55-
final Resource vertexShaderResource = resourceManager.getResource(vertexShaderIdentifier).orElse(null);
56-
if (vertexShaderResource != null && !vertexShaderResource.getPack().equals(MinecraftClient.getInstance().getDefaultResourcePack())) {
57-
modified = true;
58-
break;
67+
final ResourcePack vertexShaderResourcePack = resourceManager.getResource(vertexShaderIdentifier).map(Resource::getPack).orElse(null);
68+
if (vertexShaderResourcePack != null && !vertexShaderResourcePack.equals(MinecraftClient.getInstance().getDefaultResourcePack())) {
69+
breakingResourcePacks.add(vertexShaderResourcePack);
5970
}
6071
final Identifier fragmentShaderIdentifier = CompiledShader.Type.FRAGMENT.createFinder().toResourcePath(mixinShaderProgram.immediatelyFast$getFragmentShader().getId());
61-
final Resource fragmentShaderResource = resourceManager.getResource(fragmentShaderIdentifier).orElse(null);
62-
if (fragmentShaderResource != null && !fragmentShaderResource.getPack().equals(MinecraftClient.getInstance().getDefaultResourcePack())) {
63-
modified = true;
64-
break;
72+
final ResourcePack fragmentShaderResourcePack = resourceManager.getResource(fragmentShaderIdentifier).map(Resource::getPack).orElse(null);
73+
if (fragmentShaderResourcePack != null && !fragmentShaderResourcePack.equals(MinecraftClient.getInstance().getDefaultResourcePack())) {
74+
breakingResourcePacks.add(fragmentShaderResourcePack);
6575
}
6676
}
6777
}
68-
} catch (ShaderLoader.LoadException e) {
78+
for (ResourcePack resourcePack : breakingResourcePacks) {
79+
ImmediatelyFastResourcePackMetadata metadata = resourcePack.parseMetadata(ImmediatelyFastResourcePackMetadata.SERIALIZER);
80+
if (metadata == null) {
81+
metadata = ImmediatelyFastResourcePackMetadata.DEFAULT;
82+
}
83+
if (!metadata.compatibleFeatures().contains("font_atlas_resizing")) {
84+
resourcePackWhichBreaksFontAtlasResizing = resourcePack;
85+
}
86+
if (!metadata.compatibleFeatures().contains("hud_batching")) {
87+
resourcePackWhichBreaksHudBatching = resourcePack;
88+
}
89+
if (!metadata.compatibleFeatures().contains("experimental_screen_batching")) {
90+
resourcePackWhichBreaksScreenBatching = resourcePack;
91+
}
92+
}
93+
} catch (ShaderLoader.LoadException | IOException e) {
6994
ImmediatelyFast.LOGGER.error("Failed to check for core shader modifications", e);
7095
}
7196

72-
if (modified && !ImmediatelyFast.config.experimental_disable_resource_pack_conflict_handling) {
73-
ImmediatelyFast.LOGGER.warn("Core shader modifications detected. Temporarily disabling some parts of ImmediatelyFast.");
74-
if (ImmediatelyFast.runtimeConfig.font_atlas_resizing) {
75-
ImmediatelyFast.runtimeConfig.font_atlas_resizing = false;
76-
this.immediatelyFast$reloadFontStorages();
77-
}
78-
79-
ImmediatelyFast.runtimeConfig.hud_batching = false;
80-
ImmediatelyFast.runtimeConfig.experimental_screen_batching = false;
97+
if (ImmediatelyFast.runtimeConfig.font_atlas_resizing && resourcePackWhichBreaksFontAtlasResizing != null) {
98+
ImmediatelyFast.LOGGER.warn("Resource pack " + resourcePackWhichBreaksFontAtlasResizing.getId() + " is not compatible with font atlas resizing. Temporarily disabling font atlas resizing.");
99+
ImmediatelyFast.runtimeConfig.font_atlas_resizing = false;
100+
this.immediatelyFast$reloadFontStorages();
81101
} else {
82102
if (!ImmediatelyFast.runtimeConfig.font_atlas_resizing && ImmediatelyFast.config.font_atlas_resizing) {
83103
ImmediatelyFast.runtimeConfig.font_atlas_resizing = true;
84104
this.immediatelyFast$reloadFontStorages();
85105
}
86-
106+
}
107+
if (ImmediatelyFast.runtimeConfig.hud_batching && resourcePackWhichBreaksHudBatching != null) {
108+
ImmediatelyFast.LOGGER.warn("Resource pack " + resourcePackWhichBreaksHudBatching.getId() + " is not compatible with HUD batching. Temporarily disabling HUD batching.");
109+
ImmediatelyFast.runtimeConfig.hud_batching = false;
110+
} else {
87111
ImmediatelyFast.runtimeConfig.hud_batching = ImmediatelyFast.config.hud_batching;
112+
}
113+
if (ImmediatelyFast.runtimeConfig.experimental_screen_batching && resourcePackWhichBreaksScreenBatching != null) {
114+
ImmediatelyFast.LOGGER.warn("Resource pack " + resourcePackWhichBreaksScreenBatching.getId() + " is not compatible with experimental screen batching. Temporarily disabling experimental screen batching.");
115+
ImmediatelyFast.runtimeConfig.experimental_screen_batching = false;
116+
} else {
88117
ImmediatelyFast.runtimeConfig.experimental_screen_batching = ImmediatelyFast.config.experimental_screen_batching;
89118
}
90119
}

0 commit comments

Comments
 (0)