From eee22d7e70b1d7fd84062bb4a46f0ceeaaebd354 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 28 Jul 2023 19:56:01 -0400 Subject: [PATCH 1/5] Upgrade markdown generation script, can now detect missing descriptions outside game --- .gitignore | 2 ++ scripts/gen-markdown-patchlist.py | 32 +++++++++++++++++++++++++------ scripts/modernfixlib.py | 22 +++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 scripts/modernfixlib.py diff --git a/.gitignore b/.gitignore index f427fdd2..c2fa78c1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ eclipse run libs media +__pycache__ +*.pyc classes/ .architectury-transformer/ fabric/fabricloader.log diff --git a/scripts/gen-markdown-patchlist.py b/scripts/gen-markdown-patchlist.py index 37ac1e0b..28b86299 100644 --- a/scripts/gen-markdown-patchlist.py +++ b/scripts/gen-markdown-patchlist.py @@ -1,22 +1,30 @@ #!/usr/bin/python3 -import json -import subprocess +import json, os, subprocess, sys +# to import other scripts in same folder +sys.path.append(os.path.dirname(os.path.realpath(__file__))) + from contextlib import redirect_stdout +from modernfixlib import get_valid_mixin_options branch_name = subprocess.check_output(['git', 'branch', '--show-current']).decode("utf-8").strip() with open('doc/generated/' + branch_name + '-Summary-of-Patches.md', 'w') as output_file: + all_current_mixin_options = get_valid_mixin_options() + options_missing_descriptions = set() with redirect_stdout(output_file): with open('common/src/main/resources/assets/modernfix/lang/en_us.json') as lang_json: lang_obj = json.loads(lang_json.read()) - option_names = [] + option_names = set() for key, value in lang_obj.items(): if key.startswith("modernfix.option.mixin."): - option_names.append(key.replace("modernfix.option.", "")) - option_names.sort() + option_names.add(key.replace("modernfix.option.", "")) + option_names_sorted = list(option_names) + option_names_sorted.sort() print() - for option in option_names: + for option in option_names_sorted: + if option not in all_current_mixin_options: + continue option_description = lang_obj.get("modernfix.option." + option) option_friendly_name = lang_obj.get("modernfix.option.name." + option) print(f"### `{option}`") @@ -24,3 +32,15 @@ with open('doc/generated/' + branch_name + '-Summary-of-Patches.md', 'w') as out if option_description is not None: print(option_description) print("") + else: + options_missing_descriptions.add(option) + options_missing_descriptions.update(all_current_mixin_options.difference(option_names)) + + # sort the list of missing descriptions and print them out if there are any + missing_descriptions_list = list(options_missing_descriptions) + missing_descriptions_list.sort() + num_missing = len(missing_descriptions_list) + if num_missing > 0: + print(f"Missing {num_missing} descriptions:") + for option in missing_descriptions_list: + print(f" - {option}") \ No newline at end of file diff --git a/scripts/modernfixlib.py b/scripts/modernfixlib.py new file mode 100644 index 00000000..032aacd7 --- /dev/null +++ b/scripts/modernfixlib.py @@ -0,0 +1,22 @@ + +import os +import re + +def get_valid_mixin_options(): + all_mixin_options = set() + # gather all mixins in mixin folders + for platform in [ "common", "fabric", "forge" ]: + base_path = f"{platform}/src/main/java/org/embeddedt/modernfix/{platform}/mixin" + for root, dirs, files in os.walk(base_path): + for file in files: + if file.endswith(".java"): + mixin_name = root.replace(base_path, "").replace(os.path.sep, ".") + if mixin_name.startswith("."): + mixin_name = mixin_name[1:] + all_mixin_options.add("mixin." + mixin_name) + # gather any mixin strings referenced in ModernFixEarlyConfig + with open('common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java') as config_java: + config_str = config_java.read() + for option in re.findall(r"\"(mixin(?:\.[a-z_]+)+)\"", config_str): + all_mixin_options.add(option) + return all_mixin_options \ No newline at end of file From 5225d89210090dc87465e9bd79799cc78475b2b5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 28 Jul 2023 20:10:10 -0400 Subject: [PATCH 2/5] Allow choosing custom path to language JSON Intended for use in dev, to allow pointing at the local 1.16 file as changes are made --- scripts/gen-markdown-patchlist.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/gen-markdown-patchlist.py b/scripts/gen-markdown-patchlist.py index 28b86299..35667b35 100644 --- a/scripts/gen-markdown-patchlist.py +++ b/scripts/gen-markdown-patchlist.py @@ -1,19 +1,24 @@ #!/usr/bin/python3 -import json, os, subprocess, sys +import argparse, json, os, subprocess, sys # to import other scripts in same folder sys.path.append(os.path.dirname(os.path.realpath(__file__))) from contextlib import redirect_stdout from modernfixlib import get_valid_mixin_options +parser = argparse.ArgumentParser(description='Generate ModernFix patch summary Markdown file.') +parser.add_argument('-p', '--langpath', default='common/src/main/resources/assets/modernfix/lang/en_us.json') + +args = parser.parse_args() + branch_name = subprocess.check_output(['git', 'branch', '--show-current']).decode("utf-8").strip() with open('doc/generated/' + branch_name + '-Summary-of-Patches.md', 'w') as output_file: all_current_mixin_options = get_valid_mixin_options() options_missing_descriptions = set() with redirect_stdout(output_file): - with open('common/src/main/resources/assets/modernfix/lang/en_us.json') as lang_json: + with open(args.langpath) as lang_json: lang_obj = json.loads(lang_json.read()) option_names = set() for key, value in lang_obj.items(): From c7b6a9ed9e161bcf5a2a900023da32aa6a158852 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 28 Jul 2023 20:38:45 -0400 Subject: [PATCH 3/5] Document 1.16 options --- .../assets/modernfix/lang/en_us.json | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/common/src/main/resources/assets/modernfix/lang/en_us.json b/common/src/main/resources/assets/modernfix/lang/en_us.json index 0ae67db5..b617bfa0 100644 --- a/common/src/main/resources/assets/modernfix/lang/en_us.json +++ b/common/src/main/resources/assets/modernfix/lang/en_us.json @@ -69,5 +69,37 @@ "modernfix.option.mixin.feature.branding": "Adds ModernFix to the branding list on the title screen, and also to the F3 screen.", "modernfix.option.mixin.feature.direct_stack_trace": "Normally off, can be enabled to force the raw stack trace to be dumped to the log when a crash occurs. Occasionally vanilla's crash report system fails to work properly and gives an entirely irrelevant stack trace/report.", "modernfix.option.mixin.feature.measure_time": "Uses a couple injections to measure world load time, datapack reload time, resource reload time, bootstrap time, and adds the necessary hooks to enable vanilla's unused profiler logic for resource reloading if so configured.", - "modernfix.option.mixin.feature.spam_thread_dump": "**To be used for debugging purposes only.** Causes a thread dump to be output to the log every 60 seconds. This can help to diagnose unexplained freezes during loading/gameplay." + "modernfix.option.mixin.feature.spam_thread_dump": "**To be used for debugging purposes only.** Causes a thread dump to be output to the log every 60 seconds. This can help to diagnose unexplained freezes during loading/gameplay.", + "modernfix.option.mixin.bugfix.chunk_deadlock": "Attempts to prevent chunk system deadlocks or provide additional debug information in the log when they occur. These deadlocks usually manifest as the server freezing indefinitely (e.g. entities not moving), while the client continues to work just fine.", + "modernfix.option.mixin.bugfix.chunk_deadlock.valhesia": "Patches Valhesia Structures to fix an issue in its code that causes frequent worldgen/chunkloading deadlocks.", + "modernfix.option.mixin.bugfix.cofh_core_crash": "Fixes a multithreading issue in CoFH Core that can cause rare crashes during launch.", + "modernfix.option.mixin.bugfix.ctm_resourceutil_cme": "Fixes a multithreading issue in ConnectedTexturesMod that can cause rare crashes during launch.", + "modernfix.option.mixin.bugfix.ender_dragon_leak": "Fixes a memory leak in vanilla caused by the ender dragon retaining a reference to the previous client world.", + "modernfix.option.mixin.bugfix.entity_load_deadlock": "Fixes many issues where EntityJoinWorldEvent/EntityJoinLevelEvent cause a worldgen deadlock, by slightly deferring entity loading. Should not, however, cause any noticeable behavior changes in-game.", + "modernfix.option.mixin.bugfix.fix_config_crashes": "Fixes Forge configs occasionally becoming corrupted when launching the game.", + "modernfix.option.mixin.bugfix.item_cache_flag": "Fixes MC-258939", + "modernfix.option.mixin.bugfix.preserve_early_window_pos": "Makes the game window retain its existing size when control is handed over from Forge's early loading to Minecraft code. Fixes the window teleporting back to the center of the screen after being dragged, etc.", + "modernfix.option.mixin.bugfix.refinedstorage.te_bug": "Fixes Refined Storage external storage blocks occasionally failing to show contents of drawers, etc. when loaded. Backport of Refined Storage PR #3435, which was only applied to 1.18 and later.", + "modernfix.option.mixin.bugfix.remove_block_chunkloading": "Fixes zombie pigmen keeping the 0, 0 chunk loaded perpetually on Forge. Backport of Forge PR #8583.", + "modernfix.option.mixin.bugfix.starlight_emptiness": "Fixes an occasional Starlight crash due to emptiness maps not being initialized. Backport of the same fix in Starlight for 1.18.x.", + "modernfix.option.mixin.core": "Core patches required for ModernFix to work", + "modernfix.option.mixin.devenv": "Patches used when running in a development environment, for speed improvement and/or testing", + "modernfix.option.mixin.safety": "Concurrency patches to prevent crashes during launch", + "modernfix.option.mixin.feature.integrated_server_watchdog": "Adds the vanilla watchdog to singleplayer worlds as well, but just prints out the stacktraces rather than forcefully terminating the world. This version includes the functionality of Fullstack Watchdog, but the latter is still needed for multiplayer.", + "modernfix.option.mixin.feature.snapshot_easter_egg": "Adds easter egg features (does not affect any vanilla visuals or behavior) when running on a snapshot version.", + "modernfix.option.mixin.feature.spark_profile_launch": "If enabled, and a compatible version of Spark is installed, the entire launch sequence will be profiled until the main menu.", + "modernfix.option.mixin.feature.warn_missing_perf_mods": "Shows a warning on startup if other performance mods considered essential and highly compatible are not present", + "modernfix.option.mixin.launch.class_search_cache": "Replaces Forge's resource finder (used to find game and a mod code) with a significantly faster version, speeding up launch", + "modernfix.option.mixin.perf.clear_fabric_mapping_tables": "Reduces memory usage by clearing mapping data structures in Fabric Loader that are either redundant or rarely used by mods. Off by default for compatibility reasons.", + "modernfix.option.mixin.perf.clear_mixin_classinfo": "Force-loads all mixins when launch finishes and then clears out mixin data structures to remove most of Mixin's memory footprint. Disabled by default for compatibility reasons.", + "modernfix.option.mixin.perf.deduplicate_wall_shapes": "Makes most wall blocks share the same shape object instead of each one having its own copy. Can reduce memory usage substantially when lots of wall blocks are added by mods.", + "modernfix.option.mixin.perf.dynamic_resources.ae2": "AE2 compatibility patch for dynamic resources", + "modernfix.option.mixin.perf.dynamic_resources.ctm": "CTM compatibility patch for dynamic resources", + "modernfix.option.mixin.perf.dynamic_resources.rs": "Refined Storage compatibility patch for dynamic resources", + "modernfix.option.mixin.perf.dynamic_resources.supermartijncore": "SuperMartijn642CoreLib compatibility patch for dynamic resources", + "modernfix.option.mixin.perf.faster_advancements": "Rewrites the advancement checking logic to be faster and not cause StackOverflowError in large packs. Port of Advancements Debug from Fabric.", + "modernfix.option.mixin.perf.patchouli_deduplicate_books": "Fix Patchouli books storing many empty items with NBT tags, reducing memory usage.", + "modernfix.option.mixin.perf.remove_spawn_chunks": "Completely removes spawn chunks from the game. They are no longer loaded at all, unlike Ksyxis.", + "modernfix.option.mixin.perf.use_integrated_resources.jepb": "", + "modernfix.option.mixin.perf.use_integrated_resources.jeresources": "" } From f036350b0a5c2527edad5cc17bdfb81b0003bb44 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 28 Jul 2023 21:04:53 -0400 Subject: [PATCH 4/5] Add option parenting, gate changes to sub-options when parent option is off --- .../core/config/ModernFixEarlyConfig.java | 28 +++++++++---------- .../modernfix/core/config/Option.java | 17 +++++++++++ .../modernfix/screen/OptionList.java | 15 ++++++++-- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 3ddd4905..c50a365e 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -128,21 +128,8 @@ public class ModernFixEarlyConfig { mixinsMissingMods.put(mixinClassName, requiredModId); else if(isClientOnly && !ModernFixPlatformHooks.INSTANCE.isClient()) mixinsMissingMods.put(mixinClassName, "[not client]"); - List mixinOptionNames = dotSplitter.splitToList(mixinClassName); - StringBuilder optionBuilder = new StringBuilder(mixinClassName.length()); - optionBuilder.append("mixin"); - // mixin.core, mixin.safety can be top-level, everything else must have a subcategory - boolean allowTopLevel; - if(mixinOptionNames.size() > 0) - allowTopLevel = mixinOptionNames.get(0).equals("core") || mixinOptionNames.get(0).equals("safety"); - else - allowTopLevel = false; - for(int i = 0; i < mixinOptionNames.size() - 1; i++) { - optionBuilder.append('.'); - optionBuilder.append(mixinOptionNames.get(i)); - if(i > 0 || allowTopLevel) - mixinOptions.add(optionBuilder.toString()); - } + String mixinCategoryName = "mixin." + mixinClassName.substring(0, mixinClassName.lastIndexOf('.')); + mixinOptions.add(mixinCategoryName); } } catch(IOException e) { ModernFix.LOGGER.error("Error scanning file " + mixinPath, e); @@ -202,6 +189,17 @@ public class ModernFixEarlyConfig { this.options.putIfAbsent(optionName, option); this.optionsByCategory.put(OptionCategories.getCategoryForOption(optionName), option); } + for(Map.Entry entry : this.options.entrySet()) { + int idx = entry.getKey().lastIndexOf('.'); + if(idx <= 0) + continue; + String potentialParentKey = entry.getKey().substring(0, idx); + Option potentialParent = this.options.get(potentialParentKey); + if(potentialParent != null) { + System.out.println(potentialParentKey + " -> " + entry.getKey()); + entry.getValue().setParent(potentialParent); + } + } // Defines the default rules which can be configured by the user or other mods. // You must manually add a rule for any new mixins not covered by an existing package rule. this.addMixinRule("launch.class_search_cache", true); diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java b/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java index f370e8bc..ed245764 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java @@ -11,6 +11,7 @@ public class Option { private Set modDefined = null; private boolean enabled; private boolean userDefined; + private Option parent = null; public Option(String name, boolean enabled, boolean userDefined) { this.name = name; @@ -37,10 +38,26 @@ public class Option { this.modDefined.add(modId); } + public void setParent(Option option) { + this.parent = option; + } + + public Option getParent() { + return this.parent; + } + public boolean isEnabled() { return this.enabled; } + /** + * Checks if this option will effectively be disabled (regardless of its own status) + * by the parent rule being disabled. + */ + public boolean isEffectivelyDisabledByParent() { + return this.parent != null && (!this.parent.enabled || this.parent.isEffectivelyDisabledByParent()); + } + public boolean isOverridden() { return this.isUserDefined() || this.isModDefined(); } diff --git a/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java b/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java index 8adc08e2..cc18edec 100644 --- a/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java +++ b/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java @@ -40,6 +40,13 @@ public class OptionList extends ContainerObjectSelectionList { return baseComponent; } + public void updateOptionEntryStatuses() { + for(Entry e : this.children()) { + if(e instanceof OptionEntry) { + ((OptionEntry)e).updateStatus(); + } + } + } public OptionList(ModernFixConfigScreen arg, Minecraft arg2) { super(arg2,arg.width + 45, arg.height, 43, arg.height - 32, 20); @@ -128,6 +135,7 @@ public class OptionList extends ContainerObjectSelectionList { this.option.setEnabled(!this.option.isEnabled(), !this.option.isUserDefined()); ModernFix.LOGGER.error("Unable to save config", e); } + OptionList.this.updateOptionEntryStatuses(); }, (btn, gfx, x, y) -> { if(this.option.isModDefined()) { String disablingMods = String.join(", ", this.option.getDefiningMods()); @@ -140,8 +148,7 @@ public class OptionList extends ContainerObjectSelectionList { ); } }); - if(this.option.isModDefined()) - this.toggleButton.active = false; + updateStatus(); this.helpButton = new Button(75, 0, 20, 20, new TextComponent("?"), (arg) -> { Minecraft.getInstance().setScreen(new ModernFixOptionInfoScreen(mainScreen, optionName)); }); @@ -152,6 +159,10 @@ public class OptionList extends ContainerObjectSelectionList { } } + void updateStatus() { + this.toggleButton.active = !(this.option.isModDefined() || this.option.isEffectivelyDisabledByParent()); + } + @Override public void render(PoseStack matrixStack, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTicks) { MutableComponent nameComponent = getOptionComponent(this.name); From 5da78f75656e353ffac70305a07df02055dbf2e9 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 28 Jul 2023 21:18:56 -0400 Subject: [PATCH 5/5] Render sub-options more nicely --- .../modernfix/core/config/Option.java | 14 +++++++ .../modernfix/screen/OptionList.java | 40 +++++++++++-------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java b/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java index ed245764..6eac9434 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/Option.java @@ -46,6 +46,13 @@ public class Option { return this.parent; } + public int getDepth() { + if(this.parent == null) + return 0; + else + return this.parent.getDepth() + 1; + } + public boolean isEnabled() { return this.enabled; } @@ -74,6 +81,13 @@ public class Option { return this.name; } + public String getSelfName() { + if(this.parent == null) + return this.name; + else + return this.name.substring(this.parent.getName().length() + 1); + } + public void clearModsDefiningValue() { this.modDefined = null; } diff --git a/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java b/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java index cc18edec..4405aac8 100644 --- a/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java +++ b/common/src/main/java/org/embeddedt/modernfix/screen/OptionList.java @@ -19,10 +19,11 @@ import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; import java.io.IOException; import java.util.*; -import java.util.stream.Collectors; public class OptionList extends ContainerObjectSelectionList { - private final int maxNameWidth; + private int maxNameWidth = 0; + + private static final int DEPTH_OFFSET = 20; private static final Component OPTION_ON = new TranslatableComponent("modernfix.option.on").withStyle(style -> style.withColor(ChatFormatting.GREEN)); private static final Component OPTION_OFF = new TranslatableComponent("modernfix.option.off").withStyle(style -> style.withColor(ChatFormatting.RED)); @@ -31,9 +32,9 @@ public class OptionList extends ContainerObjectSelectionList { private ModernFixConfigScreen mainScreen; - private static MutableComponent getOptionComponent(String optionName) { - String friendlyKey = "modernfix.option.name." + optionName; - TextComponent baseComponent = new TextComponent(optionName); + private static MutableComponent getOptionComponent(Option option) { + String friendlyKey = "modernfix.option.name." + option.getName(); + TextComponent baseComponent = new TextComponent(option.getSelfName()); if(I18n.exists(friendlyKey)) return new TranslatableComponent(friendlyKey).withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, baseComponent))); else @@ -48,12 +49,25 @@ public class OptionList extends ContainerObjectSelectionList { } } + private final Set