88import net .minecraft .text .MutableText ;
99import net .minecraft .text .Text ;
1010import net .minecraft .util .Identifier ;
11+ import org .jetbrains .annotations .NotNull ;
1112import org .slf4j .Logger ;
1213import org .slf4j .LoggerFactory ;
1314import java .io .IOException ;
14- import java .util .ArrayList ;
15- import java .util .Arrays ;
16- import java .util .HashMap ;
17- import java .util .List ;
18- import java .util .Map ;
15+ import java .util .*;
16+ import java .util .stream .Collectors ;
1917
2018public class ResourcePackScanner {
21-
22- private static final Logger LOGGER = LoggerFactory .getLogger ("Sodium-InGameChecks" );
23- private static final List <String > VSH_FSH_BLACKLIST = Arrays .asList (
24- "rendertype_solid.vsh" , "rendertype_solid.fsh" ,
25- "rendertype_cutout_mipped.vsh" , "rendertype_cutout_mipped.fsh" ,
26- "rendertype_cutout.vsh" , "rendertype_cutout.fsh" ,
27- "rendertype_translucent.vsh" , "rendertype_translucent.fsh" ,
28- "rendertype_tripwire.vsh" , "rendertype_tripwire.fsh"
19+ private static final Logger LOGGER = LoggerFactory .getLogger ("Sodium-ResourcePackScanner" );
20+
21+ private static final Set <String > SHADER_PROGRAM_BLACKLIST = Set .of (
22+ "rendertype_solid.vsh" ,
23+ "rendertype_solid.fsh" ,
24+ "rendertype_cutout_mipped.vsh" ,
25+ "rendertype_cutout_mipped.fsh" ,
26+ "rendertype_cutout.vsh" ,
27+ "rendertype_cutout.fsh" ,
28+ "rendertype_translucent.vsh" ,
29+ "rendertype_translucent.fsh" ,
30+ "rendertype_tripwire.vsh" ,
31+ "rendertype_tripwire.fsh"
2932 );
30- private static final List <String > GLSL_BLACKLIST = Arrays .asList (
33+
34+ private static final Set <String > SHADER_INCLUDE_BLACKLIST = Set .of (
3135 "light.glsl" ,
3236 "fog.glsl"
3337 );
@@ -40,85 +44,138 @@ public class ResourcePackScanner {
4044 * Detailed information on shader files replaced by resource packs is printed in the client log.
4145 */
4246 public static void checkIfCoreShaderLoaded (ResourceManager manager ) {
43- HashMap <String , MessageLevel > detectedResourcePacks = new HashMap <>();
44- var customResourcePacks = manager .streamResourcePacks ();
45-
46- customResourcePacks .forEach (resourcePack -> {
47- // Omit 'vanilla' and 'fabric' resource packs
48- if (!resourcePack .getName ().equals ("vanilla" ) && !resourcePack .getName ().equals ("fabric" )) {
49- var resourcePackName = resourcePack .getName ();
50- var ignoredShaders = determineIgnoredShaders (resourcePack );
47+ var outputs = manager .streamResourcePacks ()
48+ .filter (pack -> !isBuiltInResourcePack (pack ))
49+ .collect (Collectors .toMap (ResourcePack ::getName , ResourcePackScanner ::scanResources ));
5150
52- resourcePack . findResources ( ResourceType . CLIENT_RESOURCES , Identifier . DEFAULT_NAMESPACE , "shaders" , ( path , ignored ) -> {
53- // Trim full shader file path to only contain the filename
54- var shaderName = path . getPath (). substring ( path . getPath (). lastIndexOf ( '/' ) + 1 );
51+ printToasts ( outputs );
52+ printCompatibilityReport ( outputs );
53+ }
5554
56- // Check if the pack has already acknowledged the warnings in this file,
57- // in this case we report a different info log about the situation
58- if (ignoredShaders .contains (shaderName )) {
59- if (VSH_FSH_BLACKLIST .contains (shaderName )) {
60- LOGGER .info ("Resource pack '{}' replaces core shader '{}' but indicates it can be ignored" , resourcePackName , shaderName );
61- }
55+ private static void printToasts (Map <String , ScanResults > scanResults ) {
56+ var incompatibleResourcePacks = new ArrayList <String >();
57+ var likelyIncompatibleResourcePacks = new ArrayList <String >();
6258
63- if (GLSL_BLACKLIST .contains (shaderName )) {
64- LOGGER .info ("Resource pack '{}' replaces shader '{}' but indicates it can be ignored" , resourcePackName , shaderName );
65- }
66- return ;
67- }
59+ for (var entry : scanResults .entrySet ()) {
60+ var path = entry .getKey ();
61+ var result = entry .getValue ();
6862
69- if (VSH_FSH_BLACKLIST .contains (shaderName )) {
63+ if (!result .shaderPrograms .isEmpty ()) {
64+ incompatibleResourcePacks .add (path );
65+ } else if (!result .shaderIncludes .isEmpty ()) {
66+ likelyIncompatibleResourcePacks .add (path );
67+ }
68+ }
7069
71- if (!detectedResourcePacks .containsKey (resourcePackName )) {
72- detectedResourcePacks .put (resourcePackName , MessageLevel .SEVERE );
73- } else if (detectedResourcePacks .get (resourcePackName ) == MessageLevel .WARN ) {
74- detectedResourcePacks .replace (resourcePackName , MessageLevel .SEVERE );
75- }
70+ boolean shown = false ;
7671
77- LOGGER . error ( "Resource pack '{}' replaces core shader '{}'" , resourcePackName , shaderName );
78- }
72+ if (! incompatibleResourcePacks . isEmpty ()) {
73+ showConsoleMessage ( Text . translatable ( "sodium.console.core_shaders_error" ), MessageLevel . SEVERE );
7974
80- if (GLSL_BLACKLIST .contains (shaderName )) {
75+ for (var pack : incompatibleResourcePacks ) {
76+ showConsoleMessage (Text .literal (getResourcePackName (pack )), MessageLevel .SEVERE );
77+ }
8178
82- if (!detectedResourcePacks .containsKey (resourcePackName )) {
83- detectedResourcePacks .put (resourcePackName , MessageLevel .WARN );
84- }
79+ shown = true ;
80+ }
8581
86- LOGGER .error ("Resource pack '{}' replaces shader '{}'" , resourcePackName , shaderName );
82+ if (!likelyIncompatibleResourcePacks .isEmpty ()) {
83+ showConsoleMessage (Text .translatable ("sodium.console.core_shaders_warn" ), MessageLevel .WARN );
8784
88- }
89- } );
85+ for ( var pack : likelyIncompatibleResourcePacks ) {
86+ showConsoleMessage ( Text . literal ( getResourcePackName ( pack )), MessageLevel . WARN );
9087 }
91- });
9288
93- if (detectedResourcePacks .containsValue (MessageLevel .SEVERE )) {
94- showConsoleMessage (Text .translatable ("sodium.console.core_shaders_error" ), MessageLevel .SEVERE );
89+ shown = true ;
90+ }
91+
92+ if (shown ) {
93+ showConsoleMessage (Text .translatable ("sodium.console.core_shaders_info" ), MessageLevel .INFO );
94+ }
95+ }
96+
97+ private static void printCompatibilityReport (Map <String , ScanResults > scanResults ) {
98+ var builder = new StringBuilder ();
99+
100+ for (var entry : scanResults .entrySet ()) {
101+ var path = entry .getKey ();
102+ var result = entry .getValue ();
95103
96- for (Map .Entry <String , MessageLevel > entry : detectedResourcePacks .entrySet ()) {
104+ builder .append ("- Resource pack: " ).append (getResourcePackName (path )).append ("\n " );
105+
106+ if (!result .shaderPrograms .isEmpty ()) {
107+ emitProblem (builder ,
108+ "The resource pack replaces terrain shaders, which are not supported" ,
109+ "https://github.com/CaffeineMC/sodium-fabric/wiki/Resource-Packs" ,
110+ result .shaderPrograms );
111+ }
97112
98- if (entry . getValue () == MessageLevel . SEVERE ) {
99- // Omit 'file/' prefix for the in-game message
100- var message = entry . getKey (). startsWith ( "file/" ) ? entry . getKey (). substring ( 5 ) : entry . getKey ();
101- showConsoleMessage ( Text . literal ( message ), MessageLevel . SEVERE );
102- }
113+ if (! result . shaderIncludes . isEmpty () ) {
114+ emitProblem ( builder ,
115+ "The resource pack modifies shader include files, which are not fully supported" ,
116+ "https://github.com/CaffeineMC/sodium-fabric/wiki/Resource-Packs" ,
117+ result . shaderIncludes );
103118 }
104119 }
105120
106- if (detectedResourcePacks .containsValue (MessageLevel .WARN )) {
107- showConsoleMessage (Text .translatable ("sodium.console.core_shaders_warn" ), MessageLevel .WARN );
121+ if (!builder .isEmpty ()) {
122+ LOGGER .error ("The following compatibility issues were found with installed resource packs:\n {}" , builder );
123+ }
124+ }
108125
109- for (Map .Entry <String , MessageLevel > entry : detectedResourcePacks .entrySet ()) {
126+ private static void emitProblem (StringBuilder builder , String description , String url , List <String > resources ) {
127+ builder .append ("\t - Problem found: " ).append ("\n " );
128+ builder .append ("\t \t - Description:\n \t \t \t " ).append (description ).append ("\n " );
129+ builder .append ("\t \t - More information: " ).append (url ).append ("\n " );
130+ builder .append ("\t \t - Files: " ).append ("\n " );
110131
111- if (entry .getValue () == MessageLevel .WARN ) {
112- // Omit 'file/' prefix for the in-game message
113- var message = entry .getKey ().startsWith ("file/" ) ? entry .getKey ().substring (5 ) : entry .getKey ();
114- showConsoleMessage (Text .literal (message ), MessageLevel .WARN );
115- }
116- }
132+ for (var resource : resources ) {
133+ builder .append ("\t \t \t - " ).append (resource ).append ("\n " );
117134 }
135+ }
118136
119- if (!detectedResourcePacks .isEmpty ()) {
120- showConsoleMessage (Text .translatable ("sodium.console.core_shaders_info" ), MessageLevel .INFO );
137+ @ NotNull
138+ private static ScanResults scanResources (ResourcePack pack ) {
139+ final var ignoredShaders = determineIgnoredShaders (pack );
140+
141+ if (!ignoredShaders .isEmpty ()) {
142+ LOGGER .warn ("Resource pack '{}' indicates the following shaders should be ignored: {}" ,
143+ getResourcePackName (pack .getName ()), String .join (", " , ignoredShaders ));
121144 }
145+
146+ final var unsupportedShaderPrograms = new ArrayList <String >();
147+ final var unsupportedShaderIncludes = new ArrayList <String >();
148+
149+ pack .findResources (ResourceType .CLIENT_RESOURCES , Identifier .DEFAULT_NAMESPACE , "shaders" , (identifier , supplier ) -> {
150+ // Trim full shader file path to only contain the filename
151+ final var path = identifier .getPath ();
152+ final var name = path .substring (path .lastIndexOf ('/' ) + 1 );
153+
154+ // Check if the pack has already acknowledged the warnings in this file,
155+ // in this case we report a different info log about the situation
156+ if (ignoredShaders .contains (name )) {
157+ return ;
158+ }
159+
160+ // Check the path against known problem files
161+ if (SHADER_PROGRAM_BLACKLIST .contains (name )) {
162+ unsupportedShaderPrograms .add (path );
163+ } else if (SHADER_INCLUDE_BLACKLIST .contains (name )) {
164+ unsupportedShaderIncludes .add (path );
165+ }
166+ });
167+
168+ return new ScanResults (unsupportedShaderPrograms , unsupportedShaderIncludes );
169+ }
170+
171+ private static boolean isBuiltInResourcePack (ResourcePack pack ) {
172+ var name = pack .getName ();
173+ return name .equals ("vanilla" ) || name .equals ("fabric" );
174+ }
175+
176+ private static String getResourcePackName (String path ) {
177+ // Omit 'file/' prefix for the in-game message
178+ return path .startsWith ("file/" ) ? path .substring (5 ) : path ;
122179 }
123180
124181 /**
@@ -143,7 +200,10 @@ private static List<String> determineIgnoredShaders(ResourcePack resourcePack) {
143200 }
144201
145202 private static void showConsoleMessage (MutableText message , MessageLevel messageLevel ) {
146- Console .instance ().logMessage (messageLevel , message , 20.0 );
203+ Console .instance ().logMessage (messageLevel , message , 12.5 );
147204 }
148205
206+ private record ScanResults (ArrayList <String > shaderPrograms , ArrayList <String > shaderIncludes ) {
207+
208+ }
149209}
0 commit comments